diff options
Diffstat (limited to 'client/components/sidebar')
-rw-r--r-- | client/components/sidebar/sidebar.jade | 156 | ||||
-rw-r--r-- | client/components/sidebar/sidebar.js | 224 | ||||
-rw-r--r-- | client/components/sidebar/sidebarCustomFields.js | 16 |
3 files changed, 377 insertions, 19 deletions
diff --git a/client/components/sidebar/sidebar.jade b/client/components/sidebar/sidebar.jade index ec88ce7e..4e4d355c 100644 --- a/client/components/sidebar/sidebar.jade +++ b/client/components/sidebar/sidebar.jade @@ -1,9 +1,9 @@ template(name="sidebar") .board-sidebar.sidebar(class="{{#if isOpen}}is-open{{/if}}") - a.sidebar-tongue.js-toggle-sidebar( - class="{{#if isTongueHidden}}is-hidden{{/if}}", - title="{{showTongueTitle}}") - i.fa.fa-angle-left + //a.sidebar-tongue.js-toggle-sidebar( + // class="{{#if isTongueHidden}}is-hidden{{/if}}", + // title="{{showTongueTitle}}") + // i.fa.fa-navicon .sidebar-shadow .sidebar-content.sidebar-shortcuts a.board-header-btn.js-shortcuts @@ -11,7 +11,7 @@ template(name="sidebar") span {{_ 'keyboard-shortcuts' }} .sidebar-content.js-board-sidebar-content.js-perfect-scrollbar a.hide-btn.js-hide-sidebar - i.fa.fa-angle-right + i.fa.fa-navicon unless isDefaultView h2 a.fa.fa-chevron-left.js-back-home @@ -34,6 +34,9 @@ template(name="membersWidget") h3 i.fa.fa-user | {{_ 'members'}} + a.board-header-btn.js-open-board-menu(title="{{_ 'boardMenuPopup-title'}}").right + i.board-header-btn-icon.fa.fa-cog + .board-widget-content each currentBoard.activeMembers +userAvatar(userId=this.userId showStatus=true) @@ -53,6 +56,130 @@ template(name="membersWidget") button.js-member-invite-accept.primary {{_ 'accept'}} button.js-member-invite-decline {{_ 'decline'}} +template(name="boardChangeColorPopup") + .board-backgrounds-list.clearfix + each backgroundColors + .board-background-select.js-select-background + span.background-box(class="board-color-{{this}}") + if isSelected + i.fa.fa-check + +template(name="boardSubtaskSettingsPopup") + form.board-subtask-settings + h3 {{_ 'show-parent-in-minicard'}} + a#prefix-with-full-path.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'prefix-with-full-path'}}is-checked{{/if}}") + .materialCheckBox(class="{{#if $eq presentParentTask 'prefix-with-full-path'}}is-checked{{/if}}") + span {{_ 'prefix-with-full-path'}} + a#prefix-with-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'prefix-with-parent'}}is-checked{{/if}}") + .materialCheckBox(class="{{#if $eq presentParentTask 'prefix-with-parent'}}is-checked{{/if}}") + span {{_ 'prefix-with-parent'}} + a#subtext-with-full-path.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'subtext-with-full-path'}}is-checked{{/if}}") + .materialCheckBox(class="{{#if $eq presentParentTask 'subtext-with-full-path'}}is-checked{{/if}}") + span {{_ 'subtext-with-full-path'}} + a#subtext-with-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'subtext-with-parent'}}is-checked{{/if}}") + .materialCheckBox(class="{{#if $eq presentParentTask 'subtext-with-parent'}}is-checked{{/if}}") + span {{_ 'subtext-with-parent'}} + a#no-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'no-parent'}}is-checked{{/if}}") + .materialCheckBox(class="{{#if $eq presentParentTask 'no-parent'}}is-checked{{/if}}") + span {{_ 'no-parent'}} + div + hr + + div.check-div + 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'}} + div + 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="chooseBoardSource") + ul.pop-over-list + li + a(href="{{pathFor '/import/trello'}}") {{_ 'from-trello'}} + li + a(href="{{pathFor '/import/wekan'}}") {{_ 'from-wekan'}} + +template(name="archiveBoardPopup") + p {{_ 'close-board-pop'}} + button.js-confirm.negate.full(type="submit") {{_ 'archive'}} + +template(name="outgoingWebhooksPopup") + each integrations + form.integration-form + if title + h4 {{title}} + else + h4 {{_ 'no-name'}} + label + | URL + input.js-outgoing-webhooks-url(type="text" name="url" value=url) + input(type="hidden" value=_id name="id") + input.primary.wide(type="submit" value="{{_ 'save'}}") + form.integration-form + h4 + | {{_ 'new-outgoing-webhook'}} + label + | URL + input.js-outgoing-webhooks-url(type="text" name="url" autofocus) + input.primary.wide(type="submit" value="{{_ 'save'}}") + +template(name="boardMenuPopup") + ul.pop-over-list + li: a.js-custom-fields {{_ 'custom-fields'}} + li: a.js-open-archives {{_ 'archived-items'}} + if currentUser.isBoardAdmin + li: a.js-change-board-color {{_ 'board-change-color'}} + //- + XXX Language should be handled by sandstorm, but for now display a + language selection link in the board menu. This link is normally present + in the header bar that is not displayed on sandstorm. + if isSandstorm + li: a.js-change-language {{_ 'language'}} + unless isSandstorm + if currentUser.isBoardAdmin + hr + ul.pop-over-list + li: a(href="{{exportUrl}}", download="{{exportFilename}}") {{_ 'export-board'}} + unless currentBoard.isTemplatesBoard + 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 + li: a(href="{{exportUrl}}", download="{{exportFilename}}") {{_ 'export-board'}} + li: a.js-import-board {{_ 'import-board-c'}} + 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'}} + template(name="labelsWidget") .board-widget.board-widget-labels h3 @@ -83,17 +210,16 @@ template(name="memberPopup") ul.pop-over-list li a.js-filter-member {{_ 'filter-cards'}} - unless isSandstorm - if currentUser.isBoardAdmin - li - a.js-change-role - | {{_ 'change-permissions'}} - span.quiet (#{memberType}) + if currentUser.isBoardAdmin li - if $eq currentUser._id userId - a.js-leave-member {{_ 'leave-board'}} - else if currentUser.isBoardAdmin - a.js-remove-member {{_ 'remove-from-board'}} + a.js-change-role + | {{_ 'change-permissions'}} + span.quiet (#{memberType}) + li + if $eq currentUser._id userId + a.js-leave-member {{_ 'leave-board'}} + else if currentUser.isBoardAdmin + a.js-remove-member {{_ 'remove-from-board'}} template(name="removeMemberPopup") diff --git a/client/components/sidebar/sidebar.js b/client/components/sidebar/sidebar.js index 83b12666..e8de3c96 100644 --- a/client/components/sidebar/sidebar.js +++ b/client/components/sidebar/sidebar.js @@ -142,6 +142,52 @@ Template.memberPopup.helpers({ }, }); +Template.boardMenuPopup.events({ + 'click .js-rename-board': Popup.open('boardChangeTitle'), + 'click .js-custom-fields'() { + Sidebar.setView('customFields'); + Popup.close(); + }, + 'click .js-open-archives'() { + Sidebar.setView('archives'); + Popup.close(); + }, + 'click .js-change-board-color': Popup.open('boardChangeColor'), + 'click .js-change-language': Popup.open('changeLanguage'), + 'click .js-archive-board ': Popup.afterConfirm('archiveBoard', function() { + const currentBoard = Boards.findOne(Session.get('currentBoard')); + currentBoard.archive(); + // XXX We should have some kind of notification on top of the page to + // confirm that the board was successfully archived. + FlowRouter.go('home'); + }), + 'click .js-delete-board': Popup.afterConfirm('deleteBoard', function() { + const currentBoard = Boards.findOne(Session.get('currentBoard')); + Popup.close(); + Boards.remove(currentBoard._id); + FlowRouter.go('home'); + }), + 'click .js-outgoing-webhooks': Popup.open('outgoingWebhooks'), + 'click .js-import-board': Popup.open('chooseBoardSource'), + 'click .js-subtask-settings': Popup.open('boardSubtaskSettings'), +}); + +Template.boardMenuPopup.helpers({ + exportUrl() { + const params = { + boardId: Session.get('currentBoard'), + }; + const queryParams = { + authToken: Accounts._storedLoginToken(), + }; + return FlowRouter.path('/api/boards/:boardId/export', params, queryParams); + }, + exportFilename() { + const boardId = Session.get('currentBoard'); + return `wekan-export-board-${boardId}.json`; + }, +}); + Template.memberPopup.events({ 'click .js-filter-member'() { Filter.members.toggle(this.userId); @@ -190,7 +236,14 @@ Template.membersWidget.helpers({ Template.membersWidget.events({ 'click .js-member': Popup.open('member'), + 'click .js-open-board-menu': Popup.open('boardMenu'), 'click .js-manage-board-members': Popup.open('addMember'), + 'click .js-import': Popup.open('boardImportBoard'), + submit: this.onSubmit, + 'click .js-import-board': Popup.open('chooseBoardSource'), + 'click .js-open-archived-board'() { + Modal.open('archivedBoards'); + }, 'click .sandstorm-powerbox-request-identity'() { window.sandstormRequestIdentity(); }, @@ -209,6 +262,59 @@ Template.membersWidget.events({ }, }); +BlazeComponent.extendComponent({ + integrations() { + const boardId = Session.get('currentBoard'); + return Integrations.find({ boardId: `${boardId}` }).fetch(); + }, + + integration(id) { + const boardId = Session.get('currentBoard'); + return Integrations.findOne({ _id: id, boardId: `${boardId}` }); + }, + + events() { + return [{ + 'submit'(evt) { + evt.preventDefault(); + const url = evt.target.url.value; + const boardId = Session.get('currentBoard'); + let id = null; + let integration = null; + if (evt.target.id) { + id = evt.target.id.value; + integration = this.integration(id); + if (url) { + Integrations.update(integration._id, { + $set: { + url: `${url}`, + }, + }); + } else { + Integrations.remove(integration._id); + } + } else if (url) { + Integrations.insert({ + userId: Meteor.userId(), + enabled: true, + type: 'outgoing-webhooks', + url: `${url}`, + boardId: `${boardId}`, + activities: ['all'], + }); + } + Popup.close(); + }, + }]; + }, +}).register('outgoingWebhooksPopup'); + +BlazeComponent.extendComponent({ + template() { + return 'chooseBoardSource'; + }, +}).register('chooseBoardSourcePopup'); + Template.labelsWidget.events({ 'click .js-label': Popup.open('editLabel'), 'click .js-add-label': Popup.open('createLabel'), @@ -259,6 +365,124 @@ Template.membersWidget.onRendered(draggableMembersLabelsWidgets); Template.labelsWidget.onRendered(draggableMembersLabelsWidgets); BlazeComponent.extendComponent({ + backgroundColors() { + return Boards.simpleSchema()._schema.color.allowedValues; + }, + + isSelected() { + const currentBoard = Boards.findOne(Session.get('currentBoard')); + return currentBoard.color === this.currentData().toString(); + }, + + events() { + return [{ + 'click .js-select-background'(evt) { + const currentBoard = Boards.findOne(Session.get('currentBoard')); + const newColor = this.currentData().toString(); + currentBoard.setColor(newColor); + evt.preventDefault(); + }, + }]; + }, +}).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; + }, + + presentParentTask() { + let result = this.currentBoard.presentParentTask; + if ((result === null) || (result === undefined)) { + result = 'no-parent'; + } + return result; + }, + + 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(); + }, + 'click .js-field-show-parent-in-minicard'(evt) { + const value = evt.target.id || $(evt.target).parent()[0].id || $(evt.target).parent()[0].parent()[0].id; + const options = [ + 'prefix-with-full-path', + 'prefix-with-parent', + 'subtext-with-full-path', + 'subtext-with-parent', + 'no-parent']; + options.forEach(function(element) { + if (element !== value) { + $(`#${element} .materialCheckBox`).toggleClass('is-checked', false); + $(`#${element}`).toggleClass('is-checked', false); + } + }); + $(`#${value} .materialCheckBox`).toggleClass('is-checked', true); + $(`#${value}`).toggleClass('is-checked', true); + this.currentBoard.setPresentParentTask(value); + evt.preventDefault(); + }, + }]; + }, +}).register('boardSubtaskSettingsPopup'); + +BlazeComponent.extendComponent({ onCreated() { this.error = new ReactiveVar(''); this.loading = new ReactiveVar(false); diff --git a/client/components/sidebar/sidebarCustomFields.js b/client/components/sidebar/sidebarCustomFields.js index ccc8ffb9..28af973b 100644 --- a/client/components/sidebar/sidebarCustomFields.js +++ b/client/components/sidebar/sidebarCustomFields.js @@ -2,7 +2,7 @@ BlazeComponent.extendComponent({ customFields() { return CustomFields.find({ - boardId: Session.get('currentBoard'), + boardIds: {$in: [Session.get('currentBoard')]}, }); }, @@ -103,7 +103,6 @@ const CreateCustomFieldPopup = BlazeComponent.extendComponent({ evt.preventDefault(); const data = { - boardId: Session.get('currentBoard'), name: this.find('.js-field-name').value.trim(), type: this.type.get(), settings: this.getSettings(), @@ -114,6 +113,7 @@ const CreateCustomFieldPopup = BlazeComponent.extendComponent({ // insert or update if (!this.data()._id) { + data.boardIds = [Session.get('currentBoard')]; CustomFields.insert(data); } else { CustomFields.update(this.data()._id, {$set: data}); @@ -122,8 +122,16 @@ const CreateCustomFieldPopup = BlazeComponent.extendComponent({ Popup.back(); }, 'click .js-delete-custom-field': Popup.afterConfirm('deleteCustomField', function() { - const customFieldId = this._id; - CustomFields.remove(customFieldId); + const customField = CustomFields.findOne(this._id); + if (customField.boardIds.length > 1) { + CustomFields.update(customField._id, { + $pull: { + boardIds: Session.get('currentBoard'), + }, + }); + } else { + CustomFields.remove(customField._id); + } Popup.close(); }), }]; |