| 1 | <template> |
| 2 | <div class="page"> |
| 3 | <div class="header flex flex-wrap items-center justify-between gap-4"> |
| 4 | <div class="info flex items-center gap-3"> |
| 5 | <n-button size="small" type="primary" secondary :loading @click="getData()"> |
| 6 | <template #icon> |
| 7 | <Icon :name="UpdatedIcon" :size="15" /> |
| 8 | </template> |
| 9 | </n-button> |
| 10 | <span>Last check:</span> |
| 11 | <strong>{{ lastCheck ? formatDate(lastCheck, dFormats.datetimesec) : "..." }}</strong> |
| 12 | </div> |
| 13 | |
| 14 | <div class="toolbar flex items-center gap-3"> |
| 15 | <n-button v-if="!isRunning" size="small" type="primary" class="w-24!" @click="start()"> |
| 16 | <template #icon> |
| 17 | <Icon :name="StartIcon" /> |
| 18 | </template> |
| 19 | Start |
| 20 | </n-button> |
| 21 | <n-button v-if="isRunning" size="small" type="error" ghost class="w-24!" @click="stop()"> |
| 22 | <template #icon> |
| 23 | <Icon :name="StopIcon" /> |
| 24 | </template> |
| 25 | Stop |
| 26 | </n-button> |
| 27 | <n-select v-model:value="intervalSelected" size="small" :options="intervalOptions" class="w-36!" /> |
| 28 | </div> |
| 29 | </div> |
| 30 | |
| 31 | <div class="my-6"> |
| 32 | <UncommittedEntries :value="uncommittedJournalEntries" /> |
| 33 | </div> |
| 34 | |
| 35 | <div> |
| 36 | <MetricsList :throughput-metrics /> |
| 37 | </div> |
| 38 | </div> |
| 39 | </template> |
| 40 | |
| 41 | <script setup lang="ts"> |
| 42 | import type { ThroughputMetric } from "@/types/graylog/metrics.d" |
| 43 | import { useStorage } from "@vueuse/core" |
| 44 | import { NButton, NSelect, useMessage } from "naive-ui" |
| 45 | import { computed, nextTick, onBeforeMount, onBeforeUnmount, ref, watch } from "vue" |
| 46 | import Api from "@/api" |
| 47 | import Icon from "@/components/common/Icon.vue" |
| 48 | import MetricsList from "@/components/graylog/Metrics/List.vue" |
| 49 | import UncommittedEntries from "@/components/graylog/Metrics/UncommittedEntries.vue" |
| 50 | import { useSettingsStore } from "@/stores/settings" |
| 51 | import { formatDate } from "@/utils/format" |
| 52 | |
| 53 | const UpdatedIcon = "carbon:update-now" |
| 54 | const StopIcon = "carbon:stop" |
| 55 | const StartIcon = "carbon:play" |
| 56 | |
| 57 | const message = useMessage() |
| 58 | const loading = ref(false) |
| 59 | const uncommittedJournalEntries = ref(0) |
| 60 | const throughputMetrics = ref<ThroughputMetric[]>([]) |
| 61 | const lastCheck = ref<null | Date>(null) |
| 62 | const getDataTimer = ref<NodeJS.Timeout | null>(null) |
| 63 | const dFormats = useSettingsStore().dateFormat |
| 64 | const intervalOptions = [ |
| 65 | { |
| 66 | label: "1 Second", |
| 67 | value: 1000 |
| 68 | }, |
| 69 | { |
| 70 | label: "5 Seconds", |
| 71 | value: 5000 |
| 72 | }, |
| 73 | { |
| 74 | label: "10 Seconds", |
| 75 | value: 10000 |
| 76 | }, |
| 77 | { |
| 78 | label: "30 Seconds", |
| 79 | value: 30000 |
| 80 | }, |
| 81 | { |
| 82 | label: "1 Minute", |
| 83 | value: 60000 |
| 84 | } |
| 85 | ] |
| 86 | const intervalSelected = useStorage<number>("metrics-interval", 5000, localStorage) |
| 87 | |
| 88 | const isRunning = computed<boolean>(() => { |
| 89 | return !!getDataTimer.value |
| 90 | }) |
| 91 | |
| 92 | function getData() { |
| 93 | loading.value = true |
| 94 | |
| 95 | Api.graylog |
| 96 | .getMetrics() |
| 97 | .then(res => { |
| 98 | if (res.data.success) { |
| 99 | throughputMetrics.value = res.data.throughput_metrics || [] |
| 100 | uncommittedJournalEntries.value = res.data.uncommitted_journal_entries || 0 |
| 101 | lastCheck.value = new Date() |
| 102 | } else { |
| 103 | message.warning(res.data?.message || "An error occurred. Please try again later.") |
| 104 | } |
| 105 | }) |
| 106 | .catch(err => { |
| 107 | message.error(err.response?.data?.message || "An error occurred. Please try again later.") |
| 108 | }) |
| 109 | .finally(() => { |
| 110 | loading.value = false |
| 111 | }) |
| 112 | } |
| 113 | |
| 114 | function stop() { |
| 115 | if (getDataTimer.value !== null) { |
| 116 | clearInterval(getDataTimer.value) |
| 117 | getDataTimer.value = null |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | function start() { |
| 122 | getDataTimer.value = setInterval(getData, intervalSelected.value) |
| 123 | } |
| 124 | |
| 125 | watch(intervalSelected, () => { |
| 126 | stop() |
| 127 | nextTick(() => { |
| 128 | start() |
| 129 | }) |
| 130 | }) |
| 131 | |
| 132 | onBeforeMount(() => { |
| 133 | getData() |
| 134 | start() |
| 135 | }) |
| 136 | |
| 137 | onBeforeUnmount(() => { |
| 138 | stop() |
| 139 | }) |
| 140 | </script> |