Commit 78f9d9a8 authored by Savas Vedova's avatar Savas Vedova

Attach issue to the vulnerability

- Add tests
- Add changelog
parent 69206ffd
<script>
import { GlIcon, GlLink } from '@gitlab/ui';
export default {
components: {
GlIcon,
GlLink,
},
props: {
issue: {
type: Object,
required: true,
},
},
STATE_OPENED: 'opened',
};
</script>
<template>
<gl-link
v-gl-tooltip="issue.title"
:href="issue.webUrl"
:data-testid="`issue-link-${issue.iid}`"
class="d-inline-flex align-items-center ml-2 gl-flex-shrink-0"
>
<gl-icon
class="mr-1"
:class="{ cgreen: issue.state === $options.STATE_OPENED }"
:name="issue.state === $options.STATE_OPENED ? 'issue-open-m' : 'issue-close'"
/>
#{{ issue.iid }}
</gl-link>
</template>
<script>
import { s__, __ } from '~/locale';
import { GlEmptyState, GlFormCheckbox, GlLink, GlSkeletonLoading, GlTable } from '@gitlab/ui';
import {
GlEmptyState,
GlFormCheckbox,
GlLink,
GlSkeletonLoading,
GlTable,
GlTooltipDirective,
} from '@gitlab/ui';
import RemediatedBadge from './remediated_badge.vue';
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
import SelectionSummary from 'ee/security_dashboard/components/selection_summary.vue';
import IssueLink from './issue_link.vue';
import { VULNERABILITIES_PER_PAGE } from '../constants';
export default {
......@@ -14,10 +22,14 @@ export default {
GlLink,
GlSkeletonLoading,
GlTable,
IssueLink,
RemediatedBadge,
SelectionSummary,
SeverityBadge,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
dashboardDocumentation: {
type: String,
......@@ -143,6 +155,9 @@ export default {
this.$set(this.selectedVulnerabilities, `${vulnerability.id}`, vulnerability);
}
},
issue(item) {
return item.issueLinks?.nodes[0]?.issue;
},
},
VULNERABILITIES_PER_PAGE,
};
......@@ -188,9 +203,12 @@ export default {
</template>
<template #cell(title)="{ item }">
<gl-link class="text-body js-description" :href="item.vulnerabilityPath">
{{ item.title }}
</gl-link>
<div class="d-flex flex-column flex-sm-row align-items-end align-items-sm-start">
<gl-link class="text-body js-description" :href="item.vulnerabilityPath">
{{ item.title }}
</gl-link>
<issue-link v-if="issue(item)" :issue="issue(item)" />
</div>
<div
v-if="item.location"
:data-testid="`location-${item.id}`"
......
......@@ -4,6 +4,16 @@ fragment Vulnerability on Vulnerability {
state
severity
vulnerabilityPath
issueLinks(linkType: CREATED) {
nodes {
issue {
iid
webUrl
title
state
}
}
}
location {
... on VulnerabilityLocationContainerScanning {
image
......
---
title: Show issue link on security dashboard when vulnerability has an issue
merge_request: 34157
author:
type: added
import { shallowMount } from '@vue/test-utils';
import { getBinding, createMockDirective } from 'helpers/vue_mock_directive';
import IssueLink from 'ee/vulnerabilities/components/issue_link.vue';
describe('IssueLink component', () => {
let wrapper;
const createIssue = options => ({
title: 'my-issue',
iid: 12,
webUrl: 'http://localhost/issues/~/12',
...options,
});
const createWrapper = ({ propsData }) => {
return shallowMount(IssueLink, {
propsData,
directives: {
GlTooltip: createMockDirective(),
},
});
};
const findIssueLink = id => wrapper.find(`[data-testid="issue-link-${id}"]`);
const findIssueWithState = state =>
wrapper.find(state === 'opened' ? 'issue-open-m' : 'issue-close');
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
describe.each`
state | icon
${'opened'} | ${'issue-open-m'}
${'closed'} | ${'issue-close'}
`('when issue link is mounted', ({ state }) => {
describe(`with state ${state}`, () => {
const issue = createIssue({ state });
beforeEach(() => {
wrapper = createWrapper({ propsData: { issue } });
});
test('should contain the correct issue icon', () => {
expect(findIssueWithState(state)).toBeTruthy();
});
test('should contain a link to the issue', () => {
expect(findIssueLink(issue.iid).attributes('href')).toBe(issue.webUrl);
});
test('should contain the title', () => {
const tooltip = getBinding(findIssueLink(issue.iid).element, 'gl-tooltip');
expect(tooltip).toBeDefined();
expect(tooltip.value).toBe(issue.title);
});
});
});
});
......@@ -178,6 +178,27 @@ describe('Vulnerability list component', () => {
});
});
describe('when has an issue associated', () => {
let newVulnerabilities;
beforeEach(() => {
newVulnerabilities = generateVulnerabilities();
newVulnerabilities[0].issueLinks = {
nodes: [
{
issue: {
title: 'my-title',
iid: 114,
state: 'opened',
webUrl: 'http://localhost/issues/~/114',
},
},
],
};
wrapper = createWrapper({ props: { vulnerabilities: newVulnerabilities } });
});
});
describe('when a vulnerability is resolved on the default branch', () => {
let newVulnerabilities;
......
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