main
vue 141 lines 3.61 KB
Raw
1 <template>
2 <n-popover v-model:show="show" trigger="manual" to="body" content-class="px-0" @clickoutside="closePopup()">
3 <template #trigger>
4 <slot :loading :toggle-popup />
5 </template>
6
7 <div class="flex flex-col gap-4 py-1">
8 <div class="flex items-center gap-2">
9 <n-input-group>
10 <n-select
11 v-model:value="model.unit"
12 :options="unitOptions"
13 placeholder="Time unit"
14 :disabled="loading"
15 class="w-28!"
16 />
17 <n-input-number
18 v-model:value="model.time"
19 :min="1"
20 clearable
21 placeholder="Time"
22 class="w-32!"
23 :disabled="loading"
24 />
25 </n-input-group>
26 </div>
27
28 <div class="flex justify-between gap-2">
29 <n-button quaternary size="small" @click="closePopup()">Close</n-button>
30 <n-button
31 :disabled="!dirty || !isValid"
32 :loading
33 type="primary"
34 size="small"
35 @click="updateTimeInterval()"
36 >
37 Save
38 </n-button>
39 </div>
40 </div>
41 </n-popover>
42 </template>
43
44 <script setup lang="ts">
45 // TODO-FE: refactor
46 import type { SigmaQuery, SigmaTimeInterval, SigmaTimeIntervalUnit } from "@/types/sigma.d"
47 import { NButton, NInputGroup, NInputNumber, NPopover, NSelect, useMessage } from "naive-ui"
48 import { computed, onBeforeMount, ref, toRefs, watch } from "vue"
49 import Api from "@/api"
50
51 const props = defineProps<{
52 query: SigmaQuery
53 }>()
54
55 const emit = defineEmits<{
56 (e: "updated", value: SigmaQuery): void
57 }>()
58
59 const { query } = toRefs(props)
60
61 const loading = defineModel<boolean | undefined>("loading", { default: false })
62
63 const show = ref(false)
64 const lastShow = ref(Date.now())
65 const message = useMessage()
66 const model = ref<{ time: number; unit: SigmaTimeIntervalUnit }>({ time: 1, unit: "m" })
67 const unitOptions = [
68 { label: "Minutes", value: "m" },
69 { label: "Hours", value: "h" },
70 { label: "Days", value: "d" }
71 ]
72 const timeUnit = ref<SigmaTimeIntervalUnit>("m")
73 const timeValue = ref<number>(1)
74
75 const timeInterval = computed<SigmaTimeInterval>(() => `${timeValue.value}${timeUnit.value}`)
76 const modelTimeInterval = computed<SigmaTimeInterval>(() => `${model.value.time}${model.value.unit}`)
77
78 const dirty = computed(() => timeInterval.value !== modelTimeInterval.value)
79 const isValid = computed(() => model.value.time && model.value.unit)
80
81 watch(show, val => {
82 if (val && !loading.value) {
83 setModel()
84 }
85 })
86
87 function togglePopup() {
88 if (Date.now() - lastShow.value > 500) {
89 show.value = !show.value
90 }
91 }
92
93 function closePopup() {
94 lastShow.value = Date.now()
95 show.value = false
96 }
97
98 const NUMBER_REGEX = /\d+/
99 const LETTER_REGEX = /[a-z]/i
100
101 function setModel() {
102 if (query.value.time_interval) {
103 timeUnit.value = (
104 query.value.time_interval.match(LETTER_REGEX)?.[0] || "m"
105 ).toLocaleLowerCase() as SigmaTimeIntervalUnit
106 timeValue.value = Number.parseInt(query.value.time_interval.match(NUMBER_REGEX)?.[0] || "1")
107
108 model.value.unit = timeUnit.value
109 model.value.time = timeValue.value
110 }
111 }
112
113 function updateTimeInterval() {
114 if (query.value.rule_name && modelTimeInterval.value) {
115 loading.value = true
116
117 Api.sigma
118 .setQueryTimeInterval(query.value.rule_name, modelTimeInterval.value)
119 .then(res => {
120 if (res.data.success) {
121 if (res.data.sigma_queries[0]) {
122 emit("updated", res.data.sigma_queries[0])
123 }
124 message.success(res.data?.message || "Sigma query updated successfully")
125 } else {
126 message.warning(res.data?.message || "An error occurred. Please try again later.")
127 }
128 })
129 .catch(err => {
130 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
131 })
132 .finally(() => {
133 loading.value = false
134 })
135 }
136 }
137
138 onBeforeMount(() => {
139 setModel()
140 })
141 </script>