diff options
Diffstat (limited to 'app/assets/javascripts/alert_management/components/alert_details.vue')
-rw-r--r-- | app/assets/javascripts/alert_management/components/alert_details.vue | 236 |
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">•</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> |