main
vue 126 lines 3.96 KB
Raw
1 <template>
2 <div class="h-full">
3 <CardEntity
4 clickable
5 :embedded
6 class="h-full"
7 main-box-class="grow"
8 card-entity-wrapper-class="h-full"
9 header-box-class="flex-nowrap! items-start"
10 :class="`${getComplianceBorderClass(sca.score)} transition-all duration-300`"
11 @click.stop="showDetails = true"
12 >
13 <template #headerMain>{{ sca.policy_name }}</template>
14 <template #headerExtra>
15 <ScaLevelBadge :score="sca.score" />
16 </template>
17 <template #default>
18 <div class="flex flex-col gap-4">
19 <div class="leading-snug font-medium">
20 {{ sca.description }}
21 </div>
22 <div class="text-secondary flex flex-col gap-0.5 text-sm">
23 <div class="flex items-center gap-2">
24 <Icon :name="HostIcon" :size="14" />
25 <span>{{ sca.agent_name }}</span>
26 </div>
27 <div class="mt-1 flex items-center gap-2">
28 <Icon :name="PolicyIcon" :size="14" />
29 <span>{{ sca.policy_id }}</span>
30 </div>
31 </div>
32 </div>
33 </template>
34 <template #footerMain>
35 <div class="flex flex-wrap items-center gap-2">
36 <Badge type="splitted" class="text-xs">
37 <template #label>Total</template>
38 <template #value>{{ sca.total_checks }}</template>
39 </Badge>
40
41 <Badge color="success" type="splitted" class="text-xs">
42 <template #label>Pass</template>
43 <template #value>{{ sca.pass }}</template>
44 </Badge>
45
46 <Badge color="danger" type="splitted" class="text-xs">
47 <template #label>Fail</template>
48 <template #value>{{ sca.fail }}</template>
49 </Badge>
50
51 <Badge v-if="sca.invalid > 0" color="warning" type="splitted" class="text-xs">
52 <template #label>Invalid</template>
53 <template #value>{{ sca.invalid }}</template>
54 </Badge>
55
56 <Badge v-if="sca.customer_code" class="text-xs">
57 <template #value>
58 <code
59 class="text-primary cursor-pointer"
60 @click.stop="routeCustomer({ code: sca.customer_code }).navigate()"
61 >
62 customer #{{ sca.customer_code }}
63 <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
64 </code>
65 </template>
66 </Badge>
67 </div>
68 </template>
69 <template #footerExtra>
70 <div class="text-tertiary text-xs">
71 {{ formatDate(sca.end_scan, dFormats.datetime) }}
72 </div>
73 </template>
74 </CardEntity>
75
76 <!-- SCA Details Modal -->
77 <n-modal
78 v-model:show="showDetails"
79 preset="card"
80 :style="{ maxWidth: 'min(800px, 90vw)', minHeight: 'min(500px, 90vh)' }"
81 :title="`SCA Policy: ${sca.policy_name}`"
82 :bordered="false"
83 content-class="p-0!"
84 segmented
85 >
86 <ScaCardContent :sca />
87 </n-modal>
88 </div>
89 </template>
90
91 <script setup lang="ts">
92 import type { AgentScaOverviewItem } from "@/types/sca.d"
93 import { NModal } from "naive-ui"
94 import { ref } from "vue"
95 import Badge from "@/components/common/Badge.vue"
96 import CardEntity from "@/components/common/cards/CardEntity.vue"
97 import Icon from "@/components/common/Icon.vue"
98 import { useNavigation } from "@/composables/useNavigation"
99 import { useSettingsStore } from "@/stores/settings"
100 import { formatDate } from "@/utils/format"
101 import ScaCardContent from "./ScaCardContent.vue"
102 import ScaLevelBadge from "./ScaLevelBadge.vue"
103 import { getComplianceLevel } from "./utils"
104
105 const { sca } = defineProps<{ sca: AgentScaOverviewItem; embedded?: boolean }>()
106
107 const { routeCustomer } = useNavigation()
108 const dFormats = useSettingsStore().dateFormat
109
110 const showDetails = ref(false)
111 const LinkIcon = "carbon:launch"
112 const HostIcon = "carbon:bare-metal-server"
113 const PolicyIcon = "carbon:security"
114
115 function getComplianceBorderClass(score: number): string {
116 const level = getComplianceLevel(score)
117 const borderMap: Record<string, string> = {
118 Excellent: "ring-1 ring-success/30 hover:ring-success/80",
119 Good: "ring-1 ring-info/30 hover:ring-info/80",
120 Average: "ring-1 ring-warning/30 hover:ring-warning/80",
121 Poor: "ring-1 ring-orange-500/30 hover:ring-orange-500/80",
122 Critical: "ring-1 ring-error/30 hover:ring-error/80"
123 }
124 return borderMap[level] || ""
125 }
126 </script>