| 1 | <template> |
| 2 | <n-spin :show="loading" content-class="min-h-32"> |
| 3 | <div class="mb-4"> |
| 4 | <CardKV> |
| 5 | <template #key>cve</template> |
| 6 | <template #value> |
| 7 | {{ cve }} |
| 8 | </template> |
| 9 | </CardKV> |
| 10 | </div> |
| 11 | <div v-if="epssList.length" class="@container flex flex-col gap-3"> |
| 12 | <n-card |
| 13 | v-for="item of epssList" |
| 14 | :key="item.___id" |
| 15 | embedded |
| 16 | class="item-appear item-appear-bottom item-appear-005 overflow-hidden" |
| 17 | > |
| 18 | <div class="flex flex-col justify-between gap-8 @md:flex-row"> |
| 19 | <n-statistic class="grow" label="Date" :value="`${formatDate(item.date, dFormats.date)}`" /> |
| 20 | <n-statistic class="grow" label="EPSS" :value="item.epss" tabular-nums /> |
| 21 | <n-statistic class="grow" label="Percentile" :value="item.percentile" tabular-nums /> |
| 22 | </div> |
| 23 | </n-card> |
| 24 | <p v-if="epssModelLink" class="w-full text-right"> |
| 25 | EPSS Model: |
| 26 | <a :href="epssModelLink" target="_blank">{{ epssModelLink }}</a> |
| 27 | </p> |
| 28 | </div> |
| 29 | <template v-else> |
| 30 | <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" /> |
| 31 | </template> |
| 32 | </n-spin> |
| 33 | </template> |
| 34 | |
| 35 | <script setup lang="ts"> |
| 36 | import type { EpssScore } from "@/types/threatIntel.d" |
| 37 | import { NCard, NEmpty, NSpin, NStatistic, useMessage } from "naive-ui" |
| 38 | import { nanoid } from "nanoid" |
| 39 | import { onBeforeMount, ref } from "vue" |
| 40 | import Api from "@/api" |
| 41 | import CardKV from "@/components/common/cards/CardKV.vue" |
| 42 | import { useSettingsStore } from "@/stores/settings" |
| 43 | import { formatDate } from "@/utils/format" |
| 44 | |
| 45 | interface EpssScoreExt extends EpssScore { |
| 46 | ___id?: string |
| 47 | } |
| 48 | |
| 49 | const { cve } = defineProps<{ |
| 50 | cve: string |
| 51 | }>() |
| 52 | |
| 53 | const dFormats = useSettingsStore().dateFormat |
| 54 | const message = useMessage() |
| 55 | const loading = ref(false) |
| 56 | const epssList = ref<EpssScoreExt[]>([]) |
| 57 | const epssModelLink = ref<string | null>(null) |
| 58 | |
| 59 | function getData() { |
| 60 | loading.value = true |
| 61 | |
| 62 | Api.threatIntel |
| 63 | .epssScore(cve) |
| 64 | .then(res => { |
| 65 | if (res.data.success) { |
| 66 | epssList.value = ((res.data.data as EpssScoreExt[]) || []).map(o => { |
| 67 | o.___id = nanoid() |
| 68 | return o |
| 69 | }) |
| 70 | epssModelLink.value = res.data.the_epss_model |
| 71 | } else { |
| 72 | message.warning(res.data?.message || "An error occurred. Please try again later.") |
| 73 | } |
| 74 | }) |
| 75 | .catch(err => { |
| 76 | message.error(err.response?.data?.message || "An error occurred. Please try again later.") |
| 77 | }) |
| 78 | .finally(() => { |
| 79 | loading.value = false |
| 80 | }) |
| 81 | } |
| 82 | |
| 83 | onBeforeMount(() => { |
| 84 | getData() |
| 85 | }) |
| 86 | </script> |