diff options
Diffstat (limited to 'client/components')
-rw-r--r-- | client/components/boards/boardHeader.jade | 19 | ||||
-rw-r--r-- | client/components/boards/boardHeader.js | 50 | ||||
-rw-r--r-- | client/components/cards/checklists.jade | 4 | ||||
-rw-r--r-- | client/components/cards/checklists.js | 24 | ||||
-rw-r--r-- | client/components/cards/checklists.styl | 3 | ||||
-rw-r--r-- | client/components/import/import.jade | 4 | ||||
-rw-r--r-- | client/components/import/import.js | 48 | ||||
-rw-r--r-- | client/components/import/trelloMembersMapper.js | 14 | ||||
-rw-r--r-- | client/components/import/wekanMembersMapper.js | 24 |
9 files changed, 164 insertions, 26 deletions
diff --git a/client/components/boards/boardHeader.jade b/client/components/boards/boardHeader.jade index e61aea35..d33ee11b 100644 --- a/client/components/boards/boardHeader.jade +++ b/client/components/boards/boardHeader.jade @@ -112,6 +112,7 @@ template(name="boardMenuPopup") ul.pop-over-list li: a(href="{{exportUrl}}", download="{{exportFilename}}") {{_ 'export-board'}} li: a.js-archive-board {{_ 'archive-board'}} + li: a.js-outgoing-webhooks {{_ 'outgoing-webhooks'}} template(name="boardVisibilityList") ul.pop-over-list @@ -191,8 +192,14 @@ template(name="createBoard") input.primary.wide(type="submit" value="{{_ 'create'}}") span.quiet | {{_ 'or'}} - a(href="{{pathFor 'import'}}") {{_ 'import-board'}} + a.js-import-board {{_ 'import-board'}} +template(name="chooseBoardSource") + ul.pop-over-list + li + a(href="{{pathFor 'import/trello'}}") {{_ 'from-trello'}} + li + a(href="{{pathFor 'import/wekan'}}") {{_ 'from-wekan'}} template(name="boardChangeTitlePopup") form @@ -207,3 +214,13 @@ template(name="boardChangeTitlePopup") template(name="archiveBoardPopup") p {{_ 'close-board-pop'}} button.js-confirm.negate.full(type="submit") {{_ 'archive'}} + +template(name="outgoingWebhooksPopup") + form + label + | URL + if integration.enabled + input.js-outgoing-webhooks-url(type="text" value=integration.url autofocus) + else + input.js-outgoing-webhooks-url(type="text" autofocus) + input.primary.wide(type="submit" value="{{_ 'save'}}") diff --git a/client/components/boards/boardHeader.js b/client/components/boards/boardHeader.js index 06defbfa..dafbfd30 100644 --- a/client/components/boards/boardHeader.js +++ b/client/components/boards/boardHeader.js @@ -13,6 +13,7 @@ Template.boardMenuPopup.events({ // confirm that the board was successfully archived. FlowRouter.go('home'); }), + 'click .js-outgoing-webhooks': Popup.open('outgoingWebhooks'), }); Template.boardMenuPopup.helpers({ @@ -174,10 +175,17 @@ const CreateBoard = BlazeComponent.extendComponent({ 'click .js-change-visibility': this.toggleVisibilityMenu, 'click .js-import': Popup.open('boardImportBoard'), submit: this.onSubmit, + 'click .js-import-board': Popup.open('chooseBoardSource'), }]; }, }).register('createBoardPopup'); +BlazeComponent.extendComponent({ + template() { + return 'chooseBoardSource'; + }, +}).register('chooseBoardSourcePopup'); + (class HeaderBarCreateBoard extends CreateBoard { onSubmit(evt) { super.onSubmit(evt); @@ -227,3 +235,45 @@ BlazeComponent.extendComponent({ }]; }, }).register('boardChangeWatchPopup'); + +BlazeComponent.extendComponent({ + integration() { + const boardId = Session.get('currentBoard'); + return Integrations.findOne({ boardId: `${boardId}` }); + }, + + events() { + return [{ + 'submit'(evt) { + evt.preventDefault(); + const url = this.find('.js-outgoing-webhooks-url').value.trim(); + const boardId = Session.get('currentBoard'); + const integration = this.integration(); + if (integration) { + if (url) { + Integrations.update(integration._id, { + $set: { + enabled: true, + url: `${url}`, + }, + }); + } else { + Integrations.update(integration._id, { + $set: { + enabled: false, + }, + }); + } + } else if (url) { + Integrations.insert({ + enabled: true, + type: 'outgoing-webhooks', + url: `${url}`, + boardId: `${boardId}`, + }); + } + Popup.close(); + }, + }]; + }, +}).register('outgoingWebhooksPopup'); diff --git a/client/components/cards/checklists.jade b/client/components/cards/checklists.jade index a0d89351..d04a9b60 100644 --- a/client/components/cards/checklists.jade +++ b/client/components/cards/checklists.jade @@ -4,7 +4,7 @@ template(name="checklists") each checklist in currentCard.checklists +checklistDetail(checklist = checklist) if canModifyCard - +inlinedForm(classNames="js-add-checklist" cardId = cardId) + +inlinedForm(autoclose=false classNames="js-add-checklist" cardId = cardId) +addChecklistItemForm else a.js-open-inlined-form @@ -53,7 +53,7 @@ template(name="checklistItems") else +itemDetail(item = item checklist = checklist) if canModifyCard - +inlinedForm(classNames="js-add-checklist-item" checklist = checklist) + +inlinedForm(autoclose=false classNames="js-add-checklist-item" checklist = checklist) +addChecklistItemForm else a.add-checklist-item.js-open-inlined-form diff --git a/client/components/cards/checklists.js b/client/components/cards/checklists.js index b8f5e443..24a78035 100644 --- a/client/components/cards/checklists.js +++ b/client/components/cards/checklists.js @@ -4,10 +4,18 @@ BlazeComponent.extendComponent({ const textarea = this.find('textarea.js-add-checklist-item'); const title = textarea.value.trim(); const cardId = this.currentData().cardId; - Checklists.insert({ - cardId, - title, - }); + + if (title) { + Checklists.insert({ + cardId, + title, + }); + setTimeout(() => { + this.$('.add-checklist-item').last().click(); + }, 100); + } + textarea.value = ''; + textarea.focus(); }, addChecklistItem(event) { @@ -15,7 +23,13 @@ BlazeComponent.extendComponent({ const textarea = this.find('textarea.js-add-checklist-item'); const title = textarea.value.trim(); const checklist = this.currentData().checklist; - checklist.addItem(title); + + if (title) { + checklist.addItem(title); + } + // We keep the form opened, empty it. + textarea.value = ''; + textarea.focus(); }, editChecklist(event) { diff --git a/client/components/cards/checklists.styl b/client/components/cards/checklists.styl index 885d7528..1156c577 100644 --- a/client/components/cards/checklists.styl +++ b/client/components/cards/checklists.styl @@ -46,6 +46,8 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item font-size: 1.1em margin-top: 3px display: flex + &:hover + background-color: darken(white, 8%) .check-box margin-top: 5px @@ -54,6 +56,7 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item border-right: 2px solid #3cb500 .item-title + flex-grow: 1 padding-left: 10px; &.is-checked color: #8c8c8c diff --git a/client/components/import/import.jade b/client/components/import/import.jade index d4def7d8..d1b3489a 100644 --- a/client/components/import/import.jade +++ b/client/components/import/import.jade @@ -2,7 +2,7 @@ template(name="importHeaderBar") h1 a.back-btn(href="{{pathFor 'home'}}") i.fa.fa-chevron-left - | {{_ 'import-board-title'}} + | {{_ title}} template(name="import") .wrapper @@ -12,7 +12,7 @@ template(name="import") template(name="importTextarea") form - p: label(for='import-textarea') {{_ 'import-board-trello-instruction'}} + p: label(for='import-textarea') {{_ instruction}} textarea.js-import-json(placeholder="{{_ 'import-json-placeholder'}}" autofocus) | {{jsonText}} input.primary.wide(type="submit" value="{{_ 'import'}}") diff --git a/client/components/import/import.js b/client/components/import/import.js index 11a5308a..d72a02dd 100644 --- a/client/components/import/import.js +++ b/client/components/import/import.js @@ -1,3 +1,12 @@ +import trelloMembersMapper from './trelloMembersMapper'; +import wekanMembersMapper from './wekanMembersMapper'; + +BlazeComponent.extendComponent({ + title() { + return `import-board-title-${Session.get('importSource')}`; + }, +}).register('importHeaderBar'); + BlazeComponent.extendComponent({ onCreated() { this.error = new ReactiveVar(''); @@ -5,6 +14,7 @@ BlazeComponent.extendComponent({ this._currentStepIndex = new ReactiveVar(0); this.importedData = new ReactiveVar(); this.membersToMap = new ReactiveVar([]); + this.importSource = Session.get('importSource'); }, currentTemplate() { @@ -27,7 +37,10 @@ BlazeComponent.extendComponent({ const dataObject = JSON.parse(dataJson); this.setError(''); this.importedData.set(dataObject); - this._prepareAdditionalData(dataObject); + const membersToMap = this._prepareAdditionalData(dataObject); + // store members data and mapping in Session + // (we go deep and 2-way, so storing in data context is not a viable option) + this.membersToMap.set(membersToMap); this.nextStep(); } catch (e) { this.setError('error-json-malformed'); @@ -51,7 +64,10 @@ BlazeComponent.extendComponent({ additionalData.membersMapping = mappingById; } this.membersToMap.set([]); - Meteor.call('importTrelloBoard', this.importedData.get(), additionalData, + Meteor.call('importBoard', + this.importedData.get(), + additionalData, + this.importSource, (err, res) => { if (err) { this.setError(err.error); @@ -63,20 +79,16 @@ BlazeComponent.extendComponent({ }, _prepareAdditionalData(dataObject) { - // we will work on the list itself (an ordered array of objects) when a - // mapping is done, we add a 'wekan' field to the object representing the - // imported member - const membersToMap = dataObject.members; - // auto-map based on username - membersToMap.forEach((importedMember) => { - const wekanUser = Users.findOne({ username: importedMember.username }); - if (wekanUser) { - importedMember.wekanId = wekanUser._id; - } - }); - // store members data and mapping in Session - // (we go deep and 2-way, so storing in data context is not a viable option) - this.membersToMap.set(membersToMap); + const importSource = Session.get('importSource'); + let membersToMap; + switch (importSource) { + case 'trello': + membersToMap = trelloMembersMapper.getMembersToMap(dataObject); + break; + case 'wekan': + membersToMap = wekanMembersMapper.getMembersToMap(dataObject); + break; + } return membersToMap; }, @@ -90,6 +102,10 @@ BlazeComponent.extendComponent({ return 'importTextarea'; }, + instruction() { + return `import-board-instruction-${Session.get('importSource')}`; + }, + events() { return [{ submit(evt) { diff --git a/client/components/import/trelloMembersMapper.js b/client/components/import/trelloMembersMapper.js new file mode 100644 index 00000000..0f353bf1 --- /dev/null +++ b/client/components/import/trelloMembersMapper.js @@ -0,0 +1,14 @@ +export function getMembersToMap(data) { + // we will work on the list itself (an ordered array of objects) when a + // mapping is done, we add a 'wekan' field to the object representing the + // imported member + const membersToMap = data.members; + // auto-map based on username + membersToMap.forEach((importedMember) => { + const wekanUser = Users.findOne({ username: importedMember.username }); + if (wekanUser) { + importedMember.wekanId = wekanUser._id; + } + }); + return membersToMap; +} diff --git a/client/components/import/wekanMembersMapper.js b/client/components/import/wekanMembersMapper.js new file mode 100644 index 00000000..f4c110f7 --- /dev/null +++ b/client/components/import/wekanMembersMapper.js @@ -0,0 +1,24 @@ +export function getMembersToMap(data) { + // we will work on the list itself (an ordered array of objects) when a + // mapping is done, we add a 'wekan' field to the object representing the + // imported member + const membersToMap = data.members; + const users = data.users; + // auto-map based on username + membersToMap.forEach((importedMember) => { + importedMember.id = importedMember.userId; + delete importedMember.userId; + const user = users.filter((user) => { + return user._id === importedMember.id; + })[0]; + if (user.profile && user.profile.fullname) { + importedMember.fullName = user.profile.fullname; + } + importedMember.username = user.username; + const wekanUser = Users.findOne({ username: importedMember.username }); + if (wekanUser) { + importedMember.wekanId = wekanUser._id; + } + }); + return membersToMap; +} |