Commit 614305ed authored by Denys Mishunov's avatar Denys Mishunov

Merge branch '216300-refactor-action-button' into 'master'

Refactor button to allow for multiple actions

See merge request gitlab-org/gitlab!31619
parents a277a89b d2e2adab
......@@ -9,7 +9,7 @@ import UsersCache from '~/lib/utils/users_cache';
import ResolutionAlert from './resolution_alert.vue';
import VulnerabilityStateDropdown from './vulnerability_state_dropdown.vue';
import StatusDescription from './status_description.vue';
import { VULNERABILITY_STATE_OBJECTS } from '../constants';
import { VULNERABILITY_STATE_OBJECTS, HEADER_ACTION_BUTTONS } from '../constants';
import VulnerabilitiesEventBus from './vulnerabilities_event_bus';
export default {
......@@ -48,7 +48,7 @@ export default {
data() {
return {
isLoadingVulnerability: false,
isCreatingIssue: false,
isProcessingAction: false,
isLoadingUser: false,
vulnerability: this.initialVulnerability,
user: undefined,
......@@ -56,6 +56,15 @@ export default {
},
computed: {
actionButtons() {
const buttons = [];
if (!this.hasIssue) {
buttons.push(HEADER_ACTION_BUTTONS.issueCreation);
}
return buttons;
},
hasIssue() {
return Boolean(this.finding.issue_feedback?.issue_iid);
},
......@@ -95,6 +104,10 @@ export default {
},
methods: {
triggerClick(action) {
const fn = this[action];
if (typeof fn === 'function') fn();
},
changeVulnerabilityState(newState) {
this.isLoadingVulnerability = true;
......@@ -115,7 +128,7 @@ export default {
});
},
createIssue() {
this.isCreatingIssue = true;
this.isProcessingAction = true;
axios
.post(this.createIssueUrl, {
vulnerability_feedback: {
......@@ -134,7 +147,7 @@ export default {
redirectTo(issue_url);
})
.catch(() => {
this.isCreatingIssue = false;
this.isProcessingAction = false;
createFlash(
s__('VulnerabilityManagement|Something went wrong, could not create an issue.'),
);
......@@ -182,15 +195,14 @@ export default {
@change="changeVulnerabilityState"
/>
<gl-deprecated-button
v-if="!hasIssue"
ref="create-issue-btn"
v-if="actionButtons.length > 0"
class="ml-2"
variant="success"
category="secondary"
:loading="isCreatingIssue"
@click="createIssue"
:loading="isProcessingAction"
@click="triggerClick(actionButtons[0].action)"
>
{{ s__('VulnerabilityManagement|Create issue') }}
{{ actionButtons[0].name }}
</gl-deprecated-button>
</div>
</div>
......
......@@ -29,3 +29,10 @@ export const VULNERABILITY_STATES = {
};
export const VULNERABILITIES_PER_PAGE = 20;
export const HEADER_ACTION_BUTTONS = {
issueCreation: {
name: s__('ciReport|Create issue'),
action: 'createIssue',
},
};
import { shallowMount } from '@vue/test-utils';
import { GlDeprecatedButton } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter';
import waitForPromises from 'helpers/wait_for_promises';
import UsersMockHelper from 'helpers/user_mock_data_helper';
......@@ -64,7 +65,7 @@ describe('Vulnerability Header', () => {
return user;
};
const findCreateIssueButton = () => wrapper.find({ ref: 'create-issue-btn' });
const findGlDeprecatedButton = () => wrapper.find(GlDeprecatedButton);
const findBadge = () => wrapper.find({ ref: 'badge' });
const findResolutionAlert = () => wrapper.find(ResolutionAlert);
const findStatusDescription = () => wrapper.find(StatusDescription);
......@@ -147,54 +148,57 @@ describe('Vulnerability Header', () => {
});
});
describe('create issue button', () => {
beforeEach(createWrapper);
it('does display if there is not an issue already created', () => {
expect(findCreateIssueButton().exists()).toBe(true);
});
it('does not display if there is an issue already created', () => {
describe('single action button', () => {
it('does not display if there are no actions', () => {
createWrapper({}, findingWithIssue);
expect(findCreateIssueButton().exists()).toBe(false);
expect(findGlDeprecatedButton().exists()).toBe(false);
});
it('calls create issue endpoint on click and redirects to new issue', () => {
const issueUrl = '/group/project/issues/123';
const spy = jest.spyOn(urlUtility, 'redirectTo');
mockAxios.onPost(dataset.createIssueUrl).reply(200, {
issue_url: issueUrl,
describe('create issue', () => {
beforeEach(createWrapper);
it('does display if there is only one action and not an issue already created', () => {
expect(findGlDeprecatedButton().exists()).toBe(true);
expect(findGlDeprecatedButton().text()).toBe('Create issue');
});
findCreateIssueButton().vm.$emit('click');
return waitForPromises().then(() => {
expect(mockAxios.history.post).toHaveLength(1);
const [postRequest] = mockAxios.history.post;
expect(postRequest.url).toBe(dataset.createIssueUrl);
expect(JSON.parse(postRequest.data)).toMatchObject({
vulnerability_feedback: {
feedback_type: 'issue',
category: defaultVulnerability.report_type,
project_fingerprint: dataset.projectFingerprint,
vulnerability_data: {
...defaultVulnerability,
...findingWithoutIssue,
it('calls create issue endpoint on click and redirects to new issue', () => {
const issueUrl = '/group/project/issues/123';
const spy = jest.spyOn(urlUtility, 'redirectTo');
mockAxios.onPost(dataset.createIssueUrl).reply(200, {
issue_url: issueUrl,
});
findGlDeprecatedButton().vm.$emit('click');
return waitForPromises().then(() => {
expect(mockAxios.history.post).toHaveLength(1);
const [postRequest] = mockAxios.history.post;
expect(postRequest.url).toBe(dataset.createIssueUrl);
expect(JSON.parse(postRequest.data)).toMatchObject({
vulnerability_feedback: {
feedback_type: 'issue',
category: defaultVulnerability.report_type,
vulnerability_id: defaultVulnerability.id,
project_fingerprint: dataset.projectFingerprint,
vulnerability_data: {
...defaultVulnerability,
...findingWithoutIssue,
category: defaultVulnerability.report_type,
vulnerability_id: defaultVulnerability.id,
},
},
},
});
expect(spy).toHaveBeenCalledWith(issueUrl);
});
expect(spy).toHaveBeenCalledWith(issueUrl);
});
});
it('shows an error message when issue creation fails', () => {
mockAxios.onPost(dataset.createIssueUrl).reply(500);
findCreateIssueButton().vm.$emit('click');
return waitForPromises().then(() => {
expect(mockAxios.history.post).toHaveLength(1);
expect(createFlash).toHaveBeenCalledWith(
'Something went wrong, could not create an issue.',
);
it('shows an error message when issue creation fails', () => {
mockAxios.onPost(dataset.createIssueUrl).reply(500);
findGlDeprecatedButton().vm.$emit('click');
return waitForPromises().then(() => {
expect(mockAxios.history.post).toHaveLength(1);
expect(createFlash).toHaveBeenCalledWith(
'Something went wrong, could not create an issue.',
);
});
});
});
});
......
......@@ -23694,9 +23694,6 @@ msgstr ""
msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|Create issue"
msgstr ""
msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
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