main
vue 119 lines 3.2 KB
Raw
1 <template>
2 <CardEntity>
3 <template #header>{{ link.case_name }}</template>
4 <template v-if="link.asset_description" #default>
5 <p>
6 {{ link.asset_description }}
7 </p>
8 </template>
9 <template #mainExtra>
10 <div class="flex flex-wrap items-center gap-3">
11 <Badge type="splitted" color="primary">
12 <template #label>Case open date</template>
13 <template #value>
14 {{ formatDate(link.case_open_date) }}
15 </template>
16 </Badge>
17 <Badge type="splitted" color="primary">
18 <template #label>Asset id</template>
19 <template #value>
20 {{ link.asset_id }}
21 </template>
22 </Badge>
23 <Badge type="splitted" color="primary">
24 <template #label>Compromise status</template>
25 <template #value>
26 {{ link.asset_compromise_status_id || "-" }}
27 </template>
28 </Badge>
29 </div>
30 </template>
31
32 <template #footer>
33 <n-collapse @item-header-click="showSocCase($event.expanded)">
34 <template #arrow>
35 <div class="mx-5 flex">
36 <Icon :name="ChevronIcon" />
37 </div>
38 </template>
39 <n-collapse-item>
40 <template #header>
41 <div class="-ml-2 py-3">SOC Case details</div>
42 </template>
43 <div class="min-h-14">
44 <n-spin :show="loadingCase">
45 <SocCaseItem
46 v-if="socCase"
47 :case-data="socCase"
48 embedded
49 class="-mt-4 py-2"
50 @deleted="getSocCase(link.case_id)"
51 />
52 <template v-else>
53 <n-empty
54 v-if="!loadingCase"
55 description="No Case found"
56 class="-mt-4 h-28 justify-center"
57 />
58 </template>
59 </n-spin>
60 </div>
61 </n-collapse-item>
62 </n-collapse>
63 </template>
64 </CardEntity>
65 </template>
66
67 <script setup lang="ts">
68 import type { SocCaseAssetLink } from "@/types/soc/asset.d"
69 import type { SocCase } from "@/types/soc/case.d"
70 import { NCollapse, NCollapseItem, NEmpty, NSpin, useMessage } from "naive-ui"
71 import { ref } from "vue"
72 import Api from "@/api"
73 import Badge from "@/components/common/Badge.vue"
74 import CardEntity from "@/components/common/cards/CardEntity.vue"
75 import Icon from "@/components/common/Icon.vue"
76 import { useSettingsStore } from "@/stores/settings"
77 import dayjs from "@/utils/dayjs"
78 import SocCaseItem from "./SocCaseItem.vue"
79
80 const { link } = defineProps<{ link: SocCaseAssetLink }>()
81
82 const ChevronIcon = "carbon:chevron-right"
83
84 const socCase = ref<SocCase | null>(null)
85 const loadingCase = ref(false)
86 const message = useMessage()
87
88 const dFormats = useSettingsStore().dateFormat
89
90 function formatDate(timestamp: string | number | Date, utc: boolean = true): string {
91 return dayjs(timestamp).utc(utc).format(dFormats.date)
92 }
93
94 function showSocCase(show: boolean) {
95 if (show && !socCase.value) {
96 getSocCase(link.case_id.toString())
97 }
98 }
99
100 function getSocCase(caseId: string | number) {
101 loadingCase.value = true
102
103 Api.soc
104 .getCases(caseId.toString())
105 .then(res => {
106 if (res.data.success) {
107 socCase.value = (res.data?.case as unknown as SocCase) || null
108 } else {
109 message.warning(res.data?.message || "An error occurred. Please try again later.")
110 }
111 })
112 .catch(err => {
113 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
114 })
115 .finally(() => {
116 loadingCase.value = false
117 })
118 }
119 </script>