main
vue 163 lines 4.5 KB
Raw
1 <template>
2 <div>
3 <LicenseFeatureCheck
4 feature="SOCFORTRESS AI"
5 feedback="tooltip"
6 :disabled="disabledLicenseCheck"
7 :force-show-feedback="disabledLicenseCheck && !licenseResponse"
8 @response="
9 (() => {
10 licenseChecked = true
11 licenseResponse = $event
12 })()
13 "
14 @start-loading="licenseChecking = true"
15 @stop-loading="licenseChecking = false"
16 >
17 <n-button
18 :size="size || 'small'"
19 ghost
20 type="primary"
21 :loading="loading || licenseChecking"
22 :disabled="!licenseChecked || !licenseResponse"
23 @click="analysis()"
24 >
25 <template #icon>
26 <Icon :name="AiIcon" />
27 </template>
28 <div class="flex items-center gap-2">
29 <span>AI Analyst</span>
30 <Icon v-if="!licenseResponse && licenseChecked" :name="LockIcon" :size="14" />
31 </div>
32 </n-button>
33 </LicenseFeatureCheck>
34
35 <n-modal
36 v-model:show="showModal"
37 preset="card"
38 content-class="p-0!"
39 :style="{ maxWidth: 'min(710px, 90vw)', minHeight: 'min(500px, 90vh)' }"
40 :bordered="false"
41 segmented
42 >
43 <template #header>
44 <div class="flex flex-wrap items-center gap-2">
45 <span>AI Analysis</span>
46 <code v-if="analysisResponse?.risk_evaluation" class="px-2 py-1">
47 RISK:
48 <strong
49 :class="{
50 'text-warning': analysisResponse?.risk_evaluation === 'medium',
51 'text-error': analysisResponse?.risk_evaluation === 'high'
52 }"
53 >
54 {{ analysisResponse.risk_evaluation }}
55 </strong>
56 </code>
57 </div>
58 </template>
59 <template v-if="analysisResponse" #header-extra>
60 <code class="px-2 py-1">
61 CONFIDENCE SCORE:
62 <strong>{{ analysisResponse.confidence_score * 100 }}%</strong>
63 </code>
64 </template>
65 <n-tabs type="line" animated :tabs-padding="24">
66 <n-tab-pane v-if="analysisResponse?.analysis" name="Analysis" tab="Analysis" display-directive="show">
67 <div class="p-6 pt-3">
68 <Markdown :source="analysisResponse.analysis" />
69 </div>
70 </n-tab-pane>
71 <n-tab-pane
72 v-if="analysisResponse?.base64_decoded"
73 name="Base64Decoded"
74 tab="Base64 Decoded"
75 display-directive="show"
76 >
77 <div class="p-6 pt-3">
78 <CodeSource :code="analysisResponse.base64_decoded" decode />
79 </div>
80 </n-tab-pane>
81 <n-tab-pane
82 v-if="analysisResponse?.threat_indicators"
83 name="ThreatIndicators"
84 tab="Threat Indicators"
85 display-directive="show"
86 >
87 <div class="p-6 pt-3">
88 <Markdown :source="analysisResponse.threat_indicators" />
89 </div>
90 </n-tab-pane>
91 </n-tabs>
92 </n-modal>
93 </div>
94 </template>
95
96 <script setup lang="ts">
97 import type { ButtonSize } from "naive-ui"
98 import type { AiAnalysisResponse } from "@/types/threatIntel.d"
99 import { NButton, NModal, NTabPane, NTabs, useMessage } from "naive-ui"
100 import { defineAsyncComponent, ref, watchEffect } from "vue"
101 import Api from "@/api"
102 import Icon from "@/components/common/Icon.vue"
103 import LicenseFeatureCheck from "@/components/license/LicenseFeatureCheck.vue"
104
105 const {
106 indexName,
107 indexId,
108 alertId,
109 forceLicenseResponse = undefined,
110 size
111 } = defineProps<{
112 indexName: string
113 indexId: string
114 alertId: number
115 forceLicenseResponse?: boolean
116 size?: ButtonSize
117 }>()
118
119 const CodeSource = defineAsyncComponent(() => import("@/components/common/CodeSource.vue"))
120 const Markdown = defineAsyncComponent(() => import("@/components/common/Markdown.vue"))
121
122 const LockIcon = "carbon:locked"
123 const AiIcon = "mage:stars-c"
124 const showModal = ref<boolean>(false)
125 const loading = ref<boolean>(false)
126 const message = useMessage()
127 const analysisResponse = ref<AiAnalysisResponse | null>(null)
128 const licenseChecking = ref(false)
129 const licenseChecked = ref(forceLicenseResponse !== undefined)
130 const licenseResponse = ref(forceLicenseResponse ?? false)
131 const disabledLicenseCheck = ref(forceLicenseResponse !== undefined)
132
133 function openResponse() {
134 showModal.value = true
135 }
136
137 function analysis() {
138 loading.value = true
139
140 Api.threatIntel
141 .aiAlertAnalysis({ indexName, indexId, alertId })
142 .then(res => {
143 if (res.data.success) {
144 analysisResponse.value = res.data
145 openResponse()
146 } else {
147 message.warning(res.data?.message || "An error occurred. Please try again later.")
148 }
149 })
150 .catch(err => {
151 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
152 })
153 .finally(() => {
154 loading.value = false
155 })
156 }
157
158 watchEffect(() => {
159 licenseResponse.value = forceLicenseResponse ?? false
160 licenseChecked.value = forceLicenseResponse !== undefined
161 disabledLicenseCheck.value = forceLicenseResponse !== undefined
162 })
163 </script>