main
vue 280 lines 7.09 KB
Raw
1 <template>
2 <n-spin :show="loading" class="creation-report-form">
3 <n-form ref="baseFormRef" :model="baseForm" :rules>
4 <div class="flex flex-col gap-2">
5 <div class="flex items-start gap-4">
6 <n-form-item label="Type" path="report_type" class="w-32">
7 <n-select
8 v-model:value="baseForm.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="baseForm.report_name"
18 placeholder="Please insert Report Name"
19 clearable
20 />
21 </n-form-item>
22 </div>
23
24 <AwsTypeForm
25 v-if="baseForm.report_type === ScoutSuiteReportType.AWS"
26 @model="typeForm = $event"
27 @valid="typeFormValid = $event"
28 @mounted="typeFormRef = $event"
29 />
30
31 <AzureTypeForm
32 v-if="baseForm.report_type === ScoutSuiteReportType.Azure"
33 @model="typeForm = $event"
34 @valid="typeFormValid = $event"
35 @mounted="typeFormRef = $event"
36 />
37
38 <GcpTypeForm
39 v-if="baseForm.report_type === ScoutSuiteReportType.Gcp"
40 @model="typeForm = $event"
41 @valid="typeFormValid = $event"
42 @mounted="typeFormRef = $event"
43 />
44
45 <div class="mt-8 flex justify-between gap-4">
46 <n-button :disabled="loading" @click="reset()">Reset</n-button>
47 <n-button
48 type="primary"
49 :disabled="!isValid"
50 :loading="submitting"
51 @click="validate(() => submit())"
52 >
53 Submit
54 </n-button>
55 </div>
56 </div>
57 </n-form>
58 </n-spin>
59 </template>
60
61 <script setup lang="ts">
62 import type { FormInst, FormRules, FormValidationError, MessageReactive } from "naive-ui"
63 import type {
64 ScoutSuiteAwsReportPayload,
65 ScoutSuiteAzureReportPayload,
66 ScoutSuiteGcpReportPayload,
67 ScoutSuiteReportPayload
68 } from "@/types/cloudSecurityAssessment.d"
69 import type { ApiCommonResponse, ApiError } from "@/types/common.d"
70 import { NButton, NForm, NFormItem, NInput, NSelect, NSpin, useMessage } from "naive-ui"
71 import { computed, onBeforeMount, onMounted, ref, watch } from "vue"
72 import Api from "@/api"
73 import { ScoutSuiteReportType } from "@/types/cloudSecurityAssessment.d"
74 import AwsTypeForm from "./FormTypes/AwsTypeForm.vue"
75 import AzureTypeForm from "./FormTypes/AzureTypeForm.vue"
76 import GcpTypeForm from "./FormTypes/GcpTypeForm.vue"
77
78 type BaseFormPayload = Omit<ScoutSuiteReportPayload, "report_type"> & { report_type: ScoutSuiteReportType | null }
79 type TypeFormPayload = Partial<ScoutSuiteAwsReportPayload | ScoutSuiteAzureReportPayload | ScoutSuiteGcpReportPayload>
80
81 const emit = defineEmits<{
82 (e: "submitted"): void
83 (
84 e: "mounted",
85 value: {
86 reset: () => void
87 }
88 ): void
89 }>()
90
91 const submitting = ref(false)
92 const loadingOptions = ref(false)
93 const loading = computed(() => submitting.value || loadingOptions.value)
94 const message = useMessage()
95 const baseForm = ref<BaseFormPayload>(getClearBaseForm())
96 const typeForm = ref<TypeFormPayload | null>(null)
97 const typeFormValid = ref<boolean>(false)
98 const baseFormRef = ref<FormInst | null>(null)
99 const typeFormRef = ref<FormInst | null>(null)
100
101 const availableTypes = ["aws", "azure", "gcp"]
102
103 const reportTypeOptions = ref<{ label: string; value: string; disabled: boolean }[]>([])
104
105 const rules: FormRules = {
106 report_type: {
107 required: true,
108 message: "Please input the Report Type",
109 trigger: ["input", "blur"]
110 },
111 report_name: {
112 required: true,
113 message: "Please input the Report Name",
114 trigger: ["input", "blur"]
115 }
116 }
117
118 let validationMessage: MessageReactive | null = null
119
120 const isValid = computed(() => {
121 if (!baseForm.value.report_type) {
122 return false
123 }
124 if (!baseForm.value.report_name) {
125 return false
126 }
127
128 if (!typeFormValid.value) {
129 return false
130 }
131
132 return true
133 })
134
135 watch(
136 () => baseForm.value.report_type,
137 () => {
138 typeForm.value = null
139 typeFormRef.value = null
140 typeFormValid.value = false
141 }
142 )
143
144 function validate(cb?: () => void) {
145 if (!baseFormRef.value || !typeFormRef.value) return
146
147 baseFormRef.value.validate((errors?: Array<FormValidationError>) => {
148 if (!errors) {
149 validationMessage?.destroy()
150 validationMessage = null
151 ;(typeFormRef.value as FormInst).validate((errors?: Array<FormValidationError>) => {
152 if (!errors) {
153 validationMessage?.destroy()
154 validationMessage = null
155 if (cb) cb()
156 } else {
157 if (!validationMessage) {
158 validationMessage = message.warning("You must fill in the required fields correctly.")
159 }
160 return false
161 }
162 })
163 } else {
164 if (!validationMessage) {
165 validationMessage = message.warning("You must fill in the required fields correctly.")
166 }
167 return false
168 }
169 })
170 }
171
172 function getClearBaseForm(): BaseFormPayload {
173 return {
174 report_type: null,
175 report_name: ""
176 }
177 }
178
179 function reset() {
180 if (!loading.value) {
181 resetForm()
182 baseFormRef.value?.restoreValidation()
183 }
184 }
185
186 function resetForm() {
187 baseForm.value = getClearBaseForm()
188 }
189
190 function submit() {
191 let apiCall: Promise<ApiCommonResponse> | null = null
192
193 switch (baseForm.value.report_type) {
194 case ScoutSuiteReportType.AWS:
195 apiCall = Api.cloudSecurityAssessment.generateAwsScoutSuiteReport({
196 ...baseForm.value,
197 report_type: ScoutSuiteReportType.AWS,
198 ...(typeForm.value as ScoutSuiteAwsReportPayload)
199 })
200 break
201 case ScoutSuiteReportType.Azure:
202 apiCall = Api.cloudSecurityAssessment.generateAzureScoutSuiteReport({
203 ...baseForm.value,
204 report_type: ScoutSuiteReportType.Azure,
205 ...(typeForm.value as ScoutSuiteAzureReportPayload)
206 })
207 break
208 case ScoutSuiteReportType.Gcp:
209 apiCall = Api.cloudSecurityAssessment.generateGcpScoutSuiteReport({
210 ...baseForm.value,
211 report_type: ScoutSuiteReportType.Gcp,
212 ...(typeForm.value as ScoutSuiteGcpReportPayload)
213 })
214 break
215 }
216
217 if (!apiCall) {
218 return
219 }
220
221 submitting.value = true
222
223 apiCall
224 .then(res => {
225 if (res.data.success) {
226 message.success(
227 res.data?.message ||
228 `ScoutSuite report generation started successfully. This will take a few minutes to complete. Check back in shortly.`,
229 {
230 duration: 10 * 1000
231 }
232 )
233 emit("submitted")
234 resetForm()
235 } else {
236 message.warning(res.data?.message || "An error occurred. Please try again later.")
237 }
238 })
239 .catch((err: ApiError) => {
240 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
241 })
242 .finally(() => {
243 submitting.value = false
244 })
245 }
246
247 function getScoutSuiteReportGenerationOptions() {
248 loadingOptions.value = true
249
250 Api.cloudSecurityAssessment
251 .getScoutSuiteReportGenerationOptions()
252 .then(res => {
253 if (res.data.success) {
254 reportTypeOptions.value = (res.data?.options || []).map(o => ({
255 label: o.toUpperCase(),
256 value: o,
257 disabled: !availableTypes.includes(o)
258 }))
259 } else {
260 message.warning(res.data?.message || "An error occurred. Please try again later.")
261 }
262 })
263 .catch(err => {
264 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
265 })
266 .finally(() => {
267 loadingOptions.value = false
268 })
269 }
270
271 onBeforeMount(() => {
272 getScoutSuiteReportGenerationOptions()
273 })
274
275 onMounted(() => {
276 emit("mounted", {
277 reset
278 })
279 })
280 </script>