main
vue 163 lines 4.42 KB
Raw
1 <template>
2 <div class="flex flex-col gap-2">
3 <div class="flex items-center justify-between">
4 <p class="text-secondary text-sm">Dashboard Categories</p>
5 <span class="text-secondary text-sm">{{ categories.length }} available</span>
6 </div>
7
8 <n-spin :show="loadingCategories">
9 <div
10 v-if="categories.length"
11 class="grid grid-cols-1 gap-3 @xl:grid-cols-2 @3xl:grid-cols-3 @6xl:grid-cols-4"
12 >
13 <DashboardCategoryCard
14 v-for="cat in categories"
15 :key="cat.id"
16 :category="cat"
17 :selected="selectedCategoryId === cat.id"
18 @select="selectCategory(cat.id)"
19 />
20 </div>
21 <n-empty v-else-if="!loadingCategories" description="No dashboard categories found" />
22 </n-spin>
23
24 <n-drawer
25 v-model:show="showCategoryDrawer"
26 display-directive="show"
27 :width="760"
28 class="max-w-[92vw]"
29 :trap-focus="false"
30 >
31 <n-drawer-content :title="drawerTitle" closable :native-scrollbar="false">
32 <DashboardCategoryDrawerContent
33 v-model:selected-event-source-id="selectedEventSourceId"
34 :category="selectedCategory"
35 :category-meta="selectedCategoryMeta ?? null"
36 :loading-templates
37 :selected-customer-code
38 :loading-event-sources
39 :event-sources-list
40 :selected-category-id
41 :enabled-dashboards
42 @refresh-enabled-dashboards="emit('refreshEnabledDashboards')"
43 />
44 </n-drawer-content>
45 </n-drawer>
46 </div>
47 </template>
48
49 <script setup lang="ts">
50 import type { DashboardCategory, DashboardCategoryWithTemplates, EnabledDashboard } from "@/types/dashboards.d"
51 import type { EventSource } from "@/types/eventSources.d"
52 import { NDrawer, NDrawerContent, NEmpty, NSpin, useMessage } from "naive-ui"
53 import { computed, onBeforeMount, ref, watch } from "vue"
54 import Api from "@/api"
55 import DashboardCategoryCard from "./DashboardCategoryCard.vue"
56 import DashboardCategoryDrawerContent from "./DashboardCategoryDrawerContent.vue"
57
58 const props = defineProps<{
59 selectedCustomerCode: string | null
60 eventSourcesList: EventSource[]
61 loadingEventSources: boolean
62 enabledDashboards: EnabledDashboard[]
63 }>()
64
65 const emit = defineEmits<{
66 refreshEnabledDashboards: []
67 }>()
68
69 const message = useMessage()
70
71 const loadingCategories = ref(false)
72 const categories = ref<DashboardCategory[]>([])
73 const selectedCategoryId = ref<string | null>(null)
74 const selectedCategory = ref<DashboardCategoryWithTemplates | null>(null)
75 const loadingTemplates = ref(false)
76 const selectedEventSourceId = ref<number | null>(null)
77
78 const selectedCategoryMeta = computed(() =>
79 selectedCategoryId.value ? categories.value.find(cat => cat.id === selectedCategoryId.value) : null
80 )
81
82 const drawerTitle = computed(() => selectedCategory.value?.title ?? selectedCategoryMeta.value?.title ?? "Category")
83
84 const showCategoryDrawer = computed({
85 get: () => selectedCategoryId.value !== null,
86 set(open: boolean) {
87 if (!open) {
88 selectedCategoryId.value = null
89 selectedCategory.value = null
90 }
91 }
92 })
93
94 function getCategories() {
95 loadingCategories.value = true
96 Api.siem
97 .getDashboardCategories()
98 .then(res => {
99 if (res.data.success) {
100 categories.value = res.data?.categories || []
101 } else {
102 message.warning(res.data?.message || "An error occurred. Please try again later.")
103 }
104 })
105 .catch(err => {
106 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
107 })
108 .finally(() => {
109 loadingCategories.value = false
110 })
111 }
112
113 function selectCategory(categoryId: string) {
114 if (selectedCategoryId.value === categoryId) {
115 showCategoryDrawer.value = false
116 return
117 }
118
119 selectedCategoryId.value = categoryId
120 selectedCategory.value = null
121 loadingTemplates.value = true
122
123 Api.siem
124 .getDashboardCategory(categoryId)
125 .then(res => {
126 if (res.data.success) {
127 selectedCategory.value = res.data.category
128 } else {
129 message.warning(res.data?.message || "An error occurred. Please try again later.")
130 }
131 })
132 .catch(err => {
133 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
134 })
135 .finally(() => {
136 loadingTemplates.value = false
137 })
138 }
139
140 watch(
141 () => props.selectedCustomerCode,
142 () => {
143 selectedEventSourceId.value = null
144 }
145 )
146
147 watch(
148 () => props.eventSourcesList,
149 sources => {
150 if (!selectedEventSourceId.value) return
151
152 const hasSelectedSource = sources.some(source => source.enabled && source.id === selectedEventSourceId.value)
153
154 if (!hasSelectedSource) {
155 selectedEventSourceId.value = null
156 }
157 }
158 )
159
160 onBeforeMount(() => {
161 getCategories()
162 })
163 </script>