From 850f19c02c53648b16a531a81586c05edcfa7530 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 7 Mar 2017 09:24:01 +0000 Subject: [PATCH 01/13] Added filtered search bar to issue boards Closes #28312 --- app/assets/javascripts/boards/boards_bundle.js | 3 +++ .../boards/filtered_search_boards.js | 5 +++++ .../javascripts/boards/stores/boards_store.js | 4 ++-- app/assets/stylesheets/framework/filters.scss | 5 +++++ app/views/projects/boards/_show.html.haml | 3 ++- app/views/shared/issuable/_filter.html.haml | 18 ++---------------- .../shared/issuable/_search_bar.html.haml | 16 ++++++++++++++-- .../unreleased/issue-boards-new-search-bar.yml | 4 ++++ 8 files changed, 37 insertions(+), 21 deletions(-) create mode 100644 app/assets/javascripts/boards/filtered_search_boards.js create mode 100644 changelogs/unreleased/issue-boards-new-search-bar.yml diff --git a/app/assets/javascripts/boards/boards_bundle.js b/app/assets/javascripts/boards/boards_bundle.js index 55d13be6e5f..951cb854ce8 100644 --- a/app/assets/javascripts/boards/boards_bundle.js +++ b/app/assets/javascripts/boards/boards_bundle.js @@ -4,6 +4,7 @@ window.Vue = require('vue'); window.Vue.use(require('vue-resource')); +import FilteredSearchBoards from './filtered_search_boards'; require('./models/issue'); require('./models/label'); require('./models/list'); @@ -26,6 +27,8 @@ $(() => { const Store = gl.issueBoards.BoardsStore; const ModalStore = gl.issueBoards.ModalStore; + new FilteredSearchBoards(); + window.gl = window.gl || {}; if (gl.IssueBoardsApp) { diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js new file mode 100644 index 00000000000..6a00d84faf1 --- /dev/null +++ b/app/assets/javascripts/boards/filtered_search_boards.js @@ -0,0 +1,5 @@ +export default class FilteredSearchBoards extends gl.FilteredSearchManager { + constructor() { + super('boards'); + } +} diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js index 3866c6bbfc6..c902a1d8bfc 100644 --- a/app/assets/javascripts/boards/stores/boards_store.js +++ b/app/assets/javascripts/boards/stores/boards_store.js @@ -19,8 +19,8 @@ create () { this.state.lists = []; this.state.filters = { - author_id: gl.utils.getParameterValues('author_id')[0], - assignee_id: gl.utils.getParameterValues('assignee_id')[0], + author_username: gl.utils.getParameterValues('author_username')[0], + assignee_username: gl.utils.getParameterValues('assignee_username')[0], milestone_title: gl.utils.getParameterValues('milestone_title')[0], label_name: gl.utils.getParameterValues('label_name[]'), search: '' diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss index 8f2150066c7..bf0e8e2b891 100644 --- a/app/assets/stylesheets/framework/filters.scss +++ b/app/assets/stylesheets/framework/filters.scss @@ -219,6 +219,11 @@ } } +.filter-dropdown-container { + display: -webkit-flex; + display: flex; +} + .dropdown-menu .filter-dropdown-item { padding: 0; } diff --git a/app/views/projects/boards/_show.html.haml b/app/views/projects/boards/_show.html.haml index 3ae78387938..a3593c9f5db 100644 --- a/app/views/projects/boards/_show.html.haml +++ b/app/views/projects/boards/_show.html.haml @@ -4,6 +4,7 @@ - content_for :page_specific_javascripts do = page_specific_javascript_bundle_tag('common_vue') + = page_specific_javascript_bundle_tag('filtered_search') = page_specific_javascript_bundle_tag('boards') = page_specific_javascript_bundle_tag('simulate_drag') if Rails.env.test? @@ -12,7 +13,7 @@ = render "projects/issues/head" -= render 'shared/issuable/filter', type: :boards += render 'shared/issuable/search_bar', type: :boards #board-app.boards-app{ "v-cloak" => true, data: board_data } .boards-list{ ":class" => "{ 'is-compact': detailIssueVisible }" } diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml index f17ae9f28eb..f0bad69a989 100644 --- a/app/views/shared/issuable/_filter.html.haml +++ b/app/views/shared/issuable/_filter.html.haml @@ -1,4 +1,4 @@ -- finder = controller.controller_name == 'issues' || controller.controller_name == 'boards' ? issues_finder : merge_requests_finder +- finder = controller.controller_name == 'issues' ? issues_finder : merge_requests_finder - boards_page = controller.controller_name == 'boards' .issues-filters @@ -34,21 +34,7 @@ %a{ href: page_filter_path(without: issuable_filter_params) } Reset filters .pull-right - - if boards_page - #js-boards-search.issue-boards-search - %input.pull-left.form-control{ type: "search", placeholder: "Filter by name...", "v-model" => "filters.search", "debounce" => "250" } - - if can?(current_user, :admin_list, @project) - #js-add-issues-btn.pull-right.prepend-left-10 - .dropdown.pull-right - %button.btn.btn-create.btn-inverted.js-new-board-list{ type: "button", data: { toggle: "dropdown", labels: labels_filter_path, namespace_path: @project.try(:namespace).try(:path), project_path: @project.try(:path) } } - Add list - .dropdown-menu.dropdown-menu-paging.dropdown-menu-align-right.dropdown-menu-issues-board-new.dropdown-menu-selectable - = render partial: "shared/issuable/label_page_default", locals: { show_footer: true, show_create: true, show_boards_content: true, title: "Add list" } - - if can?(current_user, :admin_label, @project) - = render partial: "shared/issuable/label_page_create" - = dropdown_loading - - else - = render 'shared/sort_dropdown' + = render 'shared/sort_dropdown' - if @bulk_edit .issues_bulk_update.hide diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml index 32128f3b3dc..515c3d4258e 100644 --- a/app/views/shared/issuable/_search_bar.html.haml +++ b/app/views/shared/issuable/_search_bar.html.haml @@ -85,8 +85,20 @@ %span.dropdown-label-box{ style: 'background: {{color}}' } %span.label-title.js-data-value {{title}} - .pull-right.filter-dropdown-container - = render 'shared/sort_dropdown' + .filter-dropdown-container + - if type == :boards + - if can?(current_user, :admin_list, @project) + .dropdown.prepend-left-10 + %button.btn.btn-create.btn-inverted.js-new-board-list{ type: "button", data: { toggle: "dropdown", labels: labels_filter_path, namespace_path: @project.try(:namespace).try(:path), project_path: @project.try(:path) } } + Add list + .dropdown-menu.dropdown-menu-paging.dropdown-menu-align-right.dropdown-menu-issues-board-new.dropdown-menu-selectable + = render partial: "shared/issuable/label_page_default", locals: { show_footer: true, show_create: true, show_boards_content: true, title: "Add list" } + - if can?(current_user, :admin_label, @project) + = render partial: "shared/issuable/label_page_create" + = dropdown_loading + #js-add-issues-btn.prepend-left-10 + - else + = render 'shared/sort_dropdown' - if @bulk_edit .issues_bulk_update.hide diff --git a/changelogs/unreleased/issue-boards-new-search-bar.yml b/changelogs/unreleased/issue-boards-new-search-bar.yml new file mode 100644 index 00000000000..b02be70c470 --- /dev/null +++ b/changelogs/unreleased/issue-boards-new-search-bar.yml @@ -0,0 +1,4 @@ +--- +title: Added new filtered search bar to issue boards +merge_request: +author: From f89782b3f25984794f4f9752979c05d5ed6f0a96 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 7 Mar 2017 11:05:37 +0000 Subject: [PATCH 02/13] Changed store Async updates the boards when searching --- .../javascripts/boards/boards_bundle.js | 4 ++-- .../javascripts/boards/components/board.js | 8 ++++---- .../boards/filtered_search_boards.js | 9 ++++++++- app/assets/javascripts/boards/models/list.js | 20 +++++++++++++++---- .../javascripts/boards/stores/boards_store.js | 11 ++++------ .../filtered_search_manager.js | 8 ++++++-- 6 files changed, 40 insertions(+), 20 deletions(-) diff --git a/app/assets/javascripts/boards/boards_bundle.js b/app/assets/javascripts/boards/boards_bundle.js index 951cb854ce8..6b294290f77 100644 --- a/app/assets/javascripts/boards/boards_bundle.js +++ b/app/assets/javascripts/boards/boards_bundle.js @@ -27,8 +27,6 @@ $(() => { const Store = gl.issueBoards.BoardsStore; const ModalStore = gl.issueBoards.ModalStore; - new FilteredSearchBoards(); - window.gl = window.gl || {}; if (gl.IssueBoardsApp) { @@ -62,6 +60,8 @@ $(() => { }, created () { gl.boardService = new BoardService(this.endpoint, this.bulkUpdatePath, this.boardId); + + new FilteredSearchBoards(Store.filter); }, mounted () { Store.disabled = this.disabled; diff --git a/app/assets/javascripts/boards/components/board.js b/app/assets/javascripts/boards/components/board.js index 18324de18b3..30d3be453be 100644 --- a/app/assets/javascripts/boards/components/board.js +++ b/app/assets/javascripts/boards/components/board.js @@ -28,16 +28,16 @@ require('./board_list'); data () { return { detailIssue: Store.detail, - filters: Store.state.filters, + filter: Store.filter, }; }, watch: { - filters: { - handler () { + filter: { + handler() { this.list.page = 1; this.list.getIssues(true); }, - deep: true + deep: true, }, detailIssue: { handler () { diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js index 6a00d84faf1..0b11237b03d 100644 --- a/app/assets/javascripts/boards/filtered_search_boards.js +++ b/app/assets/javascripts/boards/filtered_search_boards.js @@ -1,5 +1,12 @@ export default class FilteredSearchBoards extends gl.FilteredSearchManager { - constructor() { + constructor(store) { super('boards'); + + this.store = store; + this.destroyOnSubmit = false + } + + updateObject(path) { + this.store.path = path.substr(1); } } diff --git a/app/assets/javascripts/boards/models/list.js b/app/assets/javascripts/boards/models/list.js index f237567208c..ae117aa3900 100644 --- a/app/assets/javascripts/boards/models/list.js +++ b/app/assets/javascripts/boards/models/list.js @@ -10,7 +10,7 @@ class List { this.title = obj.title; this.type = obj.list_type; this.preset = ['done', 'blank'].indexOf(this.type) > -1; - this.filters = gl.issueBoards.BoardsStore.state.filters; + this.filterPath = gl.issueBoards.BoardsStore.filter.path; this.page = 1; this.loading = true; this.loadingMore = false; @@ -65,12 +65,24 @@ class List { } getIssues (emptyIssues = true) { - const filters = this.filters; const data = { page: this.page }; + gl.issueBoards.BoardsStore.filter.path.split('&').forEach((filterParam) => { + const paramSplit = filterParam.split('='); + const paramKeyNormalized = paramSplit[0].replace('[]', ''); + const isArray = paramSplit[0].indexOf('[]'); - Object.keys(filters).forEach((key) => { data[key] = filters[key]; }); + if (isArray >= 0) { + if (!data[paramKeyNormalized]) { + data[paramKeyNormalized] = []; + } - if (this.label) { + data[paramKeyNormalized].push(paramSplit[1]); + } else { + data[paramKeyNormalized] = paramSplit[1]; + } + }); + + if (this.label && data.label_name) { data.label_name = data.label_name.filter(label => label !== this.label.title); } diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js index c902a1d8bfc..d7e3973b327 100644 --- a/app/assets/javascripts/boards/stores/boards_store.js +++ b/app/assets/javascripts/boards/stores/boards_store.js @@ -8,6 +8,9 @@ gl.issueBoards.BoardsStore = { disabled: false, + filter: { + path: '', + }, state: {}, detail: { issue: {} @@ -18,13 +21,7 @@ }, create () { this.state.lists = []; - this.state.filters = { - author_username: gl.utils.getParameterValues('author_username')[0], - assignee_username: gl.utils.getParameterValues('assignee_username')[0], - milestone_title: gl.utils.getParameterValues('milestone_title')[0], - label_name: gl.utils.getParameterValues('label_name[]'), - search: '' - }; + this.filter.path = gl.utils.getUrlParamsArray().join('&'); }, addList (listObj) { const list = new List(listObj); diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js index 58a984048de..56ff091197c 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js @@ -106,7 +106,7 @@ if (!activeElements.length) { // Prevent droplab from opening dropdown - this.dropdownManager.destroyDroplab(); + //this.dropdownManager.destroyDroplab(); this.search(); } @@ -345,7 +345,11 @@ const parameterizedUrl = `?scope=all&utf8=✓&${paths.join('&')}`; - gl.utils.visitUrl(parameterizedUrl); + if (this.updateObject) { + this.updateObject(parameterizedUrl); + } else { + gl.utils.visitUrl(parameterizedUrl); + } } getUsernameParams() { From ddf71fcef5d0d7b9952d77d712007008efbb5d3f Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 7 Mar 2017 11:07:26 +0000 Subject: [PATCH 03/13] Updates the URL --- app/assets/javascripts/boards/filtered_search_boards.js | 1 + app/assets/javascripts/boards/stores/boards_store.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js index 0b11237b03d..ff8da88e6e8 100644 --- a/app/assets/javascripts/boards/filtered_search_boards.js +++ b/app/assets/javascripts/boards/filtered_search_boards.js @@ -8,5 +8,6 @@ export default class FilteredSearchBoards extends gl.FilteredSearchManager { updateObject(path) { this.store.path = path.substr(1); + gl.issueBoards.BoardsStore.updateFiltersUrl(); } } diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js index d7e3973b327..28ecb322df7 100644 --- a/app/assets/javascripts/boards/stores/boards_store.js +++ b/app/assets/javascripts/boards/stores/boards_store.js @@ -120,7 +120,7 @@ })[0]; }, updateFiltersUrl () { - history.pushState(null, null, `?${$.param(this.state.filters)}`); + history.pushState(null, null, `?${this.filter.path}`); } }; })(); From 107c39a66e621e35f808b3a257789d78bf153894 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 7 Mar 2017 14:28:50 +0000 Subject: [PATCH 04/13] Stop droplab from destroying itself is handled async --- .../javascripts/boards/filtered_search_boards.js | 3 ++- .../filtered_search/filtered_search_manager.js | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js index ff8da88e6e8..43c6d9d7237 100644 --- a/app/assets/javascripts/boards/filtered_search_boards.js +++ b/app/assets/javascripts/boards/filtered_search_boards.js @@ -3,11 +3,12 @@ export default class FilteredSearchBoards extends gl.FilteredSearchManager { super('boards'); this.store = store; - this.destroyOnSubmit = false + this.isHandledAsync = true; } updateObject(path) { this.store.path = path.substr(1); + gl.issueBoards.BoardsStore.updateFiltersUrl(); } } diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js index 56ff091197c..652d6c9be0e 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js @@ -105,8 +105,14 @@ e.preventDefault(); if (!activeElements.length) { - // Prevent droplab from opening dropdown - //this.dropdownManager.destroyDroplab(); + if (this.isHandledAsync) { + e.stopImmediatePropagation(); + this.filteredSearchInput.blur(); + this.dropdownManager.resetDropdowns(); + } else { + // Prevent droplab from opening dropdown + this.dropdownManager.destroyDroplab(); + } this.search(); } From ab7bfff08b2ba8d15f1ab5f8fa4449dc53f51bab Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 7 Mar 2017 14:43:17 +0000 Subject: [PATCH 05/13] Make changing the URL optional - future proof ourselves for the modal window --- app/assets/javascripts/boards/boards_bundle.js | 7 ++++--- app/assets/javascripts/boards/filtered_search_boards.js | 7 +++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/boards/boards_bundle.js b/app/assets/javascripts/boards/boards_bundle.js index 6b294290f77..1731f218f37 100644 --- a/app/assets/javascripts/boards/boards_bundle.js +++ b/app/assets/javascripts/boards/boards_bundle.js @@ -1,10 +1,11 @@ -/* eslint-disable one-var, quote-props, comma-dangle, space-before-function-paren */ +/* eslint-disable one-var, quote-props, comma-dangle, space-before-function-paren, no-new */ /* global Vue */ /* global BoardService */ +import FilteredSearchBoards from './filtered_search_boards'; + window.Vue = require('vue'); window.Vue.use(require('vue-resource')); -import FilteredSearchBoards from './filtered_search_boards'; require('./models/issue'); require('./models/label'); require('./models/list'); @@ -61,7 +62,7 @@ $(() => { created () { gl.boardService = new BoardService(this.endpoint, this.bulkUpdatePath, this.boardId); - new FilteredSearchBoards(Store.filter); + new FilteredSearchBoards(Store.filter, true); }, mounted () { Store.disabled = this.disabled; diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js index 43c6d9d7237..d00cb123909 100644 --- a/app/assets/javascripts/boards/filtered_search_boards.js +++ b/app/assets/javascripts/boards/filtered_search_boards.js @@ -1,14 +1,17 @@ export default class FilteredSearchBoards extends gl.FilteredSearchManager { - constructor(store) { + constructor(store, updateUrl = false) { super('boards'); this.store = store; + this.updateUrl = updateUrl; this.isHandledAsync = true; } updateObject(path) { this.store.path = path.substr(1); - gl.issueBoards.BoardsStore.updateFiltersUrl(); + if (this.updateUrl) { + gl.issueBoards.BoardsStore.updateFiltersUrl(); + } } } From 382fea7b5925ac7dc47ccfd79f7537284e68cd6f Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 7 Mar 2017 15:54:45 +0000 Subject: [PATCH 06/13] Handle clear search async --- .../javascripts/filtered_search/filtered_search_manager.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js index 652d6c9be0e..3478f1130a5 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js @@ -107,6 +107,7 @@ if (!activeElements.length) { if (this.isHandledAsync) { e.stopImmediatePropagation(); + this.filteredSearchInput.blur(); this.dropdownManager.resetDropdowns(); } else { @@ -205,6 +206,10 @@ this.handleInputPlaceholder(); this.dropdownManager.resetDropdowns(); + + if (this.isHandledAsync) { + this.search(); + } } handleInputVisualToken() { From 809bba7d02b45938494f8ae471a2b27ce4a40833 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 8 Mar 2017 12:17:01 +0000 Subject: [PATCH 07/13] Updated specs --- .../javascripts/boards/boards_bundle.js | 4 +- .../boards/components/issue_card_inner.js | 23 +-- .../boards/filtered_search_boards.js | 14 ++ app/assets/javascripts/boards/models/list.js | 8 +- app/assets/stylesheets/framework/filters.scss | 1 - .../shared/issuable/_search_bar.html.haml | 2 +- spec/features/boards/add_issues_modal_spec.rb | 2 +- spec/features/boards/boards_spec.rb | 153 +++++++----------- .../issuables/default_sort_order_spec.rb | 2 +- 9 files changed, 86 insertions(+), 123 deletions(-) diff --git a/app/assets/javascripts/boards/boards_bundle.js b/app/assets/javascripts/boards/boards_bundle.js index 1731f218f37..9e9da7dfac4 100644 --- a/app/assets/javascripts/boards/boards_bundle.js +++ b/app/assets/javascripts/boards/boards_bundle.js @@ -62,7 +62,7 @@ $(() => { created () { gl.boardService = new BoardService(this.endpoint, this.bulkUpdatePath, this.boardId); - new FilteredSearchBoards(Store.filter, true); + gl.boardsFilterManager = new FilteredSearchBoards(Store.filter, true); }, mounted () { Store.disabled = this.disabled; @@ -85,7 +85,7 @@ $(() => { }); gl.IssueBoardsSearch = new Vue({ - el: document.getElementById('js-boards-search'), + el: document.getElementById('js-add-list'), data: { filters: Store.state.filters }, diff --git a/app/assets/javascripts/boards/components/issue_card_inner.js b/app/assets/javascripts/boards/components/issue_card_inner.js index 22a8b971ff8..dce573ed6ca 100644 --- a/app/assets/javascripts/boards/components/issue_card_inner.js +++ b/app/assets/javascripts/boards/components/issue_card_inner.js @@ -31,29 +31,22 @@ return !this.list.label || label.id !== this.list.label.id; }, filterByLabel(label, e) { - let labelToggleText = label.title; - const labelIndex = Store.state.filters.label_name.indexOf(label.title); + const filterPath = gl.issueBoards.BoardsStore.filter.path.split('&'); + const labelTitle = encodeURIComponent(label.title); + const param = `label_name[]=${labelTitle}`; + const labelIndex = filterPath.indexOf(param); $(e.currentTarget).tooltip('hide'); if (labelIndex === -1) { - Store.state.filters.label_name.push(label.title); - $('.labels-filter').prepend(``); + filterPath.push(param); } else { - Store.state.filters.label_name.splice(labelIndex, 1); - labelToggleText = Store.state.filters.label_name[0]; - $(`.labels-filter input[name="label_name[]"][value="${label.title}"]`).remove(); + filterPath.splice(labelIndex, 1); } - const selectedLabels = Store.state.filters.label_name; - if (selectedLabels.length === 0) { - labelToggleText = 'Label'; - } else if (selectedLabels.length > 1) { - labelToggleText = `${selectedLabels[0]} + ${selectedLabels.length - 1} more`; - } - - $('.labels-filter .dropdown-toggle-text').text(labelToggleText); + gl.issueBoards.BoardsStore.filter.path = filterPath.join('&'); Store.updateFiltersUrl(); + gl.boardsFilterManager.updateTokens(); }, labelStyle(label) { return { diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js index d00cb123909..3014557c440 100644 --- a/app/assets/javascripts/boards/filtered_search_boards.js +++ b/app/assets/javascripts/boards/filtered_search_boards.js @@ -14,4 +14,18 @@ export default class FilteredSearchBoards extends gl.FilteredSearchManager { gl.issueBoards.BoardsStore.updateFiltersUrl(); } } + + updateTokens() { + const tokens = document.querySelectorAll('.js-visual-token'); + + // Remove all the tokens as they will be replaced by the search manager + [].forEach.call(tokens, (el) => { + el.parentNode.removeChild(el); + }); + + this.loadSearchParamsFromURL(); + + // Get the placeholder back if search is empty + this.filteredSearchInput.dispatchEvent(new Event('input')); + } } diff --git a/app/assets/javascripts/boards/models/list.js b/app/assets/javascripts/boards/models/list.js index ae117aa3900..b246c3c1503 100644 --- a/app/assets/javascripts/boards/models/list.js +++ b/app/assets/javascripts/boards/models/list.js @@ -10,7 +10,6 @@ class List { this.title = obj.title; this.type = obj.list_type; this.preset = ['done', 'blank'].indexOf(this.type) > -1; - this.filterPath = gl.issueBoards.BoardsStore.filter.path; this.page = 1; this.loading = true; this.loadingMore = false; @@ -67,18 +66,20 @@ class List { getIssues (emptyIssues = true) { const data = { page: this.page }; gl.issueBoards.BoardsStore.filter.path.split('&').forEach((filterParam) => { + if (filterParam === '') return; const paramSplit = filterParam.split('='); const paramKeyNormalized = paramSplit[0].replace('[]', ''); const isArray = paramSplit[0].indexOf('[]'); + const value = decodeURIComponent(paramSplit[1]); if (isArray >= 0) { if (!data[paramKeyNormalized]) { data[paramKeyNormalized] = []; } - data[paramKeyNormalized].push(paramSplit[1]); + data[paramKeyNormalized].push(value); } else { - data[paramKeyNormalized] = paramSplit[1]; + data[paramKeyNormalized] = value; } }); @@ -101,6 +102,7 @@ class List { } this.createIssues(data.issues); + console.log(this.issues.length); }); } diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss index bf0e8e2b891..dd2daa4b872 100644 --- a/app/assets/stylesheets/framework/filters.scss +++ b/app/assets/stylesheets/framework/filters.scss @@ -156,7 +156,6 @@ width: 100%; border: 1px solid $border-color; background-color: $white-light; - max-width: 87%; @media (max-width: $screen-xs-min) { -webkit-flex: 1 1 100%; diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml index 515c3d4258e..d73556114d8 100644 --- a/app/views/shared/issuable/_search_bar.html.haml +++ b/app/views/shared/issuable/_search_bar.html.haml @@ -88,7 +88,7 @@ .filter-dropdown-container - if type == :boards - if can?(current_user, :admin_list, @project) - .dropdown.prepend-left-10 + .dropdown.prepend-left-10#js-add-list %button.btn.btn-create.btn-inverted.js-new-board-list{ type: "button", data: { toggle: "dropdown", labels: labels_filter_path, namespace_path: @project.try(:namespace).try(:path), project_path: @project.try(:path) } } Add list .dropdown-menu.dropdown-menu-paging.dropdown-menu-align-right.dropdown-menu-issues-board-new.dropdown-menu-selectable diff --git a/spec/features/boards/add_issues_modal_spec.rb b/spec/features/boards/add_issues_modal_spec.rb index a3e24bb5ffa..f7f2d883d2f 100644 --- a/spec/features/boards/add_issues_modal_spec.rb +++ b/spec/features/boards/add_issues_modal_spec.rb @@ -51,7 +51,7 @@ describe 'Issue Boards add issue modal', :feature, :js do end it 'does not show tooltip on add issues button' do - button = page.find('.issue-boards-search button', text: 'Add issues') + button = page.find('.filter-dropdown-container button', text: 'Add issues') expect(button[:title]).not_to eq("Please add a list to your board first") end diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index ecc356f2505..e11ba10c80c 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -359,17 +359,9 @@ describe 'Issue Boards', feature: true, js: true do context 'filtering' do it 'filters by author' do - page.within '.issues-filters' do - click_button('Author') - wait_for_ajax - - page.within '.dropdown-menu-author' do - click_link(user2.name) - end - wait_for_vue_resource - - expect(find('.js-author-search')).to have_content(user2.name) - end + set_filter("author", user2.username) + click_filter_link(user2.username) + submit_filter wait_for_vue_resource wait_for_board_cards(1, 1) @@ -377,17 +369,9 @@ describe 'Issue Boards', feature: true, js: true do end it 'filters by assignee' do - page.within '.issues-filters' do - click_button('Assignee') - wait_for_ajax - - page.within '.dropdown-menu-assignee' do - click_link(user.name) - end - wait_for_vue_resource - - expect(find('.js-assignee-search')).to have_content(user.name) - end + set_filter("assignee", user.username) + click_filter_link(user.username) + submit_filter wait_for_vue_resource @@ -396,17 +380,9 @@ describe 'Issue Boards', feature: true, js: true do end it 'filters by milestone' do - page.within '.issues-filters' do - click_button('Milestone') - wait_for_ajax - - page.within '.milestone-filter' do - click_link(milestone.title) - end - wait_for_vue_resource - - expect(find('.js-milestone-select')).to have_content(milestone.title) - end + set_filter("milestone", "\"#{milestone.title}\"") + click_filter_link(milestone.title) + submit_filter wait_for_vue_resource wait_for_board_cards(1, 1) @@ -415,16 +391,9 @@ describe 'Issue Boards', feature: true, js: true do end it 'filters by label' do - page.within '.issues-filters' do - click_button('Label') - wait_for_ajax - - page.within '.dropdown-menu-labels' do - click_link(testing.title) - wait_for_vue_resource - find('.dropdown-menu-close').click - end - end + set_filter("label", testing.title) + click_filter_link(testing.title) + submit_filter wait_for_vue_resource wait_for_board_cards(1, 1) @@ -432,19 +401,14 @@ describe 'Issue Boards', feature: true, js: true do end it 'filters by label with space after reload' do - page.within '.issues-filters' do - click_button('Label') - wait_for_ajax - - page.within '.dropdown-menu-labels' do - click_link(accepting.title) - wait_for_vue_resource(spinner: false) - find('.dropdown-menu-close').click - end - end + set_filter("label", "\"#{accepting.title}\"") + click_filter_link(accepting.title) + submit_filter # Test after reload page.evaluate_script 'window.location.reload()' + wait_for_board_cards(1, 1) + wait_for_empty_boards((2..3)) wait_for_vue_resource @@ -460,26 +424,16 @@ describe 'Issue Boards', feature: true, js: true do end it 'removes filtered labels' do - wait_for_vue_resource + set_filter("label", testing.title) + click_filter_link(testing.title) + submit_filter - page.within '.labels-filter' do - click_button('Label') - wait_for_ajax + wait_for_board_cards(1, 1) - page.within '.dropdown-menu-labels' do - click_link(testing.title) - wait_for_vue_resource(spinner: false) - end + find('.clear-search').click + submit_filter - expect(page).to have_css('input[name="label_name[]"]', visible: false) - - page.within '.dropdown-menu-labels' do - click_link(testing.title) - wait_for_vue_resource(spinner: false) - end - - expect(page).not_to have_css('input[name="label_name[]"]', visible: false) - end + wait_for_board_cards(1, 8) end it 'infinite scrolls list with label filter' do @@ -487,16 +441,9 @@ describe 'Issue Boards', feature: true, js: true do create(:labeled_issue, project: project, labels: [planning, testing]) end - page.within '.issues-filters' do - click_button('Label') - wait_for_ajax - - page.within '.dropdown-menu-labels' do - click_link(testing.title) - wait_for_vue_resource - find('.dropdown-menu-close').click - end - end + set_filter("label", testing.title) + click_filter_link(testing.title) + submit_filter wait_for_vue_resource @@ -518,18 +465,13 @@ describe 'Issue Boards', feature: true, js: true do end it 'filters by multiple labels' do - page.within '.issues-filters' do - click_button('Label') - wait_for_ajax + set_filter("label", testing.title) + click_filter_link(testing.title) - page.within(find('.dropdown-menu-labels')) do - click_link(testing.title) - wait_for_vue_resource - click_link(bug.title) - wait_for_vue_resource - find('.dropdown-menu-close').click - end - end + set_filter("label", bug.title) + click_filter_link(bug.title) + + submit_filter wait_for_vue_resource @@ -545,14 +487,14 @@ describe 'Issue Boards', feature: true, js: true do wait_for_vue_resource end + page.within('.tokens-container') do + expect(page).to have_content(bug.title) + end + wait_for_vue_resource wait_for_board_cards(1, 1) wait_for_empty_boards((2..3)) - - page.within('.labels-filter') do - expect(find('.dropdown-toggle-text')).to have_content(bug.title) - end end it 'removes label filter by clicking label button on issue' do @@ -560,16 +502,13 @@ describe 'Issue Boards', feature: true, js: true do page.within(find('.card', match: :first)) do click_button(bug.title) end + wait_for_vue_resource expect(page).to have_selector('.card', count: 1) end wait_for_vue_resource - - page.within('.labels-filter') do - expect(find('.dropdown-toggle-text')).to have_content(bug.title) - end end end end @@ -643,4 +582,20 @@ describe 'Issue Boards', feature: true, js: true do wait_for_board_cards(board, 0) end end + + def set_filter(type, text) + find('.filtered-search').native.send_keys("#{type}:#{text}") + end + + def submit_filter + find('.filtered-search').native.send_keys(:enter) + end + + def click_filter_link(link_text) + page.within('.filtered-search-input-container') do + expect(page).to have_button(link_text) + + click_button(link_text) + end + end end diff --git a/spec/features/issuables/default_sort_order_spec.rb b/spec/features/issuables/default_sort_order_spec.rb index 73553f97d6f..bfe43bff10f 100644 --- a/spec/features/issuables/default_sort_order_spec.rb +++ b/spec/features/issuables/default_sort_order_spec.rb @@ -176,7 +176,7 @@ describe 'Projects > Issuables > Default sort order', feature: true do end def selected_sort_order - find('.pull-right .dropdown button').text.downcase + find('.filter-dropdown-container .dropdown button').text.downcase end def visit_merge_requests_with_state(project, state) From a12b99a7698c851ddb5ea91916e19241fb189ced Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 8 Mar 2017 12:21:07 +0000 Subject: [PATCH 08/13] Fixed eslint errors --- app/assets/javascripts/boards/boards_bundle.js | 2 +- app/assets/javascripts/boards/models/list.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/assets/javascripts/boards/boards_bundle.js b/app/assets/javascripts/boards/boards_bundle.js index 9e9da7dfac4..2fd1f43f02c 100644 --- a/app/assets/javascripts/boards/boards_bundle.js +++ b/app/assets/javascripts/boards/boards_bundle.js @@ -1,4 +1,4 @@ -/* eslint-disable one-var, quote-props, comma-dangle, space-before-function-paren, no-new */ +/* eslint-disable one-var, quote-props, comma-dangle, space-before-function-paren */ /* global Vue */ /* global BoardService */ diff --git a/app/assets/javascripts/boards/models/list.js b/app/assets/javascripts/boards/models/list.js index b246c3c1503..c2af3bb881c 100644 --- a/app/assets/javascripts/boards/models/list.js +++ b/app/assets/javascripts/boards/models/list.js @@ -102,7 +102,6 @@ class List { } this.createIssues(data.issues); - console.log(this.issues.length); }); } From 9ef84008d65dcdb5a9e2d83e7a0c053044fc91f7 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 8 Mar 2017 14:00:28 +0000 Subject: [PATCH 09/13] Hides on mobile --- app/views/projects/boards/_show.html.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/projects/boards/_show.html.haml b/app/views/projects/boards/_show.html.haml index a3593c9f5db..fa463edd526 100644 --- a/app/views/projects/boards/_show.html.haml +++ b/app/views/projects/boards/_show.html.haml @@ -13,7 +13,8 @@ = render "projects/issues/head" -= render 'shared/issuable/search_bar', type: :boards +.hidden-xs.hidden-sm + = render 'shared/issuable/search_bar', type: :boards #board-app.boards-app{ "v-cloak" => true, data: board_data } .boards-list{ ":class" => "{ 'is-compact': detailIssueVisible }" } From d701b39db9d458919976249a4b7c8bb5597b3606 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 8 Mar 2017 14:46:46 +0000 Subject: [PATCH 10/13] Fixed up boards filter spec due to CSS classes changing Also fixed issue with Vue resource encoding + in search term --- app/assets/javascripts/boards/models/list.js | 3 ++- spec/features/boards/boards_spec.rb | 14 ++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/boards/models/list.js b/app/assets/javascripts/boards/models/list.js index c2af3bb881c..ad968d2120f 100644 --- a/app/assets/javascripts/boards/models/list.js +++ b/app/assets/javascripts/boards/models/list.js @@ -70,7 +70,8 @@ class List { const paramSplit = filterParam.split('='); const paramKeyNormalized = paramSplit[0].replace('[]', ''); const isArray = paramSplit[0].indexOf('[]'); - const value = decodeURIComponent(paramSplit[1]); + let value = decodeURIComponent(paramSplit[1]); + value = value.replace(/\+/g, ' '); if (isArray >= 0) { if (!data[paramKeyNormalized]) { diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index e11ba10c80c..f7e8b78b54d 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -29,7 +29,7 @@ describe 'Issue Boards', feature: true, js: true do end it 'shows tooltip on add issues button' do - button = page.find('.issue-boards-search button', text: 'Add issues') + button = page.find('.filter-dropdown-container button', text: 'Add issues') expect(button[:"data-original-title"]).to eq("Please add a list to your board first") end @@ -115,9 +115,8 @@ describe 'Issue Boards', feature: true, js: true do end it 'search done list' do - page.within('#js-boards-search') do - find('.form-control').set(issue8.title) - end + find('.filtered-search').set(issue8.title) + find('.filtered-search').native.send_keys(:enter) wait_for_vue_resource @@ -127,9 +126,8 @@ describe 'Issue Boards', feature: true, js: true do end it 'search list' do - page.within('#js-boards-search') do - find('.form-control').set(issue5.title) - end + find('.filtered-search').set(issue5.title) + find('.filtered-search').native.send_keys(:enter) wait_for_vue_resource @@ -333,7 +331,7 @@ describe 'Issue Boards', feature: true, js: true do wait_for_vue_resource - expect(find('.issue-boards-search')).to have_selector('.open') + expect(page).to have_css('#js-add-list.open') end it 'creates new list from a new label' do From 236d6595edd2393f4ba4faadd39529fcabe48aec Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 8 Mar 2017 14:53:18 +0000 Subject: [PATCH 11/13] Removed previous filter code --- app/assets/javascripts/labels_select.js | 18 ++---------------- app/assets/javascripts/milestone_select.js | 8 +------- app/assets/javascripts/users_select.js | 5 ----- 3 files changed, 3 insertions(+), 28 deletions(-) diff --git a/app/assets/javascripts/labels_select.js b/app/assets/javascripts/labels_select.js index 9e2d14c7f87..c648a0f076c 100644 --- a/app/assets/javascripts/labels_select.js +++ b/app/assets/javascripts/labels_select.js @@ -353,31 +353,17 @@ return; } - if ($('html').hasClass('issue-boards-page') && !$dropdown.hasClass('js-issue-board-sidebar') && - !$dropdown.closest('.add-issues-modal').length) { - boardsModel = gl.issueBoards.BoardsStore.state.filters; - } else if ($dropdown.closest('.add-issues-modal').length) { + if ($dropdown.closest('.add-issues-modal').length) { boardsModel = gl.issueBoards.ModalStore.store.filter; } if (boardsModel) { if (label.isAny) { boardsModel['label_name'] = []; - } - else if ($el.hasClass('is-active')) { + } else if ($el.hasClass('is-active')) { boardsModel['label_name'].push(label.title); } - else { - var filters = boardsModel['label_name']; - filters = filters.filter(function (filteredLabel) { - return filteredLabel !== label.title; - }); - boardsModel['label_name'] = filters; - } - if (!$dropdown.closest('.add-issues-modal').length) { - gl.issueBoards.BoardsStore.updateFiltersUrl(); - } e.preventDefault(); return; } diff --git a/app/assets/javascripts/milestone_select.js b/app/assets/javascripts/milestone_select.js index 51fa5c828b3..4c4f94cb9f3 100644 --- a/app/assets/javascripts/milestone_select.js +++ b/app/assets/javascripts/milestone_select.js @@ -124,18 +124,12 @@ return; } - if ($('html').hasClass('issue-boards-page') && !$dropdown.hasClass('js-issue-board-sidebar') && - !$dropdown.closest('.add-issues-modal').length) { - boardsStore = gl.issueBoards.BoardsStore.state.filters; - } else if ($dropdown.closest('.add-issues-modal').length) { + if ($dropdown.closest('.add-issues-modal').length) { boardsStore = gl.issueBoards.ModalStore.store.filter; } if (boardsStore) { boardsStore[$dropdown.data('field-name')] = selected.name; - if (!$dropdown.closest('.add-issues-modal').length) { - gl.issueBoards.BoardsStore.updateFiltersUrl(); - } e.preventDefault(); } else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) { if (selected.name != null) { diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js index 27af859f7d8..c7a57b47834 100644 --- a/app/assets/javascripts/users_select.js +++ b/app/assets/javascripts/users_select.js @@ -217,11 +217,6 @@ } if ($el.closest('.add-issues-modal').length) { gl.issueBoards.ModalStore.store.filter[$dropdown.data('field-name')] = user.id; - } else if ($('html').hasClass('issue-boards-page') && !$dropdown.hasClass('js-issue-board-sidebar')) { - selectedId = user.id; - gl.issueBoards.BoardsStore.state.filters[$dropdown.data('field-name')] = user.id; - gl.issueBoards.BoardsStore.updateFiltersUrl(); - e.preventDefault(); } else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) { selectedId = user.id; return Issuable.filterResults($dropdown.closest('form')); From 7eabb7a9641481d89ccb52b421dcbd8cd63c3bb6 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 9 Mar 2017 12:32:43 +0000 Subject: [PATCH 12/13] Use reduce instead of a forEach Changed an isArray check to use -1 Added comment to boards search manager to explain behaviour --- app/assets/javascripts/boards/boards_bundle.js | 15 +++++++++++++-- .../javascripts/boards/components/board_card.js | 3 ++- .../boards/components/issue_card_inner.js | 10 +++++++++- .../javascripts/boards/filtered_search_boards.js | 3 +++ app/assets/javascripts/boards/models/list.js | 14 +++++++------- 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/app/assets/javascripts/boards/boards_bundle.js b/app/assets/javascripts/boards/boards_bundle.js index 2fd1f43f02c..4d60fedaeb8 100644 --- a/app/assets/javascripts/boards/boards_bundle.js +++ b/app/assets/javascripts/boards/boards_bundle.js @@ -62,7 +62,13 @@ $(() => { created () { gl.boardService = new BoardService(this.endpoint, this.bulkUpdatePath, this.boardId); - gl.boardsFilterManager = new FilteredSearchBoards(Store.filter, true); + this.filterManager = new FilteredSearchBoards(Store.filter, true); + + // Listen for updateTokens event + this.$on('updateTokens', this.updateTokens); + }, + beforeDestroy() { + this.$off('updateTokens', this.updateTokens); }, mounted () { Store.disabled = this.disabled; @@ -81,7 +87,12 @@ $(() => { Store.addBlankState(); this.loading = false; }); - } + }, + methods: { + updateTokens() { + this.filterManager.updateTokens(); + } + }, }); gl.IssueBoardsSearch = new Vue({ diff --git a/app/assets/javascripts/boards/components/board_card.js b/app/assets/javascripts/boards/components/board_card.js index 795b3cf2ec0..4b72090df31 100644 --- a/app/assets/javascripts/boards/components/board_card.js +++ b/app/assets/javascripts/boards/components/board_card.js @@ -17,7 +17,8 @@ export default { :list="list" :issue="issue" :issue-link-base="issueLinkBase" - :root-path="rootPath" /> + :root-path="rootPath" + :update-filters="true" /> `, components: { diff --git a/app/assets/javascripts/boards/components/issue_card_inner.js b/app/assets/javascripts/boards/components/issue_card_inner.js index dce573ed6ca..3d57ec429c6 100644 --- a/app/assets/javascripts/boards/components/issue_card_inner.js +++ b/app/assets/javascripts/boards/components/issue_card_inner.js @@ -23,6 +23,11 @@ type: String, required: true, }, + updateFilters: { + type: Boolean, + required: false, + default: false, + }, }, methods: { showLabel(label) { @@ -31,6 +36,8 @@ return !this.list.label || label.id !== this.list.label.id; }, filterByLabel(label, e) { + if (!this.updateFilters) return; + const filterPath = gl.issueBoards.BoardsStore.filter.path.split('&'); const labelTitle = encodeURIComponent(label.title); const param = `label_name[]=${labelTitle}`; @@ -46,7 +53,8 @@ gl.issueBoards.BoardsStore.filter.path = filterPath.join('&'); Store.updateFiltersUrl(); - gl.boardsFilterManager.updateTokens(); + + gl.IssueBoardsApp.$emit('updateTokens'); }, labelStyle(label) { return { diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js index 3014557c440..47448b02bdd 100644 --- a/app/assets/javascripts/boards/filtered_search_boards.js +++ b/app/assets/javascripts/boards/filtered_search_boards.js @@ -4,6 +4,9 @@ export default class FilteredSearchBoards extends gl.FilteredSearchManager { this.store = store; this.updateUrl = updateUrl; + + // Issue boards is slightly different, we handle all the requests async + // instead or reloading the page, we just re-fire the list ajax requests this.isHandledAsync = true; } diff --git a/app/assets/javascripts/boards/models/list.js b/app/assets/javascripts/boards/models/list.js index ad968d2120f..3251ca76b26 100644 --- a/app/assets/javascripts/boards/models/list.js +++ b/app/assets/javascripts/boards/models/list.js @@ -64,16 +64,14 @@ class List { } getIssues (emptyIssues = true) { - const data = { page: this.page }; - gl.issueBoards.BoardsStore.filter.path.split('&').forEach((filterParam) => { - if (filterParam === '') return; + const data = gl.issueBoards.BoardsStore.filter.path.split('&').reduce((data, filterParam) => { + if (filterParam === '') return data; const paramSplit = filterParam.split('='); const paramKeyNormalized = paramSplit[0].replace('[]', ''); const isArray = paramSplit[0].indexOf('[]'); - let value = decodeURIComponent(paramSplit[1]); - value = value.replace(/\+/g, ' '); + const value = decodeURIComponent(paramSplit[1]).replace(/\+/g, ' '); - if (isArray >= 0) { + if (isArray !== -1) { if (!data[paramKeyNormalized]) { data[paramKeyNormalized] = []; } @@ -82,7 +80,9 @@ class List { } else { data[paramKeyNormalized] = value; } - }); + + return data; + }, { page: this.page }); if (this.label && data.label_name) { data.label_name = data.label_name.filter(label => label !== this.label.title); From c7cecae616702a46430ed41e283912ddc22f2612 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 14 Mar 2017 11:32:58 +0000 Subject: [PATCH 13/13] added eventhub to emit update tokens event --- app/assets/javascripts/boards/boards_bundle.js | 5 +++-- app/assets/javascripts/boards/components/issue_card_inner.js | 4 +++- app/assets/javascripts/boards/eventhub.js | 3 +++ 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 app/assets/javascripts/boards/eventhub.js diff --git a/app/assets/javascripts/boards/boards_bundle.js b/app/assets/javascripts/boards/boards_bundle.js index 4d60fedaeb8..3874c2819a5 100644 --- a/app/assets/javascripts/boards/boards_bundle.js +++ b/app/assets/javascripts/boards/boards_bundle.js @@ -3,6 +3,7 @@ /* global BoardService */ import FilteredSearchBoards from './filtered_search_boards'; +import eventHub from './eventhub'; window.Vue = require('vue'); window.Vue.use(require('vue-resource')); @@ -65,10 +66,10 @@ $(() => { this.filterManager = new FilteredSearchBoards(Store.filter, true); // Listen for updateTokens event - this.$on('updateTokens', this.updateTokens); + eventHub.$on('updateTokens', this.updateTokens); }, beforeDestroy() { - this.$off('updateTokens', this.updateTokens); + eventHub.$off('updateTokens', this.updateTokens); }, mounted () { Store.disabled = this.disabled; diff --git a/app/assets/javascripts/boards/components/issue_card_inner.js b/app/assets/javascripts/boards/components/issue_card_inner.js index 3d57ec429c6..69e30cec4c5 100644 --- a/app/assets/javascripts/boards/components/issue_card_inner.js +++ b/app/assets/javascripts/boards/components/issue_card_inner.js @@ -1,4 +1,6 @@ /* global Vue */ +import eventHub from '../eventhub'; + (() => { const Store = gl.issueBoards.BoardsStore; @@ -54,7 +56,7 @@ Store.updateFiltersUrl(); - gl.IssueBoardsApp.$emit('updateTokens'); + eventHub.$emit('updateTokens'); }, labelStyle(label) { return { diff --git a/app/assets/javascripts/boards/eventhub.js b/app/assets/javascripts/boards/eventhub.js new file mode 100644 index 00000000000..0948c2e5352 --- /dev/null +++ b/app/assets/javascripts/boards/eventhub.js @@ -0,0 +1,3 @@ +import Vue from 'vue'; + +export default new Vue();