feat: phase 1C JWT UI, events/hosts API, Vue frontend

This commit is contained in:
2026-05-26 21:46:34 +10:00
parent d8a8329397
commit bdfc7016e6
27 changed files with 2498 additions and 23 deletions
+56
View File
@@ -0,0 +1,56 @@
<template>
<h1>Хосты</h1>
<p v-if="error" class="error">{{ error }}</p>
<p v-else-if="loading">Загрузка</p>
<template v-else>
<p>Всего: {{ data?.total ?? 0 }}</p>
<table>
<thead>
<tr>
<th>ID</th>
<th>Hostname</th>
<th>Product</th>
<th>OS</th>
<th>IPv4</th>
<th>Last seen</th>
<th>Events</th>
</tr>
</thead>
<tbody>
<tr v-for="h in data?.items ?? []" :key="h.id">
<td>{{ h.id }}</td>
<td>{{ h.display_name || h.hostname }}</td>
<td>{{ h.product }} {{ h.product_version || "" }}</td>
<td>{{ h.os_family }}</td>
<td>{{ h.ipv4 || "—" }}</td>
<td>{{ formatDt(h.last_seen_at) }}</td>
<td>{{ h.event_count ?? 0 }}</td>
</tr>
</tbody>
</table>
</template>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { apiFetch, type HostListResponse } from "../api";
const data = ref<HostListResponse | null>(null);
const loading = ref(false);
const error = ref("");
function formatDt(iso: string) {
return new Date(iso).toLocaleString("ru-RU");
}
onMounted(async () => {
loading.value = true;
try {
data.value = await apiFetch<HostListResponse>("/api/v1/hosts?page=1&page_size=100");
} catch (e) {
error.value = e instanceof Error ? e.message : "Ошибка";
} finally {
loading.value = false;
}
});
</script>