main
vue 182 lines 5.08 KB
Raw
1 <template>
2 <CardEntity :loading :embedded :hoverable :clickable :highlighted="agent.critical_asset" @click="$emit('click')">
3 <template #headerMain>
4 <div class="flex items-center gap-3">
5 <div v-if="selectable" class="selection-checkbox" @click.stop>
6 <n-checkbox :checked="selected" @update:checked="$emit('toggle-selection')" />
7 </div>
8 <div class="text-default text-lg font-bold">
9 {{ agent.hostname }}
10 </div>
11 </div>
12 </template>
13 <template #headerExtra>
14 <div class="flex items-center gap-2">
15 <n-tooltip>
16 <span class="text-sm">
17 {{ `${isOnline ? "online" : "last seen"}: ${formatLastSeen}` }}
18 </span>
19 <template #trigger>
20 <n-tag v-if="isOnline" type="success" round class="rounded-lg!" :bordered="false" size="small">
21 ONLINE
22 </n-tag>
23 <n-tag v-else round class="rounded-lg!" :bordered="false" size="small">OFFLINE</n-tag>
24 </template>
25 </n-tooltip>
26
27 <n-tooltip>
28 <span class="text-sm">Toggle Critical Assets</span>
29 <template #trigger>
30 <n-button
31 :type="agent.critical_asset ? 'error' : 'default'"
32 ghost
33 size="tiny"
34 @click.stop="toggleCritical(agent.agent_id, agent.critical_asset)"
35 >
36 <template #icon>
37 <Icon :name="agent.critical_asset ? 'carbon:warning-alt' : 'carbon:checkmark'" />
38 </template>
39 {{ agent.critical_asset ? "Critical Asset" : "Non-Critical Asset" }}
40 </n-button>
41 </template>
42 </n-tooltip>
43
44 <n-tag v-if="agent.quarantined" type="warning" round class="rounded-lg!" :bordered="false" size="small">
45 Quarantined
46 </n-tag>
47 </div>
48 </template>
49
50 <template #default>
51 <div class="flex flex-wrap items-center gap-2">
52 <Badge type="splitted" color="primary">
53 <template #label>ID</template>
54 <template #value>#{{ agent.agent_id }}</template>
55 </Badge>
56 <Badge type="splitted" color="primary">
57 <template #label>label</template>
58 <template #value>{{ agent.label }}</template>
59 </Badge>
60 <Badge type="splitted" color="primary">
61 <template #label>OS</template>
62 <template #value>
63 <Icon :name="iconFromOs(agent.os)" :size="14" />
64 {{ agent.os || "-" }}
65 </template>
66 </Badge>
67 <Badge type="splitted" color="primary">
68 <template #label>ip address</template>
69 <template #value>
70 {{ agent.ip_address || "-" }}
71 </template>
72 </Badge>
73 <Badge type="splitted" color="primary">
74 <template #label>wazuh agent status</template>
75 <template #value>
76 {{ agent.wazuh_agent_status || "-" }}
77 </template>
78 </Badge>
79 </div>
80 </template>
81
82 <template #footerExtra>
83 <div v-if="showActions" class="agent-actions">
84 <div class="box flex items-center justify-end gap-4">
85 <slot name="actions-left" />
86 <n-tooltip to="body">
87 <span class="text-sm">Delete Agent</span>
88 <template #trigger>
89 <n-button text type="error" size="small" @click.stop="handleDelete">
90 <template #icon>
91 <Icon :name="DeleteIcon" />
92 </template>
93 Delete
94 </n-button>
95 </template>
96 </n-tooltip>
97 </div>
98 </div>
99 </template>
100 </CardEntity>
101 </template>
102
103 <script setup lang="ts">
104 import type { Agent } from "@/types/agents.d"
105 import { NButton, NCheckbox, NTag, NTooltip, useDialog, useMessage } from "naive-ui"
106 import { computed, ref, toRefs } from "vue"
107 import Badge from "@/components/common/Badge.vue"
108 import CardEntity from "@/components/common/cards/CardEntity.vue"
109 import Icon from "@/components/common/Icon.vue"
110 import { useSettingsStore } from "@/stores/settings"
111 import { AgentStatus } from "@/types/agents.d"
112 import { iconFromOs } from "@/utils"
113 import dayjs from "@/utils/dayjs"
114 import { handleDeleteAgent, toggleAgentCritical } from "./utils"
115
116 const props = defineProps<{
117 agent: Agent
118 showActions?: boolean
119 embedded?: boolean
120 hoverable?: boolean
121 clickable?: boolean
122 selectable?: boolean
123 selected?: boolean
124 }>()
125
126 const emit = defineEmits<{
127 (e: "delete"): void
128 (e: "click"): void
129 (e: "toggle-selection"): void
130 }>()
131
132 const { agent, showActions, embedded, hoverable, clickable, selectable, selected } = toRefs(props)
133
134 const DeleteIcon = "ph:trash"
135 const dFormats = useSettingsStore().dateFormat
136 const loading = ref(false)
137 const message = useMessage()
138 const dialog = useDialog()
139 const isOnline = computed(() => {
140 return agent.value.wazuh_agent_status === AgentStatus.Active
141 })
142 const formatLastSeen = computed(() => {
143 const lastSeenDate = dayjs(agent.value.wazuh_last_seen)
144 if (!lastSeenDate.isValid()) return agent.value.wazuh_last_seen
145
146 return lastSeenDate.format(dFormats.datetime)
147 })
148
149 function handleDelete() {
150 handleDeleteAgent({
151 agent: agent.value,
152 cbBefore: () => {
153 loading.value = true
154 },
155 cbSuccess: () => {
156 emit("delete")
157 },
158 cbAfter: () => {
159 loading.value = false
160 },
161 message,
162 dialog
163 })
164 }
165
166 function toggleCritical(agentId: string, criticalStatus: boolean) {
167 toggleAgentCritical({
168 agentId,
169 criticalStatus,
170 message,
171 cbBefore: () => {
172 loading.value = true
173 },
174 cbSuccess: () => {
175 agent.value.critical_asset = !criticalStatus
176 },
177 cbAfter: () => {
178 loading.value = false
179 }
180 })
181 }
182 </script>