Commit 7c820e4e authored by Tim Zallmann's avatar Tim Zallmann

Merge branch '6240-multiple-select-filters' into 'master'

Allows the GSD to select multiple filters

See merge request gitlab-org/gitlab-ee!9031
parents f6a9a307 429259bc
...@@ -22,13 +22,12 @@ export default { ...@@ -22,13 +22,12 @@ export default {
}, },
}, },
computed: { computed: {
...mapGetters('filters', ['getFilter', 'getSelectedOptions']), ...mapGetters('filters', ['getFilter', 'getSelectedOptions', 'getSelectedOptionNames']),
filter() { filter() {
return this.getFilter(this.filterId); return this.getFilter(this.filterId);
}, },
selectedOptionText() { selectedOptionText() {
const [selectedOption] = this.getSelectedOptions(this.filterId); return this.getSelectedOptionNames(this.filterId) || '-';
return (selectedOption && selectedOption.name) || '-';
}, },
}, },
methods: { methods: {
......
import { sprintf, __ } from '~/locale';
export const getFilter = state => filterId => state.filters.find(filter => filter.id === filterId); export const getFilter = state => filterId => state.filters.find(filter => filter.id === filterId);
export const getSelectedOptions = (state, getters) => filterId => export const getSelectedOptions = (state, getters) => filterId =>
...@@ -6,6 +8,19 @@ export const getSelectedOptions = (state, getters) => filterId => ...@@ -6,6 +8,19 @@ export const getSelectedOptions = (state, getters) => filterId =>
export const getSelectedOptionIds = (state, getters) => filterId => export const getSelectedOptionIds = (state, getters) => filterId =>
getters.getSelectedOptions(filterId).map(option => option.id); getters.getSelectedOptions(filterId).map(option => option.id);
export const getSelectedOptionNames = (state, getters) => filterId => {
const selectedOptions = getters.getSelectedOptions(filterId);
const [firstOption] = selectedOptions.map(option => option.name);
const extraOptionCount = selectedOptions.length - 1;
return extraOptionCount
? sprintf(__('%{firstOption} +%{extraOptionCount} more'), {
firstOption,
extraOptionCount,
})
: firstOption;
};
export const getFilterIds = state => state.filters.map(filter => filter.id); export const getFilterIds = state => state.filters.map(filter => filter.id);
/** /**
......
...@@ -4,13 +4,41 @@ export default { ...@@ -4,13 +4,41 @@ export default {
[types.SET_FILTER](state, payload) { [types.SET_FILTER](state, payload) {
const { filterId, optionId } = payload; const { filterId, optionId } = payload;
const activeFilter = state.filters.find(filter => filter.id === filterId); const activeFilter = state.filters.find(filter => filter.id === filterId);
if (activeFilter) { if (activeFilter) {
activeFilter.options = [ let activeOptions;
...activeFilter.options.map(option => ({
if (optionId === 'all') {
activeOptions = activeFilter.options.map(option => ({
...option, ...option,
selected: option.id === optionId, selected: option.id === optionId,
})), }));
]; } else {
activeOptions = activeFilter.options.map(option => {
if (option.id === 'all') {
return {
...option,
selected: false,
};
}
if (option.id === optionId) {
return {
...option,
selected: !option.selected,
};
}
return option;
});
}
// This prevents us from selecting nothing at all
if (!activeOptions.find(option => option.selected)) {
activeOptions[0].selected = true;
}
activeFilter.options = activeOptions;
} }
}, },
}; };
---
title: Allows the Group Security Dashboard to select multiple filters
merge_request: 9031
author:
type: added
...@@ -28,14 +28,32 @@ describe('filters module getters', () => { ...@@ -28,14 +28,32 @@ describe('filters module getters', () => {
}); });
describe('getSelectedOptions', () => { describe('getSelectedOptions', () => {
it('should return "All" as the selcted option', () => { describe('with one selected option', () => {
const state = createState(); it('should return "All" as the selected option', () => {
const selectedOptions = getters.getSelectedOptions(state, mockedGetters(state))( const state = createState();
'report_type', const selectedOptions = getters.getSelectedOptions(state, mockedGetters(state))(
); 'report_type',
);
expect(selectedOptions).toHaveLength(1);
expect(selectedOptions[0].name).toEqual('All');
});
});
expect(selectedOptions).toHaveLength(1); describe('with multiple selected options', () => {
expect(selectedOptions[0].name).toEqual('All'); it('should return both "High" and "Critical" ', () => {
const state = {
filters: [
{
id: 'severity',
options: [{ id: 'critical', selected: true }, { id: 'high', selected: true }],
},
],
};
const selectedOptions = getters.getSelectedOptions(state, mockedGetters(state))('severity');
expect(selectedOptions).toHaveLength(2);
});
}); });
}); });
...@@ -56,6 +74,33 @@ describe('filters module getters', () => { ...@@ -56,6 +74,33 @@ describe('filters module getters', () => {
}); });
}); });
describe('getSelectedOptionNames', () => {
it('should return "All" as the selected option', () => {
const state = createState();
const selectedOptionNames = getters.getSelectedOptionNames(state, mockedGetters(state))(
'severity',
);
expect(selectedOptionNames).toEqual('All');
});
it('should return the correct message when multiple filters are selected', () => {
const state = {
filters: [
{
id: 'severity',
options: [{ name: 'Critical', selected: true }, { name: 'High', selected: true }],
},
],
};
const selectedOptionNames = getters.getSelectedOptionNames(state, mockedGetters(state))(
'severity',
);
expect(selectedOptionNames).toEqual('Critical +1 more');
});
});
describe('activeFilters', () => { describe('activeFilters', () => {
it('should return no severity filters', () => { it('should return no severity filters', () => {
const state = createState(); const state = createState();
......
...@@ -5,26 +5,39 @@ import mutations from 'ee/security_dashboard/store/modules/filters/mutations'; ...@@ -5,26 +5,39 @@ import mutations from 'ee/security_dashboard/store/modules/filters/mutations';
describe('filters module mutations', () => { describe('filters module mutations', () => {
describe('SET_FILTER', () => { describe('SET_FILTER', () => {
let state; let state;
let typeFilter; let severityFilter;
let sastOption; let criticalOption;
let highOption;
beforeEach(() => { beforeEach(() => {
state = createState(); state = createState();
[typeFilter] = state.filters; [severityFilter] = state.filters;
[, sastOption] = typeFilter.options; [, criticalOption, highOption] = severityFilter.options;
mutations[types.SET_FILTER](state, { mutations[types.SET_FILTER](state, {
filterId: typeFilter.id, filterId: severityFilter.id,
optionId: sastOption.id, optionId: criticalOption.id,
}); });
}); });
it('should make SAST the selected option', () => { it('should make critical the selected option', () => {
expect(state.filters[0].options[1].selected).toEqual(true); expect(state.filters[0].options[1].selected).toEqual(true);
}); });
it('should remove ALL as the selected option', () => { it('should remove ALL as the selected option', () => {
expect(state.filters[0].options[0].selected).toEqual(false); expect(state.filters[0].options[0].selected).toEqual(false);
}); });
describe('on subsequent changes', () => {
it('should add "high" to the selected options', () => {
mutations[types.SET_FILTER](state, {
filterId: severityFilter.id,
optionId: highOption.id,
});
expect(state.filters[0].options[1].selected).toEqual(true);
expect(state.filters[0].options[2].selected).toEqual(true);
});
});
}); });
}); });
...@@ -150,6 +150,9 @@ msgstr "" ...@@ -150,6 +150,9 @@ msgstr ""
msgid "%{firstLabel} +%{labelCount} more" msgid "%{firstLabel} +%{labelCount} more"
msgstr "" msgstr ""
msgid "%{firstOption} +%{extraOptionCount} more"
msgstr ""
msgid "%{group_docs_link_start}Groups%{group_docs_link_end} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects." msgid "%{group_docs_link_start}Groups%{group_docs_link_end} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects."
msgstr "" msgstr ""
......
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