diff --git a/client/components/swimlanes/swimlaneHeader.jade b/client/components/swimlanes/swimlaneHeader.jade index 49cbb95da..b50a9a336 100644 --- a/client/components/swimlanes/swimlaneHeader.jade +++ b/client/components/swimlanes/swimlaneHeader.jade @@ -39,6 +39,8 @@ template(name="swimlaneActionPopup") hr ul.pop-over-list li: a.js-close-swimlane {{_ 'archive-swimlane'}} + ul.pop-over-list + li: a.js-copy-swimlane {{_ 'copy-swimlane'}} ul.pop-over-list li: a.js-move-swimlane {{_ 'move-swimlane'}} diff --git a/client/components/swimlanes/swimlaneHeader.js b/client/components/swimlanes/swimlaneHeader.js index 61bf4bb95..9d01ee34c 100644 --- a/client/components/swimlanes/swimlaneHeader.js +++ b/client/components/swimlanes/swimlaneHeader.js @@ -55,6 +55,7 @@ Template.swimlaneActionPopup.events({ Popup.close(); }, 'click .js-move-swimlane': Popup.open('moveSwimlane'), + 'click .js-copy-swimlane': Popup.open('copySwimlane'), }); Template.swimlaneActionPopup.events({ diff --git a/client/components/swimlanes/swimlanes.jade b/client/components/swimlanes/swimlanes.jade index 68c4cc495..3c084166e 100644 --- a/client/components/swimlanes/swimlanes.jade +++ b/client/components/swimlanes/swimlanes.jade @@ -71,3 +71,13 @@ template(name="moveSwimlanePopup") .edit-controls.clearfix 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'}} diff --git a/client/components/swimlanes/swimlanes.js b/client/components/swimlanes/swimlanes.js index 99ce15e61..6d72fbfef 100644 --- a/client/components/swimlanes/swimlanes.js +++ b/client/components/swimlanes/swimlanes.js @@ -324,45 +324,54 @@ BlazeComponent.extendComponent({ }, }).register('listsGroup'); -BlazeComponent.extendComponent({ +class MoveSwimlaneComponent extends BlazeComponent { + serverMethod = 'moveSwimlane'; + onCreated() { this.currentSwimlane = this.currentData(); - }, + } board() { return Boards.findOne(Session.get('currentBoard')); - }, + } + + toBoardsSelector() { + return { + archived: false, + 'members.userId': Meteor.userId(), + type: 'board', + _id: { $ne: this.board()._id }, + }; + } toBoards() { - const boards = Boards.find( - { - archived: false, - 'members.userId': Meteor.userId(), - type: 'board', - _id: { $ne: this.board()._id }, - }, - { - sort: { title: 1 }, - }, - ); - - return boards; - }, + return Boards.find(this.toBoardsSelector(), { sort: { title: 1 } }); + } events() { return [ { 'click .js-done'() { - const swimlane = Swimlanes.findOne(this.currentSwimlane._id); + // const swimlane = Swimlanes.findOne(this.currentSwimlane._id); const bSelect = $('.js-select-boards')[0]; let boardId; if (bSelect) { boardId = bSelect.options[bSelect.selectedIndex].value; - Meteor.call('moveSwimlane', this.currentSwimlane._id, boardId); + Meteor.call(this.serverMethod, this.currentSwimlane._id, boardId); } Popup.close(); }, }, ]; - }, -}).register('moveSwimlanePopup'); + } +} +MoveSwimlaneComponent.register('moveSwimlanePopup'); + +(class extends MoveSwimlaneComponent { + serverMethod = 'copySwimlane'; + toBoardsSelector() { + const selector = super.toBoardsSelector(); + delete selector._id; + return selector; + } +}.register('copySwimlanePopup')); diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 2ea022302..14fb076a0 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -1005,5 +1005,7 @@ "filesReportTitle": "Files Report", "orphanedFilesReportTitle": "Orphaned Files Report", "reports": "Reports", - "rulesReportTitle": "Rules Report" + "rulesReportTitle": "Rules Report", + "copy-swimlane": "Copy Swimlane", + "copySwimlanePopup-title": "Copy Swimlane" } diff --git a/models/swimlanes.js b/models/swimlanes.js index 1c803cdc9..78e8b2062 100644 --- a/models/swimlanes.js +++ b/models/swimlanes.js @@ -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() { return Cards.find( Filter.mongoSelector({ diff --git a/server/publications/swimlanes.js b/server/publications/swimlanes.js index 533f5159c..4c119866a 100644 --- a/server/publications/swimlanes.js +++ b/server/publications/swimlanes.js @@ -1,49 +1,28 @@ 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) { check(swimlaneId, String); check(toBoardId, String); const swimlane = Swimlanes.findOne(swimlaneId); - const fromBoard = Boards.findOne(swimlane.boardId); const toBoard = Boards.findOne(toBoardId); if (swimlane && toBoard) { - swimlane.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, - }).forEach(card => { - card.move(toBoardId, swimlaneId, toListId); - }); - }); - - Swimlanes.update(swimlaneId, { - $set: { - boardId: toBoardId, - }, - }); - - // make sure there is a default swimlane - fromBoard.getDefaultSwimline(); + swimlane.move(toBoardId); return true; }