Commit d1ec236d authored by Fernando Arias's avatar Fernando Arias Committed by Paul Slaughter

Add toast messages for vuln dismissals

* Add toast message for add/edit/delete dismissal reasons
parent f24ff741
import Vue from 'vue';
import { GlToast } from '@gitlab/ui';
Vue.use(GlToast);
export default function showGlobalToast(...args) {
return Vue.toasted.show(...args);
}
import $ from 'jquery';
import axios from '~/lib/utils/axios_utils';
import downloadPatchHelper from 'ee/vue_shared/security_reports/store/utils/download_patch_helper';
import * as types from './mutation_types';
import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
import { s__ } from '~/locale';
import { s__, sprintf } from '~/locale';
import createFlash from '~/flash';
import toast from '~/vue_shared/plugins/global_toast';
import * as types from './mutation_types';
/**
* A lot of this file has duplicate actions in
......@@ -153,6 +154,10 @@ export const dismissVulnerability = (
) => {
dispatch('requestDismissVulnerability');
const toastMsg = sprintf(s__("Security Reports|Dismissed '%{vulnerabilityName}'"), {
vulnerabilityName: vulnerability.name,
});
axios
.post(vulnerability.create_vulnerability_feedback_dismissal_path, {
vulnerability_feedback: {
......@@ -170,6 +175,7 @@ export const dismissVulnerability = (
.then(({ data }) => {
dispatch('closeDismissalCommentBox');
dispatch('receiveDismissVulnerabilitySuccess', { vulnerability, data });
toast(toastMsg);
})
.catch(() => {
dispatch('receiveDismissVulnerabilityError', { flashError });
......@@ -198,10 +204,20 @@ export const receiveDismissVulnerabilityError = ({ commit }, { flashError }) =>
export const addDismissalComment = ({ dispatch }, { vulnerability, comment }) => {
dispatch('requestAddDismissalComment');
const { dismissal_feedback } = vulnerability;
const url = `${vulnerability.create_vulnerability_feedback_dismissal_path}/${dismissal_feedback.id}`;
const editingDismissalContent =
dismissal_feedback.comment_details && dismissal_feedback.comment_details.comment;
const toastMsg = editingDismissalContent
? sprintf(s__("Security Reports|Comment edited on '%{vulnerabilityName}'"), {
vulnerabilityName: vulnerability.name,
})
: sprintf(s__("Security Reports|Comment added to '%{vulnerabilityName}'"), {
vulnerabilityName: vulnerability.name,
});
axios
.patch(url, {
project_id: dismissal_feedback.project_id,
......@@ -211,6 +227,7 @@ export const addDismissalComment = ({ dispatch }, { vulnerability, comment }) =>
.then(({ data }) => {
dispatch('closeDismissalCommentBox');
dispatch('receiveAddDismissalCommentSuccess', { vulnerability, data });
toast(toastMsg);
})
.catch(() => {
dispatch('receiveAddDismissalCommentError');
......@@ -222,6 +239,9 @@ export const deleteDismissalComment = ({ dispatch }, { vulnerability }) => {
const { dismissal_feedback } = vulnerability;
const url = `${vulnerability.create_vulnerability_feedback_dismissal_path}/${dismissal_feedback.id}`;
const toastMsg = sprintf(s__("Security Reports|Comment deleted on '%{vulnerabilityName}'"), {
vulnerabilityName: vulnerability.name,
});
axios
.patch(url, {
......@@ -232,6 +252,7 @@ export const deleteDismissalComment = ({ dispatch }, { vulnerability }) => {
const { id } = vulnerability;
dispatch('closeDismissalCommentBox');
dispatch('receiveDeleteDismissalCommentSuccess', { id, data });
toast(toastMsg);
})
.catch(() => {
dispatch('receiveDeleteDismissalCommentError');
......
import $ from 'jquery';
import axios from '~/lib/utils/axios_utils';
import { s__ } from '~/locale';
import { s__, sprintf } from '~/locale';
import { visitUrl } from '~/lib/utils/url_utility';
import toast from '~/vue_shared/plugins/global_toast';
import * as types from './mutation_types';
import downloadPatchHelper from './utils/download_patch_helper';
import { pollUntilComplete } from './utils';
......@@ -290,6 +291,10 @@ export const receiveDismissVulnerabilityError = ({ commit }, error) =>
export const dismissVulnerability = ({ state, dispatch }, comment) => {
dispatch('requestDismissVulnerability');
const toastMsg = sprintf(s__("Security Reports|Dismissed '%{vulnerabilityName}'"), {
vulnerabilityName: state.modal.vulnerability.name,
});
axios
.post(state.createVulnerabilityFeedbackDismissalPath, {
vulnerability_feedback: {
......@@ -310,8 +315,8 @@ export const dismissVulnerability = ({ state, dispatch }, comment) => {
dispatch('closeDismissalCommentBox');
dispatch('receiveDismissVulnerability', updatedIssue);
hideModal();
toast(toastMsg);
})
.catch(() => {
dispatch(
......@@ -328,6 +333,17 @@ export const addDismissalComment = ({ state, dispatch }, { comment }) => {
const { dismissalFeedback } = vulnerability;
const url = `${state.createVulnerabilityFeedbackDismissalPath}/${dismissalFeedback.id}`;
const editingDismissalContent =
dismissalFeedback.comment_details && dismissalFeedback.comment_details.comment;
const toastMsg = editingDismissalContent
? sprintf(s__("Security Reports|Comment edited on '%{vulnerabilityName}'"), {
vulnerabilityName: vulnerability.name,
})
: sprintf(s__("Security Reports|Comment added to '%{vulnerabilityName}'"), {
vulnerabilityName: vulnerability.name,
});
axios
.patch(url, {
project_id: dismissalFeedback.project_id,
......@@ -337,6 +353,7 @@ export const addDismissalComment = ({ state, dispatch }, { comment }) => {
.then(({ data }) => {
dispatch('closeDismissalCommentBox');
dispatch('receiveAddDismissalCommentSuccess', { data });
toast(toastMsg);
})
.catch(() => {
dispatch(
......@@ -352,6 +369,9 @@ export const deleteDismissalComment = ({ state, dispatch }) => {
const { vulnerability } = state.modal;
const { dismissalFeedback } = vulnerability;
const url = `${state.createVulnerabilityFeedbackDismissalPath}/${dismissalFeedback.id}`;
const toastMsg = sprintf(s__("Security Reports|Comment deleted on '%{vulnerabilityName}'"), {
vulnerabilityName: vulnerability.name,
});
axios
.patch(url, {
......@@ -361,6 +381,7 @@ export const deleteDismissalComment = ({ state, dispatch }) => {
.then(({ data }) => {
dispatch('closeDismissalCommentBox');
dispatch('receiveDeleteDismissalCommentSuccess', { data });
toast(toastMsg);
})
.catch(() => {
dispatch(
......
---
title: Add browser notications to add/edit/delete vulnability dismissal reasons
merge_request: 15015
author:
type: changed
import Vue from 'vue';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import testAction from 'spec/helpers/vuex_action_helper';
......@@ -709,6 +710,31 @@ describe('vulnerability dismissal', () => {
done,
);
});
it('should show the dismissal toast message', done => {
spyOn(Vue.toasted, 'show').and.callThrough();
const checkToastMessage = () => {
expect(Vue.toasted.show).toHaveBeenCalledTimes(1);
done();
};
testAction(
actions.dismissVulnerability,
{ vulnerability, comment },
{},
[],
[
{ type: 'requestDismissVulnerability' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDismissVulnerabilitySuccess',
payload: { data, vulnerability },
},
],
checkToastMessage,
);
});
});
describe('on error', () => {
......@@ -811,9 +837,35 @@ describe('add vulnerability dismissal comment', () => {
it('should dispatch the request and success actions', done => {
const checkPassedData = () => {
const { project_id, id } = vulnerability.dismissal_feedback;
const expected = { project_id, id, comment };
const expected = JSON.stringify({ project_id, id, comment });
expect(mock.history.patch[0].data).toBe(JSON.stringify(expected));
expect(mock.history.patch[0].data).toBe(expected);
done();
};
testAction(
actions.addDismissalComment,
{ vulnerability, comment },
{},
[],
[
{ type: 'requestAddDismissalComment' },
{ type: 'closeDismissalCommentBox' },
{ type: 'receiveAddDismissalCommentSuccess', payload: { data, vulnerability } },
],
checkPassedData,
);
});
it('should show the add dismissal toast message', done => {
spyOn(Vue.toasted, 'show').and.callThrough();
const checkPassedData = () => {
const { project_id, id } = vulnerability.dismissal_feedback;
const expected = JSON.stringify({ project_id, id, comment });
expect(mock.history.patch[0].data).toBe(expected);
expect(Vue.toasted.show).toHaveBeenCalledTimes(1);
done();
};
......@@ -912,9 +964,38 @@ describe('add vulnerability dismissal comment', () => {
it('should dispatch the request and success actions', done => {
const checkPassedData = () => {
const { project_id } = vulnerability.dismissal_feedback;
const expected = { project_id, comment };
const expected = JSON.stringify({ project_id, comment });
expect(mock.history.patch[0].data).toBe(expected);
done();
};
testAction(
actions.deleteDismissalComment,
{ vulnerability },
{},
[],
[
{ type: 'requestDeleteDismissalComment' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDeleteDismissalCommentSuccess',
payload: { data, id: vulnerability.id },
},
],
checkPassedData,
);
});
it('should show the delete dismissal comment toast message', done => {
spyOn(Vue.toasted, 'show').and.callThrough();
const checkPassedData = () => {
const { project_id } = vulnerability.dismissal_feedback;
const expected = JSON.stringify({ project_id, comment });
expect(mock.history.patch[0].data).toBe(JSON.stringify(expected));
expect(mock.history.patch[0].data).toBe(expected);
expect(Vue.toasted.show).toHaveBeenCalledTimes(1);
done();
};
......
import Vue from 'vue';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import actions, {
......@@ -987,6 +988,35 @@ describe('security reports actions', () => {
done,
);
});
it('show dismiss vulnerability toast message', done => {
spyOn(Vue.toasted, 'show');
const checkToastMessage = () => {
expect(Vue.toasted.show).toHaveBeenCalledTimes(1);
done();
};
testAction(
dismissVulnerability,
payload,
mockedState,
[],
[
{
type: 'requestDismissVulnerability',
},
{
type: 'closeDismissalCommentBox',
},
{
type: 'receiveDismissVulnerability',
payload,
},
],
checkToastMessage,
);
});
});
it('with error should dispatch `receiveDismissVulnerabilityError`', done => {
......@@ -1044,6 +1074,31 @@ describe('security reports actions', () => {
done,
);
});
it('should show added dismissal comment toast message', done => {
spyOn(Vue.toasted, 'show').and.callThrough();
const checkToastMessage = () => {
expect(Vue.toasted.show).toHaveBeenCalledTimes(1);
done();
};
testAction(
addDismissalComment,
{ comment },
{ modal: { vulnerability } },
[],
[
{ type: 'requestAddDismissalComment' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveAddDismissalCommentSuccess',
payload: { data },
},
],
checkToastMessage,
);
});
});
describe('on error', () => {
......@@ -1146,6 +1201,31 @@ describe('security reports actions', () => {
done,
);
});
it('should show deleted dismissal comment toast message', done => {
spyOn(Vue.toasted, 'show').and.callThrough();
const checkToastMessage = () => {
expect(Vue.toasted.show).toHaveBeenCalledTimes(1);
done();
};
testAction(
deleteDismissalComment,
{ comment },
{ modal: { vulnerability } },
[],
[
{ type: 'requestDeleteDismissalComment' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDeleteDismissalCommentSuccess',
payload: { data },
},
],
checkToastMessage,
);
});
});
describe('on error', () => {
......
......@@ -13494,12 +13494,24 @@ msgstr ""
msgid "Security Dashboard|Issue Created"
msgstr ""
msgid "Security Reports|Comment added to '%{vulnerabilityName}'"
msgstr ""
msgid "Security Reports|Comment deleted on '%{vulnerabilityName}'"
msgstr ""
msgid "Security Reports|Comment edited on '%{vulnerabilityName}'"
msgstr ""
msgid "Security Reports|Create issue"
msgstr ""
msgid "Security Reports|Dismiss vulnerability"
msgstr ""
msgid "Security Reports|Dismissed '%{vulnerabilityName}'"
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 ""
......
import toast from '~/vue_shared/plugins/global_toast';
import Vue from 'vue';
describe('Global toast', () => {
let spyFunc;
beforeEach(() => {
spyFunc = jest.spyOn(Vue.toasted, 'show').mockImplementation(() => {});
});
afterEach(() => {
spyFunc.mockRestore();
});
it('should pass all args to Vue toasted', () => {
const arg1 = 'TestMessage';
const arg2 = { className: 'foo' };
toast(arg1, arg2);
expect(Vue.toasted.show).toHaveBeenCalledTimes(1);
expect(Vue.toasted.show).toHaveBeenCalledWith(arg1, arg2);
});
});
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