summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/alert_management/components/alert_details.vue
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/alert_management/components/alert_details.vue')
-rw-r--r--app/assets/javascripts/alert_management/components/alert_details.vue236
1 files changed, 236 insertions, 0 deletions
diff --git a/app/assets/javascripts/alert_management/components/alert_details.vue b/app/assets/javascripts/alert_management/components/alert_details.vue
new file mode 100644
index 00000000000..89db7db77d5
--- /dev/null
+++ b/app/assets/javascripts/alert_management/components/alert_details.vue
@@ -0,0 +1,236 @@
+<script>
+import * as Sentry from '@sentry/browser';
+import {
+ GlAlert,
+ GlIcon,
+ GlLoadingIcon,
+ GlDropdown,
+ GlDropdownItem,
+ GlSprintf,
+ GlTabs,
+ GlTab,
+ GlButton,
+ GlTable,
+} from '@gitlab/ui';
+import createFlash from '~/flash';
+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';
+import updateAlertStatus from '../graphql/mutations/update_alert_status.graphql';
+
+export default {
+ statuses: {
+ TRIGGERED: s__('AlertManagement|Triggered'),
+ ACKNOWLEDGED: s__('AlertManagement|Acknowledged'),
+ RESOLVED: s__('AlertManagement|Resolved'),
+ },
+ i18n: {
+ errorMsg: s__(
+ 'AlertManagement|There was an error displaying the alert. Please refresh the page to try again.',
+ ),
+ fullAlertDetailsTitle: s__('AlertManagement|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,
+ GlSprintf,
+ GlDropdown,
+ GlDropdownItem,
+ GlTab,
+ GlTabs,
+ GlButton,
+ GlTable,
+ TimeAgoTooltip,
+ },
+ mixins: [glFeatureFlagsMixin()],
+ props: {
+ alertId: {
+ type: String,
+ required: true,
+ },
+ projectPath: {
+ type: String,
+ required: true,
+ },
+ newIssuePath: {
+ type: String,
+ required: true,
+ },
+ },
+ apollo: {
+ alert: {
+ fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
+ query,
+ variables() {
+ return {
+ fullPath: this.projectPath,
+ alertId: this.alertId,
+ };
+ },
+ update(data) {
+ return data?.project?.alertManagementAlerts?.nodes?.[0] ?? null;
+ },
+ error(error) {
+ this.errored = true;
+ Sentry.captureException(error);
+ },
+ },
+ },
+ data() {
+ return { alert: null, errored: false, isErrorDismissed: false };
+ },
+ computed: {
+ 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;
+ },
+ },
+ methods: {
+ dismissError() {
+ this.isErrorDismissed = true;
+ },
+ updateAlertStatus(status) {
+ this.$apollo
+ .mutate({
+ mutation: updateAlertStatus,
+ variables: {
+ iid: this.alertId,
+ status: status.toUpperCase(),
+ projectPath: this.projectPath,
+ },
+ })
+ .catch(() => {
+ createFlash(
+ s__(
+ 'AlertManagement|There was an error while updating the status of the alert. Please try again.',
+ ),
+ );
+ });
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-alert v-if="showErrorMsg" variant="danger" @dismiss="dismissError">
+ {{ $options.i18n.errorMsg }}
+ </gl-alert>
+ <div v-if="loading"><gl-loading-icon size="lg" class="gl-mt-5" /></div>
+ <div v-if="alert" class="alert-management-details gl-relative">
+ <div
+ class="gl-display-flex gl-justify-content-space-between gl-align-items-baseline gl-px-1 py-3 py-md-4 gl-border-b-1 gl-border-b-gray-200 gl-border-b-solid flex-column flex-sm-row"
+ >
+ <div
+ data-testid="alert-header"
+ class="gl-display-flex gl-align-items-center gl-justify-content-center"
+ >
+ <div
+ class="gl-display-inline-flex gl-align-items-center gl-justify-content-space-between"
+ >
+ <gl-icon
+ class="gl-mr-3 align-middle"
+ :size="12"
+ :name="`severity-${alert.severity.toLowerCase()}`"
+ :class="`icon-${alert.severity.toLowerCase()}`"
+ />
+ <strong>{{ $options.severityLabels[alert.severity] }}</strong>
+ </div>
+ <span class="mx-2">&bull;</span>
+ <gl-sprintf :message="reportedAtMessage">
+ <template #when>
+ <time-ago-tooltip :time="alert.createdAt" class="gl-ml-3" />
+ </template>
+ <template #tool>{{ alert.monitoringTool }}</template>
+ </gl-sprintf>
+ </div>
+ <gl-button
+ v-if="glFeatures.createIssueFromAlertEnabled"
+ class="gl-mt-3 mt-sm-0 align-self-center align-self-sm-baseline alert-details-create-issue-button"
+ 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>
+ </div>
+ <gl-dropdown :text="$options.statuses[alert.status]" class="gl-absolute gl-right-0" right>
+ <gl-dropdown-item
+ v-for="(label, field) in $options.statuses"
+ :key="field"
+ data-testid="statusDropdownItem"
+ class="gl-vertical-align-middle"
+ @click="updateAlertStatus(label)"
+ >
+ <span class="d-flex">
+ <gl-icon
+ class="flex-shrink-0 append-right-4"
+ :class="{ invisible: label.toUpperCase() !== alert.status }"
+ name="mobile-issue-close"
+ />
+ {{ label }}
+ </span>
+ </gl-dropdown-item>
+ </gl-dropdown>
+ <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-table
+ class="alert-management-details-table"
+ :items="[{ key: 'Value', ...alert }]"
+ :show-empty="true"
+ :busy="loading"
+ stacked
+ >
+ <template #empty>
+ {{ s__('AlertManagement|No alert data to display.') }}
+ </template>
+ <template #table-busy>
+ <gl-loading-icon size="lg" color="dark" class="mt-3" />
+ </template>
+ </gl-table>
+ </gl-tab>
+ </gl-tabs>
+ </div>
+ </div>
+</template>