main
vue 267 lines 6.85 KB
Raw
1 <template>
2 <n-spin :show="loading" class="source-configuration-wizard">
3 <div class="flex min-h-48 flex-col">
4 <div class="flex grow flex-col">
5 <n-scrollbar x-scrollable trigger="none">
6 <div class="p-6 pt-3">
7 <n-steps :current size="small" :status="currentStatus">
8 <n-step title="Source" />
9 <n-step title="Configuration" />
10 </n-steps>
11 </div>
12 </n-scrollbar>
13
14 <div class="mt-4 flex grow flex-col">
15 <Transition :name="`slide-form-${slideFormDirection}`">
16 <div v-if="current === 1" class="flex flex-col gap-4 px-7">
17 <n-select
18 v-model:value="selectedIndex"
19 placeholder="Indices list"
20 clearable
21 filterable
22 to="body"
23 :loading="loadingIndices"
24 :options="indexNamesOptions"
25 @update:value="setSourceConfiguration(selectedIndex)"
26 ></n-select>
27
28 <div class="flex justify-end gap-4">
29 <n-button @click="overrideMode()">Manual override</n-button>
30 <n-button
31 v-if="isNextStepEnabled"
32 icon-placement="right"
33 :disabled="!selectedIndex"
34 @click="standardMode()"
35 >
36 <template #icon>
37 <Icon :name="ArrowRightIcon" />
38 </template>
39 Next
40 </n-button>
41 </div>
42 </div>
43
44 <div v-else-if="current === 2" class="flex min-h-[401px] grow flex-col px-7 pb-7">
45 <SourceConfigurationForm
46 v-if="sourceConfigurationModel"
47 :source-configuration-model
48 show-source-field
49 disable-source-field
50 :show-index-name-field
51 :arbitrary-source-field
52 disable-index-name-field
53 :disabled-sources
54 @mounted="formCTX = $event"
55 @submitted="createSourceConfiguration($event)"
56 >
57 <template #additionalActions>
58 <n-button v-if="isPrevStepEnabled" :disabled="submitting" @click="prev()">
59 <template #icon>
60 <Icon :name="ArrowLeftIcon" />
61 </template>
62 Prev
63 </n-button>
64 </template>
65 </SourceConfigurationForm>
66 </div>
67 </Transition>
68 </div>
69 </div>
70 </div>
71 </n-spin>
72 </template>
73
74 <script setup lang="ts">
75 import type { StepsProps } from "naive-ui"
76 import type { ApiError } from "@/types/common.d"
77 import type { SourceConfiguration, SourceConfigurationModel, SourceName } from "@/types/incidentManagement/sources.d"
78 import { NButton, NScrollbar, NSelect, NSpin, NStep, NSteps, useMessage } from "naive-ui"
79 import { computed, onBeforeMount, onMounted, ref, toRefs, watch } from "vue"
80 import Api from "@/api"
81 import Icon from "@/components/common/Icon.vue"
82 import SourceConfigurationForm from "./SourceConfigurationForm.vue"
83
84 const props = defineProps<{ disabledSources?: SourceName[] }>()
85
86 const emit = defineEmits<{
87 (e: "update:loading", value: boolean): void
88 (e: "submitted"): void
89 (
90 e: "mounted",
91 value: {
92 reset: () => void
93 }
94 ): void
95 }>()
96
97 const { disabledSources } = toRefs(props)
98
99 const ArrowLeftIcon = "carbon:arrow-left"
100 const ArrowRightIcon = "carbon:arrow-right"
101 const loadingIndices = ref(false)
102 const submitting = ref(false)
103 const loading = computed(() => submitting.value)
104 const slideFormDirection = ref<"right" | "left">("right")
105 const message = useMessage()
106 const current = ref<number>(1)
107 const currentStatus = ref<StepsProps["status"]>("process")
108 const formCTX = ref<{ reset: () => void; toggleSubmittingFlag: () => boolean } | null>(null)
109 const selectedIndex = ref<string | null>(null)
110 const sourceConfigurationModel = ref<SourceConfigurationModel | null>(null)
111 const indexNamesOptions = ref<{ label: string; value: string }[]>([])
112
113 watch(loading, val => {
114 emit("update:loading", val)
115 })
116
117 const isPrevStepEnabled = computed(() => current.value > 1)
118 const isNextStepEnabled = computed(() => current.value < 2)
119 const showIndexNameField = ref(true)
120 const arbitrarySourceField = ref(false)
121
122 function overrideMode() {
123 showIndexNameField.value = false
124 arbitrarySourceField.value = true
125 setSourceConfiguration(null)
126 next()
127 }
128
129 function standardMode() {
130 showIndexNameField.value = true
131 arbitrarySourceField.value = false
132 next()
133 }
134
135 function next() {
136 currentStatus.value = "process"
137 slideFormDirection.value = "right"
138 current.value++
139 }
140
141 function prev() {
142 currentStatus.value = "process"
143 slideFormDirection.value = "left"
144 current.value--
145 formCTX.value?.reset()
146 }
147
148 function reset(force?: boolean) {
149 if (!submitting.value || force) {
150 currentStatus.value = "process"
151 slideFormDirection.value = "right"
152 current.value = 1
153 selectedIndex.value = null
154 sourceConfigurationModel.value = null
155 formCTX.value?.reset()
156 }
157 }
158
159 function setSourceConfiguration(indexName: string | null) {
160 if (indexName) {
161 sourceConfigurationModel.value = {
162 field_names: [],
163 ioc_field_names: [],
164 asset_name: null,
165 timefield_name: null,
166 alert_title_name: null,
167 source: "",
168 index_name: indexName
169 }
170 next()
171 } else {
172 sourceConfigurationModel.value = {
173 field_names: [],
174 ioc_field_names: [],
175 asset_name: null,
176 timefield_name: null,
177 alert_title_name: null,
178 source: "",
179 index_name: ""
180 }
181 }
182 }
183
184 function getIndices() {
185 loadingIndices.value = true
186
187 Api.graylog
188 .getIndices()
189 .then(res => {
190 if (res.data.success) {
191 indexNamesOptions.value = (res.data?.indices || []).map(o => ({
192 label: o.index_name,
193 value: o.index_name
194 }))
195 } else {
196 message.warning(res.data?.message || "An error occurred. Please try again later.")
197 }
198 })
199 .catch(err => {
200 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
201 })
202 .finally(() => {
203 loadingIndices.value = false
204 })
205 }
206
207 function createSourceConfiguration(payload: SourceConfiguration) {
208 submitting.value = formCTX.value?.toggleSubmittingFlag() || true
209
210 Api.incidentManagement.sources
211 .createSourceConfiguration(payload)
212 .then(res => {
213 if (res.data.success) {
214 message.success(res.data?.message || `Source Configuration sent successfully`)
215 reset(true)
216 emit("submitted")
217 } else {
218 message.warning(res.data?.message || "An error occurred. Please try again later.")
219 }
220 })
221 .catch((err: ApiError) => {
222 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
223 })
224 .finally(() => {
225 submitting.value = formCTX.value?.toggleSubmittingFlag() || false
226 })
227 }
228
229 onBeforeMount(() => {
230 getIndices()
231 })
232
233 onMounted(() => {
234 emit("mounted", {
235 reset
236 })
237 })
238 </script>
239
240 <style lang="scss" scoped>
241 .source-configuration-wizard {
242 .slide-form-right-enter-active,
243 .slide-form-right-leave-active,
244 .slide-form-left-enter-active,
245 .slide-form-left-leave-active {
246 transition: all 0.2s ease-out;
247 position: absolute;
248 width: 100%;
249 }
250
251 .slide-form-left-enter-from {
252 transform: translateX(-100%);
253 }
254
255 .slide-form-left-leave-to {
256 transform: translateX(100%);
257 }
258
259 .slide-form-right-enter-from {
260 transform: translateX(100%);
261 }
262
263 .slide-form-right-leave-to {
264 transform: translateX(-100%);
265 }
266 }
267 </style>