diff options
Diffstat (limited to 'app/assets/javascripts/boards/components/modal')
7 files changed, 322 insertions, 4 deletions
diff --git a/app/assets/javascripts/boards/components/modal/filters.js.es6 b/app/assets/javascripts/boards/components/modal/filters.js.es6 new file mode 100644 index 00000000000..6de06811d94 --- /dev/null +++ b/app/assets/javascripts/boards/components/modal/filters.js.es6 @@ -0,0 +1,49 @@ +/* global Vue */ +const userFilter = require('./filters/user'); +const milestoneFilter = require('./filters/milestone'); +const labelFilter = require('./filters/label'); + +module.exports = Vue.extend({ + name: 'modal-filters', + props: { + projectId: { + type: Number, + required: true, + }, + milestonePath: { + type: String, + required: true, + }, + labelPath: { + type: String, + required: true, + }, + }, + destroyed() { + gl.issueBoards.ModalStore.setDefaultFilter(); + }, + components: { + userFilter, + milestoneFilter, + labelFilter, + }, + template: ` + <div class="modal-filters"> + <user-filter + dropdown-class-name="dropdown-menu-author" + toggle-class-name="js-user-search js-author-search" + toggle-label="Author" + field-name="author_id" + :project-id="projectId"></user-filter> + <user-filter + dropdown-class-name="dropdown-menu-author" + toggle-class-name="js-assignee-search" + toggle-label="Assignee" + field-name="assignee_id" + :null-user="true" + :project-id="projectId"></user-filter> + <milestone-filter :milestone-path="milestonePath"></milestone-filter> + <label-filter :label-path="labelPath"></label-filter> + </div> + `, +}); diff --git a/app/assets/javascripts/boards/components/modal/filters/label.js.es6 b/app/assets/javascripts/boards/components/modal/filters/label.js.es6 new file mode 100644 index 00000000000..4fc8f72a145 --- /dev/null +++ b/app/assets/javascripts/boards/components/modal/filters/label.js.es6 @@ -0,0 +1,54 @@ +/* eslint-disable no-new */ +/* global Vue */ +/* global LabelsSelect */ +module.exports = Vue.extend({ + name: 'filter-label', + props: { + labelPath: { + type: String, + required: true, + }, + }, + mounted() { + new LabelsSelect(this.$refs.dropdown); + }, + template: ` + <div class="dropdown"> + <button + class="dropdown-menu-toggle js-label-select js-multiselect js-extra-options" + type="button" + data-toggle="dropdown" + data-show-any="true" + data-show-no="true" + :data-labels="labelPath" + ref="dropdown"> + <span class="dropdown-toggle-text"> + Label + </span> + <i class="fa fa-chevron-down"></i> + </button> + <div class="dropdown-menu dropdown-select dropdown-menu-paging dropdown-menu-labels dropdown-menu-selectable"> + <div class="dropdown-title"> + Filter by label + <button + class="dropdown-title-button dropdown-menu-close" + aria-label="Close" + type="button"> + <i class="fa fa-times dropdown-menu-close-icon"></i> + </button> + </div> + <div class="dropdown-input"> + <input + type="search" + class="dropdown-input-field" + placeholder="Search" + autocomplete="off" /> + <i class="fa fa-search dropdown-input-search"></i> + <i role="button" class="fa fa-times dropdown-input-clear js-dropdown-input-clear"></i> + </div> + <div class="dropdown-content"></div> + <div class="dropdown-loading"><i class="fa fa-spinner fa-spin"></i></div> + </div> + </div> + `, +}); diff --git a/app/assets/javascripts/boards/components/modal/filters/milestone.js.es6 b/app/assets/javascripts/boards/components/modal/filters/milestone.js.es6 new file mode 100644 index 00000000000..d555599d300 --- /dev/null +++ b/app/assets/javascripts/boards/components/modal/filters/milestone.js.es6 @@ -0,0 +1,55 @@ +/* eslint-disable no-new */ +/* global Vue */ +/* global MilestoneSelect */ +module.exports = Vue.extend({ + name: 'filter-milestone', + props: { + milestonePath: { + type: String, + required: true, + }, + }, + mounted() { + new MilestoneSelect(null, this.$refs.dropdown); + }, + template: ` + <div class="dropdown"> + <button + class="dropdown-menu-toggle js-milestone-select" + type="button" + data-toggle="dropdown" + data-show-any="true" + data-show-upcoming="true" + data-field-name="milestone_title" + :data-milestones="milestonePath" + ref="dropdown"> + <span class="dropdown-toggle-text"> + Milestone + </span> + <i class="fa fa-chevron-down"></i> + </button> + <div class="dropdown-menu dropdown-select dropdown-menu-selectable dropdown-menu-milestone"> + <div class="dropdown-title"> + <span>Filter by milestone</span> + <button + class="dropdown-title-button dropdown-menu-close" + aria-label="Close" + type="button"> + <i class="fa fa-times dropdown-menu-close-icon"></i> + </button> + </div> + <div class="dropdown-input"> + <input + type="search" + class="dropdown-input-field" + placeholder="Search milestones" + autocomplete="off" /> + <i class="fa fa-search dropdown-input-search"></i> + <i role="button" class="fa fa-times dropdown-input-clear js-dropdown-input-clear"></i> + </div> + <div class="dropdown-content"></div> + <div class="dropdown-loading"><i class="fa fa-spinner fa-spin"></i></div> + </div> + </div> + `, +}); diff --git a/app/assets/javascripts/boards/components/modal/filters/user.js.es6 b/app/assets/javascripts/boards/components/modal/filters/user.js.es6 new file mode 100644 index 00000000000..8523028c29c --- /dev/null +++ b/app/assets/javascripts/boards/components/modal/filters/user.js.es6 @@ -0,0 +1,96 @@ +/* eslint-disable no-new */ +/* global Vue */ +/* global UsersSelect */ +module.exports = Vue.extend({ + name: 'filter-user', + props: { + toggleClassName: { + type: String, + required: true, + }, + dropdownClassName: { + type: String, + required: false, + default: '', + }, + toggleLabel: { + type: String, + required: true, + }, + fieldName: { + type: String, + required: true, + }, + nullUser: { + type: Boolean, + required: false, + default: false, + }, + projectId: { + type: Number, + required: true, + }, + }, + mounted() { + new UsersSelect(null, this.$refs.dropdown); + }, + computed: { + currentUsername() { + return gon.current_username; + }, + dropdownTitle() { + return `Filter by ${this.toggleLabel.toLowerCase()}`; + }, + inputPlaceholder() { + return `Search ${this.toggleLabel.toLowerCase()}`; + }, + }, + template: ` + <div class="dropdown"> + <button + class="dropdown-menu-toggle js-user-search" + :class="toggleClassName" + type="button" + data-toggle="dropdown" + data-current-user="true" + :data-any-user="'Any ' + toggleLabel" + :data-null-user="nullUser" + :data-field-name="fieldName" + :data-project-id="projectId" + :data-first-user="currentUsername" + ref="dropdown"> + <span class="dropdown-toggle-text"> + {{ toggleLabel }} + </span> + <i class="fa fa-chevron-down"></i> + </button> + <div + class="dropdown-menu dropdown-select dropdown-menu-user dropdown-menu-selectable" + :class="dropdownClassName"> + <div class="dropdown-title"> + {{ dropdownTitle }} + <button + class="dropdown-title-button dropdown-menu-close" + aria-label="Close" + type="button"> + <i class="fa fa-times dropdown-menu-close-icon"></i> + </button> + </div> + <div class="dropdown-input"> + <input + type="search" + class="dropdown-input-field" + autocomplete="off" + :placeholder="inputPlaceholder" /> + <i class="fa fa-search dropdown-input-search"></i> + <i + role="button" + class="fa fa-times dropdown-input-clear js-dropdown-input-clear"> + </i> + </div> + <div class="dropdown-content"></div> + <div class="dropdown-loading"><i class="fa fa-spinner fa-spin"></i></div> + </div> + </div> + `, +}); diff --git a/app/assets/javascripts/boards/components/modal/header.js.es6 b/app/assets/javascripts/boards/components/modal/header.js.es6 index ab903722ba4..70c088f9054 100644 --- a/app/assets/javascripts/boards/components/modal/header.js.es6 +++ b/app/assets/javascripts/boards/components/modal/header.js.es6 @@ -1,12 +1,26 @@ /* global Vue */ - require('./tabs'); +const modalFilters = require('./filters'); (() => { const ModalStore = gl.issueBoards.ModalStore; gl.issueBoards.ModalHeader = Vue.extend({ mixins: [gl.issueBoards.ModalMixins], + props: { + projectId: { + type: Number, + required: true, + }, + milestonePath: { + type: String, + required: true, + }, + labelPath: { + type: String, + required: true, + }, + }, data() { return ModalStore.store; }, @@ -31,6 +45,7 @@ require('./tabs'); }, components: { 'modal-tabs': gl.issueBoards.ModalTabs, + modalFilters, }, template: ` <div> @@ -51,6 +66,11 @@ require('./tabs'); <div class="add-issues-search append-bottom-10" v-if="showSearch"> + <modal-filters + :project-id="projectId" + :milestone-path="milestonePath" + :label-path="labelPath"> + </modal-filters> <input placeholder="Search issues..." class="form-control" diff --git a/app/assets/javascripts/boards/components/modal/index.js.es6 b/app/assets/javascripts/boards/components/modal/index.js.es6 index d367b7e4246..f290cd13763 100644 --- a/app/assets/javascripts/boards/components/modal/index.js.es6 +++ b/app/assets/javascripts/boards/components/modal/index.js.es6 @@ -27,6 +27,18 @@ require('./empty_state'); type: String, required: true, }, + projectId: { + type: Number, + required: true, + }, + milestonePath: { + type: String, + required: true, + }, + labelPath: { + type: String, + required: true, + }, }, data() { return ModalStore.store; @@ -52,17 +64,27 @@ require('./empty_state'); this.issuesCount = false; } }, + filter: { + handler() { + this.loadIssues(true); + }, + deep: true, + }, }, methods: { searchOperation: _.debounce(function searchOperationDebounce() { this.loadIssues(true); }, 500), loadIssues(clearIssues = false) { - return gl.boardService.getBacklog({ + if (!this.showAddIssuesModal) return false; + + const queryData = Object.assign({}, this.filter, { search: this.searchTerm, page: this.page, per: this.perPage, - }).then((res) => { + }); + + return gl.boardService.getBacklog(queryData).then((res) => { const data = res.json(); if (clearIssues) { @@ -112,8 +134,13 @@ require('./empty_state'); class="add-issues-modal" v-if="showAddIssuesModal"> <div class="add-issues-container"> - <modal-header></modal-header> + <modal-header + :project-id="projectId" + :milestone-path="milestonePath" + :label-path="labelPath"> + </modal-header> <modal-list + :image="blankStateImage" :issue-link-base="issueLinkBase" :root-path="rootPath" v-if="!loading && showList"></modal-list> diff --git a/app/assets/javascripts/boards/components/modal/list.js.es6 b/app/assets/javascripts/boards/components/modal/list.js.es6 index d0901219216..3730c1ecaeb 100644 --- a/app/assets/javascripts/boards/components/modal/list.js.es6 +++ b/app/assets/javascripts/boards/components/modal/list.js.es6 @@ -14,6 +14,10 @@ type: String, required: true, }, + image: { + type: String, + required: true, + }, }, data() { return ModalStore.store; @@ -111,6 +115,19 @@ class="add-issues-list add-issues-list-columns" ref="list"> <div + class="empty-state add-issues-empty-state-filter text-center" + v-if="issuesCount > 0 && issues.length === 0"> + <div + class="svg-content" + v-html="image"> + </div> + <div class="text-content"> + <h4> + There are no issues to show. + </h4> + </div> + </div> + <div v-for="group in groupedIssues" class="add-issues-list-column"> <div |