main
vue 135 lines 4.26 KB
Raw
1 <template>
2 <div class="flex flex-col gap-2">
3 <div v-if="alert.linked_cases?.length" class="flex items-center justify-end gap-2">
4 <n-button size="small" :loading="creatingCase" @click="createCase">Create Case</n-button>
5 <LinkAlert :alert-id="alert.id" size="small" secondary label="Link Case" @linked="handleCaseLinked" />
6 </div>
7
8 <div v-if="alert.linked_cases?.length" class="flex flex-col gap-2">
9 <CardEntity v-for="linkedCase in alert.linked_cases" :key="linkedCase.id" size="small" embedded>
10 <template #header-main>#{{ linkedCase.id }}</template>
11 <template #header-extra>
12 <div class="flex flex-wrap items-center justify-end gap-2">
13 <Chip v-if="linkedCase.assigned_to" :value="linkedCase.assigned_to" label="Assigned to" />
14 <Chip :type="getStatusColor(linkedCase.case_status)">
15 {{ linkedCase.case_status.replace("_", " ").toUpperCase() }}
16 </Chip>
17 </div>
18 </template>
19 <template #default>
20 {{ linkedCase.case_name }}
21 </template>
22 <template #footer-main>
23 Created: {{ formatDate(linkedCase.case_creation_time, dFormats.datetime) }}
24 </template>
25 <template #footer-extra>
26 <div class="flex flex-wrap items-center justify-end gap-2">
27 <UnlinkCase
28 :alert-id="alert.id"
29 :case-id="linkedCase.id"
30 size="small"
31 @unlinked="handleCaseUnlinked"
32 />
33 <CaseDetailsButton
34 :case-id="linkedCase.id"
35 size="small"
36 @status-updated="handleStatusUpdated"
37 @assigned-to-updated="handleAssignedToUpdated"
38 />
39 </div>
40 </template>
41 </CardEntity>
42 </div>
43
44 <div v-else-if="alert.case_ids?.length" class="flex flex-wrap gap-2">
45 <code v-for="caseId in alert.case_ids" :key="caseId">Case #{{ caseId }}</code>
46 </div>
47
48 <n-empty v-else description="No linked cases found" class="min-h-50 justify-center">
49 <template #extra>
50 <div class="flex items-center justify-center gap-2">
51 <n-button type="primary" size="small" :loading="creatingCase" @click="createCase">
52 Create Case
53 </n-button>
54 <LinkAlert
55 :alert-id="alert.id"
56 size="small"
57 secondary
58 label="Link Case"
59 @linked="handleCaseLinked"
60 />
61 </div>
62 </template>
63 </n-empty>
64 </div>
65 </template>
66
67 <script setup lang="ts">
68 import type { CaseAssignedUpdateSuccessPayload } from "@/components/cases/CaseAssignedSelect.vue"
69 import type { CaseStatusUpdateSuccessPayload } from "@/components/cases/CaseStatusSelect.vue"
70 import type { Alert } from "@/types/alerts"
71 import type { ApiError } from "@/types/common"
72 import { NButton, NEmpty, useMessage } from "naive-ui"
73 import { ref } from "vue"
74 import Api from "@/api"
75 import LinkAlert from "@/components/alerts/LinkAlert.vue"
76 import CaseDetailsButton from "@/components/cases/CaseDetailsButton.vue"
77 import UnlinkCase from "@/components/cases/UnlinkCase.vue"
78 import CardEntity from "@/components/common/cards/CardEntity.vue"
79 import Chip from "@/components/common/Chip.vue"
80 import { useSettingsStore } from "@/stores/settings"
81 import { getApiErrorMessage, getStatusColor } from "@/utils"
82 import { formatDate } from "@/utils/format"
83
84 const { alert } = defineProps<{
85 alert: Alert
86 }>()
87
88 const emit = defineEmits<{
89 (e: "created", value: number): void
90 (e: "updated", value: number): void
91 (e: "unlinked", value: number): void
92 (e: "linked", value: number): void
93 }>()
94
95 const dFormats = useSettingsStore().dateFormat
96 const creatingCase = ref(false)
97 const message = useMessage()
98
99 function createCase() {
100 creatingCase.value = true
101
102 Api.cases
103 .createCaseFromAlert(alert.id)
104 .then(res => {
105 if (res.data.success) {
106 emit("created", res.data.case_alert_link.case_id)
107 message.success(res.data?.message || "Case created successfully")
108 } else {
109 message.error(res.data?.message || "An error occurred. Please try again later.")
110 }
111 })
112 .catch(err => {
113 message.error(getApiErrorMessage(err as ApiError))
114 })
115 .finally(() => {
116 creatingCase.value = false
117 })
118 }
119
120 function handleStatusUpdated(payload: CaseStatusUpdateSuccessPayload) {
121 emit("updated", payload.caseId)
122 }
123
124 function handleAssignedToUpdated(payload: CaseAssignedUpdateSuccessPayload) {
125 emit("updated", payload.caseId)
126 }
127
128 function handleCaseUnlinked(caseId: number) {
129 emit("unlinked", caseId)
130 }
131
132 function handleCaseLinked(caseId: number) {
133 emit("linked", caseId)
134 }
135 </script>