| 1 | <template> |
| 2 | <div v-if="visible" ref="wrapperRef" class="flex flex-col gap-2"> |
| 3 | <div class="flex items-center justify-between"> |
| 4 | <p class="text-secondary text-sm">Enabled Dashboards</p> |
| 5 | <span class="text-secondary text-sm">{{ enabledDashboards.length }} enabled</span> |
| 6 | </div> |
| 7 | |
| 8 | <n-data-table |
| 9 | bordered |
| 10 | :loading="loadingEnabled" |
| 11 | size="small" |
| 12 | :data="enabledDashboards" |
| 13 | :columns="enabledColumns" |
| 14 | :scroll-x="600" |
| 15 | :pagination="false" |
| 16 | class="[&_.n-data-table-th\_\_title]:whitespace-nowrap" |
| 17 | > |
| 18 | <template #empty> |
| 19 | <n-empty description="No enabled dashboards" /> |
| 20 | </template> |
| 21 | </n-data-table> |
| 22 | </div> |
| 23 | </template> |
| 24 | |
| 25 | <script setup lang="ts"> |
| 26 | import type { DataTableColumns } from "naive-ui" |
| 27 | import type { EnabledDashboard } from "@/types/dashboards.d" |
| 28 | import type { EventSource } from "@/types/eventSources.d" |
| 29 | import { useElementSize } from "@vueuse/core" |
| 30 | import { NButton, NDataTable, NEmpty, useDialog, useMessage } from "naive-ui" |
| 31 | import { computed, h, ref, useTemplateRef, watch } from "vue" |
| 32 | import { useRouter } from "vue-router" |
| 33 | import Api from "@/api" |
| 34 | |
| 35 | const props = defineProps<{ |
| 36 | customerCode: string | null |
| 37 | visible: boolean |
| 38 | eventSourcesList: EventSource[] |
| 39 | }>() |
| 40 | |
| 41 | const enabledDashboards = defineModel<EnabledDashboard[]>("enabledDashboards", { default: () => [] }) |
| 42 | |
| 43 | const loadingEnabled = ref(false) |
| 44 | |
| 45 | const message = useMessage() |
| 46 | const dialog = useDialog() |
| 47 | const { width: headerWidthRef } = useElementSize(useTemplateRef("wrapperRef")) |
| 48 | const router = useRouter() |
| 49 | const simpleMode = computed(() => headerWidthRef.value < 600) |
| 50 | |
| 51 | function fetchEnabledDashboards(customerCode: string) { |
| 52 | loadingEnabled.value = true |
| 53 | |
| 54 | Api.siem |
| 55 | .getEnabledDashboards(customerCode) |
| 56 | .then(res => { |
| 57 | if (res.data.success) { |
| 58 | enabledDashboards.value = res.data?.enabled_dashboards || [] |
| 59 | } else { |
| 60 | message.warning(res.data?.message || "An error occurred. Please try again later.") |
| 61 | } |
| 62 | }) |
| 63 | .catch(err => { |
| 64 | message.error(err.response?.data?.message || "An error occurred. Please try again later.") |
| 65 | }) |
| 66 | .finally(() => { |
| 67 | loadingEnabled.value = false |
| 68 | }) |
| 69 | } |
| 70 | |
| 71 | function refreshEnabledDashboards() { |
| 72 | const code = props.customerCode |
| 73 | if (code) { |
| 74 | fetchEnabledDashboards(code) |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | watch( |
| 79 | () => props.customerCode, |
| 80 | code => { |
| 81 | if (!code) { |
| 82 | loadingEnabled.value = false |
| 83 | enabledDashboards.value = [] |
| 84 | return |
| 85 | } |
| 86 | fetchEnabledDashboards(code) |
| 87 | }, |
| 88 | { immediate: true } |
| 89 | ) |
| 90 | |
| 91 | defineExpose({ |
| 92 | refreshEnabledDashboards |
| 93 | }) |
| 94 | |
| 95 | const enabledColumns = computed<DataTableColumns<EnabledDashboard>>(() => [ |
| 96 | { title: "Display Name", key: "display_name", minWidth: 240 }, |
| 97 | { title: "Category", key: "library_card", width: 150 }, |
| 98 | { title: "Template", key: "template_id", width: 180 }, |
| 99 | { |
| 100 | title: "Event Source", |
| 101 | key: "event_source_id", |
| 102 | width: 180, |
| 103 | render(row) { |
| 104 | const source = props.eventSourcesList.find(s => s.id === row.event_source_id) |
| 105 | return source ? `${source.name} (${source.event_type})` : `#${row.event_source_id}` |
| 106 | } |
| 107 | }, |
| 108 | { |
| 109 | title: "Created", |
| 110 | key: "created_at", |
| 111 | width: 180, |
| 112 | render(row) { |
| 113 | return new Date(row.created_at).toLocaleString() |
| 114 | } |
| 115 | }, |
| 116 | { |
| 117 | title: "", |
| 118 | key: "actions", |
| 119 | width: 160, |
| 120 | fixed: simpleMode.value ? undefined : "right", |
| 121 | render(row) { |
| 122 | return h("div", { class: "flex gap-2" }, [ |
| 123 | h( |
| 124 | NButton, |
| 125 | { |
| 126 | size: "small", |
| 127 | type: "primary", |
| 128 | quaternary: true, |
| 129 | onClick: () => { |
| 130 | router.push({ name: "DashboardView", params: { id: String(row.id) } }) |
| 131 | } |
| 132 | }, |
| 133 | { default: () => "View" } |
| 134 | ), |
| 135 | h( |
| 136 | NButton, |
| 137 | { |
| 138 | size: "small", |
| 139 | type: "error", |
| 140 | quaternary: true, |
| 141 | onClick: () => { |
| 142 | dialog.warning({ |
| 143 | title: "Disable Dashboard", |
| 144 | content: `Are you sure you want to disable "${row.display_name}"?`, |
| 145 | positiveText: "Disable", |
| 146 | negativeText: "Cancel", |
| 147 | onPositiveClick: () => { |
| 148 | Api.siem |
| 149 | .disableDashboard(row.id) |
| 150 | .then(res => { |
| 151 | if (res.data.success) { |
| 152 | message.success("Dashboard disabled successfully") |
| 153 | refreshEnabledDashboards() |
| 154 | } else { |
| 155 | message.warning( |
| 156 | res.data?.message || "An error occurred. Please try again later." |
| 157 | ) |
| 158 | } |
| 159 | }) |
| 160 | .catch(err => { |
| 161 | message.error( |
| 162 | err.response?.data?.message || |
| 163 | "An error occurred. Please try again later." |
| 164 | ) |
| 165 | }) |
| 166 | } |
| 167 | }) |
| 168 | } |
| 169 | }, |
| 170 | { default: () => "Disable" } |
| 171 | ) |
| 172 | ]) |
| 173 | } |
| 174 | } |
| 175 | ]) |
| 176 | </script> |