main
vue 130 lines 3.9 KB
Raw
1 <template>
2 <div class="vulnerabilities-section">
3 <div class="toolbar mb-8 flex items-center gap-3">
4 <n-form-item label="Severity" label-placement="left" size="small" :show-feedback="false">
5 <n-select v-model:value="severity" :options="severityOptions" class="w-28!" />
6 </n-form-item>
7
8 <n-button
9 v-if="vulnerabilities.length && !loading"
10 :loading="downloading"
11 size="small"
12 @click="vulnerabilitiesDownload(agent.agent_id)"
13 >
14 Download CSV
15 </n-button>
16 </div>
17 <n-spin content-class="min-h-48" :show="loading">
18 <div class="grid-auto-fill-200 group grid gap-4">
19 <VulnerabilityCard v-for="item of vulnerabilities" :key="item.id" :vulnerability="item" hide-tooltip />
20 </div>
21 <n-empty
22 v-if="!loading && !vulnerabilities.length"
23 description="No vulnerabilities detected"
24 class="h-48 justify-center"
25 />
26 </n-spin>
27 </div>
28 </template>
29
30 <script setup lang="ts">
31 import type { VulnerabilitySeverityType } from "@/api/endpoints/agents"
32 import type { Agent, AgentVulnerabilities } from "@/types/agents.d"
33 import axios from "axios"
34 import { saveAs } from "file-saver"
35 import { NButton, NEmpty, NFormItem, NSelect, NSpin, useMessage } from "naive-ui"
36 import { nanoid } from "nanoid"
37 import { computed, onBeforeMount, ref, toRefs, watch } from "vue"
38 import Api from "@/api"
39 import { useSettingsStore } from "@/stores/settings"
40 import { formatDate } from "@/utils/format"
41 import VulnerabilityCard from "./VulnerabilityCard.vue"
42
43 const props = defineProps<{
44 agent: Agent
45 }>()
46 const { agent } = toRefs(props)
47
48 let abortController: AbortController | null = null
49 const message = useMessage()
50 const loading = ref(false)
51 const dFormats = useSettingsStore().dateFormat
52 const downloading = ref(false)
53 const severity = ref<VulnerabilitySeverityType>("Critical")
54 const vulnerabilitiesCache = ref<{ [key in VulnerabilitySeverityType | string]: AgentVulnerabilities[] }>({})
55 const vulnerabilities = computed<AgentVulnerabilities[]>(() => vulnerabilitiesCache.value[severity.value] || [])
56
57 const severityOptions: { label: string; value: VulnerabilitySeverityType }[] = [
58 { label: "All", value: "All" },
59 { label: "Critical", value: "Critical" },
60 { label: "High", value: "High" },
61 { label: "Medium", value: "Medium" },
62 { label: "Low", value: "Low" }
63 ]
64
65 watch(severity, () => {
66 if (agent?.value?.agent_id) getVulnerabilities(agent.value.agent_id)
67 })
68
69 function getVulnerabilities(id: string) {
70 if (severity.value in vulnerabilitiesCache.value) {
71 return
72 }
73
74 abortController?.abort()
75 abortController = new AbortController()
76
77 loading.value = true
78
79 Api.agents
80 .agentVulnerabilities(id, severity.value, abortController.signal)
81 .then(res => {
82 if (res.data.success) {
83 vulnerabilitiesCache.value[severity.value] = (res.data.vulnerabilities || []).map(o => {
84 o.id = nanoid()
85 return o
86 })
87 } else {
88 message.warning(res.data?.message || "An error occurred. Please try again later.")
89 }
90 loading.value = false
91 })
92 .catch(err => {
93 if (!axios.isCancel(err)) {
94 vulnerabilitiesCache.value[severity.value] = []
95
96 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
97 loading.value = false
98 }
99 })
100 }
101
102 function vulnerabilitiesDownload(id: string) {
103 downloading.value = true
104
105 const fileName = `vulnerabilities_agent:${id}_severity:${severity.value.toLowerCase()}_${formatDate(
106 new Date(),
107 dFormats.datetimesec
108 )}.csv`
109
110 Api.agents
111 .agentVulnerabilitiesDownload(id, severity.value)
112 .then(res => {
113 if (res.data) {
114 saveAs(new Blob([res.data], { type: "text/csv;charset=utf-8" }), fileName)
115 } else {
116 message.warning("An error occurred. Please try again later.")
117 }
118 })
119 .catch(err => {
120 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
121 })
122 .finally(() => {
123 downloading.value = false
124 })
125 }
126
127 onBeforeMount(() => {
128 if (agent?.value?.agent_id) getVulnerabilities(agent.value.agent_id)
129 })
130 </script>