diff options
author | Andrés Manelli <andresmanelli@gmail.com> | 2018-03-20 00:13:42 -0300 |
---|---|---|
committer | Andrés Manelli <andresmanelli@gmail.com> | 2018-08-10 23:55:19 +0200 |
commit | dcc7b2970f3635b95bc71e3fc163a51cacad0931 (patch) | |
tree | 58f4bffdfef29b2bdab8d04a64fd8c873a0f20a4 | |
parent | 193af893ee4da894e9494792306f5825e99de74a (diff) | |
download | wekan-dcc7b2970f3635b95bc71e3fc163a51cacad0931.tar.gz wekan-dcc7b2970f3635b95bc71e3fc163a51cacad0931.tar.bz2 wekan-dcc7b2970f3635b95bc71e3fc163a51cacad0931.zip |
Add UI for importing card-as-card and board-as-card
-rw-r--r-- | client/components/forms/forms.styl | 3 | ||||
-rw-r--r-- | client/components/lists/list.styl | 11 | ||||
-rw-r--r-- | client/components/lists/listBody.jade | 53 | ||||
-rw-r--r-- | client/components/lists/listBody.js | 106 | ||||
-rw-r--r-- | i18n/en.i18n.json | 5 | ||||
-rw-r--r-- | models/boards.js | 4 | ||||
-rw-r--r-- | models/cards.js | 7 | ||||
-rw-r--r-- | server/migrations.js | 11 |
8 files changed, 199 insertions, 1 deletions
diff --git a/client/components/forms/forms.styl b/client/components/forms/forms.styl index 0a905943..5be70b7a 100644 --- a/client/components/forms/forms.styl +++ b/client/components/forms/forms.styl @@ -225,9 +225,12 @@ textarea .edit-controls, .add-controls + display: flex + align-items: baseline margin-top: 0 button[type=submit] + input[type=button] float: left height: 32px margin-top: -2px diff --git a/client/components/lists/list.styl b/client/components/lists/list.styl index fa32ff6d..0e170ebf 100644 --- a/client/components/lists/list.styl +++ b/client/components/lists/list.styl @@ -187,3 +187,14 @@ padding: 7px top: -@padding right: 17px + +.import-board-wrapper + display: flex + align-items: baseline + + .js-import-board + margin-left: 15px + +.search-card-results + max-height: 250px + overflow: hidden diff --git a/client/components/lists/listBody.jade b/client/components/lists/listBody.jade index 32c6b278..e0655fc2 100644 --- a/client/components/lists/listBody.jade +++ b/client/components/lists/listBody.jade @@ -34,8 +34,59 @@ template(name="addCardForm") .add-controls.clearfix button.primary.confirm(type="submit") {{_ 'add'}} - a.fa.fa-times-thin.js-close-inlined-form + span.quiet + | {{_ 'or'}} + a.js-import {{_ 'import'}} template(name="autocompleteLabelLine") .minicard-label(class="card-label-{{colorName}}" title=labelName) span(class="{{#if hasNoName}}quiet{{/if}}")= labelName + +template(name="importCardPopup") + label {{_ 'boards'}}: + .import-board-wrapper + select.js-select-boards + each boards + if $eq _id currentBoard._id + option(value="{{_id}}" selected) {{_ 'current'}} + else + option(value="{{_id}}") {{title}} + input.primary.confirm.js-import-board(type="submit" value="{{_ 'add'}}") + + label {{_ 'swimlanes'}}: + select.js-select-swimlanes + each swimlanes + option(value="{{_id}}") {{title}} + + label {{_ 'lists'}}: + select.js-select-lists + each lists + option(value="{{_id}}") {{title}} + + label {{_ 'cards'}}: + select.js-select-lists + each cards + option(value="{{_id}}") {{title}} + + .edit-controls.clearfix + input.primary.confirm.js-done(type="submit" value="{{_ 'done'}}") + span.quiet + | {{_ 'or'}} + a.js-search {{_ 'search'}} + +template(name="searchCardPopup") + label {{_ 'boards'}}: + .import-board-wrapper + select.js-select-boards + each boards + if $eq _id currentBoard._id + option(value="{{_id}}" selected) {{_ 'current'}} + else + option(value="{{_id}}") {{title}} + form.js-search-term-form + input(type="text" name="searchTerm" placeholder="{{_ 'search-example'}}" autofocus) + .list-body.js-perfect-scrollbar.search-card-results + .minicards.clearfix.js-minicards + each results + a.minicard-wrapper.js-minicard + +minicard(this) diff --git a/client/components/lists/listBody.js b/client/components/lists/listBody.js index 0a10f7d5..4cae9f0b 100644 --- a/client/components/lists/listBody.js +++ b/client/components/lists/listBody.js @@ -1,3 +1,5 @@ +const subManager = new SubsManager(); + BlazeComponent.extendComponent({ mixins() { return [Mixins.PerfectScrollbar]; @@ -55,6 +57,7 @@ BlazeComponent.extendComponent({ boardId: boardId._id, sort: sortIndex, swimlaneId, + type: 'cardType-card', }); // 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 @@ -197,6 +200,7 @@ BlazeComponent.extendComponent({ events() { return [{ keydown: this.pressKey, + 'click .js-import': Popup.open('importCard'), }]; }, @@ -268,3 +272,105 @@ BlazeComponent.extendComponent({ }); }, }).register('addCardForm'); + +BlazeComponent.extendComponent({ + onCreated() { + subManager.subscribe('board', Session.get('currentBoard')); + this.selectedBoardId = new ReactiveVar(Session.get('currentBoard')); + }, + + boards() { + const boards = Boards.find({ + archived: false, + 'members.userId': Meteor.userId(), + }, { + sort: ['title'], + }); + return boards; + }, + + swimlanes() { + const board = Boards.findOne(this.selectedBoardId.get()); + return board.swimlanes(); + }, + + lists() { + const board = Boards.findOne(this.selectedBoardId.get()); + return board.lists(); + }, + + cards() { + const board = Boards.findOne(this.selectedBoardId.get()); + return board.cards(); + }, + + events() { + return [{ + 'change .js-select-boards'(evt) { + this.selectedBoardId.set($(evt.currentTarget).val()); + subManager.subscribe('board', this.selectedBoardId.get()); + }, + 'submit .js-done' (evt) { + // IMPORT CARD + evt.preventDefault(); + // XXX We should *not* get the currentCard from the global state, but + // instead from a “component” state. + const card = Cards.findOne(Session.get('currentCard')); + const lSelect = $('.js-select-lists')[0]; + const newListId = lSelect.options[lSelect.selectedIndex].value; + const slSelect = $('.js-select-swimlanes')[0]; + card.swimlaneId = slSelect.options[slSelect.selectedIndex].value; + Popup.close(); + }, + 'submit .js-import-board' (evt) { + //IMPORT BOARD + evt.preventDefault(); + Popup.close(); + }, + 'click .js-search': Popup.open('searchCard'), + }]; + }, +}).register('importCardPopup'); + +BlazeComponent.extendComponent({ + mixins() { + return [Mixins.PerfectScrollbar]; + }, + + onCreated() { + subManager.subscribe('board', Session.get('currentBoard')); + this.selectedBoardId = new ReactiveVar(Session.get('currentBoard')); + this.term = new ReactiveVar(''); + }, + + boards() { + const boards = Boards.find({ + archived: false, + 'members.userId': Meteor.userId(), + }, { + sort: ['title'], + }); + return boards; + }, + + results() { + const board = Boards.findOne(this.selectedBoardId.get()); + return board.searchCards(this.term.get()); + }, + + events() { + return [{ + 'change .js-select-boards'(evt) { + this.selectedBoardId.set($(evt.currentTarget).val()); + subManager.subscribe('board', this.selectedBoardId.get()); + }, + 'submit .js-search-term-form'(evt) { + evt.preventDefault(); + this.term.set(evt.target.searchTerm.value); + }, + 'click .js-minicard'() { + // IMPORT CARD + }, + }]; + }, +}).register('searchCardPopup'); diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 9244af9c..08fc129f 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -135,6 +135,9 @@ "cards": "Cards", "cards-count": "Cards", "casSignIn" : "Sign In with CAS", + "cardType-card": "Card", + "cardType-importedCard": "Imported Card", + "cardType-importedBoard": "Imported Board", "change": "Change", "change-avatar": "Change Avatar", "change-password": "Change Password", @@ -171,6 +174,8 @@ "confirm-subtask-delete-dialog": "Are you sure you want to delete subtask?", "confirm-checklist-delete-dialog": "Are you sure you want to delete checklist?", "copy-card-link-to-clipboard": "Copy card link to clipboard", + "importCardPopup-title": "Import Card", + "searchCardPopup-title": "Search Card", "copyCardPopup-title": "Copy Card", "copyChecklistToManyCardsPopup-title": "Copy Checklist Template to Many Cards", "copyChecklistToManyCardsPopup-instructions": "Destination Card Titles and Descriptions in this JSON format", diff --git a/models/boards.js b/models/boards.js index c51a9865..eda34bf4 100644 --- a/models/boards.js +++ b/models/boards.js @@ -212,6 +212,10 @@ Boards.helpers({ return this.permission === 'public'; }, + cards() { + return Cards.find({ boardId: this._id, archived: false }, { sort: { title: 1 } }); + }, + lists() { return Lists.find({ boardId: this._id, archived: false }, { sort: { sort: 1 } }); }, diff --git a/models/cards.js b/models/cards.js index b6a7b4c6..af8bea48 100644 --- a/models/cards.js +++ b/models/cards.js @@ -133,6 +133,13 @@ Cards.attachSchema(new SimpleSchema({ defaultValue: -1, optional: true, }, + type: { + type: String, + }, + importedId: { + type: String, + optional: true, + }, })); Cards.allow({ diff --git a/server/migrations.js b/server/migrations.js index 6135f1be..32f24e4c 100644 --- a/server/migrations.js +++ b/server/migrations.js @@ -213,6 +213,17 @@ Migrations.add('add-profile-view', () => { }); }); +Migrations.add('add-card-types', () => { + Cards.find().forEach((card) => { + Cards.direct.update( + { _id: card._id }, + { $set: { + type: 'cardType-card', + importedId: null } }, + noValidate + ); + }); + Migrations.add('add-custom-fields-to-cards', () => { Cards.update({ customFields: { |