From 94a52080cff14f7587c0ee837c1fca131cd6aff0 Mon Sep 17 00:00:00 2001 From: Nicu Tofan Date: Mon, 25 Jun 2018 23:12:20 +0300 Subject: Board level settings for subtasks --- client/components/boards/boardHeader.jade | 31 ++++++++++++++ client/components/boards/boardHeader.js | 70 +++++++++++++++++++++++++++++++ client/components/cards/cardDetails.jade | 5 ++- client/components/cards/subtasks.js | 1 + i18n/en.i18n.json | 7 +++- models/boards.js | 16 +++++++ models/cards.js | 2 +- server/migrations.js | 12 ++++++ 8 files changed, 140 insertions(+), 4 deletions(-) diff --git a/client/components/boards/boardHeader.jade b/client/components/boards/boardHeader.jade index b4ccd3b3..59691a61 100644 --- a/client/components/boards/boardHeader.jade +++ b/client/components/boards/boardHeader.jade @@ -130,6 +130,10 @@ template(name="boardMenuPopup") li: a(href="{{exportUrl}}", download="{{exportFilename}}") {{_ 'export-board'}} li: a.js-archive-board {{_ 'archive-board'}} li: a.js-outgoing-webhooks {{_ 'outgoing-webhooks'}} + hr + ul.pop-over-list + li: a.js-subtask-settings {{_ 'subtask-settings'}} + if isSandstorm hr ul.pop-over-list @@ -193,6 +197,33 @@ template(name="boardChangeColorPopup") if isSelected i.fa.fa-check +template(name="boardSubtaskSettingsPopup") + form.board-subtask-settings + a.flex.js-field-has-subtasks(class="{{#if allowsSubtasks}}is-checked{{/if}}") + .materialCheckBox(class="{{#if allowsSubtasks}}is-checked{{/if}}") + span {{_ 'show-subtasks-field'}} + label + | {{_ 'deposit-subtasks-board'}} + select.js-field-deposit-board(disabled="{{#unless allowsSubtasks}}disabled{{/unless}}") + each boards + if isBoardSelected + option(value=_id selected="selected") {{title}} + else + option(value=_id) {{title}} + if isNullBoardSelected + option(value='null' selected="selected") {{_ 'custom-field-dropdown-none'}} + else + option(value='null') {{_ 'custom-field-dropdown-none'}} + hr + label + | {{_ 'deposit-subtasks-list'}} + select.js-field-deposit-list(disabled="{{#unless hasLists}}disabled{{/unless}}") + each lists + if isListSelected + option(value=_id selected="selected") {{title}} + else + option(value=_id) {{title}} + template(name="createBoard") form label diff --git a/client/components/boards/boardHeader.js b/client/components/boards/boardHeader.js index b2640474..bafee9b9 100644 --- a/client/components/boards/boardHeader.js +++ b/client/components/boards/boardHeader.js @@ -25,6 +25,7 @@ Template.boardMenuPopup.events({ }), 'click .js-outgoing-webhooks': Popup.open('outgoingWebhooks'), 'click .js-import-board': Popup.open('chooseBoardSource'), + 'click .js-subtask-settings': Popup.open('boardSubtaskSettings'), }); Template.boardMenuPopup.helpers({ @@ -151,6 +152,75 @@ BlazeComponent.extendComponent({ }, }).register('boardChangeColorPopup'); +BlazeComponent.extendComponent({ + onCreated() { + this.currentBoard = Boards.findOne(Session.get('currentBoard')); + }, + + allowsSubtasks() { + return this.currentBoard.allowsSubtasks; + }, + + isBoardSelected() { + return this.currentBoard.subtasksDefaultBoardId === this.currentData()._id; + }, + + isNullBoardSelected() { + return (this.currentBoard.subtasksDefaultBoardId === null) || (this.currentBoard.subtasksDefaultBoardId === undefined); + }, + + boards() { + return Boards.find({ + archived: false, + 'members.userId': Meteor.userId(), + }, { + sort: ['title'], + }); + }, + + lists() { + return Lists.find({ + boardId: this.currentBoard._id, + archived: false, + }, { + sort: ['title'], + }); + }, + + hasLists() { + return this.lists().count() > 0; + }, + + isListSelected() { + return this.currentBoard.subtasksDefaultBoardId === this.currentData()._id; + }, + + events() { + return [{ + 'click .js-field-has-subtasks'(evt) { + evt.preventDefault(); + this.currentBoard.allowsSubtasks = !this.currentBoard.allowsSubtasks; + this.currentBoard.setAllowsSubtasks(this.currentBoard.allowsSubtasks); + $('.js-field-has-subtasks .materialCheckBox').toggleClass('is-checked', this.currentBoard.allowsSubtasks); + $('.js-field-has-subtasks').toggleClass('is-checked', this.currentBoard.allowsSubtasks); + $('.js-field-deposit-board').prop('disabled', !this.currentBoard.allowsSubtasks); + }, + 'change .js-field-deposit-board'(evt) { + let value = evt.target.value; + if (value === 'null') { + value = null; + } + this.currentBoard.setSubtasksDefaultBoardId(value); + evt.preventDefault(); + }, + 'change .js-field-deposit-list'(evt) { + this.currentBoard.setSubtasksDefaultListId(evt.target.value); + evt.preventDefault(); + }, + }]; + }, +}).register('boardSubtaskSettingsPopup'); + const CreateBoard = BlazeComponent.extendComponent({ template() { return 'createBoard'; diff --git a/client/components/cards/cardDetails.jade b/client/components/cards/cardDetails.jade index bc0ce45c..789cc4b1 100644 --- a/client/components/cards/cardDetails.jade +++ b/client/components/cards/cardDetails.jade @@ -144,8 +144,9 @@ template(name="cardDetails") hr +checklists(cardId = _id) - hr - +subtasks(cardId = _id) + if currentBoard.allowsSubtasks + hr + +subtasks(cardId = _id) hr h3 diff --git a/client/components/cards/subtasks.js b/client/components/cards/subtasks.js index 335eba36..9c6f265e 100644 --- a/client/components/cards/subtasks.js +++ b/client/components/cards/subtasks.js @@ -30,6 +30,7 @@ BlazeComponent.extendComponent({ sort: sortIndex, swimlaneId, }); + // In case the filter is active we need to add the newly inserted card in // the list of exceptions -- cards that are not filtered. Otherwise the // card will disappear instantly. diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 5e1a99e8..e410572f 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -482,5 +482,10 @@ "delete-board": "Delete Board", "default-subtasks-board": "Subtasks for __board__ board", "default": "Default", - "queue": "Queue" + "queue": "Queue", + "subtask-settings": "Subtasks Settings", + "boardSubtaskSettingsPopup-title": "Board Subtasks Settings", + "show-subtasks-field": "Cards can have subtasks:", + "deposit-subtasks-board": "Deposit subtasks to this board:", + "deposit-subtasks-list": "Landing list for subtasks deposited here:" } diff --git a/models/boards.js b/models/boards.js index fce674ae..b5b0b0fc 100644 --- a/models/boards.js +++ b/models/boards.js @@ -161,6 +161,10 @@ Boards.attachSchema(new SimpleSchema({ optional: true, defaultValue: null, }, + allowsSubtasks: { + type: Boolean, + defaultValue: true, + }, })); @@ -473,6 +477,18 @@ Boards.mutations({ }, }; }, + + setAllowsSubtasks(allowsSubtasks) { + return { $set: { allowsSubtasks } }; + }, + + setSubtasksDefaultBoardId(subtasksDefaultBoardId) { + return { $set: { subtasksDefaultBoardId } }; + }, + + setSubtasksDefaultListId(subtasksDefaultListId) { + return { $set: { subtasksDefaultListId } }; + }, }); if (Meteor.isServer) { diff --git a/models/cards.js b/models/cards.js index 2563fdf8..8d7a93d0 100644 --- a/models/cards.js +++ b/models/cards.js @@ -258,7 +258,7 @@ Cards.helpers({ return finishCount > 0 && this.subtasksCount() === finishCount; }, - hasSubtasks() { + allowsSubtasks() { return this.subtasksCount() !== 0; }, diff --git a/server/migrations.js b/server/migrations.js index af866d13..c3da3221 100644 --- a/server/migrations.js +++ b/server/migrations.js @@ -287,3 +287,15 @@ Migrations.add('add-subtasks-sort', () => { }, noValidateMulti); }); +Migrations.add('add-subtasks-allowed', () => { + Boards.update({ + allowsSubtasks: { + $exists: false, + }, + }, { + $set: { + allowsSubtasks: -1, + }, + }, noValidateMulti); +}); + -- cgit v1.2.3-1-g7c22