Commit 7fa802be authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera

Merge branch 'ss/add-filtered-search-to-swimlanes' into 'master'

Add GlFilteredSearch to Group Issue Boards [RUN ALL RSPEC] [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!54641
parents bcb7a223 6ec19865
<script>
import { mapActions } from 'vuex';
import { historyPushState } from '~/lib/utils/common_utils';
import { setUrlParams } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
import FilteredSearch from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
export default {
i18n: {
search: __('Search'),
},
components: { FilteredSearch },
props: {
search: {
type: String,
required: false,
default: '',
},
},
computed: {
initialSearch() {
return [{ type: 'filtered-search-term', value: { data: this.search } }];
},
},
methods: {
...mapActions(['performSearch']),
handleSearch(filters) {
let itemValue = '';
const [item] = filters;
if (filters.length === 0) {
itemValue = '';
} else {
itemValue = item?.value?.data;
}
historyPushState(setUrlParams({ search: itemValue }, window.location.href));
this.performSearch();
},
},
};
</script>
<template>
<filtered-search
class="gl-w-full"
namespace=""
:tokens="[]"
:search-input-placeholder="$options.i18n.search"
:initial-filter-value="initialSearch"
@onFilter="handleSearch"
/>
</template>
import Vue from 'vue';
import store from '~/boards/stores';
import { queryToObject } from '~/lib/utils/url_utility';
import FilteredSearch from './components/filtered_search.vue';
export default () => {
const queryParams = queryToObject(window.location.search);
const el = document.getElementById('js-board-filtered-search');
/*
When https://github.com/vuejs/vue-apollo/pull/1153 is merged and deployed
we can remove apolloProvider option from here. Currently without it its causing
an error
*/
return new Vue({
el,
store,
apolloProvider: {},
render: (createElement) =>
createElement(FilteredSearch, {
props: { search: queryParams.search },
}),
});
};
...@@ -53,7 +53,6 @@ let issueBoardsApp; ...@@ -53,7 +53,6 @@ let issueBoardsApp;
export default () => { export default () => {
const $boardApp = document.getElementById('board-app'); const $boardApp = document.getElementById('board-app');
// check for browser back and trigger a hard reload to circumvent browser caching. // check for browser back and trigger a hard reload to circumvent browser caching.
window.addEventListener('pageshow', (event) => { window.addEventListener('pageshow', (event) => {
const isNavTypeBackForward = const isNavTypeBackForward =
...@@ -73,6 +72,14 @@ export default () => { ...@@ -73,6 +72,14 @@ export default () => {
boardsStore.setTimeTrackingLimitToHours($boardApp.dataset.timeTrackingLimitToHours); boardsStore.setTimeTrackingLimitToHours($boardApp.dataset.timeTrackingLimitToHours);
} }
if (gon?.features?.boardsFilteredSearch) {
import('~/boards/filtered_search')
.then(({ default: initFilteredSearch }) => {
initFilteredSearch(apolloProvider);
})
.catch(() => {});
}
// eslint-disable-next-line @gitlab/no-runtime-template-compiler // eslint-disable-next-line @gitlab/no-runtime-template-compiler
issueBoardsApp = new Vue({ issueBoardsApp = new Vue({
el: $boardApp, el: $boardApp,
...@@ -164,8 +171,15 @@ export default () => { ...@@ -164,8 +171,15 @@ export default () => {
eventHub.$off('initialBoardLoad', this.initialBoardLoad); eventHub.$off('initialBoardLoad', this.initialBoardLoad);
}, },
mounted() { mounted() {
this.filterManager = new FilteredSearchBoards(boardsStore.filter, true, boardsStore.cantEdit); if (!gon.features?.boardsFilteredSearch) {
this.filterManager.setup(); this.filterManager = new FilteredSearchBoards(
boardsStore.filter,
true,
boardsStore.cantEdit,
);
this.filterManager.setup();
}
this.performSearch(); this.performSearch();
......
...@@ -9,6 +9,7 @@ class Groups::BoardsController < Groups::ApplicationController ...@@ -9,6 +9,7 @@ class Groups::BoardsController < Groups::ApplicationController
before_action :assign_endpoint_vars before_action :assign_endpoint_vars
before_action do before_action do
push_frontend_feature_flag(:graphql_board_lists, group, default_enabled: false) push_frontend_feature_flag(:graphql_board_lists, group, default_enabled: false)
push_frontend_feature_flag(:boards_filtered_search, group)
end end
feature_category :boards feature_category :boards
......
---
name: boards_filtered_search
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/54641
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/322778
milestone: '13.10'
type: development
group: group::project management
default_enabled: false
import { createLocalVue, shallowMount } from '@vue/test-utils';
import Vuex from 'vuex';
import FilteredSearch from '~/boards/components/filtered_search.vue';
import { createStore } from '~/boards/stores';
import * as commonUtils from '~/lib/utils/common_utils';
import FilteredSearchBarRoot from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('FilteredSearch', () => {
let wrapper;
let store;
const createComponent = () => {
wrapper = shallowMount(FilteredSearch, {
localVue,
propsData: { search: '' },
store,
attachTo: document.body,
});
};
beforeEach(() => {
// this needed for actions call for performSearch
window.gon = { features: {} };
});
afterEach(() => {
wrapper.destroy();
});
describe('default', () => {
beforeEach(() => {
store = createStore();
jest.spyOn(store, 'dispatch');
createComponent();
});
it('finds FilteredSearch', () => {
expect(wrapper.find(FilteredSearchBarRoot).exists()).toBe(true);
});
describe('when onFilter is emitted', () => {
it('calls performSearch', () => {
wrapper.find(FilteredSearchBarRoot).vm.$emit('onFilter', [{ value: { data: '' } }]);
expect(store.dispatch).toHaveBeenCalledWith('performSearch');
});
it('calls historyPushState', () => {
commonUtils.historyPushState = jest.fn();
wrapper
.find(FilteredSearchBarRoot)
.vm.$emit('onFilter', [{ value: { data: 'searchQuery' } }]);
expect(commonUtils.historyPushState).toHaveBeenCalledWith(
'http://test.host/?search=searchQuery',
);
});
});
});
});
...@@ -16,6 +16,8 @@ RSpec.describe Projects::IssuesController, '(JavaScript fixtures)', type: :contr ...@@ -16,6 +16,8 @@ RSpec.describe Projects::IssuesController, '(JavaScript fixtures)', type: :contr
end end
before do before do
stub_feature_flags(boards_filtered_search: false)
project.add_maintainer(user) project.add_maintainer(user)
sign_in(user) sign_in(user)
end end
......
...@@ -246,6 +246,12 @@ RSpec.configure do |config| ...@@ -246,6 +246,12 @@ RSpec.configure do |config|
stub_feature_flags(unified_diff_components: false) stub_feature_flags(unified_diff_components: false)
# Disable this feature flag as we iterate and
# refactor filtered search to use gitlab ui
# components to meet feature parody. More details found
# https://gitlab.com/groups/gitlab-org/-/epics/5501
stub_feature_flags(boards_filtered_search: false)
allow(Gitlab::GitalyClient).to receive(:can_use_disk?).and_return(enable_rugged) allow(Gitlab::GitalyClient).to receive(:can_use_disk?).and_return(enable_rugged)
else else
unstub_all_feature_flags unstub_all_feature_flags
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment