1
+<template>
2
+ <n-spin :show="loading" class="creation-report-form">
3
+ <n-form :label-width="80" :model="form" :rules="rules" ref="formRef">
4
+ <div class="flex flex-col gap-2">
5
+ <div class="flex gap-4 items-start">
6
+ <n-form-item label="Type" path="report_type" class="w-32">
7
+ <n-select
8
+ v-model:value="form.report_type"
9
+ :options="reportTypeOptions"
10
+ placeholder="Select..."
11
+ clearable
12
+ :loading="loadingOptions"
13
+ />
14
+ </n-form-item>
15
+ <n-form-item label="Name" path="report_name" class="grow">
16
+ <n-input
17
+ v-model:value.trim="form.report_name"
18
+ placeholder="Please insert Report Name"
19
+ clearable
20
+ />
21
+ </n-form-item>
22
+ </div>
23
+ <div class="flex flex-col gap-2">
24
+ <n-form-item label="Access Key ID" path="access_key_id">
25
+ <n-input
26
+ v-model:value.trim="form.access_key_id"
27
+ placeholder="Please insert Access Key ID"
28
+ clearable
29
+ />
30
+ </n-form-item>
31
+ <n-form-item label="Secret Access Key" path="secret_access_key">
32
+ <n-input
33
+ v-model:value.trim="form.secret_access_key"
34
+ placeholder="Please insert Secret Access Key"
35
+ type="password"
36
+ show-password-on="click"
37
+ clearable
38
+ />
39
+ </n-form-item>
40
+ </div>
41
+
42
+ <div class="flex justify-between gap-4">
43
+ <n-button @click="reset()" :disabled="loading">Reset</n-button>
44
+ <n-button
45
+ type="primary"
46
+ :disabled="!isValid"
47
+ @click="validate(() => submit())"
48
+ :loading="submitting"
49
+ >
50
+ Submit
51
+ </n-button>
52
+ </div>
53
+ </div>
54
+ </n-form>
55
+ </n-spin>
56
+</template>
57
+
58
+<script setup lang="ts">
59
+import { computed, onBeforeMount, onMounted, ref } from "vue"
60
+import Api from "@/api"
61
+import {
62
+ useMessage,
63
+ NForm,
64
+ NFormItem,
65
+ NInput,
66
+ NButton,
67
+ NSpin,
68
+ NSelect,
69
+ type FormValidationError,
70
+ type FormInst,
71
+ type FormRules,
72
+ type MessageReactive
73
+} from "naive-ui"
74
+import type { ScoutSuiteReportPayload } from "@/types/cloudSecurityAssessment.d"
75
+
76
+type FormPayload = Omit<ScoutSuiteReportPayload, "report_type"> & { report_type: string | null }
77
+
78
+const emit = defineEmits<{
79
+ (e: "submitted"): void
80
+ (
81
+ e: "mounted",
82
+ value: {
83
+ reset: () => void
84
+ }
85
+ ): void
86
+}>()
87
+
88
+const submitting = ref(false)
89
+const loadingOptions = ref(false)
90
+const loading = computed(() => submitting.value || loadingOptions.value)
91
+const message = useMessage()
92
+const form = ref<FormPayload>(getClearForm())
93
+const formRef = ref<FormInst | null>(null)
94
+
95
+const availableTypes = ["aws"]
96
+
97
+const reportTypeOptions = ref<{ label: string; value: string; disabled: boolean }[]>([])
98
+
99
+const rules: FormRules = {
100
+ report_type: {
101
+ required: true,
102
+ message: "Please input the Report Type",
103
+ trigger: ["input", "blur"]
104
+ },
105
+ access_key_id: {
106
+ required: true,
107
+ message: "Please input the Access Key ID",
108
+ trigger: ["input", "blur"]
109
+ },
110
+ secret_access_key: {
111
+ required: true,
112
+ message: "Please input the Secret Access Key",
113
+ trigger: ["input", "blur"]
114
+ },
115
+ report_name: {
116
+ required: true,
117
+ message: "Please input the Report Name",
118
+ trigger: ["input", "blur"]
119
+ }
120
+}
121
+
122
+let validationMessage: MessageReactive | null = null
123
+
124
+const isValid = computed(() => {
125
+ if (!form.value.access_key_id) {
126
+ return false
127
+ }
128
+ if (!form.value.secret_access_key) {
129
+ return false
130
+ }
131
+ if (!form.value.report_type) {
132
+ return false
133
+ }
134
+ if (!form.value.report_name) {
135
+ return false
136
+ }
137
+
138
+ return true
139
+})
140
+
141
+function validate(cb?: () => void) {
142
+ if (!formRef.value) return
143
+
144
+ formRef.value.validate((errors?: Array<FormValidationError>) => {
145
+ if (!errors) {
146
+ validationMessage?.destroy()
147
+ validationMessage = null
148
+ if (cb) cb()
149
+ } else {
150
+ if (!validationMessage) {
151
+ validationMessage = message.warning("You must fill in the required fields correctly.")
152
+ }
153
+ return false
154
+ }
155
+ })
156
+}
157
+
158
+function getClearForm(): FormPayload {
159
+ return {
160
+ report_type: null,
161
+ access_key_id: "",
162
+ secret_access_key: "",
163
+ report_name: ""
164
+ }
165
+}
166
+
167
+function reset() {
168
+ if (!loading.value) {
169
+ resetForm()
170
+ formRef.value?.restoreValidation()
171
+ }
172
+}
173
+
174
+function resetForm() {
175
+ form.value = getClearForm()
176
+}
177
+
178
+function submit() {
179
+ const method = form.value.report_type === "aws" ? "generateAwsScoutSuiteReport" : null
180
+
181
+ if (!method) {
182
+ return
183
+ }
184
+
185
+ submitting.value = true
186
+
187
+ const payload: ScoutSuiteReportPayload = {
188
+ ...form.value,
189
+ report_type: form.value.report_type || ""
190
+ }
191
+
192
+ Api.cloudSecurityAssessment[method](payload)
193
+ .then(res => {
194
+ if (res.data.success) {
195
+ message.success(res.data?.message || `ScoutSuite report generation started successfully`, {
196
+ duration: 10 * 1000
197
+ })
198
+ emit("submitted")
199
+ resetForm()
200
+ } else {
201
+ message.warning(res.data?.message || "An error occurred. Please try again later.")
202
+ }
203
+ })
204
+ .catch(err => {
205
+ message.error(err.response?.data?.message || "An error occurred. Please try again later.")
206
+ })
207
+ .finally(() => {
208
+ submitting.value = false
209
+ })
210
+}
211
+
212
+function getScoutSuiteReportGenerationOptions() {
213
+ loadingOptions.value = true
214
+
215
+ Api.cloudSecurityAssessment
216
+ .getScoutSuiteReportGenerationOptions()
217
+ .then(res => {
218
+ if (res.data.success) {
219
+ reportTypeOptions.value = (res.data?.options || []).map(o => ({
220
+ label: o.toUpperCase(),
221
+ value: o,
222
+ disabled: !availableTypes.includes(o)
223
+ }))
224
+ } else {
225
+ message.warning(res.data?.message || "An error occurred. Please try again later.")
226
+ }
227
+ })
228
+ .catch(err => {
229
+ message.error(err.response?.data?.message || "An error occurred. Please try again later.")
230
+ })
231
+ .finally(() => {
232
+ loadingOptions.value = false
233
+ })
234
+}
235
+
236
+onBeforeMount(() => {
237
+ getScoutSuiteReportGenerationOptions()
238
+})
239
+
240
+onMounted(() => {
241
+ emit("mounted", {
242
+ reset
243
+ })
244
+})
245
+</script>