Commit 17010a6e authored by Kushal Pandya's avatar Kushal Pandya

Merge branch 'edit-delete-vuln-dismissal-message' into 'master'

Edit delete vuln dismissal message

See merge request gitlab-org/gitlab-ee!14770
parents eebca4db f862daaf
......@@ -97,6 +97,7 @@ export default {
methods: {
...mapActions('vulnerabilities', [
'addDismissalComment',
'deleteDismissalComment',
'closeDismissalCommentBox',
'createIssue',
'createMergeRequest',
......@@ -108,6 +109,8 @@ export default {
'setVulnerabilitiesCountEndpoint',
'setVulnerabilitiesEndpoint',
'setVulnerabilitiesHistoryEndpoint',
'showDismissalDeleteButtons',
'hideDismissalDeleteButtons',
'undoDismiss',
'downloadPatch',
]),
......@@ -138,6 +141,10 @@ export default {
:can-create-merge-request="canCreateMergeRequest"
:can-dismiss-vulnerability="canDismissVulnerability"
@addDismissalComment="addDismissalComment({ vulnerability, comment: $event })"
@editVulnerabilityDismissalComment="openDismissalCommentBox()"
@showDismissalDeleteButtons="showDismissalDeleteButtons"
@hideDismissalDeleteButtons="hideDismissalDeleteButtons"
@deleteDismissalComment="deleteDismissalComment({ vulnerability })"
@closeDismissalCommentBox="closeDismissalCommentBox()"
@createMergeRequest="createMergeRequest({ vulnerability })"
@createNewIssue="createIssue({ vulnerability })"
......
......@@ -213,6 +213,27 @@ export const addDismissalComment = ({ dispatch }, { vulnerability, comment }) =>
});
};
export const deleteDismissalComment = ({ dispatch }, { vulnerability }) => {
dispatch('requestDeleteDismissalComment');
const { dismissal_feedback } = vulnerability;
const url = `${vulnerability.create_vulnerability_feedback_dismissal_path}/${dismissal_feedback.id}`;
axios
.patch(url, {
project_id: dismissal_feedback.project_id,
comment: '',
})
.then(({ data }) => {
const { id } = vulnerability;
dispatch('closeDismissalCommentBox');
dispatch('receiveDeleteDismissalCommentSuccess', { id, data });
})
.catch(() => {
dispatch('receiveDeleteDismissalCommentError');
});
};
export const requestAddDismissalComment = ({ commit }) => {
commit(types.REQUEST_ADD_DISMISSAL_COMMENT);
};
......@@ -226,6 +247,27 @@ export const receiveAddDismissalCommentError = ({ commit }) => {
commit(types.RECEIVE_ADD_DISMISSAL_COMMENT_ERROR);
};
export const requestDeleteDismissalComment = ({ commit }) => {
commit(types.REQUEST_DELETE_DISMISSAL_COMMENT);
};
export const receiveDeleteDismissalCommentSuccess = ({ commit }, payload) => {
commit(types.RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS, payload);
hideModal();
};
export const receiveDeleteDismissalCommentError = ({ commit }) => {
commit(types.RECEIVE_DELETE_DISMISSAL_COMMENT_ERROR);
};
export const showDismissalDeleteButtons = ({ commit }) => {
commit(types.SHOW_DISMISSAL_DELETE_BUTTONS);
};
export const hideDismissalDeleteButtons = ({ commit }) => {
commit(types.HIDE_DISMISSAL_DELETE_BUTTONS);
};
export const undoDismiss = ({ dispatch }, { vulnerability, flashError }) => {
const { destroy_vulnerability_feedback_dismissal_path } = vulnerability.dismissal_feedback;
......
......@@ -29,10 +29,17 @@ export const REQUEST_ADD_DISMISSAL_COMMENT = 'REQUEST_ADD_DISMISSAL_COMMENT';
export const RECEIVE_ADD_DISMISSAL_COMMENT_SUCCESS = 'RECEIVE_ADD_DISMISSAL_COMMENT_SUCCESS';
export const RECEIVE_ADD_DISMISSAL_COMMENT_ERROR = 'RECEIVE_ADD_DISMISSAL_COMMENT_ERROR';
export const REQUEST_DELETE_DISMISSAL_COMMENT = 'REQUEST_DELETE_DISMISSAL_COMMENT';
export const RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS = 'REQUEST_DELETE_DISMISSAL_COMMENT_SUCCESS';
export const RECEIVE_DELETE_DISMISSAL_COMMENT_ERROR = 'RECEIVE_DELETE_DISMISSAL_COMMENT_ERROR';
export const REQUEST_REVERT_DISMISSAL = 'REQUEST_REVERT_DISMISSAL';
export const RECEIVE_REVERT_DISMISSAL_SUCCESS = 'RECEIVE_REVERT_DISMISSAL_SUCCESS';
export const RECEIVE_REVERT_DISMISSAL_ERROR = 'RECEIVE_REVERT_DISMISSAL_ERROR';
export const SHOW_DISMISSAL_DELETE_BUTTONS = 'SHOW_DISMISSAL_DELETE_BUTTONS';
export const HIDE_DISMISSAL_DELETE_BUTTONS = 'HIDE_DISMISSAL_DELETE_BUTTONS';
export const REQUEST_CREATE_MERGE_REQUEST = 'REQUEST_CREATE_MERGE_REQUEST';
export const RECEIVE_CREATE_MERGE_REQUEST_SUCCESS = 'RECEIVE_CREATE_MERGE_REQUEST_SUCCESS';
export const RECEIVE_CREATE_MERGE_REQUEST_ERROR = 'RECEIVE_CREATE_MERGE_REQUEST_ERROR';
......
......@@ -186,19 +186,37 @@ export default {
},
[types.RECEIVE_ADD_DISMISSAL_COMMENT_SUCCESS](state, payload) {
const vulnerability = state.vulnerabilities.find(vuln => vuln.id === payload.id);
if (!vulnerability) {
return;
if (vulnerability) {
vulnerability.dismissal_feedback = payload.data;
state.isDismissingVulnerability = false;
Vue.set(state.modal, 'isDismissingVulnerability', false);
Vue.set(state.modal.vulnerability, 'isDismissed', true);
}
vulnerability.dismissal_feedback = payload.data;
state.isDismissingVulnerability = false;
Vue.set(state.modal, 'isDismissingVulnerability', false);
Vue.set(state.modal.vulnerability, 'isDismissed', true);
},
[types.RECEIVE_ADD_DISMISSAL_COMMENT_ERROR](state) {
state.isDismissingVulnerability = false;
Vue.set(state.modal, 'isDismissingVulnerability', false);
Vue.set(state.modal, 'error', s__('Security Reports|There was an error adding the comment.'));
},
[types.REQUEST_DELETE_DISMISSAL_COMMENT](state) {
state.isDismissingVulnerability = true;
Vue.set(state.modal, 'isDismissingVulnerability', true);
Vue.set(state.modal, 'error', null);
},
[types.RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS](state, payload) {
const vulnerability = state.vulnerabilities.find(vuln => vuln.id === payload.id);
if (vulnerability) {
vulnerability.dismissal_feedback = payload.data;
state.isDismissingVulnerability = false;
Vue.set(state.modal, 'isDismissingVulnerability', false);
Vue.set(state.modal.vulnerability, 'isDismissed', true);
}
},
[types.RECEIVE_DELETE_DISMISSAL_COMMENT_ERROR](state) {
state.isDismissingVulnerability = false;
Vue.set(state.modal, 'isDismissingVulnerability', false);
Vue.set(state.modal, 'error', s__('Security Reports|There was an error deleting the comment.'));
},
[types.REQUEST_REVERT_DISMISSAL](state) {
state.isDismissingVulnerability = true;
Vue.set(state.modal, 'isDismissingVulnerability', true);
......@@ -220,6 +238,12 @@ export default {
s__('Security Reports|There was an error reverting the dismissal.'),
);
},
[types.SHOW_DISMISSAL_DELETE_BUTTONS](state) {
Vue.set(state.modal, 'isShowingDeleteButtons', true);
},
[types.HIDE_DISMISSAL_DELETE_BUTTONS](state) {
Vue.set(state.modal, 'isShowingDeleteButtons', false);
},
[types.REQUEST_CREATE_MERGE_REQUEST](state) {
state.isCreatingMergeRequest = true;
Vue.set(state.modal, 'isCreatingMergeRequest', true);
......@@ -242,6 +266,8 @@ export default {
Vue.set(state.modal, 'isCommentingOnDismissal', true);
},
[types.CLOSE_DISMISSAL_COMMENT_BOX](state) {
Vue.set(state.modal, 'isShowingDeleteButtons', false);
Vue.set(state.modal, 'isCommentingOnDismissal', false);
Vue.set(state.modal, 'isShowingDeleteButtons', false);
},
};
......@@ -40,8 +40,8 @@ export default () => ({
isCreatingMergeRequest: false,
isDismissingVulnerability: false,
isCommentingOnDismissal: false,
isShowingDeleteButtons: false,
},
isCreatingIssue: false,
isCreatingMergeRequest: false,
isDismissingVulnerability: false,
});
......@@ -24,6 +24,11 @@ export default {
type: Boolean,
required: true,
},
disabled: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
buttonText() {
......@@ -48,7 +53,7 @@ export default {
<div class="btn-group" role="group">
<loading-button
:loading="isDismissing"
:disabled="isDismissing"
:disabled="isDismissing || disabled"
:label="buttonText"
container-class="js-dismiss-btn btn btn-close"
@click="handleDismissClick"
......@@ -57,6 +62,7 @@ export default {
v-if="!isDismissed"
v-gl-tooltip.hover
v-gl-tooltip.focus
:disabled="disabled"
:title="s__('vulnerability|Add comment & dismiss')"
variant="close"
class="js-dismiss-with-comment "
......
......@@ -21,6 +21,11 @@ export default {
required: false,
default: '',
},
dismissalComment: {
type: String,
required: false,
default: '',
},
errorMessage: {
type: String,
required: false,
......@@ -44,7 +49,8 @@ export default {
},
},
mounted() {
this.$emit('input', '');
this.$emit('input', this.dismissalComment);
this.$emit('clearError');
this.$refs.dismissalComment.$el.focus();
},
......
......@@ -21,6 +21,11 @@ export default {
required: false,
default: '',
},
dismissalComment: {
type: String,
required: false,
default: '',
},
errorMessage: {
type: String,
required: false,
......@@ -52,6 +57,7 @@ export default {
<dismissal-comment-box
v-if="isActive"
v-model="localComment"
:dismissal-comment="dismissalComment"
:error-message="errorMessage"
:placeholder="$options.PLACEHOLDER"
@submit="$emit('submit')"
......
......@@ -21,12 +21,21 @@ export default {
required: false,
default: false,
},
isEditingExistingFeedback: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
submitLabel() {
return this.isDismissed
? s__('vulnerability|Add comment')
: s__('vulnerability|Add comment & dismiss');
if (this.isEditingExistingFeedback) {
return s__('vulnerability|Save comment');
}
if (this.isDismissed) {
return s__('vulnerability|Add comment');
}
return s__('vulnerability|Add comment & dismiss');
},
},
methods: {
......@@ -35,7 +44,12 @@ export default {
this.$emit('addCommentAndDismiss');
},
addDismissalComment() {
Tracking.event(document.body.dataset.page, 'click_add_comment');
if (this.isEditingExistingFeedback) {
Tracking.event(document.body.dataset.page, 'click_edit_comment');
} else {
Tracking.event(document.body.dataset.page, 'click_add_comment');
}
this.$emit('addDismissalComment');
},
handleSubmit() {
......
......@@ -2,10 +2,14 @@
import _ from 'underscore';
import { __, sprintf } from '~/locale';
import EventItem from 'ee/vue_shared/security_reports/components/event_item.vue';
import { GlButton } from '@gitlab/ui';
import LoadingButton from '~/vue_shared/components/loading_button.vue';
export default {
components: {
EventItem,
GlButton,
LoadingButton,
},
props: {
feedback: {
......@@ -17,6 +21,26 @@ export default {
required: false,
default: () => ({}),
},
isCommentingOnDismissal: {
type: Boolean,
required: false,
default: false,
},
isShowingDeleteButtons: {
type: Boolean,
required: false,
default: false,
},
showDismissalCommentActions: {
type: Boolean,
required: false,
default: false,
},
isDismissingVulnerability: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
eventText() {
......@@ -49,6 +73,20 @@ export default {
commentDetails() {
return this.feedback.comment_details;
},
vulnDismissalActionButtons() {
return [
{
iconName: 'pencil',
emit: 'editVulnerabilityDismissalComment',
title: __('Edit Comment'),
},
{
iconName: 'remove',
emit: 'showDismissalDeleteButtons',
title: __('Delete Comment'),
},
];
},
},
};
</script>
......@@ -63,15 +101,36 @@ export default {
>
<div v-html="eventText"></div>
</event-item>
<template v-if="commentDetails">
<template v-if="commentDetails && !isCommentingOnDismissal">
<hr class="my-3" />
<event-item
:action-buttons="vulnDismissalActionButtons"
:author="commentDetails.comment_author"
:created-at="commentDetails.comment_timestamp"
:show-right-slot="isShowingDeleteButtons"
:show-action-buttons="showDismissalCommentActions"
icon-name="comment"
icon-style="ci-status-icon-pending"
@editVulnerabilityDismissalComment="$emit('editVulnerabilityDismissalComment')"
@showDismissalDeleteButtons="$emit('showDismissalDeleteButtons')"
@hideDismissalDeleteButtons="$emit('hideDismissalDeleteButtons')"
@deleteDismissalComment="$emit('deleteDismissalComment')"
>
{{ commentDetails.comment }}
<template v-slot:right-content>
<div class="d-flex flex-grow-1 align-self-start flex-row-reverse">
<loading-button
:label="__('Delete comment')"
container-class="btn btn-remove"
@click="$emit('deleteDismissalComment')"
/>
<gl-button class="mr-2" @click="$emit('hideDismissalDeleteButtons')">
{{ __('Cancel') }}
</gl-button>
</div>
</template>
</event-item>
</template>
</div>
......
<script>
import { GlTooltipDirective, GlButton } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
......@@ -7,6 +8,10 @@ export default {
components: {
Icon,
TimeAgoTooltip,
GlButton,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
author: {
......@@ -28,6 +33,21 @@ export default {
required: false,
default: 'ci-status-icon-success',
},
actionButtons: {
type: Array,
required: false,
default: () => [],
},
showRightSlot: {
type: Boolean,
required: false,
default: false,
},
showActionButtons: {
type: Boolean,
required: false,
default: true,
},
},
};
</script>
......@@ -58,5 +78,24 @@ export default {
</div>
<slot></slot>
</div>
<slot v-if="showRightSlot" name="right-content"></slot>
<div v-else class="d-flex flex-grow-1 align-self-start flex-row-reverse">
<div v-if="showActionButtons" class="action-buttons">
<gl-button
v-for="button in actionButtons"
:key="button.title"
ref="button"
v-gl-tooltip
class="px-1"
variant="transparent"
:title="button.title"
@click="$emit(button.emit)"
>
<icon :name="button.iconName" css-classes="link-highlight" />
</gl-button>
</div>
</div>
</div>
</template>
......@@ -115,6 +115,9 @@ export default {
(this.vulnerability.dismissal_feedback || this.vulnerability.dismissalFeedback)
);
},
isEditingExistingFeedback() {
return this.dismissalFeedback && this.modal.isCommentingOnDismissal;
},
valuedFields() {
const { data } = this.modal;
const result = {};
......@@ -225,10 +228,29 @@ export default {
<div v-if="dismissalFeedback || modal.isCommentingOnDismissal" class="card my-4">
<div class="card-body">
<dismissal-note :feedback="dismissalFeedbackObject" :project="project" />
<dismissal-note
:feedback="dismissalFeedbackObject"
:is-commenting-on-dismissal="modal.isCommentingOnDismissal"
:is-showing-delete-buttons="modal.isShowingDeleteButtons"
:project="project"
:show-dismissal-comment-actions="
!dismissalFeedback || !dismissalFeedback.comment_details || !isEditingExistingFeedback
"
@editVulnerabilityDismissalComment="$emit('editVulnerabilityDismissalComment')"
@showDismissalDeleteButtons="$emit('showDismissalDeleteButtons')"
@hideDismissalDeleteButtons="$emit('hideDismissalDeleteButtons')"
@deleteDismissalComment="$emit('deleteDismissalComment')"
/>
<dismissal-comment-box-toggle
v-if="!dismissalFeedback || !dismissalFeedback.comment_details"
v-if="
!dismissalFeedback || !dismissalFeedback.comment_details || isEditingExistingFeedback
"
v-model="localDismissalComment"
:dismissal-comment="
dismissalFeedback &&
dismissalFeedback.comment_details &&
dismissalFeedback.comment_details.comment
"
:is-active="modal.isCommentingOnDismissal"
:error-message="dismissalCommentErrorMessage"
@openDismissalCommentBox="$emit('openDismissalCommentBox')"
......@@ -244,6 +266,7 @@ export default {
<dismissal-comment-modal-footer
v-if="modal.isCommentingOnDismissal"
:is-dismissed="vulnerability.isDismissed"
:is-editing-existing-feedback="isEditingExistingFeedback"
@addCommentAndDismiss="addCommentAndDismiss"
@addDismissalComment="addDismissalComment"
@cancel="$emit('closeDismissalCommentBox')"
......@@ -252,6 +275,7 @@ export default {
v-else-if="shouldRenderFooterSection"
:modal="modal"
:vulnerability="vulnerability"
:disabled="modal.isShowingDeleteButtons"
:can-create-issue="Boolean(!vulnerability.hasIssue && canCreateIssue)"
:can-create-merge-request="Boolean(!vulnerability.hasMergeRequest && remediation)"
:can-download-patch="canDownloadPatch"
......
......@@ -43,6 +43,11 @@ export default {
required: false,
default: false,
},
disabled: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
actionButtons() {
......@@ -85,7 +90,7 @@ export default {
<template>
<div>
<gl-button data-dismiss="modal">
<gl-button data-dismiss="modal" :disabled="disabled">
{{ __('Cancel') }}
</gl-button>
......@@ -93,6 +98,7 @@ export default {
v-if="canDismissVulnerability"
:is-dismissing="modal.isDismissingVulnerability"
:is-dismissed="isDismissed"
:disabled="disabled"
@dismissVulnerability="$emit('dismissVulnerability')"
@openDismissalCommentBox="$emit('openDismissalCommentBox')"
@revertDismissVulnerability="$emit('revertDismissVulnerability')"
......@@ -103,6 +109,7 @@ export default {
:buttons="actionButtons"
class="js-split-button"
data-qa-selector="resolve_split_button"
:disabled="disabled"
@createMergeRequest="$emit('createMergeRequest')"
@createNewIssue="$emit('createNewIssue')"
@downloadPatch="$emit('downloadPatch')"
......@@ -111,7 +118,7 @@ export default {
<loading-button
v-else-if="actionButtons.length > 0"
:loading="actionButtons[0].isLoading"
:disabled="actionButtons[0].isLoading"
:disabled="actionButtons[0].isLoading || disabled"
:label="actionButtons[0].name"
container-class="btn btn-success btn-inverted"
class="js-action-button"
......
......@@ -13,6 +13,11 @@ export default {
type: Array,
required: true,
},
disabled: {
type: Boolean,
required: false,
default: false,
},
},
data: () => ({
selectedButton: {},
......@@ -34,6 +39,7 @@ export default {
<template>
<gl-dropdown
v-if="selectedButton"
:disabled="disabled"
no-caret
right
split
......
......@@ -254,6 +254,9 @@ export default {
'closeDismissalCommentBox',
'downloadPatch',
'addDismissalComment',
'deleteDismissalComment',
'showDismissalDeleteButtons',
'hideDismissalDeleteButtons',
]),
...mapActions('sast', {
setSastHeadPath: 'setHeadPath',
......@@ -364,9 +367,13 @@ export default {
@createNewIssue="createNewIssue"
@dismissVulnerability="dismissVulnerability"
@openDismissalCommentBox="openDismissalCommentBox()"
@editVulnerabilityDismissalComment="openDismissalCommentBox()"
@revertDismissVulnerability="revertDismissVulnerability"
@downloadPatch="downloadPatch"
@addDismissalComment="addDismissalComment({ comment: $event })"
@deleteDismissalComment="deleteDismissalComment"
@showDismissalDeleteButtons="showDismissalDeleteButtons"
@hideDismissalDeleteButtons="hideDismissalDeleteButtons"
/>
</div>
</report-section>
......
......@@ -236,6 +236,9 @@ export default {
'closeDismissalCommentBox',
'downloadPatch',
'addDismissalComment',
'deleteDismissalComment',
'showDismissalDeleteButtons',
'hideDismissalDeleteButtons',
]),
...mapActions('sast', {
setSastHeadPath: 'setHeadPath',
......@@ -331,6 +334,10 @@ export default {
@revertDismissVulnerability="revertDismissVulnerability"
@downloadPatch="downloadPatch"
@addDismissalComment="addDismissalComment({ comment: $event })"
@editVulnerabilityDismissalComment="openDismissalCommentBox()"
@deleteDismissalComment="deleteDismissalComment"
@showDismissalDeleteButtons="showDismissalDeleteButtons"
@hideDismissalDeleteButtons="hideDismissalDeleteButtons"
/>
</div>
</template>
......@@ -254,6 +254,43 @@ export const addDismissalComment = ({ state, dispatch }, { comment }) => {
});
};
export const deleteDismissalComment = ({ state, dispatch }) => {
dispatch('requestDeleteDismissalComment');
const { vulnerability } = state.modal;
const { dismissalFeedback } = vulnerability;
const url = `${state.createVulnerabilityFeedbackDismissalPath}/${dismissalFeedback.id}`;
axios
.patch(url, {
project_id: dismissalFeedback.project_id,
comment: '',
})
.then(({ data }) => {
dispatch('closeDismissalCommentBox');
dispatch('receiveDeleteDismissalCommentSuccess', { data });
})
.catch(() => {
dispatch(
'receiveDeleteDismissalCommentError',
s__('Security Reports|There was an error deleting the comment.'),
);
});
};
export const requestDeleteDismissalComment = ({ commit }) => {
commit(types.REQUEST_DELETE_DISMISSAL_COMMENT);
};
export const receiveDeleteDismissalCommentSuccess = ({ commit }, payload) => {
commit(types.RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS, payload);
hideModal();
};
export const receiveDeleteDismissalCommentError = ({ commit }, error) => {
commit(types.RECEIVE_DELETE_DISMISSAL_COMMENT_ERROR, error);
};
export const requestAddDismissalComment = ({ commit }) => {
commit(types.REQUEST_ADD_DISMISSAL_COMMENT);
};
......@@ -293,6 +330,14 @@ export const revertDismissVulnerability = ({ state, dispatch }) => {
);
};
export const showDismissalDeleteButtons = ({ commit }) => {
commit(types.SHOW_DISMISSAL_DELETE_BUTTONS);
};
export const hideDismissalDeleteButtons = ({ commit }) => {
commit(types.HIDE_DISMISSAL_DELETE_BUTTONS);
};
export const requestCreateIssue = ({ commit }) => commit(types.REQUEST_CREATE_ISSUE);
export const receiveCreateIssue = ({ commit }) => commit(types.RECEIVE_CREATE_ISSUE_SUCCESS);
export const receiveCreateIssueError = ({ commit }, error) =>
......
......@@ -43,6 +43,10 @@ export const REQUEST_ADD_DISMISSAL_COMMENT = 'REQUEST_ADD_DISMISSAL_COMMENT';
export const RECEIVE_ADD_DISMISSAL_COMMENT_SUCCESS = 'RECEIVE_ADD_DISMISSAL_COMMENT_SUCCESS';
export const RECEIVE_ADD_DISMISSAL_COMMENT_ERROR = 'RECEIVE_ADD_DISMISSAL_COMMENT_ERROR';
export const REQUEST_DELETE_DISMISSAL_COMMENT = 'REQUEST_DELETE_DISMISSAL_COMMENT';
export const RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS = 'REQUEST_DELETE_DISMISSAL_COMMENT_SUCCESS';
export const RECEIVE_DELETE_DISMISSAL_COMMENT_ERROR = 'RECEIVE_DELETE_DISMISSAL_COMMENT_ERROR';
export const REQUEST_CREATE_ISSUE = 'CREATE_DISMISS_VULNERABILITY';
export const RECEIVE_CREATE_ISSUE_SUCCESS = 'CREATE_DISMISS_VULNERABILITY_SUCCESS';
export const RECEIVE_CREATE_ISSUE_ERROR = 'CREATE_DISMISS_VULNERABILITY_ERROR';
......@@ -51,6 +55,9 @@ export const REQUEST_CREATE_MERGE_REQUEST = 'REQUEST_CREATE_MERGE_REQUEST';
export const RECEIVE_CREATE_MERGE_REQUEST_SUCCESS = 'RECEIVE_CREATE_MERGE_REQUEST_SUCCESS';
export const RECEIVE_CREATE_MERGE_REQUEST_ERROR = 'RECEIVE_CREATE_MERGE_REQUEST_ERROR';
export const SHOW_DISMISSAL_DELETE_BUTTONS = 'SHOW_DISMISSAL_DELETE_BUTTONS';
export const HIDE_DISMISSAL_DELETE_BUTTONS = 'HIDE_DISMISSAL_DELETE_BUTTONS';
export const UPDATE_DEPENDENCY_SCANNING_ISSUE = 'UPDATE_DEPENDENCY_SCANNING_ISSUE';
export const UPDATE_CONTAINER_SCANNING_ISSUE = 'UPDATE_CONTAINER_SCANNING_ISSUE';
export const UPDATE_DAST_ISSUE = 'UPDATE_DAST_ISSUE';
......
......@@ -282,7 +282,28 @@ export default {
Vue.set(state.modal, 'isDismissingVulnerability', false);
Vue.set(state.modal, 'error', error);
},
[types.REQUEST_DELETE_DISMISSAL_COMMENT](state) {
state.isDismissingVulnerability = true;
Vue.set(state.modal, 'isDismissingVulnerability', true);
Vue.set(state.modal, 'error', null);
},
[types.RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS](state, payload) {
state.isDismissingVulnerability = false;
Vue.set(state.modal, 'isDismissingVulnerability', false);
Vue.set(state.modal.vulnerability, 'isDismissed', true);
Vue.set(state.modal.vulnerability, 'dismissalFeedback', payload.data);
},
[types.RECEIVE_DELETE_DISMISSAL_COMMENT_ERROR](state, error) {
state.isDismissingVulnerability = false;
Vue.set(state.modal, 'isDismissingVulnerability', false);
Vue.set(state.modal, 'error', error);
},
[types.SHOW_DISMISSAL_DELETE_BUTTONS](state) {
Vue.set(state.modal, 'isShowingDeleteButtons', true);
},
[types.HIDE_DISMISSAL_DELETE_BUTTONS](state) {
Vue.set(state.modal, 'isShowingDeleteButtons', false);
},
[types.UPDATE_DEPENDENCY_SCANNING_ISSUE](state, issue) {
// Find issue in the correct list and update it
......@@ -367,6 +388,7 @@ export default {
Vue.set(state.modal, 'isCommentingOnDismissal', true);
},
[types.CLOSE_DISMISSAL_COMMENT_BOX](state) {
Vue.set(state.modal, 'isShowingDeleteButtons', false);
Vue.set(state.modal, 'isCommentingOnDismissal', false);
},
};
......@@ -127,7 +127,8 @@ export default () => ({
isCreatingNewIssue: false,
isDismissingVulnerability: false,
isShowingDeleteButtons: false,
isCommentingOnDismissal: false,
error: null,
},
});
---
title: Edit delete vuln dismissal message
merge_request: 14770
author:
type: added
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Event Item with action buttons renders the action buttons 1`] = `
VueWrapper {
"_emitted": Object {
"hook:mounted": Array [
Array [],
],
},
"_emittedByOrder": Array [
Object {
"args": Array [],
"name": "hook:mounted",
},
],
"isFunctionalComponent": undefined,
}
`;
......@@ -46,22 +46,45 @@ describe('DismissalCommentModalFooter', () => {
});
describe('with an already dismissed vulnerability', () => {
beforeEach(() => {
const propsData = {
isDismissed: true,
};
wrapper = mount(component, { propsData });
});
describe('and adding a comment', () => {
beforeEach(() => {
const propsData = {
isDismissed: true,
};
wrapper = mount(component, { propsData });
});
it('should render the "Add comment and dismiss" button', () => {
expect(wrapper.find(LoadingButton).text()).toBe('Add comment');
it('should render the "Add comment and dismiss" button', () => {
expect(wrapper.find(LoadingButton).text()).toBe('Add comment');
});
it('should emit the "addCommentAndDismiss" event when clicked', () => {
wrapper.find(LoadingButton).trigger('click');
expect(wrapper.emitted().addDismissalComment).toBeTruthy();
expect(Tracking.event).toHaveBeenCalledWith('_track_category_', 'click_add_comment');
});
});
it('should emit the "addCommentAndDismiss" event when clicked', () => {
wrapper.find(LoadingButton).trigger('click');
describe('and editing a comment', () => {
beforeEach(() => {
const propsData = {
isDismissed: true,
isEditingExistingFeedback: true,
};
wrapper = mount(component, { propsData });
});
it('should render the "Save comment" button', () => {
expect(wrapper.find(LoadingButton).text()).toBe('Save comment');
});
it('should emit the "addCommentAndDismiss" event when clicked', () => {
wrapper.find(LoadingButton).trigger('click');
expect(wrapper.emitted().addDismissalComment).toBeTruthy();
expect(Tracking.event).toHaveBeenCalledWith('_track_category_', 'click_add_comment');
expect(wrapper.emitted().addDismissalComment).toBeTruthy();
expect(Tracking.event).toHaveBeenCalledWith('_track_category_', 'click_edit_comment');
});
});
});
});
import { shallowMount } from '@vue/test-utils';
import { shallowMount, mount } from '@vue/test-utils';
import component from 'ee/vue_shared/security_reports/components/dismissal_note.vue';
import EventItem from 'ee/vue_shared/security_reports/components/event_item.vue';
......@@ -114,29 +114,53 @@ describe('dismissal note', () => {
};
let commentItem;
beforeEach(() => {
wrapper = shallowMount(component, {
propsData: {
feedback: {
...feedback,
comment_details: commentDetails,
describe('without confirm deletion buttons', () => {
beforeEach(() => {
wrapper = shallowMount(component, {
propsData: {
feedback: {
...feedback,
comment_details: commentDetails,
},
project,
},
project,
},
});
commentItem = wrapper.findAll(EventItem).at(1);
});
commentItem = wrapper.findAll(EventItem).at(1);
});
it('should render the comment', () => {
expect(commentItem.text()).toBe(commentDetails.comment);
});
it('should render the comment', () => {
expect(commentItem.text()).toBe(commentDetails.comment);
});
it('should render the comment author', () => {
expect(commentItem.props().author).toBe(commentDetails.comment_author);
it('should render the comment author', () => {
expect(commentItem.props().author).toBe(commentDetails.comment_author);
});
it('should render the comment timestamp', () => {
expect(commentItem.props().createdAt).toBe(commentDetails.comment_timestamp);
});
});
it('should render the comment timestamp', () => {
expect(commentItem.props().createdAt).toBe(commentDetails.comment_timestamp);
describe('with confirm deletion buttons', () => {
beforeEach(() => {
wrapper = mount(component, {
propsData: {
feedback: {
...feedback,
comment_details: commentDetails,
},
project,
isShowingDeleteButtons: true,
},
});
commentItem = wrapper.findAll(EventItem).at(1);
});
it('should render deletion buttons slot', () => {
const buttons = commentItem.findAll('button');
expect(buttons.at(1).text()).toEqual('Cancel');
expect(buttons.at(0).text()).toEqual('Delete comment');
});
});
});
});
import Vue from 'vue';
import component from 'ee/vue_shared/security_reports/components/event_item.vue';
import mountComponent from 'helpers/vue_mount_component_helper';
import Component from 'ee/vue_shared/security_reports/components/event_item.vue';
import { shallowMount, mount } from '@vue/test-utils';
describe('Event Item', () => {
const Component = Vue.extend(component);
const props = {
author: {
name: 'Tanuki',
username: 'gitlab',
},
};
let vm;
afterEach(() => {
vm.$destroy();
});
describe('initial state', () => {
let wrapper;
beforeEach(() => {
vm = mountComponent(Component, props);
});
const propsData = {
author: {
name: 'Tanuki',
username: 'gitlab',
},
};
it('uses the author name', () => {
expect(vm.$el.querySelector('.js-author').textContent).toContain(props.author.name);
});
afterEach(() => {
wrapper.destroy();
});
it('uses the author username', () => {
expect(vm.$el.querySelector('.js-author').textContent).toContain(`@${props.author.username}`);
});
beforeEach(() => {
wrapper = shallowMount(Component, { propsData });
});
it('uses the author name', () => {
expect(wrapper.find('.js-author').text()).toContain(propsData.author.name);
});
it('uses the author username', () => {
expect(wrapper.find('.js-author').text()).toContain(`@${propsData.author.username}`);
});
it('uses the fallback icon', () => {
expect(wrapper.props().iconName).toBe('plus');
});
it('uses the fallback icon', () => {
expect(vm.iconName).toBe('plus');
it('uses the fallback icon class', () => {
expect(wrapper.props().iconStyle).toBe('ci-status-icon-success');
});
it('renders the action buttons tontainer', () => {
expect(wrapper.find('.action-buttons')).toExist();
});
});
describe('with action buttons', () => {
let wrapper;
const propsData = {
author: {
name: 'Tanuki',
username: 'gitlab',
},
actionButtons: [
{
iconName: 'pencil',
emit: 'fooEvent',
title: 'Foo Action',
},
{
iconName: 'remove',
emit: 'barEvent',
title: 'Bar Action',
},
],
};
afterEach(() => {
wrapper.destroy();
});
beforeEach(() => {
wrapper = mount(Component, { propsData });
});
it('renders the action buttons container', () => {
expect(wrapper.find('.action-buttons')).toExist();
});
it('renders the action buttons', () => {
expect(wrapper.findAll('.action-buttons > button').length).toBe(2);
expect(wrapper).toMatchSnapshot();
});
it('emits the button events when clicked', () => {
const buttons = wrapper.findAll('.action-buttons > button');
buttons.at(0).trigger('click');
buttons.at(1).trigger('click');
it('uses the fallback icon class', () => {
expect(vm.iconStyle).toBe('ci-status-icon-success');
expect(wrapper.emitted().fooEvent.length).toEqual(1);
expect(wrapper.emitted().barEvent.length).toEqual(1);
});
});
});
......@@ -525,6 +525,113 @@ describe('security reports mutations', () => {
});
});
describe(types.REQUEST_DELETE_DISMISSAL_COMMENT, () => {
beforeEach(() => {
mutations[types.REQUEST_DELETE_DISMISSAL_COMMENT](stateCopy);
});
it('should set isDismissingVulnerability to true', () => {
expect(stateCopy.isDismissingVulnerability).toBe(true);
});
it('should set isDismissingVulnerability in the modal data to true', () => {
expect(stateCopy.modal.isDismissingVulnerability).toBe(true);
});
it('should nullify the error state on the modal', () => {
expect(stateCopy.modal.error).toBeNull();
});
});
describe(types.RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS, () => {
let payload;
let vulnerability;
let data;
beforeEach(() => {
vulnerability = { id: 1 };
data = { name: 'dismissal feedback' };
payload = { id: vulnerability.id, data };
mutations[types.RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS](stateCopy, payload);
});
it('should set isDismissingVulnerability to false', () => {
expect(stateCopy.isDismissingVulnerability).toBe(false);
});
it('should set isDismissingVulnerability on the modal to false', () => {
expect(stateCopy.modal.isDismissingVulnerability).toBe(false);
});
it('shoulfd set isDissmissed on the modal vulnerability to be true', () => {
expect(stateCopy.modal.vulnerability.isDismissed).toBe(true);
});
});
describe(types.RECEIVE_DELETE_DISMISSAL_COMMENT_ERROR, () => {
const error = 'There was an error deleting the comment.';
beforeEach(() => {
mutations[types.RECEIVE_DELETE_DISMISSAL_COMMENT_ERROR](stateCopy, error);
});
it('should set isDismissingVulnerability to false', () => {
expect(stateCopy.isDismissingVulnerability).toBe(false);
});
it('should set isDismissingVulnerability in the modal data to false', () => {
expect(stateCopy.modal.isDismissingVulnerability).toBe(false);
});
it('should set the error state on the modal', () => {
expect(stateCopy.modal.error).toEqual(error);
});
});
describe(types.SHOW_DISMISSAL_DELETE_BUTTONS, () => {
beforeEach(() => {
mutations[types.SHOW_DISMISSAL_DELETE_BUTTONS](stateCopy);
});
it('should set isShowingDeleteButtonsto to true', () => {
expect(stateCopy.modal.isShowingDeleteButtons).toBe(true);
});
});
describe(types.HIDE_DISMISSAL_DELETE_BUTTONS, () => {
beforeEach(() => {
mutations[types.HIDE_DISMISSAL_DELETE_BUTTONS](stateCopy);
});
it('should set isShowingDeleteButtons to false', () => {
expect(stateCopy.modal.isShowingDeleteButtons).toBe(false);
});
});
describe('OPEN_DISMISSAL_COMMENT_BOX', () => {
beforeEach(() => {
mutations[types.OPEN_DISMISSAL_COMMENT_BOX](stateCopy);
});
it('should set isCommentingOnDismissal to true', () => {
expect(stateCopy.modal.isCommentingOnDismissal).toBe(true);
});
});
describe('CLOSE_DISMISSAL_COMMENT_BOX', () => {
beforeEach(() => {
mutations[types.CLOSE_DISMISSAL_COMMENT_BOX](stateCopy);
});
it('should set isCommentingOnDismissal to false', () => {
expect(stateCopy.modal.isCommentingOnDismissal).toBe(false);
});
it('should set isShowingDeleteButtons to false', () => {
expect(stateCopy.modal.isShowingDeleteButtons).toBe(false);
});
});
describe('REQUEST_CREATE_ISSUE', () => {
it('sets isCreatingNewIssue prop to true and resets error', () => {
mutations[types.REQUEST_CREATE_ISSUE](stateCopy);
......
......@@ -847,6 +847,157 @@ describe('add vulnerability dismissal comment', () => {
});
});
});
describe('deleteDismissalComment', () => {
const vulnerability = mockDataVulnerabilities[2];
const data = { vulnerability };
const url = `${vulnerability.create_vulnerability_feedback_dismissal_path}/${vulnerability.dismissal_feedback.id}`;
const comment = '';
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock.onPatch(url).replyOnce(200, data);
});
it('should dispatch the request and success actions', done => {
const checkPassedData = () => {
const { project_id } = vulnerability.dismissal_feedback;
const expected = { project_id, comment };
expect(mock.history.patch[0].data).toBe(JSON.stringify(expected));
done();
};
testAction(
actions.deleteDismissalComment,
{ vulnerability },
{},
[],
[
{ type: 'requestDeleteDismissalComment' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDeleteDismissalCommentSuccess',
payload: { data, id: vulnerability.id },
},
],
checkPassedData,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onPatch(url).replyOnce(404);
});
it('should dispatch the request and error actions', done => {
testAction(
actions.deleteDismissalComment,
{ vulnerability },
{},
[],
[
{ type: 'requestDeleteDismissalComment' },
{ type: 'receiveDeleteDismissalCommentError' },
],
done,
);
});
});
describe('receiveDeleteDismissalCommentSuccess', () => {
it('should commit the success mutation', done => {
const state = initialState;
testAction(
actions.receiveDeleteDismissalCommentSuccess,
{ data },
state,
[{ type: types.RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS, payload: { data } }],
[],
done,
);
});
});
describe('receiveDeleteDismissalCommentError', () => {
it('should commit the error mutation', done => {
const state = initialState;
testAction(
actions.receiveDeleteDismissalCommentError,
{},
state,
[{ type: types.RECEIVE_DELETE_DISMISSAL_COMMENT_ERROR }],
[],
done,
);
});
});
describe('requestDeleteDismissalComment', () => {
it('should commit the request mutation', done => {
const state = initialState;
testAction(
actions.requestDeleteDismissalComment,
{},
state,
[{ type: types.REQUEST_DELETE_DISMISSAL_COMMENT }],
[],
done,
);
});
});
});
});
describe('showDismissalDeleteButtons', () => {
it('commits show dismissal delete buttons', done => {
const state = initialState;
testAction(
actions.showDismissalDeleteButtons,
null,
state,
[
{
type: types.SHOW_DISMISSAL_DELETE_BUTTONS,
},
],
[],
done,
);
});
});
describe('hideDismissalDeleteButtons', () => {
it('commits hide dismissal delete buttons', done => {
const state = initialState;
testAction(
actions.hideDismissalDeleteButtons,
null,
state,
[
{
type: types.HIDE_DISMISSAL_DELETE_BUTTONS,
},
],
[],
done,
);
});
});
describe('revert vulnerability dismissal', () => {
......@@ -1128,12 +1279,12 @@ describe('vulnerabilities history actions', () => {
});
describe('openDismissalCommentBox', () => {
it('should commit the open comment mutation', done => {
it('should commit the open comment mutation with a default payload', done => {
const state = initialState();
testAction(
actions.openDismissalCommentBox,
{},
undefined,
state,
[{ type: types.OPEN_DISMISSAL_COMMENT_BOX }],
[],
......
......@@ -542,7 +542,107 @@ describe('vulnerabilities module mutations', () => {
});
});
describe('REQUEST_DISMISSAL_COMMENT', () => {
describe('REQUEST_DELETE_DISMISSAL_COMMENT', () => {
let state;
beforeEach(() => {
state = createState();
mutations[types.REQUEST_DELETE_DISMISSAL_COMMENT](state);
});
it('should set isDismissingVulnerability to true', () => {
expect(state.isDismissingVulnerability).toBe(true);
});
it('should set isDismissingVulnerability in the modal data to true', () => {
expect(state.modal.isDismissingVulnerability).toBe(true);
});
it('should nullify the error state on the modal', () => {
expect(state.modal.error).toBeNull();
});
});
describe('RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS', () => {
let state;
let payload;
let vulnerability;
let data;
beforeEach(() => {
state = createState();
state.vulnerabilities = mockData;
[vulnerability] = mockData;
data = { name: '' };
payload = { id: vulnerability.id, data };
mutations[types.RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS](state, payload);
});
it('should set the dismissal feedback on the passed vulnerability to an empty string', () => {
expect(state.vulnerabilities[0].dismissal_feedback).toEqual({ name: '' });
});
it('should set isDismissingVulnerability to false', () => {
expect(state.isDismissingVulnerability).toBe(false);
});
it('should set isDismissingVulnerability on the modal to false', () => {
expect(state.modal.isDismissingVulnerability).toBe(false);
});
it('should set isDissmissed on the modal vulnerability to be true', () => {
expect(state.modal.vulnerability.isDismissed).toBe(true);
});
});
describe('RECEIVE_DELETE_DISMISSAL_COMMENT_ERROR', () => {
let state;
beforeEach(() => {
state = createState();
mutations[types.RECEIVE_DELETE_DISMISSAL_COMMENT_ERROR](state);
});
it('should set isDismissingVulnerability to false', () => {
expect(state.isDismissingVulnerability).toBe(false);
});
it('should set isDismissingVulnerability in the modal data to false', () => {
expect(state.modal.isDismissingVulnerability).toBe(false);
});
it('should set the error state on the modal', () => {
expect(state.modal.error).toEqual('There was an error deleting the comment.');
});
});
describe(types.SHOW_DISMISSAL_DELETE_BUTTONS, () => {
let state;
beforeEach(() => {
state = createState();
mutations[types.SHOW_DISMISSAL_DELETE_BUTTONS](state);
});
it('should set isShowingDeleteButtonsto to true', () => {
expect(state.modal.isShowingDeleteButtons).toBe(true);
});
});
describe(types.HIDE_DISMISSAL_DELETE_BUTTONS, () => {
let state;
beforeEach(() => {
state = createState();
mutations[types.HIDE_DISMISSAL_DELETE_BUTTONS](state);
});
it('should set isShowingDeleteButtons to false', () => {
expect(state.modal.isShowingDeleteButtons).toBe(false);
});
});
describe('REQUEST_ADD_DISMISSAL_COMMENT', () => {
let state;
beforeEach(() => {
......@@ -563,7 +663,7 @@ describe('vulnerabilities module mutations', () => {
});
});
describe('RECEIVE_DISMISSAL_COMMENT_SUCCESS', () => {
describe('RECEIVE_ADD_DISMISSAL_COMMENT_SUCCESS', () => {
let state;
let payload;
let vulnerability;
......@@ -595,7 +695,7 @@ describe('vulnerabilities module mutations', () => {
});
});
describe('RECEIVE_DISMISSAL_COMMENT_ERROR', () => {
describe('RECEIVE_ADD_DISMISSAL_COMMENT_ERROR', () => {
let state;
beforeEach(() => {
......@@ -689,20 +789,32 @@ describe('vulnerabilities module mutations', () => {
});
describe('OPEN_DISMISSAL_COMMENT_BOX', () => {
it('should set isCommentingOnDismissal to true', () => {
const state = createState();
let state;
beforeEach(() => {
state = createState();
mutations[types.OPEN_DISMISSAL_COMMENT_BOX](state);
});
it('should set isCommentingOnDismissal to true', () => {
expect(state.modal.isCommentingOnDismissal).toBe(true);
});
});
describe('CLOSE_DISMISSAL_COMMENT_BOX', () => {
it('should set isCommentingOnDismissal to false', () => {
const state = createState();
let state;
beforeEach(() => {
state = createState();
mutations[types.CLOSE_DISMISSAL_COMMENT_BOX](state);
});
it('should set isCommentingOnDismissal to false', () => {
expect(state.modal.isCommentingOnDismissal).toBe(false);
});
it('should set isShowingDeleteButtons to false', () => {
expect(state.modal.isShowingDeleteButtons).toBe(false);
});
});
});
......@@ -49,6 +49,12 @@ import actions, {
receiveAddDismissalCommentError,
receiveAddDismissalCommentSuccess,
requestAddDismissalComment,
deleteDismissalComment,
receiveDeleteDismissalCommentError,
receiveDeleteDismissalCommentSuccess,
requestDeleteDismissalComment,
showDismissalDeleteButtons,
hideDismissalDeleteButtons,
} from 'ee/vue_shared/security_reports/store/actions';
import * as types from 'ee/vue_shared/security_reports/store/mutation_types';
import state from 'ee/vue_shared/security_reports/store/state';
......@@ -1095,6 +1101,142 @@ describe('security reports actions', () => {
});
});
describe('deleteDismissalComment', () => {
const vulnerability = {
id: 0,
vulnerability_feedback_dismissal_path: 'foo',
dismissalFeedback: { id: 1 },
};
const data = { vulnerability };
const url = `${state.createVulnerabilityFeedbackDismissalPath}/${vulnerability.dismissalFeedback.id}`;
const comment = '';
describe('on success', () => {
beforeEach(() => {
mock.onPatch(url).replyOnce(200, data);
});
it('should dispatch the request and success actions', done => {
testAction(
deleteDismissalComment,
{ comment },
{ modal: { vulnerability } },
[],
[
{ type: 'requestDeleteDismissalComment' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDeleteDismissalCommentSuccess',
payload: { data },
},
],
done,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onPatch(url).replyOnce(404);
});
it('should dispatch the request and error actions', done => {
testAction(
deleteDismissalComment,
{ comment },
{ modal: { vulnerability } },
[],
[
{ type: 'requestDeleteDismissalComment' },
{
type: 'receiveDeleteDismissalCommentError',
payload: 'There was an error deleting the comment.',
},
],
done,
);
});
});
describe('receiveDeleteDismissalCommentSuccess', () => {
it('should commit the success mutation', done => {
testAction(
receiveDeleteDismissalCommentSuccess,
{ data },
state,
[{ type: types.RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS, payload: { data } }],
[],
done,
);
});
});
describe('receiveDeleteDismissalCommentError', () => {
it('should commit the error mutation', done => {
testAction(
receiveDeleteDismissalCommentError,
{},
state,
[
{
type: types.RECEIVE_DELETE_DISMISSAL_COMMENT_ERROR,
payload: {},
},
],
[],
done,
);
});
});
describe('requestDeleteDismissalComment', () => {
it('should commit the request mutation', done => {
testAction(
requestDeleteDismissalComment,
{},
state,
[{ type: types.REQUEST_DELETE_DISMISSAL_COMMENT }],
[],
done,
);
});
});
});
describe('showDismissalDeleteButtons', () => {
it('commits show dismissal delete buttons', done => {
testAction(
showDismissalDeleteButtons,
null,
mockedState,
[
{
type: types.SHOW_DISMISSAL_DELETE_BUTTONS,
},
],
[],
done,
);
});
});
describe('hideDismissalDeleteButtons', () => {
it('commits hide dismissal delete buttons', done => {
testAction(
hideDismissalDeleteButtons,
null,
mockedState,
[
{
type: types.HIDE_DISMISSAL_DELETE_BUTTONS,
},
],
[],
done,
);
});
});
describe('revertDismissVulnerability', () => {
describe('with success', () => {
let payload;
......
......@@ -4581,6 +4581,9 @@ msgstr ""
msgid "Delete"
msgstr ""
msgid "Delete Comment"
msgstr ""
msgid "Delete Package"
msgstr ""
......@@ -5164,6 +5167,9 @@ msgstr ""
msgid "Edit %{name}"
msgstr ""
msgid "Edit Comment"
msgstr ""
msgid "Edit Deploy Key"
msgstr ""
......@@ -13167,6 +13173,9 @@ msgstr ""
msgid "Security Reports|There was an error creating the merge request."
msgstr ""
msgid "Security Reports|There was an error deleting the comment."
msgstr ""
msgid "Security Reports|There was an error dismissing the vulnerability."
msgstr ""
......@@ -18755,6 +18764,9 @@ msgstr ""
msgid "vulnerability|Dismiss vulnerability"
msgstr ""
msgid "vulnerability|Save comment"
msgstr ""
msgid "vulnerability|Undo dismiss"
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