Commit 3c9f65d3 authored by Martin Wortschack's avatar Martin Wortschack

Merge branch...

Merge branch '229266-mlunoe-handle-lists-and-individual-values-in-analytics-filter-bar-store-module' into 'master'

Feat(Analytics filter module): lists + values

See merge request gitlab-org/gitlab!40845
parents cef050d2 6c98c4c1
<script> <script>
import { mapState, mapActions } from 'vuex'; import { mapState, mapActions } from 'vuex';
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import { __ } from '~/locale'; import { __ } from '~/locale';
import MilestoneToken from '../../shared/components/tokens/milestone_token.vue'; import MilestoneToken from '../../shared/components/tokens/milestone_token.vue';
import LabelToken from '../../shared/components/tokens/label_token.vue'; import LabelToken from '../../shared/components/tokens/label_token.vue';
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import { processFilters } from '../../shared/utils'; import { processFilters } from '../../shared/utils';
export default { export default {
...@@ -23,12 +23,12 @@ export default { ...@@ -23,12 +23,12 @@ export default {
}, },
computed: { computed: {
...mapState('filters', { ...mapState('filters', {
milestonePath: 'milestonePath',
labelsPath: 'labelsPath',
milestones: state => state.milestones.data,
milestonesLoading: state => state.milestones.isLoading, milestonesLoading: state => state.milestones.isLoading,
labels: state => state.labels.data,
labelsLoading: state => state.labels.isLoading, labelsLoading: state => state.labels.isLoading,
selectedMilestone: state => state.milestones.selected,
selectedLabelList: state => state.labels.selectedList,
milestonesData: state => state.milestones.data,
labelsData: state => state.labels.data,
}), }),
tokens() { tokens() {
return [ return [
...@@ -37,7 +37,7 @@ export default { ...@@ -37,7 +37,7 @@ export default {
title: __('Milestone'), title: __('Milestone'),
type: 'milestone', type: 'milestone',
token: MilestoneToken, token: MilestoneToken,
milestones: this.milestones, milestones: this.milestonesData,
unique: true, unique: true,
symbol: '%', symbol: '%',
isLoading: this.milestonesLoading, isLoading: this.milestonesLoading,
...@@ -48,7 +48,7 @@ export default { ...@@ -48,7 +48,7 @@ export default {
title: __('Label'), title: __('Label'),
type: 'labels', type: 'labels',
token: LabelToken, token: LabelToken,
labels: this.labels, labels: this.labelsData,
unique: false, unique: false,
symbol: '~', symbol: '~',
isLoading: this.labelsLoading, isLoading: this.labelsLoading,
...@@ -62,13 +62,13 @@ export default { ...@@ -62,13 +62,13 @@ export default {
this.fetchLabels(); this.fetchLabels();
}, },
methods: { methods: {
...mapActions('filters', ['fetchMilestones', 'fetchLabels', 'setFilters']), ...mapActions('filters', ['setFilters', 'fetchMilestones', 'fetchLabels']),
handleFilter(filters) { handleFilter(filters) {
const { labels, milestone } = processFilters(filters); const { labels, milestone } = processFilters(filters);
this.setFilters({ this.setFilters({
selectedMilestone: milestone ? milestone[0] : null, selectedMilestone: milestone ? milestone[0] : null,
selectedLabels: labels, selectedLabelList: labels,
}); });
}, },
}, },
......
...@@ -12,7 +12,7 @@ export const fetchMergeRequests = ({ commit, state, rootState }) => { ...@@ -12,7 +12,7 @@ export const fetchMergeRequests = ({ commit, state, rootState }) => {
const { projectId, pageInfo } = state; const { projectId, pageInfo } = state;
const { selected: milestoneTitle } = rootState.filters.milestones; const { selected: milestoneTitle } = rootState.filters.milestones;
const { selected: labelNames } = rootState.filters.labels; const { selectedList: labelNames } = rootState.filters.labels;
const params = { const params = {
project_id: projectId, project_id: projectId,
......
...@@ -28,8 +28,8 @@ export default { ...@@ -28,8 +28,8 @@ export default {
...mapState('filters', { ...mapState('filters', {
selectedMilestone: state => state.milestones.selected, selectedMilestone: state => state.milestones.selected,
selectedAuthor: state => state.authors.selected, selectedAuthor: state => state.authors.selected,
selectedLabels: state => state.labels.selected, selectedLabelList: state => state.labels.selectedList,
selectedAssignees: state => state.assignees.selected, selectedAssigneeList: state => state.assignees.selectedList,
milestonesData: state => state.milestones.data, milestonesData: state => state.milestones.data,
labelsData: state => state.labels.data, labelsData: state => state.labels.data,
authorsData: state => state.authors.data, authorsData: state => state.authors.data,
...@@ -83,14 +83,16 @@ export default { ...@@ -83,14 +83,16 @@ export default {
]; ];
}, },
query() { query() {
const selectedLabels = this.selectedLabels?.length ? this.selectedLabels : null; const selectedLabelList = this.selectedLabelList?.length ? this.selectedLabelList : null;
const selectedAssignees = this.selectedAssignees?.length ? this.selectedAssignees : null; const selectedAssigneeList = this.selectedAssigneeList?.length
? this.selectedAssigneeList
: null;
return { return {
milestone_title: this.selectedMilestone, milestone_title: this.selectedMilestone,
author_username: this.selectedAuthor, author_username: this.selectedAuthor,
label_name: selectedLabels, label_name: selectedLabelList,
assignee_username: selectedAssignees, assignee_username: selectedAssigneeList,
}; };
}, },
}, },
...@@ -106,8 +108,8 @@ export default { ...@@ -106,8 +108,8 @@ export default {
const { const {
selectedMilestone: milestone = null, selectedMilestone: milestone = null,
selectedAuthor: author = null, selectedAuthor: author = null,
selectedAssignees: assignees = [], selectedAssigneeList: assignees = [],
selectedLabels: labels = [], selectedLabelList: labels = [],
} = this; } = this;
return prepareTokens({ milestone, author, assignees, labels }); return prepareTokens({ milestone, author, assignees, labels });
}, },
...@@ -117,8 +119,8 @@ export default { ...@@ -117,8 +119,8 @@ export default {
this.setFilters({ this.setFilters({
selectedAuthor: author ? author[0].value : null, selectedAuthor: author ? author[0].value : null,
selectedMilestone: milestone ? milestone[0].value : null, selectedMilestone: milestone ? milestone[0].value : null,
selectedAssignees: assignees ? assignees.map(a => a.value) : [], selectedAssigneeList: assignees ? assignees.map(a => a.value) : [],
selectedLabels: labels ? labels.map(l => l.value) : [], selectedLabelList: labels ? labels.map(l => l.value) : [],
}); });
}, },
}, },
......
...@@ -22,8 +22,8 @@ export const cycleAnalyticsRequestParams = (state, getters) => { ...@@ -22,8 +22,8 @@ export const cycleAnalyticsRequestParams = (state, getters) => {
filters: { filters: {
authors: { selected: selectedAuthor = null }, authors: { selected: selectedAuthor = null },
milestones: { selected: selectedMilestone = null }, milestones: { selected: selectedMilestone = null },
assignees: { selected: selectedAssignees = [] }, assignees: { selectedList: selectedAssigneeList = [] },
labels: { selected: selectedLabels = [] }, labels: { selectedList: selectedLabelList = [] },
}, },
} = state; } = state;
...@@ -33,8 +33,8 @@ export const cycleAnalyticsRequestParams = (state, getters) => { ...@@ -33,8 +33,8 @@ export const cycleAnalyticsRequestParams = (state, getters) => {
created_before: endDate ? dateFormat(endDate, dateFormats.isoDate) : null, created_before: endDate ? dateFormat(endDate, dateFormats.isoDate) : null,
author_username: selectedAuthor, author_username: selectedAuthor,
milestone_title: selectedMilestone, milestone_title: selectedMilestone,
assignee_username: selectedAssignees, assignee_username: selectedAssigneeList,
label_name: selectedLabels, label_name: selectedLabelList,
}; };
}; };
......
...@@ -4,14 +4,22 @@ export default { ...@@ -4,14 +4,22 @@ export default {
[types.SET_SELECTED_FILTERS](state, params) { [types.SET_SELECTED_FILTERS](state, params) {
const { const {
selectedAuthor = null, selectedAuthor = null,
selectedAuthorList = [],
selectedMilestone = null, selectedMilestone = null,
selectedAssignees = [], selectedMilestoneList = [],
selectedLabels = [], selectedAssignee = null,
selectedAssigneeList = [],
selectedLabel = null,
selectedLabelList = [],
} = params; } = params;
state.authors.selected = selectedAuthor; state.authors.selected = selectedAuthor;
state.assignees.selected = selectedAssignees; state.authors.selectedList = selectedAuthorList;
state.assignees.selected = selectedAssignee;
state.assignees.selectedList = selectedAssigneeList;
state.milestones.selected = selectedMilestone; state.milestones.selected = selectedMilestone;
state.labels.selected = selectedLabels; state.milestones.selectedList = selectedMilestoneList;
state.labels.selected = selectedLabel;
state.labels.selectedList = selectedLabelList;
}, },
[types.SET_MILESTONES_ENDPOINT](state, milestonesEndpoint) { [types.SET_MILESTONES_ENDPOINT](state, milestonesEndpoint) {
state.milestonesEndpoint = milestonesEndpoint; state.milestonesEndpoint = milestonesEndpoint;
......
...@@ -7,23 +7,27 @@ export default () => ({ ...@@ -7,23 +7,27 @@ export default () => ({
errorCode: null, errorCode: null,
data: [], data: [],
selected: null, selected: null,
selectedList: [],
}, },
labels: { labels: {
isLoading: false, isLoading: false,
errorCode: null, errorCode: null,
data: [], data: [],
selected: [], selected: null,
selectedList: [],
}, },
authors: { authors: {
isLoading: false, isLoading: false,
errorCode: null, errorCode: null,
data: [], data: [],
selected: null, selected: null,
selectedList: [],
}, },
assignees: { assignees: {
isLoading: false, isLoading: false,
errorCode: null, errorCode: null,
data: [], data: [],
selected: [], selected: null,
selectedList: [],
}, },
}); });
...@@ -118,7 +118,7 @@ describe('FilteredSearchBar', () => { ...@@ -118,7 +118,7 @@ describe('FilteredSearchBar', () => {
expect(setFiltersMock).toHaveBeenCalledWith( expect(setFiltersMock).toHaveBeenCalledWith(
expect.anything(), expect.anything(),
{ {
selectedLabels: [{ value: 'my-label', operator: '=' }], selectedLabelList: [{ value: 'my-label', operator: '=' }],
selectedMilestone: { value: 'my-milestone', operator: '=' }, selectedMilestone: { value: 'my-milestone', operator: '=' },
}, },
undefined, undefined,
......
...@@ -23,8 +23,8 @@ const assigneesTokenType = 'assignees'; ...@@ -23,8 +23,8 @@ const assigneesTokenType = 'assignees';
const initialFilterBarState = { const initialFilterBarState = {
selectedMilestone: null, selectedMilestone: null,
selectedAuthor: null, selectedAuthor: null,
selectedAssignees: null, selectedAssigneeList: null,
selectedLabels: null, selectedLabelList: null,
}; };
const defaultParams = { const defaultParams = {
...@@ -91,7 +91,7 @@ describe('Filter bar', () => { ...@@ -91,7 +91,7 @@ describe('Filter bar', () => {
}); });
const selectedMilestone = [filterMilestones[0]]; const selectedMilestone = [filterMilestones[0]];
const selectedLabels = [filterLabels[0]]; const selectedLabelList = [filterLabels[0]];
const findFilteredSearch = () => wrapper.find(FilteredSearchBar); const findFilteredSearch = () => wrapper.find(FilteredSearchBar);
const getSearchToken = type => const getSearchToken = type =>
...@@ -114,7 +114,7 @@ describe('Filter bar', () => { ...@@ -114,7 +114,7 @@ describe('Filter bar', () => {
beforeEach(() => { beforeEach(() => {
store = createStore({ store = createStore({
milestones: { data: selectedMilestone }, milestones: { data: selectedMilestone },
labels: { data: selectedLabels }, labels: { data: selectedLabelList },
authors: { data: [] }, authors: { data: [] },
assignees: { data: [] }, assignees: { data: [] },
}); });
...@@ -140,7 +140,7 @@ describe('Filter bar', () => { ...@@ -140,7 +140,7 @@ describe('Filter bar', () => {
it('provides the initial label token', () => { it('provides the initial label token', () => {
const { initialLabels: labelToken } = getSearchToken(labelsTokenType); const { initialLabels: labelToken } = getSearchToken(labelsTokenType);
expect(labelToken).toHaveLength(selectedLabels.length); expect(labelToken).toHaveLength(selectedLabelList.length);
}); });
}); });
...@@ -157,7 +157,7 @@ describe('Filter bar', () => { ...@@ -157,7 +157,7 @@ describe('Filter bar', () => {
it('clicks on the search button, setFilters is dispatched', () => { it('clicks on the search button, setFilters is dispatched', () => {
const filters = [ const filters = [
{ type: 'milestone', value: { data: selectedMilestone[0].title, operator: '=' } }, { type: 'milestone', value: { data: selectedMilestone[0].title, operator: '=' } },
{ type: 'labels', value: { data: selectedLabels[0].title, operator: '=' } }, { type: 'labels', value: { data: selectedLabelList[0].title, operator: '=' } },
]; ];
findFilteredSearch().vm.$emit('onFilter', filters); findFilteredSearch().vm.$emit('onFilter', filters);
...@@ -167,9 +167,9 @@ describe('Filter bar', () => { ...@@ -167,9 +167,9 @@ describe('Filter bar', () => {
expect(setFiltersMock).toHaveBeenCalledWith( expect(setFiltersMock).toHaveBeenCalledWith(
expect.anything(), expect.anything(),
{ {
selectedLabels: [selectedLabels[0].title], selectedLabelList: [selectedLabelList[0].title],
selectedMilestone: selectedMilestone[0].title, selectedMilestone: selectedMilestone[0].title,
selectedAssignees: [], selectedAssigneeList: [],
selectedAuthor: null, selectedAuthor: null,
}, },
undefined, undefined,
...@@ -178,11 +178,11 @@ describe('Filter bar', () => { ...@@ -178,11 +178,11 @@ describe('Filter bar', () => {
}); });
describe.each` describe.each`
stateKey | payload | paramKey stateKey | payload | paramKey
${'selectedMilestone'} | ${'12.0'} | ${'milestone_title'} ${'selectedMilestone'} | ${'12.0'} | ${'milestone_title'}
${'selectedAuthor'} | ${'rootUser'} | ${'author_username'} ${'selectedAuthor'} | ${'rootUser'} | ${'author_username'}
${'selectedLabels'} | ${['Afternix', 'Brouceforge']} | ${'label_name'} ${'selectedLabelList'} | ${['Afternix', 'Brouceforge']} | ${'label_name'}
${'selectedAssignees'} | ${['rootUser', 'secondaryUser']} | ${'assignee_username'} ${'selectedAssigneeList'} | ${['rootUser', 'secondaryUser']} | ${'assignee_username'}
`('with a $stateKey updates the $paramKey url parameter', ({ stateKey, payload, paramKey }) => { `('with a $stateKey updates the $paramKey url parameter', ({ stateKey, payload, paramKey }) => {
beforeEach(() => { beforeEach(() => {
commonUtils.historyPushState = jest.fn(); commonUtils.historyPushState = jest.fn();
......
...@@ -73,8 +73,8 @@ describe('Cycle analytics getters', () => { ...@@ -73,8 +73,8 @@ describe('Cycle analytics getters', () => {
describe('cycleAnalyticsRequestParams', () => { describe('cycleAnalyticsRequestParams', () => {
const selectedAuthor = 'Gohan'; const selectedAuthor = 'Gohan';
const selectedMilestone = 'SSJ4'; const selectedMilestone = 'SSJ4';
const selectedAssignees = ['krillin', 'gotenks']; const selectedAssigneeList = ['krillin', 'gotenks'];
const selectedLabels = ['cell saga', 'buu saga']; const selectedLabelList = ['cell saga', 'buu saga'];
beforeEach(() => { beforeEach(() => {
const fullPath = 'cool-beans'; const fullPath = 'cool-beans';
...@@ -88,8 +88,8 @@ describe('Cycle analytics getters', () => { ...@@ -88,8 +88,8 @@ describe('Cycle analytics getters', () => {
filters: { filters: {
authors: { selected: selectedAuthor }, authors: { selected: selectedAuthor },
milestones: { selected: selectedMilestone }, milestones: { selected: selectedMilestone },
assignees: { selected: selectedAssignees }, assignees: { selectedList: selectedAssigneeList },
labels: { selected: selectedLabels }, labels: { selectedList: selectedLabelList },
}, },
}; };
}); });
...@@ -101,8 +101,8 @@ describe('Cycle analytics getters', () => { ...@@ -101,8 +101,8 @@ describe('Cycle analytics getters', () => {
${'project_ids'} | ${[1, 2]} ${'project_ids'} | ${[1, 2]}
${'author_username'} | ${selectedAuthor} ${'author_username'} | ${selectedAuthor}
${'milestone_title'} | ${selectedMilestone} ${'milestone_title'} | ${selectedMilestone}
${'assignee_username'} | ${selectedAssignees} ${'assignee_username'} | ${selectedAssigneeList}
${'label_name'} | ${selectedLabels} ${'label_name'} | ${selectedLabelList}
`('should return the $param with value $value', ({ param, value }) => { `('should return the $param with value $value', ({ param, value }) => {
expect( expect(
getters.cycleAnalyticsRequestParams(state, { selectedProjectIds: [1, 2] }), getters.cycleAnalyticsRequestParams(state, { selectedProjectIds: [1, 2] }),
...@@ -112,9 +112,9 @@ describe('Cycle analytics getters', () => { ...@@ -112,9 +112,9 @@ describe('Cycle analytics getters', () => {
}); });
it.each` it.each`
param | stateKey | value param | stateKey | value
${'assignee_username'} | ${'selectedAssignees'} | ${[]} ${'assignee_username'} | ${'selectedAssigneeList'} | ${[]}
${'label_name'} | ${'selectedLabels'} | ${[]} ${'label_name'} | ${'selectedLabelList'} | ${[]}
`('should not return the $param when $stateKey=$value', ({ param, stateKey, value }) => { `('should not return the $param when $stateKey=$value', ({ param, stateKey, value }) => {
expect( expect(
getters.cycleAnalyticsRequestParams( getters.cycleAnalyticsRequestParams(
......
...@@ -9,14 +9,16 @@ const milestones = filterMilestones.map(convertObjectPropsToCamelCase); ...@@ -9,14 +9,16 @@ const milestones = filterMilestones.map(convertObjectPropsToCamelCase);
const users = filterUsers.map(convertObjectPropsToCamelCase); const users = filterUsers.map(convertObjectPropsToCamelCase);
const labels = filterLabels.map(convertObjectPropsToCamelCase); const labels = filterLabels.map(convertObjectPropsToCamelCase);
const filterValue = { value: 'foo' };
describe('Filters mutations', () => { describe('Filters mutations', () => {
const errorCode = 500; const errorCode = 500;
beforeEach(() => { beforeEach(() => {
state = { state = {
authors: { selected: null }, authors: { selected: null, selectedList: [] },
milestones: { selected: null }, milestones: { selected: null, selectedList: [] },
assignees: { selected: [] }, assignees: { selected: null, selectedList: [] },
labels: { selected: [] }, labels: { selected: null, selectedList: [] },
}; };
}); });
...@@ -28,6 +30,7 @@ describe('Filters mutations', () => { ...@@ -28,6 +30,7 @@ describe('Filters mutations', () => {
mutation | stateKey | value mutation | stateKey | value
${types.SET_MILESTONES_ENDPOINT} | ${'milestonesEndpoint'} | ${'new-milestone-endpoint'} ${types.SET_MILESTONES_ENDPOINT} | ${'milestonesEndpoint'} | ${'new-milestone-endpoint'}
${types.SET_LABELS_ENDPOINT} | ${'labelsEndpoint'} | ${'new-label-endpoint'} ${types.SET_LABELS_ENDPOINT} | ${'labelsEndpoint'} | ${'new-label-endpoint'}
${types.SET_GROUP_ENDPOINT} | ${'groupEndpoint'} | ${'new-group-endpoint'}
`('$mutation will set $stateKey=$value', ({ mutation, stateKey, value }) => { `('$mutation will set $stateKey=$value', ({ mutation, stateKey, value }) => {
mutations[mutation](state, value); mutations[mutation](state, value);
...@@ -35,16 +38,31 @@ describe('Filters mutations', () => { ...@@ -35,16 +38,31 @@ describe('Filters mutations', () => {
}); });
it.each` it.each`
mutation | stateKey | value mutation | stateKey | stateProp | filterName | value
${types.SET_SELECTED_FILTERS} | ${'authors'} | ${null} ${types.SET_SELECTED_FILTERS} | ${'authors'} | ${'selected'} | ${'selectedAuthor'} | ${null}
${types.SET_SELECTED_FILTERS} | ${'milestones'} | ${null} ${types.SET_SELECTED_FILTERS} | ${'authors'} | ${'selected'} | ${'selectedAuthor'} | ${filterValue}
${types.SET_SELECTED_FILTERS} | ${'assignees'} | ${[]} ${types.SET_SELECTED_FILTERS} | ${'authors'} | ${'selectedList'} | ${'selectedAuthorList'} | ${[]}
${types.SET_SELECTED_FILTERS} | ${'labels'} | ${[]} ${types.SET_SELECTED_FILTERS} | ${'authors'} | ${'selectedList'} | ${'selectedAuthorList'} | ${[filterValue]}
`('$mutation will set $stateKey with a given value', ({ mutation, stateKey, value }) => { ${types.SET_SELECTED_FILTERS} | ${'milestones'} | ${'selected'} | ${'selectedMilestone'} | ${null}
mutations[mutation](state, { [stateKey]: { selected: value } }); ${types.SET_SELECTED_FILTERS} | ${'milestones'} | ${'selected'} | ${'selectedMilestone'} | ${filterValue}
${types.SET_SELECTED_FILTERS} | ${'milestones'} | ${'selectedList'} | ${'selectedMilestoneList'} | ${[]}
${types.SET_SELECTED_FILTERS} | ${'milestones'} | ${'selectedList'} | ${'selectedMilestoneList'} | ${[filterValue]}
${types.SET_SELECTED_FILTERS} | ${'assignees'} | ${'selected'} | ${'selectedAssignee'} | ${null}
${types.SET_SELECTED_FILTERS} | ${'assignees'} | ${'selected'} | ${'selectedAssignee'} | ${filterValue}
${types.SET_SELECTED_FILTERS} | ${'assignees'} | ${'selectedList'} | ${'selectedAssigneeList'} | ${[]}
${types.SET_SELECTED_FILTERS} | ${'assignees'} | ${'selectedList'} | ${'selectedAssigneeList'} | ${[filterValue]}
${types.SET_SELECTED_FILTERS} | ${'labels'} | ${'selected'} | ${'selectedLabel'} | ${null}
${types.SET_SELECTED_FILTERS} | ${'labels'} | ${'selected'} | ${'selectedLabel'} | ${filterValue}
${types.SET_SELECTED_FILTERS} | ${'labels'} | ${'selectedList'} | ${'selectedLabelList'} | ${[]}
${types.SET_SELECTED_FILTERS} | ${'labels'} | ${'selectedList'} | ${'selectedLabelList'} | ${[filterValue]}
`(
'$mutation will set $stateKey with a given value',
({ mutation, stateKey, stateProp, filterName, value }) => {
mutations[mutation](state, { [filterName]: value });
expect(state[stateKey].selected).toEqual(value); expect(state[stateKey][stateProp]).toEqual(value);
}); },
);
it.each` it.each`
mutation | rootKey | stateKey | value mutation | rootKey | stateKey | value
......
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