Add UI for importing card-as-card and board-as-card

This commit is contained in:
Andrés Manelli 2018-03-20 00:13:42 -03:00
parent 193af893ee
commit dcc7b2970f
8 changed files with 199 additions and 1 deletions

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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');

View file

@ -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",

View file

@ -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 } });
},

View file

@ -133,6 +133,13 @@ Cards.attachSchema(new SimpleSchema({
defaultValue: -1,
optional: true,
},
type: {
type: String,
},
importedId: {
type: String,
optional: true,
},
}));
Cards.allow({

View file

@ -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: {