Commit c59d8b0d authored by Alexander Turinske's avatar Alexander Turinske

Create incident column for threat alerts

- shows incident number if there is an incident
  created from the alert
- otherwise shows none
- add tests
- update screenshots

Changelog: added
parent b2e96410
......@@ -221,7 +221,7 @@ to set the status for each alert:
By default, the list doesn't display resolved or dismissed alerts. To show these alerts, clear the
checkbox **Hide dismissed alerts**.
![Policy Alert List](img/threat_monitoring_policy_alert_list_v13_11.png)
![Policy Alert List](img/threat_monitoring_policy_alert_list_v13_12.png)
Clicking an alert's name takes the user to the [alert details page](../../../operations/incident_management/alerts.md#alert-details-page).
......
......@@ -16,7 +16,15 @@ import { joinPaths } from '~/lib/utils/url_utility';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import AlertFilters from './alert_filters.vue';
import AlertStatus from './alert_status.vue';
import { DEFAULT_FILTERS, FIELDS, MESSAGES, PAGE_SIZE, STATUSES, DOMAIN } from './constants';
import {
DEFAULT_FILTERS,
FIELDS,
MESSAGES,
PAGE_SIZE,
STATUSES,
DOMAIN,
CLOSED,
} from './constants';
export default {
PAGE_SIZE,
......@@ -25,6 +33,7 @@ export default {
FIELDS,
MESSAGES,
STATUSES,
CLOSED,
},
components: {
AlertStatus,
......@@ -119,6 +128,12 @@ export default {
this.sort = `${sortingColumn}_${sortingDirection}`;
},
getIssueMeta({ issue: { iid, state } }) {
return {
state: state === 'closed' ? `(${this.$options.i18n.CLOSED})` : '',
link: joinPaths('/', this.projectPath, '-', 'issues/incident', iid),
};
},
handleAlertError(msg) {
this.errored = true;
this.errorMsg = msg;
......@@ -198,6 +213,19 @@ export default {
</div>
</template>
<template #cell(issue)="{ item }">
<gl-link
v-if="item.issue"
v-gl-tooltip
:title="item.issue.title"
data-testid="threat-alerts-issue"
:href="getIssueMeta(item).link"
>
#{{ item.issue.iid }} {{ getIssueMeta(item).state }}
</gl-link>
<div v-else data-testid="threat-alerts-issue">{{ __('None') }}</div>
</template>
<template #cell(status)="{ item }">
<alert-status
:alert="item"
......
......@@ -41,6 +41,11 @@ export const FIELDS = [
tdClass: `gl-pl-6! gl-text-right`,
sortable: true,
},
{
key: 'issue',
label: s__('ThreatMonitoring|Incident'),
thClass: 'gl-bg-white! gl-w-15p',
},
{
key: 'status',
label: s__('ThreatMonitoring|Status'),
......@@ -60,3 +65,5 @@ export const DOMAIN = 'threat_monitoring';
export const DEBOUNCE = 250;
export const ALL = { key: 'ALL', value: __('All') };
export const CLOSED = __('closed');
---
title: Create incident column for threat alerts
merge_request: 59821
author:
type: added
......@@ -44,6 +44,9 @@ describe('AlertsList component', () => {
const findStartedAtColumnHeader = () => wrapper.findByTestId('threat-alerts-started-at-header');
const findIdColumn = () => wrapper.findByTestId('threat-alerts-id');
const findEventCountColumn = () => wrapper.findByTestId('threat-alerts-event-count');
const findIssueColumn = () => wrapper.findByTestId('threat-alerts-issue');
const findIssueColumnTextAt = (id) =>
wrapper.findAll('[data-testid="threat-alerts-issue"').at(id).text();
const findStatusColumn = () => wrapper.findComponent(AlertStatus);
const findStatusColumnHeader = () => wrapper.findByTestId('threat-alerts-status-header');
const findEmptyState = () => wrapper.findByTestId('threat-alerts-empty-state');
......@@ -128,6 +131,7 @@ describe('AlertsList component', () => {
expect(findStartedAtColumn().exists()).toBe(true);
expect(findIdColumn().exists()).toBe(true);
expect(findEventCountColumn().exists()).toBe(true);
expect(findIssueColumn().exists()).toBe(true);
expect(findStatusColumn().exists()).toBe(true);
});
......@@ -171,6 +175,17 @@ describe('AlertsList component', () => {
it('navigates to the alert details page on title click', () => {
expect(findIdColumn().attributes('href')).toBe('/alerts/01');
});
describe('issue column', () => {
it.each`
description | id | text
${'when an issue is created and is open'} | ${0} | ${'#5'}
${'when an issue is created and is closed'} | ${1} | ${'#6 (closed)'}
${'when an issue is not created'} | ${2} | ${'None'}
`('displays the correct text $description', ({ id, text }) => {
expect(findIssueColumnTextAt(id)).toBe(text);
});
});
});
describe('empty state', () => {
......
......@@ -97,7 +97,7 @@ export const mockAlerts = [
assignees: { nodes: [] },
eventCount: '1',
issueIid: null,
issue: { iid: '1', state: '', title: '' },
issue: { iid: '5', state: 'opened', title: 'Issue 01' },
title: 'Issue 01',
severity: 'HIGH',
status: 'TRIGGERED',
......@@ -108,7 +108,7 @@ export const mockAlerts = [
eventCount: '2',
assignees: { nodes: [] },
issueIid: null,
issue: { iid: '2', state: '', title: '' },
issue: { iid: '6', state: 'closed', title: 'Issue 02' },
severity: 'CRITICAL',
title: 'Issue 02',
status: 'ACKNOWLEDGED',
......@@ -119,7 +119,7 @@ export const mockAlerts = [
eventCount: '3',
assignees: { nodes: [] },
issueIid: null,
issue: { iid: '3', state: '', title: '' },
issue: null,
severity: 'MEDIUM',
title: 'Issue 03',
status: 'RESOLVED',
......@@ -129,7 +129,7 @@ export const mockAlerts = [
iid: '04',
assignees: { nodes: [] },
issueIid: null,
issue: { iid: '4', state: '', title: '' },
issue: null,
severity: 'LOW',
eventCount: '4',
title: 'Issue 04',
......
......@@ -32664,6 +32664,9 @@ msgstr ""
msgid "ThreatMonitoring|In review"
msgstr ""
msgid "ThreatMonitoring|Incident"
msgstr ""
msgid "ThreatMonitoring|Name"
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