Commit c318e74a authored by Tristan Read's avatar Tristan Read Committed by Andrew Fontaine

Add Alert Details header

parent f1ef6fdc
......@@ -2,18 +2,21 @@
import * as Sentry from '@sentry/browser';
import {
GlAlert,
GlIcon,
GlLoadingIcon,
GlNewDropdown,
GlNewDropdownItem,
GlSprintf,
GlTabs,
GlTab,
GlButton,
} from '@gitlab/ui';
import timeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import { s__ } from '~/locale';
import query from '../graphql/queries/details.query.graphql';
import { fetchPolicies } from '~/lib/graphql';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { ALERTS_SEVERITY_LABELS } from '../constants';
export default {
statuses: {
......@@ -27,16 +30,21 @@ export default {
),
fullAlertDetailsTitle: s__('AlertManagement|Full alert details'),
overviewTitle: s__('AlertManagement|Overview'),
reportedAt: s__('AlertManagement|Reported %{when}'),
reportedAtWithTool: s__('AlertManagement|Reported %{when} by %{tool}'),
},
severityLabels: ALERTS_SEVERITY_LABELS,
components: {
GlAlert,
GlIcon,
GlLoadingIcon,
GlNewDropdown,
GlNewDropdownItem,
timeAgoTooltip,
GlSprintf,
GlTab,
GlTabs,
GlButton,
TimeAgoTooltip,
},
mixins: [glFeatureFlagsMixin()],
props: {
......@@ -79,6 +87,11 @@ export default {
loading() {
return this.$apollo.queries.alert.loading;
},
reportedAtMessage() {
return this.alert?.monitoringTool
? this.$options.i18n.reportedAtWithTool
: this.$options.i18n.reportedAt;
},
showErrorMsg() {
return this.errored && !this.isErrorDismissed;
},
......@@ -95,58 +108,79 @@ export default {
<gl-alert v-if="showErrorMsg" variant="danger" @dismiss="dismissError">
{{ $options.i18n.errorMsg }}
</gl-alert>
<div v-if="loading"><gl-loading-icon size="lg" class="mt-3" /></div>
<div
v-if="alert"
class="gl-display-flex justify-content-end gl-border-b-1 gl-border-b-gray-200 gl-border-b-solid gl-p-4"
>
<gl-button
v-if="glFeatures.createIssueFromAlertEnabled"
data-testid="createIssueBtn"
:href="newIssuePath"
category="primary"
variant="success"
<div v-if="loading"><gl-loading-icon size="lg" class="gl-mt-5" /></div>
<div v-if="alert" class="alert-management-details">
<div
class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-px-1 gl-py-6 gl-border-b-1 gl-border-b-gray-200 gl-border-b-solid"
>
{{ s__('AlertManagement|Create issue') }}
</gl-button>
</div>
<div
v-if="alert"
class="gl-display-flex gl-justify-content-space-between gl-align-items-center"
>
<h2 data-testid="title">{{ alert.title }}</h2>
<gl-new-dropdown right>
<gl-new-dropdown-item
v-for="(label, field) in $options.statuses"
:key="field"
data-testid="statusDropdownItem"
class="align-middle"
>{{ label }}
</gl-new-dropdown-item>
</gl-new-dropdown>
<div data-testid="alert-header">
<div
class="gl-display-inline-flex gl-align-items-center gl-justify-content-space-between"
>
<gl-icon
class="gl-mr-3"
:size="12"
:name="`severity-${alert.severity.toLowerCase()}`"
:class="`icon-${alert.severity.toLowerCase()}`"
/>
<strong>{{ $options.severityLabels[alert.severity] }}</strong>
</div>
<span class="gl-shim-mx-2">&bull;</span>
<gl-sprintf :message="reportedAtMessage">
<template #when>
<time-ago-tooltip :time="alert.createdAt" />
</template>
<template #tool>{{ alert.monitoringTool }}</template>
</gl-sprintf>
</div>
<gl-button
v-if="glFeatures.createIssueFromAlertEnabled"
data-testid="createIssueBtn"
:href="newIssuePath"
category="primary"
variant="success"
>
{{ s__('AlertManagement|Create issue') }}
</gl-button>
</div>
<div
v-if="alert"
class="gl-display-flex gl-justify-content-space-between gl-align-items-center"
>
<h2 data-testid="title">{{ alert.title }}</h2>
<gl-new-dropdown right>
<gl-new-dropdown-item
v-for="(label, field) in $options.statuses"
:key="field"
data-testid="statusDropdownItem"
class="gl-vertical-align-middle"
>{{ label }}
</gl-new-dropdown-item>
</gl-new-dropdown>
</div>
<gl-tabs v-if="alert" data-testid="alertDetailsTabs">
<gl-tab data-testid="overviewTab" :title="$options.i18n.overviewTitle">
<ul class="pl-4 mb-n1">
<li v-if="alert.startedAt" class="my-2">
<strong class="bold">{{ s__('AlertManagement|Start time') }}:</strong>
<time-ago-tooltip data-testid="startTimeItem" :time="alert.startedAt" />
</li>
<li v-if="alert.eventCount" class="my-2">
<strong class="bold">{{ s__('AlertManagement|Events') }}:</strong>
<span data-testid="eventCount">{{ alert.eventCount }}</span>
</li>
<li v-if="alert.monitoringTool" class="my-2">
<strong class="bold">{{ s__('AlertManagement|Tool') }}:</strong>
<span data-testid="monitoringTool">{{ alert.monitoringTool }}</span>
</li>
<li v-if="alert.service" class="my-2">
<strong class="bold">{{ s__('AlertManagement|Service') }}:</strong>
<span data-testid="service">{{ alert.service }}</span>
</li>
</ul>
</gl-tab>
<gl-tab data-testid="fullDetailsTab" :title="$options.i18n.fullAlertDetailsTitle" />
</gl-tabs>
</div>
<gl-tabs v-if="alert" data-testid="alertDetailsTabs">
<gl-tab data-testid="overviewTab" :title="$options.i18n.overviewTitle">
<ul class="pl-4 mb-n1">
<li v-if="alert.startedAt" class="my-2">
<strong class="bold">{{ s__('AlertManagement|Start time') }}:</strong>
<time-ago-tooltip data-testid="startTimeItem" :time="alert.startedAt" />
</li>
<li v-if="alert.eventCount" class="my-2">
<strong class="bold">{{ s__('AlertManagement|Events') }}:</strong>
<span data-testid="eventCount">{{ alert.eventCount }}</span>
</li>
<li v-if="alert.monitoringTool" class="my-2">
<strong class="bold">{{ s__('AlertManagement|Tool') }}:</strong>
<span data-testid="monitoringTool">{{ alert.monitoringTool }}</span>
</li>
<li v-if="alert.service" class="my-2">
<strong class="bold">{{ s__('AlertManagement|Service') }}:</strong>
<span data-testid="service">{{ alert.service }}</span>
</li>
</ul>
</gl-tab>
<gl-tab data-testid="fullDetailsTab" :title="$options.i18n.fullAlertDetailsTitle" />
</gl-tabs>
</div>
</template>
......@@ -3,6 +3,7 @@ query alertDetails($fullPath: ID!, $alertId: String) {
alertManagementAlerts(iid: $alertId) {
nodes {
iid
createdAt
endedAt
eventCount
monitoringTool
......
.alert-management-list {
.alert-management-list,
.alert-management-details {
.icon-critical {
color: $red-800;
}
......
......@@ -97,6 +97,11 @@
padding-top: 16px;
}
.gl-shim-mx-2 {
margin-left: 4px;
margin-right: 4px;
}
.gl-text-purple { color: $purple; }
.gl-text-gray-800 { color: $gray-800; }
.gl-bg-purple-light { background-color: $purple-light; }
......
......@@ -1769,6 +1769,12 @@ msgstr ""
msgid "AlertManagement|Overview"
msgstr ""
msgid "AlertManagement|Reported %{when}"
msgstr ""
msgid "AlertManagement|Reported %{when} by %{tool}"
msgstr ""
msgid "AlertManagement|Resolved"
msgstr ""
......
import { shallowMount } from '@vue/test-utils';
import { mount, shallowMount } from '@vue/test-utils';
import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
import AlertDetails from '~/alert_management/components/alert_details.vue';
......@@ -11,18 +11,20 @@ describe('AlertDetails', () => {
const newIssuePath = 'root/alerts/-/issues/new';
function mountComponent({
data = { alert: {} },
data,
createIssueFromAlertEnabled = false,
loading = false,
mountMethod = shallowMount,
stubs = {},
} = {}) {
wrapper = shallowMount(AlertDetails, {
wrapper = mountMethod(AlertDetails, {
propsData: {
alertId: 'alertId',
projectPath: 'projectPath',
newIssuePath,
},
data() {
return data;
return { alert: { ...mockAlert }, ...data };
},
provide: {
glFeatures: { createIssueFromAlertEnabled },
......@@ -36,6 +38,7 @@ describe('AlertDetails', () => {
},
},
},
stubs,
});
}
......@@ -149,5 +152,33 @@ describe('AlertDetails', () => {
expect(wrapper.find(GlAlert).exists()).toBe(false);
});
});
describe('header', () => {
const findHeader = () => wrapper.find('[data-testid="alert-header"]');
const stubs = { TimeAgoTooltip: '<span>now</span>' };
describe('individual header fields', () => {
describe.each`
severity | createdAt | monitoringTool | result
${'MEDIUM'} | ${'2020-04-17T23:18:14.996Z'} | ${null} | ${'Medium • Reported now'}
${'INFO'} | ${'2020-04-17T23:18:14.996Z'} | ${'Datadog'} | ${'Info • Reported now by Datadog'}
`(
`When severity=$severity, createdAt=$createdAt, monitoringTool=$monitoringTool`,
({ severity, createdAt, monitoringTool, result }) => {
beforeEach(() => {
mountComponent({
data: { alert: { ...mockAlert, severity, createdAt, monitoringTool } },
mountMethod: mount,
stubs,
});
});
it('header text is shown correctly', () => {
expect(findHeader().text()).toBe(result);
});
},
);
});
});
});
});
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