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 {
<gl-toggle-vuex
class="d-block mt-1 js-toggle"
store-module="filters"
state-property="hide_dismissed"
state-property="hideDismissed"
set-action="setToggleValue"
/>
</div>
......
......@@ -27,7 +27,7 @@ export const lockFilter = ({ commit }, payload) => {
export const setHideDismissedToggleInitialState = ({ commit }) => {
const [urlParam] = getParameterValues('scope');
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 }) => {
......
......@@ -32,10 +32,10 @@ export const activeFilters = state => {
acc[filter.id] = [...Array.from(filter.selection)].filter(id => !isBaseFilterOption(id));
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
if (gon.features && gon.features.hideDismissedVulnerabilities) {
filters.scope = state.hide_dismissed ? 'dismissed' : 'all';
filters.scope = state.hideDismissed ? 'dismissed' : 'all';
}
return filters;
};
......
......@@ -19,7 +19,7 @@ export default {
return { ...filter, selection };
});
state.hide_dismissed = payload.scope !== 'all';
state.hideDismissed = payload.scope !== 'all';
},
[types.SET_FILTER](state, payload) {
const { filterId, optionId } = payload;
......
......@@ -34,5 +34,5 @@ export default () => ({
selection: new Set([BASE_FILTERS.project_id.id]),
},
],
hide_dismissed: true,
hideDismissed: true,
});
......@@ -149,14 +149,40 @@ export const receiveCreateIssueError = ({ commit }, { flashError }) => {
};
export const dismissVulnerability = (
{ dispatch, state },
{ dispatch, state, rootState },
{ vulnerability, flashError, comment },
) => {
const page = state.pageInfo && state.pageInfo.page ? state.pageInfo.page : 1;
const dismissedVulnerabilitiesHidden = Boolean(
rootState.filters && rootState.filters.hideDismissed,
);
dispatch('requestDismissVulnerability');
const toastMsg = sprintf(s__("Security Reports|Dismissed '%{vulnerabilityName}'"), {
vulnerabilityName: vulnerability.name,
});
const toastMsg = sprintf(
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
.post(vulnerability.create_vulnerability_feedback_dismissal_path, {
......@@ -175,7 +201,14 @@ export const dismissVulnerability = (
.then(({ data }) => {
dispatch('closeDismissalCommentBox');
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(() => {
dispatch('receiveDismissVulnerabilityError', { flashError });
......@@ -298,7 +331,7 @@ export const undoDismiss = ({ dispatch }, { vulnerability, flashError }) => {
dispatch('requestUndoDismiss');
axios
return axios
.delete(destroy_vulnerability_feedback_dismissal_path)
.then(() => {
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', () => {
`('$description', ({ getParameterValuesReturnValue, expected }) => {
getParameterValues.mockImplementation(() => getParameterValuesReturnValue);
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', () => {
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: [],
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'],
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'],
hideDismissedValue: true,
},
......@@ -101,7 +101,7 @@ describe('filters actions', () => {
{
type: types.SET_TOGGLE_VALUE,
payload: {
key: 'hide_dismissed',
key: 'hideDismissed',
value: testCase.hideDismissedValue,
},
},
......
......@@ -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', () => {
......
......@@ -14387,6 +14387,9 @@ msgstr ""
msgid "Security Reports|Dismissed '%{vulnerabilityName}'"
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."
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