| 1 | <template> |
| 2 | <div> |
| 3 | <CardEntity :status="statusType"> |
| 4 | <template #headerMain> |
| 5 | <div class="flex items-center gap-2"> |
| 6 | <span>{{ alert.check_name }}</span> |
| 7 | <n-tag |
| 8 | v-if="alert.status === InfluxDBAlertStatus.Active" |
| 9 | type="error" |
| 10 | size="small" |
| 11 | :bordered="false" |
| 12 | > |
| 13 | Active |
| 14 | </n-tag> |
| 15 | <n-tag v-else type="success" size="small" :bordered="false">Cleared</n-tag> |
| 16 | </div> |
| 17 | </template> |
| 18 | <template #headerExtra> |
| 19 | <div class="flex items-center gap-2"> |
| 20 | <n-tag v-if="alert.severity" :type="severityTagType" size="small" :bordered="false"> |
| 21 | {{ alert.severity.toUpperCase() }} |
| 22 | </n-tag> |
| 23 | <span>{{ formatDate(alert.time) }}</span> |
| 24 | </div> |
| 25 | </template> |
| 26 | <template #default> |
| 27 | <div class="flex items-center gap-3"> |
| 28 | <div class="mt-1"> |
| 29 | <Icon :name="severityIcon" :size="20" :class="severityIconClass" /> |
| 30 | </div> |
| 31 | <div class="grow"> |
| 32 | <div class="font-mono text-sm" v-html="formattedMessage"></div> |
| 33 | <div v-if="alert.sensor_type" class="mt-1 text-xs opacity-50"> |
| 34 | Sensor: {{ alert.sensor_type }} |
| 35 | </div> |
| 36 | </div> |
| 37 | </div> |
| 38 | </template> |
| 39 | </CardEntity> |
| 40 | </div> |
| 41 | </template> |
| 42 | |
| 43 | <script setup lang="ts"> |
| 44 | import type { InfluxDBAlert } from "@/types/healthchecks.d" |
| 45 | import { NTag } from "naive-ui" |
| 46 | import { computed } from "vue" |
| 47 | import CardEntity from "@/components/common/cards/CardEntity.vue" |
| 48 | import Icon from "@/components/common/Icon.vue" |
| 49 | import { useSettingsStore } from "@/stores/settings" |
| 50 | import { InfluxDBAlertSeverity, InfluxDBAlertStatus } from "@/types/healthchecks.d" |
| 51 | import dayjs from "@/utils/dayjs" |
| 52 | |
| 53 | const { alert } = defineProps<{ alert: InfluxDBAlert }>() |
| 54 | |
| 55 | const NEWLINE_REGEX = /\r?\n/g |
| 56 | |
| 57 | const formattedMessage = computed(() => { |
| 58 | return alert.message.replace(NEWLINE_REGEX, " <span class='mx-1'>•</span> ") |
| 59 | }) |
| 60 | |
| 61 | const statusType = computed(() => { |
| 62 | if (alert.severity === InfluxDBAlertSeverity.Critical) { |
| 63 | return "error" |
| 64 | } else if (alert.severity === InfluxDBAlertSeverity.Warning) { |
| 65 | return "warning" |
| 66 | } |
| 67 | return undefined |
| 68 | }) |
| 69 | |
| 70 | const severityTagType = computed(() => { |
| 71 | switch (alert.severity) { |
| 72 | case InfluxDBAlertSeverity.Critical: |
| 73 | return "error" |
| 74 | case InfluxDBAlertSeverity.Warning: |
| 75 | return "warning" |
| 76 | case InfluxDBAlertSeverity.Info: |
| 77 | return "info" |
| 78 | default: |
| 79 | return "success" |
| 80 | } |
| 81 | }) |
| 82 | |
| 83 | const severityIcon = computed(() => { |
| 84 | switch (alert.severity) { |
| 85 | case InfluxDBAlertSeverity.Critical: |
| 86 | return "carbon:warning-alt-filled" |
| 87 | case InfluxDBAlertSeverity.Warning: |
| 88 | return "carbon:warning" |
| 89 | case InfluxDBAlertSeverity.Info: |
| 90 | return "carbon:information-filled" |
| 91 | default: |
| 92 | return "carbon:checkmark-filled" |
| 93 | } |
| 94 | }) |
| 95 | |
| 96 | const severityIconClass = computed(() => { |
| 97 | switch (alert.severity) { |
| 98 | case InfluxDBAlertSeverity.Critical: |
| 99 | return "text-error-500" |
| 100 | case InfluxDBAlertSeverity.Warning: |
| 101 | return "text-warning-500" |
| 102 | case InfluxDBAlertSeverity.Info: |
| 103 | return "text-info-500" |
| 104 | default: |
| 105 | return "text-success-500" |
| 106 | } |
| 107 | }) |
| 108 | |
| 109 | const dFormats = useSettingsStore().dateFormat |
| 110 | |
| 111 | function formatDate(timestamp: string | number | Date, utc: boolean = true): string { |
| 112 | return dayjs(timestamp).utc(utc).format(dFormats.datetime) |
| 113 | } |
| 114 | </script> |