Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 172 additions & 0 deletions .github/workflows/nmc-custom-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
name: MagentaCLOUD custom build strategy

# Test call: act --container-architecture linux/amd64 --secret-file ../secrets.env --env-file ../nmc-master-build.env -j build-custom

# we already try to build a custom release as soon as people
# created a customisation PR
on:
workflow_dispatch:

env:
TARGET_TRUNK: "master"
TARGET_STABLE: "nmcstable/25.0.6"
CUSTOM_REPO: ${{ github.repository }}
CUSTOM_BRANCH: ${{ github.ref }}
BUILD_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# BUILD_TOKEN: ${{ secrets.BUILD_TOKEN }}


jobs:
build-custom:
runs-on: ubuntu-latest
steps:

- name: "Find customisation candidates"
uses: octokit/[email protected]
id: find_customisations
env:
GITHUB_TOKEN: ${{ env.BUILD_TOKEN }}
with:
query: |
query findCustomisations($searchexpr: String!) {
search(query: $searchexpr, type: ISSUE, first: 100) {
edges {
node {
... on PullRequest {
state
number
title
baseRefName
headRefName
mergeable
isDraft
url
}
}
}
}
}
searchexpr: "type:pr state:open repo:${{ env.CUSTOM_REPO }} base:${{ env.TARGET_TRUNK }} base:${{ env.TARGET_STABLE }} label:custom label:build-ready"
# note that the search has OR semantice for base:, but AND semantice for label: !
# see: https://docs.github.com/en/search-github/searching-on-github/searching-issues-and-pull-requests#search-by-label
- id: customisations
run: |
pulls=$(echo '${{ steps.find_customisations.outputs.data }}' | jq -s '.[].search.edges | map(.node) | sort_by(.headRefName)')
echo ::set-output name=pulls::$pulls

- name: Picking backports
id: pickbackports
uses: actions/github-script@v6
env:
customisations: ${{ steps.customisations.outputs.pulls }}
target_trunk: ${{ env.TARGET_TRUNK }}
target_stable: ${{ env.TARGET_STABLE }}
with:
script: |
const customisations = JSON.parse(process.env.customisations);
const target_trunk = process.env.target_trunk;
const target_stable = process.env.target_stable;

function shuffleArray(array) {
return array.reduce((acc, current, index) => {
const randomIndex = Math.floor(Math.random() * (index + 1));
[acc[index], acc[randomIndex]] = [acc[randomIndex], acc[index]];
return acc;
}, [...array]);
}

function isBackportFor(port, master) {
if (( port.baseRefName === target_stable ) &&
( master.baseRefName === target_trunk ) &&
( port.headRefName.startsWith( master.headRefName ))) {
return true;
} else {
return false;
}
}

if ( target_stable == target_trunk ) {
// only sort out backports it it is not a master build
// which means that the target stable branch is not the name for the trunk branch
core.setOutput('buildparts', JSON.stringify(shuffleArray(customisations)) );
core.setOutput('newerparts', JSON.stringify([]) );
return "";
}

var buildparts = [];
var newerparts =[];

for (cIdx=0; cIdx < customisations.length; cIdx++) {
if (cIdx+1 < customisations.length) {
// detect master - backport pairs
if (isBackportFor( customisations[cIdx], customisations[cIdx+1] )) {
buildparts.push(customisations[cIdx]);
newerparts.push(customisations[cIdx+1]);
cIdx++;
} else if (isBackportFor( customisations[cIdx+1], customisations[cIdx] )) {
buildparts.push(customisations[cIdx+1]);
newerparts.push(customisations[cIdx]);
cIdx++;
} else {
// handle as single entry
buildparts.push(customisations[cIdx]);
}
} else {
// handle as last entry
buildparts.push(customisations[cIdx]);
}
}
core.setOutput('buildparts', JSON.stringify(shuffleArray(buildparts)) );
core.setOutput('newerparts', JSON.stringify(shuffleArray(newerparts)) );
return "";

# we exclude non-mergeable branches and exclude them from build
- name: Check mergeability
id: checkmergeable
uses: actions/github-script@v6
env:
buildparts: ${{ steps.pickbackports.outputs.buildparts }}
with:
script: |
const buildparts = JSON.parse(process.env.buildparts);
var mergeableparts = [];
result = 0;

buildparts.forEach( (buildpart) => {
if ( buildpart.mergeable === 'MERGEABLE' ) {
mergeableparts.push(buildpart);
} else {
notMergeableError = `${buildpart.mergeable} #${buildpart.number}: Incomplete package, lacking '${buildpart.title}'! `
core.error(notMergeableError);
result++;
}
});
core.setOutput('mergeableparts', JSON.stringify(mergeableparts) );
return result;

- name: Checkout build target branch
uses: actions/checkout@v3
with:
repository: ${{ env.CUSTOM_REPO }}
ref: ${{ env.CUSTOM_BRANCH }}
fetch-depth: 1
token: ${{ secrets.BUILD_TOKEN }}
- run: |
git rebase --onto ${{ env.TARGET_STABLE }} ${{ env.CUSTOM_BRANCH }}

# todo do merge trials for all newerparts
# if one successfully merges with stable branch
# it is a potential candidate to replace a backport
# with a master patch

- name: Custom merges
id: custommerge
run:
echo ::debug::Merging for '${{ env.TARGET_STABLE }}' on '${{ env.CUSTOM_BRANCH }}'
for mergepull in $(echo '${{ steps.checkmergeable.outputs.mergeableparts }}' | jq -r '.[]')
do
head=$(echo $mergepull | jq -r '.headRefName')
base=$(echo $mergepull | jq -r '.baseRefName')
echo "::group::$head(type:$base)--->$TARGET_STABLE"
echo "::endgroup::"
done
76 changes: 76 additions & 0 deletions apps/files/js/filelist.js
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,9 @@

this.$el.on('show', this._onResize);

this.resizeFileActionMenu = _.debounce(_.bind(this.resizeFileActionMenu, this), 250);
$(window).resize(this.resizeFileActionMenu);

// reload files list on share accept
$('body').on('OCA.Notification.Action', function(eventObject) {
if (eventObject.notification.app === 'files_sharing' && eventObject.action.type === 'POST') {
Expand Down Expand Up @@ -677,6 +680,7 @@
* @param {boolean} [show=true] whether to open the sidebar if it was closed
*/
_updateDetailsView: function(fileName, show) {
this.resizeFileActionMenu();
if (!(OCA.Files && OCA.Files.Sidebar)) {
console.error('No sidebar available');
return;
Expand Down Expand Up @@ -1501,6 +1505,12 @@
this.fileMultiSelectMenu.render();
this.$el.find('.selectedActions .filesSelectMenu').remove();
this.$el.find('.selectedActions').append(this.fileMultiSelectMenu.$el);
this.fileMultipleSelectionMenu = new OCA.Files.FileMultipleSelectionMenu(this.multiSelectMenuItems.sort(function(a, b) {
return a.order - b.order
}));
this.fileMultipleSelectionMenu.render();
this.$el.find('.selectedActions .filesSelectionMenu').remove();
this.$el.find('.selectedActions').append(this.fileMultipleSelectionMenu.$el);
},

/**
Expand Down Expand Up @@ -3501,6 +3511,72 @@
}
},

/**
* Show or hide file action menu based on the current selection
*/
resizeFileActionMenu: function() {
const appList = this.$el.find('.filesSelectionMenu ul li:not(.hidden-action)');
const appListWidth = 179;
const checkWidth = Math.ceil(this.$el.find('.column-selection').outerWidth());
const headerNameWidth = Math.ceil(this.$el.find('.column-name').outerWidth());
const actionWidth = Math.ceil(this.$el.find('#selectedActionLabel').outerWidth());
const allLabelWidth = Math.ceil(this.$el.find('#allLabel').not('#allLabel:hidden').outerWidth());
let headerWidth = Math.ceil(this.$el.find('.files-filestable thead').outerWidth());

if($('#app-sidebar-vue').length>0){
headerWidth = headerWidth - Math.ceil($('#app-sidebar-vue').outerWidth());
}

var availableWidth;
if(!allLabelWidth){
availableWidth = headerWidth - (checkWidth + headerNameWidth);
}
else{
availableWidth = headerWidth - (checkWidth + allLabelWidth+ headerNameWidth);
}

let appCount = Math.floor((availableWidth / appListWidth));

if(appCount < appList.length) {

if(!allLabelWidth){
availableWidth = headerWidth - (checkWidth + headerNameWidth + actionWidth);
}
else{
availableWidth = headerWidth - (checkWidth + allLabelWidth+ headerNameWidth + actionWidth);
}
appCount = Math.floor((availableWidth / appListWidth));
}

var summary = this._selectionSummary.summary;
if (summary.totalFiles === 0 && summary.totalDirs === 0) {
this.$el.find('#selectedActionLabel').css('display','none');
}
else{
if(appCount < appList.length) {
this.$el.find('#selectedActionLabel').css('display','block');
}
else if(appCount == appList.length){
this.$el.find('#selectedActionLabel').css('display','none');
}
else if (!isFinite(appCount))
{
this.$el.find('#selectedActionLabel').css('display','block');
}
else if(appCount > appList.length){
this.$el.find('#selectedActionLabel').css('display','none');
}
}

for (let k = 0; k < appList.length; k++) {
if (k < appCount) {
$(appList[k]).removeClass('hidden');
} else {
$(appList[k]).addClass('hidden');
}
}
},

/**
* Check whether all selected files are copiable
*/
Expand Down
91 changes: 91 additions & 0 deletions apps/files/js/filemultipleselectionmenu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2018
*
* This file is licensed under the Affero General Public License version 3
* or later.
*
* See the COPYING-README file.
*
*/

(function() {
var FileMultipleSelectionMenu = OC.Backbone.View.extend({
tagName: 'div',
className: 'filesSelectionMenu',
_scopes: null,
initialize: function(menuItems) {
this._scopes = menuItems;
},
events: {
'click a.action': '_onClickAction'
},

/**
* Renders the menu with the currently set items
*/
render: function() {
this.$el.html(OCA.Files.Templates['filemultiselectmenu']({
items: this._scopes
}));
},
/**
* Displays the menu under the given element
*
* @param {OCA.Files.FileActionContext} context context
* @param {Object} $trigger trigger element
*/
show: function(context) {
this._context = context;
return false;
},
toggleItemVisibility: function (itemName, show) {
var toggle= $('.filesSelectionMenu');
if (show) {
toggle.find('.item-' + itemName).removeClass('hidden-action');
} else {
toggle.find('.item-' + itemName).addClass('hidden-action');
}
},
updateItemText: function (itemName, translation) {
this.$el.find('.item-' + itemName).find('.label').text(translation);
},
toggleLoading: function (itemName, showLoading) {
var $actionElement = this.$el.find('.item-' + itemName);
if ($actionElement.length === 0) {
return;
}
var $icon = $actionElement.find('.icon');
if (showLoading) {
var $loadingIcon = $('<span class="icon icon-loading-small"></span>');
$icon.after($loadingIcon);
$icon.addClass('hidden');
$actionElement.addClass('disabled');
} else {
$actionElement.find('.icon-loading-small').remove();
$actionElement.find('.icon').removeClass('hidden');
$actionElement.removeClass('disabled');
}
},
isDisabled: function (itemName) {
var $actionElement = this.$el.find('.item-' + itemName);
return $actionElement.hasClass('disabled');
},
/**
* Event handler whenever an action has been clicked within the menu
*
* @param {Object} event event object
*/
_onClickAction: function (event) {
var $target = $(event.currentTarget);
if (!$target.hasClass('menuitem')) {
$target = $target.closest('.menuitem');
}

OC.hideMenus();
this._context.multiSelectMenuClick(event, $target.data('action'));
return false;
}
});

OCA.Files.FileMultipleSelectionMenu = FileMultipleSelectionMenu;
})(OC, OCA);
7 changes: 1 addition & 6 deletions apps/files/js/filemultiselectmenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
(function() {
var FileMultiSelectMenu = OC.Backbone.View.extend({
tagName: 'div',
className: 'filesSelectMenu popovermenu bubble menu-center',
className: 'filesSelectMenu popovermenu bubble menu-right',
_scopes: null,
initialize: function(menuItems) {
this._scopes = menuItems;
Expand All @@ -37,11 +37,6 @@
show: function(context) {
this._context = context;
this.$el.removeClass('hidden');
if (window.innerWidth < 480) {
this.$el.removeClass('menu-center').addClass('menu-right');
} else {
this.$el.removeClass('menu-right').addClass('menu-center');
}
OC.showMenu(null, this.$el);
return false;
},
Expand Down