Commit e0727b2a authored by Savas Vedova's avatar Savas Vedova

Merge branch '289815-jira-integration-fe' into 'master'

Display create jira issue button when available

See merge request gitlab-org/gitlab!53469
parents cadc4528 3eeef9cf
...@@ -5,7 +5,6 @@ import SplitButton from 'ee/vue_shared/security_reports/components/split_button. ...@@ -5,7 +5,6 @@ import SplitButton from 'ee/vue_shared/security_reports/components/split_button.
import { s__ } from '~/locale'; import { s__ } from '~/locale';
export default { export default {
name: 'ModalFooter',
components: { components: {
DismissButton, DismissButton,
GlButton, GlButton,
...@@ -58,15 +57,26 @@ export default { ...@@ -58,15 +57,26 @@ export default {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
vulnerability: {
type: Object,
required: true,
},
}, },
computed: { computed: {
createIssueButtonText() {
return this.vulnerability.create_jira_issue_url
? s__('ciReport|Create Jira issue')
: s__('ciReport|Create issue');
},
actionButtons() { actionButtons() {
const buttons = []; const buttons = [];
const issueButton = { const issueButton = {
name: s__('ciReport|Create issue'), name: this.createIssueButtonText,
tagline: s__('ciReport|Investigate this vulnerability by creating an issue'), tagline: s__('ciReport|Investigate this vulnerability by creating an issue'),
isLoading: this.isCreatingIssue, isLoading: this.isCreatingIssue,
action: 'createNewIssue', action: this.vulnerability.create_jira_issue_url ? undefined : 'createNewIssue',
href: this.vulnerability.create_jira_issue_url,
}; };
const MRButton = { const MRButton = {
name: s__('ciReport|Resolve with merge request'), name: s__('ciReport|Resolve with merge request'),
...@@ -128,11 +138,13 @@ export default { ...@@ -128,11 +138,13 @@ export default {
<gl-button <gl-button
v-else-if="actionButtons.length > 0" v-else-if="actionButtons.length > 0"
:loading="actionButtons[0].isLoading" :loading="actionButtons[0].isLoading"
:disabled="actionButtons[0].isLoading || disabled" :disabled="disabled"
variant="success" variant="success"
category="secondary" category="secondary"
class="js-action-button" data-testid="create-issue-button"
data-qa-selector="create_issue_button" data-qa-selector="create_issue_button"
:target="actionButtons[0].href ? '_blank' : undefined"
:href="actionButtons[0].href"
@click="$emit(actionButtons[0].action)" @click="$emit(actionButtons[0].action)"
> >
{{ __(actionButtons[0].name) }} {{ __(actionButtons[0].name) }}
......
<script> <script>
import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { visitUrl } from '~/lib/utils/url_utility';
export default { export default {
components: { components: {
...@@ -28,7 +29,11 @@ export default { ...@@ -28,7 +29,11 @@ export default {
this.selectedButton = button; this.selectedButton = button;
}, },
handleClick() { handleClick() {
this.$emit(this.selectedButton.action); if (this.selectedButton.href) {
visitUrl(this.selectedButton.href, true);
} else {
this.$emit(this.selectedButton.action);
}
}, },
}, },
}; };
...@@ -40,6 +45,7 @@ export default { ...@@ -40,6 +45,7 @@ export default {
:disabled="disabled" :disabled="disabled"
variant="success" variant="success"
:text="selectedButton.name" :text="selectedButton.name"
:href="selectedButton.href"
split split
@click="handleClick" @click="handleClick"
> >
......
...@@ -13,11 +13,14 @@ describe('Security Reports modal footer', () => { ...@@ -13,11 +13,14 @@ describe('Security Reports modal footer', () => {
isCreatingIssue: false, isCreatingIssue: false,
isDismissingVulnerability: false, isDismissingVulnerability: false,
isCreatingMergeRequest: false, isCreatingMergeRequest: false,
vulnerability: {},
...propsData, ...propsData,
}, },
}); });
}; };
const findActionButton = () => wrapper.find('[data-testid=create-issue-button]');
describe('can only create issue', () => { describe('can only create issue', () => {
beforeEach(() => { beforeEach(() => {
const propsData = { const propsData = {
...@@ -33,11 +36,11 @@ describe('Security Reports modal footer', () => { ...@@ -33,11 +36,11 @@ describe('Security Reports modal footer', () => {
it('only renders the create issue button', () => { it('only renders the create issue button', () => {
expect(wrapper.vm.actionButtons[0].name).toBe('Create issue'); expect(wrapper.vm.actionButtons[0].name).toBe('Create issue');
expect(wrapper.find('.js-action-button').text()).toBe('Create issue'); expect(findActionButton().text()).toBe('Create issue');
}); });
it('emits createIssue when create issue button is clicked', () => { it('emits createIssue when create issue button is clicked', () => {
wrapper.find('.js-action-button').trigger('click'); findActionButton().trigger('click');
return wrapper.vm.$nextTick().then(() => { return wrapper.vm.$nextTick().then(() => {
expect(wrapper.emitted().createNewIssue).toBeTruthy(); expect(wrapper.emitted().createNewIssue).toBeTruthy();
...@@ -45,6 +48,34 @@ describe('Security Reports modal footer', () => { ...@@ -45,6 +48,34 @@ describe('Security Reports modal footer', () => {
}); });
}); });
describe('can only create jira issue', () => {
const url = 'https://gitlab.atlassian.net/create-issue';
beforeEach(() => {
const propsData = {
modal: createState().modal,
canCreateIssue: true,
vulnerability: {
create_jira_issue_url: url,
},
};
mountComponent(propsData);
});
it('has target property properly set', () => {
expect(findActionButton().props('target')).toBe('_blank');
expect(findActionButton().props('action')).toBeUndefined();
});
it('has href attribute properly set', () => {
expect(findActionButton().attributes('href')).toBe(url);
});
it('has the correct text', () => {
expect(findActionButton().text()).toBe('Create Jira issue');
});
});
describe('can only create merge request', () => { describe('can only create merge request', () => {
beforeEach(() => { beforeEach(() => {
const propsData = { const propsData = {
...@@ -56,11 +87,11 @@ describe('Security Reports modal footer', () => { ...@@ -56,11 +87,11 @@ describe('Security Reports modal footer', () => {
it('only renders the create merge request button', () => { it('only renders the create merge request button', () => {
expect(wrapper.vm.actionButtons[0].name).toBe('Resolve with merge request'); expect(wrapper.vm.actionButtons[0].name).toBe('Resolve with merge request');
expect(wrapper.find('.js-action-button').text()).toBe('Resolve with merge request'); expect(findActionButton().text()).toBe('Resolve with merge request');
}); });
it('emits createMergeRequest when create merge request button is clicked', () => { it('emits createMergeRequest when create merge request button is clicked', () => {
wrapper.find('.js-action-button').trigger('click'); findActionButton().trigger('click');
return wrapper.vm.$nextTick().then(() => { return wrapper.vm.$nextTick().then(() => {
expect(wrapper.emitted().createMergeRequest).toBeTruthy(); expect(wrapper.emitted().createMergeRequest).toBeTruthy();
...@@ -79,11 +110,11 @@ describe('Security Reports modal footer', () => { ...@@ -79,11 +110,11 @@ describe('Security Reports modal footer', () => {
it('renders the download patch button', () => { it('renders the download patch button', () => {
expect(wrapper.vm.actionButtons[0].name).toBe('Download patch to resolve'); expect(wrapper.vm.actionButtons[0].name).toBe('Download patch to resolve');
expect(wrapper.find('.js-action-button').text()).toBe('Download patch to resolve'); expect(findActionButton().text()).toBe('Download patch to resolve');
}); });
it('emits downloadPatch when download patch button is clicked', () => { it('emits downloadPatch when download patch button is clicked', () => {
wrapper.find('.js-action-button').trigger('click'); findActionButton().trigger('click');
return wrapper.vm.$nextTick().then(() => { return wrapper.vm.$nextTick().then(() => {
expect(wrapper.emitted().downloadPatch).toBeTruthy(); expect(wrapper.emitted().downloadPatch).toBeTruthy();
......
...@@ -108,6 +108,8 @@ describe('Security Reports modal', () => { ...@@ -108,6 +108,8 @@ describe('Security Reports modal', () => {
}); });
describe('with merge request created', () => { describe('with merge request created', () => {
const findActionButton = () => wrapper.find('[data-testid=create-issue-button]');
it('renders the issue button as a single button', (done) => { it('renders the issue button as a single button', (done) => {
const propsData = { const propsData = {
modal: createState().modal, modal: createState().modal,
...@@ -122,11 +124,9 @@ describe('Security Reports modal', () => { ...@@ -122,11 +124,9 @@ describe('Security Reports modal', () => {
Vue.nextTick() Vue.nextTick()
.then(() => { .then(() => {
expect(wrapper.find('.js-split-button').exists()).toBe(false); expect(wrapper.find('.js-split-button').exists()).toBe(false);
expect(wrapper.find('.js-action-button').exists()).toBe(true); expect(findActionButton().exists()).toBe(true);
expect(wrapper.find('.js-action-button').text()).not.toContain( expect(findActionButton().text()).not.toContain('Resolve with merge request');
'Resolve with merge request', expect(findActionButton().text()).toContain('Create issue');
);
expect(wrapper.find('.js-action-button').text()).toContain('Create issue');
done(); done();
}) })
.catch(done.fail); .catch(done.fail);
......
import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import SplitButton from 'ee/vue_shared/security_reports/components/split_button.vue'; import SplitButton from 'ee/vue_shared/security_reports/components/split_button.vue';
import * as urlUtility from '~/lib/utils/url_utility';
const buttons = [ const buttons = [
{ {
...@@ -64,6 +65,20 @@ describe('Split Button', () => { ...@@ -64,6 +65,20 @@ describe('Split Button', () => {
expect(wrapper.emitted('button1Action')).toHaveLength(1); expect(wrapper.emitted('button1Action')).toHaveLength(1);
}); });
it('visits url if href property is specified', () => {
const spy = jest.spyOn(urlUtility, 'visitUrl').mockReturnValue({});
const href = 'https://gitlab.com';
createComponent({
buttons: [{ ...buttons.slice(0), action: undefined, href }],
});
findDropdown().vm.$emit('click');
expect(wrapper.emitted('button1Action')).toBeUndefined();
expect(spy).toHaveBeenCalledWith(href, true);
});
it('renders a correct amount of dropdown items', () => { it('renders a correct amount of dropdown items', () => {
createComponent({ createComponent({
buttons, buttons,
......
...@@ -34149,6 +34149,9 @@ msgstr "" ...@@ -34149,6 +34149,9 @@ msgstr ""
msgid "ciReport|Coverage fuzzing" msgid "ciReport|Coverage fuzzing"
msgstr "" msgstr ""
msgid "ciReport|Create Jira issue"
msgstr ""
msgid "ciReport|Create a merge request to implement this solution, or download and apply the patch manually." msgid "ciReport|Create a merge request to implement this solution, or download and apply the patch manually."
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