main
vue 196 lines 4.88 KB
Raw
1 <template>
2 <div class="sigma-queries-list">
3 <div ref="header" class="header @container flex items-center justify-end gap-2">
4 <div class="info flex grow gap-2">
5 <n-popover v-if="showInfoPopover" overlap placement="bottom-start">
6 <template #trigger>
7 <div class="bg-default rounded-lg">
8 <n-button size="small" class="cursor-help!">
9 <template #icon>
10 <Icon :name="InfoIcon" />
11 </template>
12 </n-button>
13 </div>
14 </template>
15 <div class="flex flex-col gap-2">
16 <div class="box">
17 Total :
18 <code>{{ total }}</code>
19 </div>
20 </div>
21 </n-popover>
22
23 <NewExclusionRuleButton
24 v-if="showCreationButton"
25 :hide-button-extended-label="simpleMode"
26 @success="getData()"
27 />
28 </div>
29
30 <div class="hidden @md:block">
31 <n-checkbox v-model:checked="filters.enabledOnly">Enabled only</n-checkbox>
32 </div>
33 <div class="block @md:hidden">
34 <n-popover overlap placement="right" class="px-0!">
35 <template #trigger>
36 <div class="bg-default rounded-lg">
37 <n-badge :show="filters.enabledOnly" dot type="success" :offset="[-3, 4]">
38 <n-button size="small">
39 <template #icon>
40 <Icon :name="FilterIcon" />
41 </template>
42 </n-button>
43 </n-badge>
44 </div>
45 </template>
46 <div class="py-1">
47 <div class="px-4">
48 <n-checkbox v-model:checked="filters.enabledOnly">Enabled only</n-checkbox>
49 </div>
50 </div>
51 </n-popover>
52 </div>
53
54 <n-pagination
55 v-model:page="currentPage"
56 v-model:page-size="pageSize"
57 :page-slot
58 :show-size-picker
59 :page-sizes
60 :item-count="total"
61 :simple="simpleMode"
62 />
63 </div>
64
65 <n-spin :show="loading">
66 <div class="my-3 flex min-h-52 flex-col gap-2">
67 <template v-if="list.length">
68 <ExclusionRuleItem
69 v-for="item of list"
70 :key="item.id"
71 :entity="item"
72 class="item-appear item-appear-bottom item-appear-005"
73 @deleted="getData()"
74 @updated="getData()"
75 />
76 </template>
77 <template v-else>
78 <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
79 </template>
80 </div>
81 </n-spin>
82
83 <div class="footer flex justify-end">
84 <n-pagination
85 v-if="list.length > 3"
86 v-model:page="currentPage"
87 :page-size
88 :item-count="total"
89 :page-slot="6"
90 />
91 </div>
92 </div>
93 </template>
94
95 <script setup lang="ts">
96 // TODO-FE: refactor
97 import type { ExclusionRulesQuery } from "@/api/endpoints/incidentManagement/exclusionRules"
98 import type { ExclusionRule } from "@/types/incidentManagement/exclusionRules.d"
99 import { useResizeObserver } from "@vueuse/core"
100 import { NBadge, NButton, NCheckbox, NEmpty, NPagination, NPopover, NSpin, useMessage } from "naive-ui"
101 import { onBeforeMount, ref, watch } from "vue"
102 import Api from "@/api"
103 import Icon from "@/components/common/Icon.vue"
104 import ExclusionRuleItem from "./ExclusionRuleItem.vue"
105 import NewExclusionRuleButton from "./NewExclusionRuleButton.vue"
106
107 const { showCreationButton = true, showInfoPopover = true } = defineProps<{
108 showCreationButton?: boolean
109 showInfoPopover?: boolean
110 }>()
111
112 const emit = defineEmits<{
113 (
114 e: "mounted",
115 value: {
116 reload: () => void
117 }
118 ): void
119 (e: "loaded", value: number): void
120 }>()
121
122 const FilterIcon = "carbon:filter-edit"
123 const InfoIcon = "carbon:information"
124 const message = useMessage()
125 const filters = ref({ enabledOnly: false })
126 const loading = ref(false)
127 const list = ref<ExclusionRule[]>([])
128 const total = ref(0)
129
130 const currentPage = ref(1)
131 const pageSizes = [10, 25, 50, 100]
132 const pageSize = ref(pageSizes[1])
133 const header = ref()
134 const pageSlot = ref(8)
135 const simpleMode = ref(false)
136 const showSizePicker = ref(true)
137
138 function getData() {
139 loading.value = true
140
141 const query: Partial<ExclusionRulesQuery> = {
142 pagination: {
143 limit: pageSize.value ?? 25,
144 skip: (currentPage.value - 1) * (pageSize.value ?? 25)
145 }
146 }
147
148 if (filters.value.enabledOnly) {
149 query.filters = { enabledOnly: filters.value.enabledOnly }
150 }
151
152 Api.incidentManagement.exclusionRules
153 .getExclusionRulesList(query)
154 .then(res => {
155 if (res.data.success) {
156 list.value = res.data.exclusions || []
157 total.value = res.data.pagination.total || 0
158 } else {
159 message.warning(res.data?.message || "An error occurred. Please try again later.")
160 }
161 })
162 .catch(err => {
163 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
164 })
165 .finally(() => {
166 loading.value = false
167 emit("loaded", total.value)
168 })
169 }
170
171 useResizeObserver(header, entries => {
172 const entry = entries[0]
173 if (!entry) return
174
175 const { width } = entry.contentRect
176
177 pageSlot.value = width < 700 ? 5 : 8
178 simpleMode.value = width < 550
179 })
180
181 watch(pageSize, () => {
182 currentPage.value = 1
183 })
184
185 watch([currentPage, pageSize, () => filters.value.enabledOnly], () => {
186 getData()
187 })
188
189 onBeforeMount(() => {
190 getData()
191
192 emit("mounted", {
193 reload: getData
194 })
195 })
196 </script>