Skip to content

Commit

Permalink
Merge #217 127-file multiselection action
Browse files Browse the repository at this point in the history
  • Loading branch information
tsdicloud committed Jun 20, 2023
2 parents d5731ec + 7b32738 commit 52f6bdc
Show file tree
Hide file tree
Showing 4 changed files with 340 additions and 6 deletions.
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/graphql-action@v2.x
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 @@ -680,6 +683,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 @@ -1504,6 +1508,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 @@ -3504,6 +3514,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

0 comments on commit 52f6bdc

Please sign in to comment.