Add copy swimlane functionality

This commit is contained in:
John R. Supplee 2021-04-22 14:05:20 +02:00
parent 2119a3a51e
commit 4940af0573
7 changed files with 101 additions and 59 deletions

View file

@ -39,6 +39,8 @@ template(name="swimlaneActionPopup")
hr hr
ul.pop-over-list ul.pop-over-list
li: a.js-close-swimlane {{_ 'archive-swimlane'}} li: a.js-close-swimlane {{_ 'archive-swimlane'}}
ul.pop-over-list
li: a.js-copy-swimlane {{_ 'copy-swimlane'}}
ul.pop-over-list ul.pop-over-list
li: a.js-move-swimlane {{_ 'move-swimlane'}} li: a.js-move-swimlane {{_ 'move-swimlane'}}

View file

@ -55,6 +55,7 @@ Template.swimlaneActionPopup.events({
Popup.close(); Popup.close();
}, },
'click .js-move-swimlane': Popup.open('moveSwimlane'), 'click .js-move-swimlane': Popup.open('moveSwimlane'),
'click .js-copy-swimlane': Popup.open('copySwimlane'),
}); });
Template.swimlaneActionPopup.events({ Template.swimlaneActionPopup.events({

View file

@ -71,3 +71,13 @@ template(name="moveSwimlanePopup")
.edit-controls.clearfix .edit-controls.clearfix
button.primary.confirm.js-done {{_ 'done'}} button.primary.confirm.js-done {{_ 'done'}}
template(name="copySwimlanePopup")
unless currentUser.isWorker
label {{_ 'boards'}}:
select.js-select-boards(autofocus)
each toBoard in toBoards
option(value="{{toBoard._id}}" selected="{{#if $eq toBoard.title board.title}}1{{/if}}") {{toBoard.title}}
.edit-controls.clearfix
button.primary.confirm.js-done {{_ 'done'}}

View file

@ -324,45 +324,54 @@ BlazeComponent.extendComponent({
}, },
}).register('listsGroup'); }).register('listsGroup');
BlazeComponent.extendComponent({ class MoveSwimlaneComponent extends BlazeComponent {
serverMethod = 'moveSwimlane';
onCreated() { onCreated() {
this.currentSwimlane = this.currentData(); this.currentSwimlane = this.currentData();
}, }
board() { board() {
return Boards.findOne(Session.get('currentBoard')); return Boards.findOne(Session.get('currentBoard'));
}, }
toBoards() { toBoardsSelector() {
const boards = Boards.find( return {
{
archived: false, archived: false,
'members.userId': Meteor.userId(), 'members.userId': Meteor.userId(),
type: 'board', type: 'board',
_id: { $ne: this.board()._id }, _id: { $ne: this.board()._id },
}, };
{ }
sort: { title: 1 },
},
);
return boards; toBoards() {
}, return Boards.find(this.toBoardsSelector(), { sort: { title: 1 } });
}
events() { events() {
return [ return [
{ {
'click .js-done'() { 'click .js-done'() {
const swimlane = Swimlanes.findOne(this.currentSwimlane._id); // const swimlane = Swimlanes.findOne(this.currentSwimlane._id);
const bSelect = $('.js-select-boards')[0]; const bSelect = $('.js-select-boards')[0];
let boardId; let boardId;
if (bSelect) { if (bSelect) {
boardId = bSelect.options[bSelect.selectedIndex].value; boardId = bSelect.options[bSelect.selectedIndex].value;
Meteor.call('moveSwimlane', this.currentSwimlane._id, boardId); Meteor.call(this.serverMethod, this.currentSwimlane._id, boardId);
} }
Popup.close(); Popup.close();
}, },
}, },
]; ];
}, }
}).register('moveSwimlanePopup'); }
MoveSwimlaneComponent.register('moveSwimlanePopup');
(class extends MoveSwimlaneComponent {
serverMethod = 'copySwimlane';
toBoardsSelector() {
const selector = super.toBoardsSelector();
delete selector._id;
return selector;
}
}.register('copySwimlanePopup'));

View file

@ -1005,5 +1005,7 @@
"filesReportTitle": "Files Report", "filesReportTitle": "Files Report",
"orphanedFilesReportTitle": "Orphaned Files Report", "orphanedFilesReportTitle": "Orphaned Files Report",
"reports": "Reports", "reports": "Reports",
"rulesReportTitle": "Rules Report" "rulesReportTitle": "Rules Report",
"copy-swimlane": "Copy Swimlane",
"copySwimlanePopup-title": "Copy Swimlane"
} }

View file

@ -147,6 +147,45 @@ Swimlanes.helpers({
}); });
}, },
move(toBoardId) {
this.lists().forEach(list => {
const toList = Lists.findOne({
boardId: toBoardId,
title: list.title,
archived: false,
});
let toListId;
if (toList) {
toListId = toList._id;
} else {
toListId = Lists.insert({
title: list.title,
boardId: toBoardId,
type: list.type,
archived: false,
wipLimit: list.wipLimit,
});
}
Cards.find({
listId: list._id,
swimlaneId: this._id,
}).forEach(card => {
card.move(toBoardId, this._id, toListId);
});
});
Swimlanes.update(this._id, {
$set: {
boardId: toBoardId,
},
});
// make sure there is a default swimlane
this.board().getDefaultSwimline();
},
cards() { cards() {
return Cards.find( return Cards.find(
Filter.mongoSelector({ Filter.mongoSelector({

View file

@ -1,49 +1,28 @@
Meteor.methods({ Meteor.methods({
copySwimlane(swimlaneId, toBoardId) {
check(swimlaneId, String);
check(toBoardId, String);
const swimlane = Swimlanes.findOne(swimlaneId);
const toBoard = Boards.findOne(toBoardId);
if (swimlane && toBoard) {
swimlane.copy(toBoardId);
return true;
}
return false;
},
moveSwimlane(swimlaneId, toBoardId) { moveSwimlane(swimlaneId, toBoardId) {
check(swimlaneId, String); check(swimlaneId, String);
check(toBoardId, String); check(toBoardId, String);
const swimlane = Swimlanes.findOne(swimlaneId); const swimlane = Swimlanes.findOne(swimlaneId);
const fromBoard = Boards.findOne(swimlane.boardId);
const toBoard = Boards.findOne(toBoardId); const toBoard = Boards.findOne(toBoardId);
if (swimlane && toBoard) { if (swimlane && toBoard) {
swimlane.lists().forEach(list => { swimlane.move(toBoardId);
const toList = Lists.findOne({
boardId: toBoardId,
title: list.title,
archived: false,
});
let toListId;
if (toList) {
toListId = toList._id;
} else {
toListId = Lists.insert({
title: list.title,
boardId: toBoardId,
type: list.type,
archived: false,
wipLimit: list.wipLimit,
});
}
Cards.find({
listId: list._id,
swimlaneId,
}).forEach(card => {
card.move(toBoardId, swimlaneId, toListId);
});
});
Swimlanes.update(swimlaneId, {
$set: {
boardId: toBoardId,
},
});
// make sure there is a default swimlane
fromBoard.getDefaultSwimline();
return true; return true;
} }