diff --git a/client/components/cards/checklists.jade b/client/components/cards/checklists.jade index 2a3055e41..d387de307 100644 --- a/client/components/cards/checklists.jade +++ b/client/components/cards/checklists.jade @@ -140,3 +140,34 @@ template(name="checklistActionsPopup") a.js-delete-checklist.delete-checklist i.fa.fa-trash | {{_ "delete"}} ... + a.js-move-checklist.move-checklist + i.fa.fa-arrow-right + | {{_ "moveChecklist"}} ... + +template(name="moveChecklistPopup") + unless currentUser.isWorker + label {{_ 'boards'}}: + select.js-select-boards(autofocus) + each boards + if $eq _id currentBoard._id + option(value="{{_id}}" selected) {{_ 'current'}} + else + option(value="{{_id}}" selected="{{#if isMoveChecklistDialogOptionBoardId _id}}selected{{/if}}") {{title}} + + label {{_ 'swimlanes'}}: + select.js-select-swimlanes + each swimlanes + option(value="{{_id}}" selected="{{#if isMoveChecklistDialogOptionSwimlaneId _id}}selected{{/if}}") {{title}} + + label {{_ 'lists'}}: + select.js-select-lists + each lists + option(value="{{_id}}" selected="{{#if isMoveChecklistDialogOptionListId _id}}selected{{/if}}") {{title}} + + label {{_ 'cards'}}: + select.js-select-cards + each cards + option(value="{{_id}}" selected="{{#if isMoveChecklistDialogOptionCardId _id}}selected{{/if}}") {{title}} + + .edit-controls.clearfix + button.primary.confirm.js-done {{_ 'done'}} diff --git a/client/components/cards/checklists.js b/client/components/cards/checklists.js index 745740895..fcb404b95 100644 --- a/client/components/cards/checklists.js +++ b/client/components/cards/checklists.js @@ -298,6 +298,7 @@ BlazeComponent.extendComponent({ Checklists.remove(checklist._id); } }), + 'click .js-move-checklist' : Popup.open('moveChecklist'), } ] } @@ -362,3 +363,155 @@ BlazeComponent.extendComponent({ ]; }, }).register('checklistItemDetail'); + +BlazeComponent.extendComponent({ + onCreated() { + const boardId = Utils.getCurrentBoardId(); + subManager.subscribe('board', boardId, false); + // subManager.subscribe('swimlane', swimlaneId, false); + // subManager.subscribe('list', listId, false); + // subManager.subscribe('card', cardId, false); + this.selectedBoardId = new ReactiveVar(boardId); + this.selectedSwimlaneId = new ReactiveVar(''); + this.selectedListId = new ReactiveVar(''); + this.selectedCardId = new ReactiveVar(''); + this.setMoveChecklistDialogOption(boardId); + }, + + /** set the last confirmed dialog field values + * @param boardId the current board id + */ + setMoveChecklistDialogOption(boardId) { + this.moveChecklistDialogOption = { + 'boardId' : "", + 'swimlaneId' : "", + 'listId' : "", + 'cardId': "", + } + + let currentOptions = Meteor.user().getMoveChecklistDialogOptions(); + if (currentOptions && boardId && currentOptions[boardId]) { + this.moveChecklistDialogOption = currentOptions[boardId]; + } + const board = Boards.findOne(boardId); + try { + const swimlaneId = board.swimlanes().fetch()[0]._id; + this.selectedSwimlaneId.set(swimlaneId); + } catch (e) {} + + try { + const listId = board.lists().fetch()[0]; + this.selectedListId.set(listId); + } catch (e) {} + + const cardId = Utils.getCurrentCardId(); + this.selectedCardId.set(cardId); + }, + + /** returns if the board id was the last confirmed one + * @param boardId check this board id + * @return if the board id was the last confirmed one + */ + isMoveChecklistDialogOptionBoardId(boardId) { + let ret = this.moveChecklistDialogOption.boardId == boardId; + return ret; + }, + + /** returns if the swimlane id was the last confirmed one + * @param swimlaneId check this swimlane id + * @return if the swimlane id was the last confirmed one + */ + isMoveChecklistDialogOptionSwimlaneId(swimlaneId) { + let ret = this.moveChecklistDialogOption.swimlaneId == swimlaneId; + return ret; + }, + + /** returns if the list id was the last confirmed one + * @param listId check this list id + * @return if the list id was the last confirmed one + */ + isMoveChecklistDialogOptionListId(listId) { + let ret = this.moveChecklistDialogOption.listId == listId; + return ret; + }, + + /** returns if the card id was the last confirmed one + * @param cardId check this card id + * @return if the card id was the last confirmed one + */ + isMoveChecklistDialogOptionCardId(cardId) { + let ret = this.moveChecklistDialogOption.cardId == cardId; + return ret; + }, + + boards() { + return Boards.find( + { + archived: false, + 'members.userId': Meteor.userId(), + _id: { $ne: Meteor.user().getTemplatesBoardId() }, + }, + { + sort: { sort: 1 }, + }, + ); + }, + + swimlanes() { + const board = Boards.findOne(this.selectedBoardId.get()); + return board.swimlanes(); + }, + + lists() { + const board = Boards.findOne(this.selectedBoardId.get()); + return board.lists(); + }, + + cards() { + const list = Lists.findOne(this.selectedListId.get()); + const ret = list.cards(this.selectedSwimlaneId.get()); + return ret; + }, + + events() { + return [ + { + 'click .js-done'() { + const boardSelect = this.$('.js-select-boards')[0]; + const boardId = boardSelect.options[boardSelect.selectedIndex].value; + + const listSelect = this.$('.js-select-lists')[0]; + const listId = listSelect.options[listSelect.selectedIndex].value; + + const swimlaneSelect = this.$('.js-select-swimlanes')[0]; + const swimlaneId = swimlaneSelect.options[swimlaneSelect.selectedIndex].value; + + const cardSelect = this.$('.js-select-cards')[0]; + const cardId = cardSelect.options[cardSelect.selectedIndex].value; + + const options = { + 'boardId' : boardId, + 'swimlaneId' : swimlaneId, + 'listId' : listId, + 'cardId': cardId, + } + Meteor.user().setMoveChecklistDialogOption(boardId, options); + this.data().checklist.move(cardId); + Popup.back(2); + }, + 'change .js-select-boards'(event) { + const boardId = $(event.currentTarget).val(); + subManager.subscribe('board', boardId, false); + this.setMoveChecklistDialogOption(boardId); + this.selectedBoardId.set(boardId); + }, + 'change .js-select-swimlanes'(event) { + this.selectedSwimlaneId.set($(event.currentTarget).val()); + }, + 'change .js-select-lists'(event) { + this.selectedListId.set($(event.currentTarget).val()); + }, + }, + ]; + }, +}).register('moveChecklistPopup'); diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 94460e7e5..39dad5c4b 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -1139,5 +1139,7 @@ "acceptance_of_our_legalNotice": "By continuing, you accept our", "legalNotice": "legal notice", "copied": "Copied!", - "checklistActionsPopup-title": "Checklist Actions" + "checklistActionsPopup-title": "Checklist Actions", + "moveChecklist": "Move Checklist", + "moveChecklistPopup-title": "Move Checklist" } diff --git a/models/checklists.js b/models/checklists.js index 30a6f2c2d..0e76d4001 100644 --- a/models/checklists.js +++ b/models/checklists.js @@ -147,6 +147,37 @@ Checklists.mutations({ setTitle(title) { return { $set: { title } }; }, + /** move the checklist to another card + * @param newCardId move the checklist to this cardId + */ + move(newCardId) { + // update every activity + Activities.find( + {checklistId: this._id} + ).forEach(activity => { + Activities.update(activity._id, { + $set: { + cardId: newCardId, + }, + }); + }); + // update every checklist-item + ChecklistItems.find( + {checklistId: this._id} + ).forEach(checklistItem => { + ChecklistItems.update(checklistItem._id, { + $set: { + cardId: newCardId, + }, + }); + }); + // update the checklist itself + return { + $set: { + cardId: newCardId, + }, + }; + }, }); if (Meteor.isServer) { diff --git a/models/users.js b/models/users.js index 98f658412..60047a17a 100644 --- a/models/users.js +++ b/models/users.js @@ -252,6 +252,38 @@ Users.attachSchema( */ type: String, }, + 'profile.moveChecklistDialog' : { + /** + * move and copy card dialog + */ + type: Object, + optional: true, + blackbox: true, + }, + 'profile.moveChecklistDialog.$.boardId': { + /** + * last selected board id + */ + type: String, + }, + 'profile.moveChecklistDialog.$.swimlaneId': { + /** + * last selected swimlane id + */ + type: String, + }, + 'profile.moveChecklistDialog.$.listId': { + /** + * last selected list id + */ + type: String, + }, + 'profile.moveChecklistDialog.$.cardId': { + /** + * last selected card id + */ + type: String, + }, 'profile.notifications': { /** * enabled notifications for the user @@ -653,6 +685,17 @@ Users.helpers({ return _ret; }, + /** returns all confirmed move checklist dialog field values + *
  • the board, swimlane, list and card id is stored for each board + */ + getMoveChecklistDialogOptions() { + let _ret = {} + if (this.profile && this.profile.moveChecklistDialog) { + _ret = this.profile.moveChecklistDialog; + } + return _ret; + }, + hasTag(tag) { const { tags = [] } = this.profile || {}; return _.contains(tags, tag); @@ -781,6 +824,19 @@ Users.mutations({ }, }; }, + /** set the confirmed board id/swimlane id/list id/card id of a board + * @param boardId the current board id + * @param options an object with the confirmed field values + */ + setMoveChecklistDialogOption(boardId, options) { + let currentOptions = this.getMoveChecklistDialogOptions(); + currentOptions[boardId] = options; + return { + $set: { + 'profile.moveChecklistDialog': currentOptions, + }, + }; + }, toggleBoardStar(boardId) { const queryKind = this.hasStarred(boardId) ? '$pull' : '$addToSet'; return {