Commit cd151e26 authored by Martin Wortschack's avatar Martin Wortschack

Merge branch '9102-hide-dismissed-vulnerabilities-dismiss-action' into 'master'

Implement dismissal behavior when dismissed vulnerabilities are hidden

See merge request gitlab-org/gitlab!16207
parents 270ad0a0 5ee7b315
...@@ -37,7 +37,7 @@ export default { ...@@ -37,7 +37,7 @@ export default {
<gl-toggle-vuex <gl-toggle-vuex
class="d-block mt-1 js-toggle" class="d-block mt-1 js-toggle"
store-module="filters" store-module="filters"
state-property="hide_dismissed" state-property="hideDismissed"
set-action="setToggleValue" set-action="setToggleValue"
/> />
</div> </div>
......
...@@ -27,7 +27,7 @@ export const lockFilter = ({ commit }, payload) => { ...@@ -27,7 +27,7 @@ export const lockFilter = ({ commit }, payload) => {
export const setHideDismissedToggleInitialState = ({ commit }) => { export const setHideDismissedToggleInitialState = ({ commit }) => {
const [urlParam] = getParameterValues('scope'); const [urlParam] = getParameterValues('scope');
const showDismissed = urlParam === 'all'; const showDismissed = urlParam === 'all';
commit(types.SET_TOGGLE_VALUE, { key: 'hide_dismissed', value: !showDismissed }); commit(types.SET_TOGGLE_VALUE, { key: 'hideDismissed', value: !showDismissed });
}; };
export const setToggleValue = ({ commit }, { key, value }) => { export const setToggleValue = ({ commit }, { key, value }) => {
......
...@@ -32,10 +32,10 @@ export const activeFilters = state => { ...@@ -32,10 +32,10 @@ export const activeFilters = state => {
acc[filter.id] = [...Array.from(filter.selection)].filter(id => !isBaseFilterOption(id)); acc[filter.id] = [...Array.from(filter.selection)].filter(id => !isBaseFilterOption(id));
return acc; return acc;
}, {}); }, {});
// hide_dismissed is hardcoded as it currently is an edge-case, more info in the MR: // hideDismissed is hardcoded as it currently is an edge-case, more info in the MR:
// https://gitlab.com/gitlab-org/gitlab/merge_requests/15333#note_208301144 // https://gitlab.com/gitlab-org/gitlab/merge_requests/15333#note_208301144
if (gon.features && gon.features.hideDismissedVulnerabilities) { if (gon.features && gon.features.hideDismissedVulnerabilities) {
filters.scope = state.hide_dismissed ? 'dismissed' : 'all'; filters.scope = state.hideDismissed ? 'dismissed' : 'all';
} }
return filters; return filters;
}; };
......
...@@ -19,7 +19,7 @@ export default { ...@@ -19,7 +19,7 @@ export default {
return { ...filter, selection }; return { ...filter, selection };
}); });
state.hide_dismissed = payload.scope !== 'all'; state.hideDismissed = payload.scope !== 'all';
}, },
[types.SET_FILTER](state, payload) { [types.SET_FILTER](state, payload) {
const { filterId, optionId } = payload; const { filterId, optionId } = payload;
......
...@@ -34,5 +34,5 @@ export default () => ({ ...@@ -34,5 +34,5 @@ export default () => ({
selection: new Set([BASE_FILTERS.project_id.id]), selection: new Set([BASE_FILTERS.project_id.id]),
}, },
], ],
hide_dismissed: true, hideDismissed: true,
}); });
...@@ -149,14 +149,40 @@ export const receiveCreateIssueError = ({ commit }, { flashError }) => { ...@@ -149,14 +149,40 @@ export const receiveCreateIssueError = ({ commit }, { flashError }) => {
}; };
export const dismissVulnerability = ( export const dismissVulnerability = (
{ dispatch, state }, { dispatch, state, rootState },
{ vulnerability, flashError, comment }, { vulnerability, flashError, comment },
) => { ) => {
const page = state.pageInfo && state.pageInfo.page ? state.pageInfo.page : 1;
const dismissedVulnerabilitiesHidden = Boolean(
rootState.filters && rootState.filters.hideDismissed,
);
dispatch('requestDismissVulnerability'); dispatch('requestDismissVulnerability');
const toastMsg = sprintf(s__("Security Reports|Dismissed '%{vulnerabilityName}'"), { const toastMsg = sprintf(
vulnerabilityName: vulnerability.name, dismissedVulnerabilitiesHidden
}); ? s__(
"Security Reports|Dismissed '%{vulnerabilityName}'. Turn off the hide dismissed toggle to view.",
)
: s__("Security Reports|Dismissed '%{vulnerabilityName}'"),
{
vulnerabilityName: vulnerability.name,
},
);
const toastOptions = dismissedVulnerabilitiesHidden
? {
action: {
text: s__('Security Reports|Undo dismiss'),
onClick: (e, toastObject) => {
if (vulnerability.dismissal_feedback) {
dispatch('undoDismiss', { vulnerability })
.then(() => dispatch('fetchVulnerabilities', { page }))
.catch(() => {});
toastObject.goAway(0);
}
},
},
}
: {};
axios axios
.post(vulnerability.create_vulnerability_feedback_dismissal_path, { .post(vulnerability.create_vulnerability_feedback_dismissal_path, {
...@@ -175,7 +201,14 @@ export const dismissVulnerability = ( ...@@ -175,7 +201,14 @@ export const dismissVulnerability = (
.then(({ data }) => { .then(({ data }) => {
dispatch('closeDismissalCommentBox'); dispatch('closeDismissalCommentBox');
dispatch('receiveDismissVulnerabilitySuccess', { vulnerability, data }); dispatch('receiveDismissVulnerabilitySuccess', { vulnerability, data });
toast(toastMsg); if (dismissedVulnerabilitiesHidden) {
dispatch('fetchVulnerabilities', {
// If we just dismissed the last vulnerability on the active page,
// we load the previous page if any
page: state.vulnerabilities.length === 1 && page > 1 ? page - 1 : page,
});
}
toast(toastMsg, toastOptions);
}) })
.catch(() => { .catch(() => {
dispatch('receiveDismissVulnerabilityError', { flashError }); dispatch('receiveDismissVulnerabilityError', { flashError });
...@@ -298,7 +331,7 @@ export const undoDismiss = ({ dispatch }, { vulnerability, flashError }) => { ...@@ -298,7 +331,7 @@ export const undoDismiss = ({ dispatch }, { vulnerability, flashError }) => {
dispatch('requestUndoDismiss'); dispatch('requestUndoDismiss');
axios return axios
.delete(destroy_vulnerability_feedback_dismissal_path) .delete(destroy_vulnerability_feedback_dismissal_path)
.then(() => { .then(() => {
dispatch('receiveUndoDismissSuccess', { vulnerability }); dispatch('receiveUndoDismissSuccess', { vulnerability });
......
---
title: Implement dismissal behaviour when dismissed vulnerabilities are hidden
merge_request: 16207
author:
type: changed
...@@ -175,7 +175,7 @@ describe('Security Dashboard app', () => { ...@@ -175,7 +175,7 @@ describe('Security Dashboard app', () => {
`('$description', ({ getParameterValuesReturnValue, expected }) => { `('$description', ({ getParameterValuesReturnValue, expected }) => {
getParameterValues.mockImplementation(() => getParameterValuesReturnValue); getParameterValues.mockImplementation(() => getParameterValuesReturnValue);
createComponent(); createComponent();
expect(wrapper.vm.$store.state.filters.hide_dismissed).toBe(expected); expect(wrapper.vm.$store.state.filters.hideDismissed).toBe(expected);
}); });
}); });
}); });
...@@ -75,17 +75,17 @@ describe('filters actions', () => { ...@@ -75,17 +75,17 @@ describe('filters actions', () => {
describe('setHideDismissedToggleInitialState', () => { describe('setHideDismissedToggleInitialState', () => {
[ [
{ {
description: 'should set hide_dismissed to true if scope param is not present', description: 'should set hideDismissed to true if scope param is not present',
returnValue: [], returnValue: [],
hideDismissedValue: true, hideDismissedValue: true,
}, },
{ {
description: 'should set hide_dismissed to false if scope param is "all"', description: 'should set hideDismissed to false if scope param is "all"',
returnValue: ['all'], returnValue: ['all'],
hideDismissedValue: false, hideDismissedValue: false,
}, },
{ {
description: 'should set hide_dismissed to true if scope param is "dismissed"', description: 'should set hideDismissed to true if scope param is "dismissed"',
returnValue: ['dismissed'], returnValue: ['dismissed'],
hideDismissedValue: true, hideDismissedValue: true,
}, },
...@@ -101,7 +101,7 @@ describe('filters actions', () => { ...@@ -101,7 +101,7 @@ describe('filters actions', () => {
{ {
type: types.SET_TOGGLE_VALUE, type: types.SET_TOGGLE_VALUE,
payload: { payload: {
key: 'hide_dismissed', key: 'hideDismissed',
value: testCase.hideDismissedValue, value: testCase.hideDismissedValue,
}, },
}, },
......
...@@ -758,6 +758,71 @@ describe('vulnerability dismissal', () => { ...@@ -758,6 +758,71 @@ describe('vulnerability dismissal', () => {
); );
}); });
}); });
describe('with dismissed vulnerabilities hidden', () => {
beforeEach(() => {
state = {
...initialState(),
filters: {
hideDismissed: true,
},
};
mock
.onPost(vulnerability.create_vulnerability_feedback_dismissal_path)
.replyOnce(200, data);
});
it('should show the dismissal toast message and refresh vulnerabilities', done => {
spyOn(Vue.toasted, 'show').and.callThrough();
const checkToastMessage = () => {
const [message, options] = Vue.toasted.show.calls.argsFor(0);
expect(Vue.toasted.show).toHaveBeenCalledTimes(1);
expect(message).toContain('Turn off the hide dismissed toggle to view');
expect(options.action.length).toBe(2);
done();
};
testAction(
actions.dismissVulnerability,
{ vulnerability, comment },
state,
[],
[
{ type: 'requestDismissVulnerability' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDismissVulnerabilitySuccess',
payload: { data, vulnerability },
},
{ type: 'fetchVulnerabilities', payload: { page: 1 } },
],
checkToastMessage,
);
});
it('should load the previous page if there is no more vulnerabiliy on the current one and page > 1', () => {
state.vulnerabilities = [mockDataVulnerabilities[0]];
state.pageInfo.page = 3;
testAction(
actions.dismissVulnerability,
{ vulnerability, comment },
state,
[],
[
{ type: 'requestDismissVulnerability' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDismissVulnerabilitySuccess',
payload: { data, vulnerability },
},
{ type: 'fetchVulnerabilities', payload: { page: 2 } },
],
);
});
});
}); });
describe('receiveDismissVulnerabilitySuccess', () => { describe('receiveDismissVulnerabilitySuccess', () => {
......
...@@ -14387,6 +14387,9 @@ msgstr "" ...@@ -14387,6 +14387,9 @@ msgstr ""
msgid "Security Reports|Dismissed '%{vulnerabilityName}'" msgid "Security Reports|Dismissed '%{vulnerabilityName}'"
msgstr "" msgstr ""
msgid "Security Reports|Dismissed '%{vulnerabilityName}'. Turn off the hide dismissed toggle to view."
msgstr ""
msgid "Security Reports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed." msgid "Security Reports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
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