Commit a6526096 authored by Martin Wortschack's avatar Martin Wortschack

Merge branch '249591-mlunoe-fix-getter-data-structure-for-filter' into 'master'

Fix(Analytics Filter Bars): ensure correct queries

Closes #249591

See merge request gitlab-org/gitlab!42477
parents 684630e8 b61be345
......@@ -3,6 +3,7 @@ import * as types from './mutation_types';
import { __ } from '~/locale';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import { normalizeHeaders, parseIntPagination } from '~/lib/utils/common_utils';
import { filterToQueryObject } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
export const setProjectId = ({ commit }, projectId) => commit(types.SET_PROJECT_ID, projectId);
......@@ -10,17 +11,21 @@ export const fetchMergeRequests = ({ commit, state, rootState }) => {
commit(types.REQUEST_MERGE_REQUESTS);
const { projectId, pageInfo } = state;
const {
filters: {
milestones: { selected: selectedMilestone },
labels: { selectedList: selectedLabelList },
},
} = rootState;
const { selected: milestoneTitle } = rootState.filters.milestones;
const { selectedList: labelNames } = rootState.filters.labels;
const filterBarQuery = filterToQueryObject({
milestone_title: selectedMilestone,
label_name: selectedLabelList,
});
const params = {
project_id: projectId,
milestone_title: milestoneTitle?.operator === '=' ? milestoneTitle.value : null,
label_name: labelNames?.filter(l => l.operator === '=').map(l => l.value),
'not[label_name]': labelNames?.filter(l => l.operator === '!=').map(l => l.value),
'not[milestone_title]': milestoneTitle?.operator === '!=' ? milestoneTitle.value : null,
page: pageInfo.page,
...filterBarQuery,
};
return API.codeReviewAnalytics(params)
......
import dateFormat from 'dateformat';
import { isNumber } from 'lodash';
import httpStatus from '~/lib/utils/http_status';
import { filterToQueryObject } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
import { dateFormats } from '../../shared/constants';
import { transformStagesForPathNavigation } from '../utils';
import { DEFAULT_VALUE_STREAM_ID } from '../constants';
......@@ -20,21 +21,25 @@ export const cycleAnalyticsRequestParams = (state, getters) => {
startDate = null,
endDate = null,
filters: {
authors: { selected: selectedAuthor = null },
milestones: { selected: selectedMilestone = null },
assignees: { selectedList: selectedAssigneeList = [] },
labels: { selectedList: selectedLabelList = [] },
authors: { selected: selectedAuthor },
milestones: { selected: selectedMilestone },
assignees: { selectedList: selectedAssigneeList },
labels: { selectedList: selectedLabelList },
},
} = state;
const filterBarQuery = filterToQueryObject({
milestone_title: selectedMilestone,
author_username: selectedAuthor,
label_name: selectedLabelList,
assignee_username: selectedAssigneeList,
});
return {
project_ids: getters.selectedProjectIds,
created_after: startDate ? dateFormat(startDate, dateFormats.isoDate) : null,
created_before: endDate ? dateFormat(endDate, dateFormats.isoDate) : null,
author_username: selectedAuthor,
milestone_title: selectedMilestone,
assignee_username: selectedAssigneeList,
label_name: selectedLabelList,
...filterBarQuery,
};
};
......
......@@ -8,9 +8,10 @@ import initialFiltersState from 'ee/analytics/shared/store/modules/filters/state
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import * as utils from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
import UrlSync from '~/vue_shared/components/url_sync.vue';
import { filterMilestones, filterLabels } from '../../shared/store/modules/filters/mock_data';
import * as commonUtils from '~/lib/utils/common_utils';
import * as urlUtils from '~/lib/utils/url_utility';
import { filterMilestones, filterLabels } from '../../shared/store/modules/filters/mock_data';
import { getFilterParams, getFilterValues } from '../../shared/store/modules/filters/test_helper';
const localVue = createLocalVue();
localVue.use(Vuex);
......@@ -38,20 +39,10 @@ async function shouldMergeUrlParams(wrapper, result) {
expect(commonUtils.historyPushState).toHaveBeenCalled();
}
function getFilterParams(tokens, operator, key = 'value') {
return tokens.map(token => {
return { [key]: token.title, operator };
});
}
function getFilterValues(tokens) {
return tokens.map(token => token.title);
}
const selectedMilestoneParams = getFilterParams(filterMilestones, '=');
const unselectedMilestoneParams = getFilterParams(filterMilestones, '!=');
const selectedLabelParams = getFilterParams(filterLabels, '=');
const unselectedLabelParams = getFilterParams(filterLabels, '!=');
const selectedMilestoneParams = getFilterParams(filterMilestones);
const unselectedMilestoneParams = getFilterParams(filterMilestones, { operator: '!=' });
const selectedLabelParams = getFilterParams(filterLabels);
const unselectedLabelParams = getFilterParams(filterLabels, { operator: '!=' });
const milestoneValues = getFilterValues(filterMilestones);
const labelValues = getFilterValues(filterLabels);
......@@ -163,9 +154,12 @@ describe('Filter bar', () => {
it('clicks on the search button, setFilters is dispatched', () => {
const filters = [
{ type: 'milestone', value: getFilterParams(filterMilestones, '=', 'data')[2] },
{ type: 'labels', value: getFilterParams(filterLabels, '=', 'data')[2] },
{ type: 'labels', value: getFilterParams(filterLabels, '!=', 'data')[4] },
{ type: 'milestone', value: getFilterParams(filterMilestones, { key: 'data' })[2] },
{ type: 'labels', value: getFilterParams(filterLabels, { key: 'data' })[2] },
{
type: 'labels',
value: getFilterParams(filterLabels, { key: 'data', operator: '!=' })[4],
},
];
findFilteredSearch().vm.$emit('onFilter', filters);
......
......@@ -8,9 +8,23 @@ import {
issueStage,
stageMedians,
} from '../mock_data';
import {
filterMilestones,
filterUsers,
filterLabels,
} from '../../shared/store/modules/filters/mock_data';
import { getFilterParams, getFilterValues } from '../../shared/store/modules/filters/test_helper';
let state = null;
const selectedMilestoneParams = getFilterParams(filterMilestones);
const selectedLabelParams = getFilterParams(filterLabels);
const selectedUserParams = getFilterParams(filterUsers, { prop: 'name' });
const milestoneValues = getFilterValues(filterMilestones);
const labelValues = getFilterValues(filterLabels);
const userValues = getFilterValues(filterUsers, { prop: 'name' });
describe('Cycle analytics getters', () => {
describe('hasNoAccessError', () => {
beforeEach(() => {
......@@ -71,11 +85,6 @@ describe('Cycle analytics getters', () => {
});
describe('cycleAnalyticsRequestParams', () => {
const selectedAuthor = 'Gohan';
const selectedMilestone = 'SSJ4';
const selectedAssigneeList = ['krillin', 'gotenks'];
const selectedLabelList = ['cell saga', 'buu saga'];
beforeEach(() => {
const fullPath = 'cool-beans';
state = {
......@@ -86,10 +95,10 @@ describe('Cycle analytics getters', () => {
endDate,
selectedProjects,
filters: {
authors: { selected: selectedAuthor },
milestones: { selected: selectedMilestone },
assignees: { selectedList: selectedAssigneeList },
labels: { selectedList: selectedLabelList },
authors: { selected: selectedUserParams[0] },
milestones: { selected: selectedMilestoneParams[1] },
assignees: { selectedList: selectedUserParams[1] },
labels: { selectedList: selectedLabelParams },
},
};
});
......@@ -99,10 +108,10 @@ describe('Cycle analytics getters', () => {
${'created_after'} | ${'2018-12-15'}
${'created_before'} | ${'2019-01-14'}
${'project_ids'} | ${[1, 2]}
${'author_username'} | ${selectedAuthor}
${'milestone_title'} | ${selectedMilestone}
${'assignee_username'} | ${selectedAssigneeList}
${'label_name'} | ${selectedLabelList}
${'author_username'} | ${userValues[0]}
${'milestone_title'} | ${milestoneValues[1]}
${'assignee_username'} | ${userValues[1]}
${'label_name'} | ${labelValues}
`('should return the $param with value $value', ({ param, value }) => {
expect(
getters.cycleAnalyticsRequestParams(state, { selectedProjectIds: [1, 2] }),
......@@ -112,9 +121,9 @@ describe('Cycle analytics getters', () => {
});
it.each`
param | stateKey | value
${'assignee_username'} | ${'selectedAssigneeList'} | ${[]}
${'label_name'} | ${'selectedLabelList'} | ${[]}
param | stateKey | value
${'assignee_username'} | ${'userValues'} | ${[]}
${'label_name'} | ${'labelValues'} | ${[]}
`('should not return the $param when $stateKey=$value', ({ param, stateKey, value }) => {
expect(
getters.cycleAnalyticsRequestParams(
......
......@@ -17,6 +17,7 @@ import {
filterLabels,
filterUsers,
} from '../../shared/store/modules/filters/mock_data';
import { getFilterParams, getFilterValues } from '../../shared/store/modules/filters/test_helper';
const localVue = createLocalVue();
localVue.use(Vuex);
......@@ -60,18 +61,6 @@ async function shouldMergeUrlParams(wrapper, result) {
expect(commonUtils.historyPushState).toHaveBeenCalled();
}
function getFilterParams(tokens, options = {}) {
const { key = 'value', operator = '=', prop = 'title' } = options;
return tokens.map(token => {
return { [key]: token[prop], operator };
});
}
function getFilterValues(tokens, options = {}) {
const { prop = 'title' } = options;
return tokens.map(token => token[prop]);
}
const selectedBranchParams = getFilterParams(mockBranches, { prop: 'name' });
const selectedMilestoneParams = getFilterParams(filterMilestones);
const selectedLabelParams = getFilterParams(filterLabels);
......
export function getFilterParams(tokens, options = {}) {
const { key = 'value', operator = '=', prop = 'title' } = options;
return tokens.map(token => {
return { [key]: token[prop], operator };
});
}
export function getFilterValues(tokens, options = {}) {
const { prop = 'title' } = options;
return tokens.map(token => token[prop]);
}
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