Commit 5cf6c84a authored by Michael Lunøe's avatar Michael Lunøe Committed by Jose Ivan Vargas

Fix(filtered search manager): add state option

Add option parameter to use default state, so
usages of the filtered_search_manager can specify
whether to use the default state, or not.

This created issues around the application where
state='opened' had an unintentional effect and
would cause inconsistencies between what was being
displayed when. See ticket for more information:
https://gitlab.com/gitlab-org/gitlab/-/issues/232734
parent 025aeb49
...@@ -10,6 +10,7 @@ export default class FilteredSearchBoards extends FilteredSearchManager { ...@@ -10,6 +10,7 @@ export default class FilteredSearchBoards extends FilteredSearchManager {
isGroupDecendent: true, isGroupDecendent: true,
stateFiltersSelector: '.issues-state-filters', stateFiltersSelector: '.issues-state-filters',
isGroup: IS_EE, isGroup: IS_EE,
useDefaultState: false,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys, filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
}); });
......
...@@ -29,6 +29,7 @@ export default class FilteredSearchManager { ...@@ -29,6 +29,7 @@ export default class FilteredSearchManager {
isGroup = false, isGroup = false,
isGroupAncestor = true, isGroupAncestor = true,
isGroupDecendent = false, isGroupDecendent = false,
useDefaultState = false,
filteredSearchTokenKeys = IssuableFilteredSearchTokenKeys, filteredSearchTokenKeys = IssuableFilteredSearchTokenKeys,
stateFiltersSelector = '.issues-state-filters', stateFiltersSelector = '.issues-state-filters',
placeholder = __('Search or filter results...'), placeholder = __('Search or filter results...'),
...@@ -37,6 +38,7 @@ export default class FilteredSearchManager { ...@@ -37,6 +38,7 @@ export default class FilteredSearchManager {
this.isGroup = isGroup; this.isGroup = isGroup;
this.isGroupAncestor = isGroupAncestor; this.isGroupAncestor = isGroupAncestor;
this.isGroupDecendent = isGroupDecendent; this.isGroupDecendent = isGroupDecendent;
this.useDefaultState = useDefaultState;
this.states = ['opened', 'closed', 'merged', 'all']; this.states = ['opened', 'closed', 'merged', 'all'];
this.page = page; this.page = page;
...@@ -724,8 +726,13 @@ export default class FilteredSearchManager { ...@@ -724,8 +726,13 @@ export default class FilteredSearchManager {
search(state = null) { search(state = null) {
const paths = []; const paths = [];
const { tokens, searchToken } = this.getSearchTokens(); const { tokens, searchToken } = this.getSearchTokens();
const currentState = state || getParameterByName('state') || 'opened'; let currentState = state || getParameterByName('state');
if (!currentState && this.useDefaultState) {
currentState = 'opened';
}
if (this.states.includes(currentState)) {
paths.push(`state=${currentState}`); paths.push(`state=${currentState}`);
}
tokens.forEach(token => { tokens.forEach(token => {
const condition = this.filteredSearchTokenKeys.searchByConditionKeyValue( const condition = this.filteredSearchTokenKeys.searchByConditionKeyValue(
......
...@@ -6,5 +6,6 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -6,5 +6,6 @@ document.addEventListener('DOMContentLoaded', () => {
initFilteredSearch({ initFilteredSearch({
page: FILTERED_SEARCH.ADMIN_RUNNERS, page: FILTERED_SEARCH.ADMIN_RUNNERS,
filteredSearchTokenKeys: AdminRunnersFilteredSearchTokenKeys, filteredSearchTokenKeys: AdminRunnersFilteredSearchTokenKeys,
useDefaultState: true,
}); });
}); });
...@@ -8,6 +8,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -8,6 +8,7 @@ document.addEventListener('DOMContentLoaded', () => {
initFilteredSearch({ initFilteredSearch({
page: FILTERED_SEARCH.ISSUES, page: FILTERED_SEARCH.ISSUES,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys, filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
useDefaultState: true,
}); });
projectSelect(); projectSelect();
......
...@@ -10,6 +10,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -10,6 +10,7 @@ document.addEventListener('DOMContentLoaded', () => {
initFilteredSearch({ initFilteredSearch({
page: FILTERED_SEARCH.MERGE_REQUESTS, page: FILTERED_SEARCH.MERGE_REQUESTS,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys, filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
useDefaultState: true,
}); });
projectSelect(); projectSelect();
......
...@@ -17,6 +17,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -17,6 +17,7 @@ document.addEventListener('DOMContentLoaded', () => {
initFilteredSearch({ initFilteredSearch({
page: FILTERED_SEARCH.ISSUES, page: FILTERED_SEARCH.ISSUES,
isGroupDecendent: true, isGroupDecendent: true,
useDefaultState: true,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys, filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
}); });
projectSelect(); projectSelect();
......
...@@ -14,6 +14,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -14,6 +14,7 @@ document.addEventListener('DOMContentLoaded', () => {
initFilteredSearch({ initFilteredSearch({
page: FILTERED_SEARCH.MERGE_REQUESTS, page: FILTERED_SEARCH.MERGE_REQUESTS,
isGroupDecendent: true, isGroupDecendent: true,
useDefaultState: true,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys, filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
}); });
projectSelect(); projectSelect();
......
...@@ -13,6 +13,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -13,6 +13,7 @@ document.addEventListener('DOMContentLoaded', () => {
page: FILTERED_SEARCH.ADMIN_RUNNERS, page: FILTERED_SEARCH.ADMIN_RUNNERS,
filteredSearchTokenKeys: GroupRunnersFilteredSearchTokenKeys, filteredSearchTokenKeys: GroupRunnersFilteredSearchTokenKeys,
anchor: FILTERED_SEARCH.GROUP_RUNNERS_ANCHOR, anchor: FILTERED_SEARCH.GROUP_RUNNERS_ANCHOR,
useDefaultState: false,
}); });
if (gon.features.newVariablesUi) { if (gon.features.newVariablesUi) {
......
...@@ -17,6 +17,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -17,6 +17,7 @@ document.addEventListener('DOMContentLoaded', () => {
initFilteredSearch({ initFilteredSearch({
page: FILTERED_SEARCH.ISSUES, page: FILTERED_SEARCH.ISSUES,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys, filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
useDefaultState: true,
}); });
new IssuableIndex(ISSUABLE_INDEX.ISSUE); new IssuableIndex(ISSUABLE_INDEX.ISSUE);
......
...@@ -9,6 +9,7 @@ export default class FilteredSearchServiceDesk extends FilteredSearchManager { ...@@ -9,6 +9,7 @@ export default class FilteredSearchServiceDesk extends FilteredSearchManager {
super({ super({
page: 'service_desk', page: 'service_desk',
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys, filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
useDefaultState: true,
}); });
this.supportBotData = supportBotData; this.supportBotData = supportBotData;
......
...@@ -13,6 +13,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -13,6 +13,7 @@ document.addEventListener('DOMContentLoaded', () => {
initFilteredSearch({ initFilteredSearch({
page: FILTERED_SEARCH.MERGE_REQUESTS, page: FILTERED_SEARCH.MERGE_REQUESTS,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys, filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
useDefaultState: true,
}); });
new IssuableIndex(ISSUABLE_INDEX.MERGE_REQUEST); // eslint-disable-line no-new new IssuableIndex(ISSUABLE_INDEX.MERGE_REQUEST); // eslint-disable-line no-new
......
...@@ -6,6 +6,7 @@ export default ({ ...@@ -6,6 +6,7 @@ export default ({
isGroup, isGroup,
isGroupAncestor, isGroupAncestor,
isGroupDecendent, isGroupDecendent,
useDefaultState,
stateFiltersSelector, stateFiltersSelector,
anchor, anchor,
}) => { }) => {
...@@ -16,6 +17,7 @@ export default ({ ...@@ -16,6 +17,7 @@ export default ({
isGroup, isGroup,
isGroupAncestor, isGroupAncestor,
isGroupDecendent, isGroupDecendent,
useDefaultState,
filteredSearchTokenKeys, filteredSearchTokenKeys,
stateFiltersSelector, stateFiltersSelector,
anchor, anchor,
......
---
title: Fix bug where filtering would sometimes display only open issues on different pages listing issues
merge_request: 38906
author:
type: fixed
...@@ -12,6 +12,7 @@ export default class FilteredSearchCodeReviewAnalytics extends FilteredSearchMan ...@@ -12,6 +12,7 @@ export default class FilteredSearchCodeReviewAnalytics extends FilteredSearchMan
isGroupDecendent: true, isGroupDecendent: true,
stateFiltersSelector: '.issues-state-filters', stateFiltersSelector: '.issues-state-filters',
isGroup: true, isGroup: true,
useDefaultState: false,
filteredSearchTokenKeys: CodeReviewAnalyticsFilteredSearchTokenKeys, filteredSearchTokenKeys: CodeReviewAnalyticsFilteredSearchTokenKeys,
placeholder: __('Filter results...'), placeholder: __('Filter results...'),
}); });
......
...@@ -11,6 +11,7 @@ export default class FilteredSearchProductivityAnalytics extends FilteredSearchM ...@@ -11,6 +11,7 @@ export default class FilteredSearchProductivityAnalytics extends FilteredSearchM
isGroupDecendent: true, isGroupDecendent: true,
stateFiltersSelector: '.issues-state-filters', stateFiltersSelector: '.issues-state-filters',
isGroup, isGroup,
useDefaultState: false,
filteredSearchTokenKeys: ProductivityAnalyticsFilteredSearchTokenKeys, filteredSearchTokenKeys: ProductivityAnalyticsFilteredSearchTokenKeys,
placeholder: __('Filter results...'), placeholder: __('Filter results...'),
}); });
......
...@@ -20,6 +20,7 @@ export default class FilteredSearchIssueAnalytics extends FilteredSearchManager ...@@ -20,6 +20,7 @@ export default class FilteredSearchIssueAnalytics extends FilteredSearchManager
isGroupDecendent: true, isGroupDecendent: true,
stateFiltersSelector: '.issues-state-filters', stateFiltersSelector: '.issues-state-filters',
isGroup: true, isGroup: true,
useDefaultState: false,
filteredSearchTokenKeys: issuesAnalyticsTokenKeys, filteredSearchTokenKeys: issuesAnalyticsTokenKeys,
placeholder: __('Filter results...'), placeholder: __('Filter results...'),
}); });
......
...@@ -10,6 +10,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -10,6 +10,7 @@ document.addEventListener('DOMContentLoaded', () => {
page: 'epics', page: 'epics',
isGroup: true, isGroup: true,
isGroupDecendent: true, isGroupDecendent: true,
useDefaultState: true,
filteredSearchTokenKeys: FilteredSearchTokenKeysEpics, filteredSearchTokenKeys: FilteredSearchTokenKeysEpics,
stateFiltersSelector: '.epics-state-filters', stateFiltersSelector: '.epics-state-filters',
}); });
......
...@@ -9,6 +9,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -9,6 +9,7 @@ document.addEventListener('DOMContentLoaded', () => {
page: 'epics', page: 'epics',
isGroup: true, isGroup: true,
isGroupDecendent: true, isGroupDecendent: true,
useDefaultState: false,
filteredSearchTokenKeys: FilteredSearchTokenKeysEpics, filteredSearchTokenKeys: FilteredSearchTokenKeysEpics,
stateFiltersSelector: '.epics-state-filters', stateFiltersSelector: '.epics-state-filters',
}); });
......
...@@ -77,7 +77,7 @@ describe('Filtered Search Manager', () => { ...@@ -77,7 +77,7 @@ describe('Filtered Search Manager', () => {
jest.spyOn(FilteredSearchDropdownManager.prototype, 'setDropdown').mockImplementation(); jest.spyOn(FilteredSearchDropdownManager.prototype, 'setDropdown').mockImplementation();
}); });
const initializeManager = () => { const initializeManager = ({ useDefaultState } = {}) => {
jest.spyOn(FilteredSearchManager.prototype, 'loadSearchParamsFromURL').mockImplementation(); jest.spyOn(FilteredSearchManager.prototype, 'loadSearchParamsFromURL').mockImplementation();
jest.spyOn(FilteredSearchManager.prototype, 'tokenChange').mockImplementation(); jest.spyOn(FilteredSearchManager.prototype, 'tokenChange').mockImplementation();
jest jest
...@@ -88,7 +88,7 @@ describe('Filtered Search Manager', () => { ...@@ -88,7 +88,7 @@ describe('Filtered Search Manager', () => {
input = document.querySelector('.filtered-search'); input = document.querySelector('.filtered-search');
tokensContainer = document.querySelector('.tokens-container'); tokensContainer = document.querySelector('.tokens-container');
manager = new FilteredSearchManager({ page }); manager = new FilteredSearchManager({ page, useDefaultState });
manager.setup(); manager.setup();
}; };
...@@ -184,17 +184,27 @@ describe('Filtered Search Manager', () => { ...@@ -184,17 +184,27 @@ describe('Filtered Search Manager', () => {
}); });
describe('search', () => { describe('search', () => {
const defaultParams = '?scope=all&utf8=%E2%9C%93&state=opened'; const defaultParams = '?scope=all&utf8=%E2%9C%93';
const defaultState = '&state=opened';
beforeEach(() => { it('should search with a single word', done => {
initializeManager(); initializeManager();
input.value = 'searchTerm';
visitUrl.mockImplementation(url => {
expect(url).toEqual(`${defaultParams}&search=searchTerm`);
done();
}); });
it('should search with a single word', done => { manager.search();
});
it('sets default state', done => {
initializeManager({ useDefaultState: true });
input.value = 'searchTerm'; input.value = 'searchTerm';
visitUrl.mockImplementation(url => { visitUrl.mockImplementation(url => {
expect(url).toEqual(`${defaultParams}&search=searchTerm`); expect(url).toEqual(`${defaultParams}${defaultState}&search=searchTerm`);
done(); done();
}); });
...@@ -202,6 +212,7 @@ describe('Filtered Search Manager', () => { ...@@ -202,6 +212,7 @@ describe('Filtered Search Manager', () => {
}); });
it('should search with multiple words', done => { it('should search with multiple words', done => {
initializeManager();
input.value = 'awesome search terms'; input.value = 'awesome search terms';
visitUrl.mockImplementation(url => { visitUrl.mockImplementation(url => {
...@@ -213,6 +224,7 @@ describe('Filtered Search Manager', () => { ...@@ -213,6 +224,7 @@ describe('Filtered Search Manager', () => {
}); });
it('should search with special characters', done => { it('should search with special characters', done => {
initializeManager();
input.value = '~!@#$%^&*()_+{}:<>,.?/'; input.value = '~!@#$%^&*()_+{}:<>,.?/';
visitUrl.mockImplementation(url => { visitUrl.mockImplementation(url => {
...@@ -226,6 +238,7 @@ describe('Filtered Search Manager', () => { ...@@ -226,6 +238,7 @@ describe('Filtered Search Manager', () => {
}); });
it('should use replacement URL for condition', done => { it('should use replacement URL for condition', done => {
initializeManager();
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML( tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', '13', true), FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', '13', true),
); );
...@@ -246,6 +259,7 @@ describe('Filtered Search Manager', () => { ...@@ -246,6 +259,7 @@ describe('Filtered Search Manager', () => {
}); });
it('removes duplicated tokens', done => { it('removes duplicated tokens', done => {
initializeManager();
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(` tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug')} ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug')}
${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug')} ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug')}
......
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