feat(frontend): git agent versions plate on Hosts list (0.20.32)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
PTah
2026-06-22 15:17:47 +10:00
parent 54c1d96933
commit 5e26834e16
7 changed files with 97 additions and 9 deletions
+3
View File
@@ -286,6 +286,9 @@ export interface HostListResponse {
latest_agent_versions?: Record<string, string>;
/** Эталон для «устарела»: max(git latest, min, max в fleet) */
reference_agent_versions?: Record<string, string>;
/** Последние версии из git (version.txt на main) */
git_latest_rdp_version?: string | null;
git_latest_ssh_version?: string | null;
}
export interface ProblemSummary {
+1 -1
View File
@@ -1,4 +1,4 @@
/** Fallback до загрузки /health; при релизе держите в sync с backend/app/version.py */
export const APP_NAME = "Security Alert Center";
export const APP_VERSION = "0.20.31";
export const APP_VERSION = "0.20.32";
export const APP_VERSION_LABEL = `${APP_NAME} v.${APP_VERSION}`;
+75 -4
View File
@@ -19,10 +19,24 @@
<p v-if="error" class="error">{{ error }}</p>
<p v-else-if="loading">Загрузка</p>
<template v-else>
<p>
Всего: {{ data?.total ?? 0 }}
<span v-if="live" class="live-badge">live</span>
</p>
<div class="hosts-list-meta">
<p class="hosts-list-total">
Всего: {{ data?.total ?? 0 }}
<span v-if="live" class="live-badge">live</span>
</p>
<aside
class="agent-releases-plate"
title="Версии из git-репозиториев агентов (version.txt, ветка main)"
>
<span class="agent-releases-plate__label">Последние версии агентов:</span>
<span class="agent-releases-plate__item">
Win: <code>{{ gitWinVersion }}</code>
</span>
<span class="agent-releases-plate__item">
SSH: <code>{{ gitSshVersion }}</code>
</span>
</aside>
</div>
<table class="hosts-table">
<thead>
<tr>
@@ -242,6 +256,13 @@ function setSort(key: SortKey) {
saveHostsSortPrefs(sortBy.value, sortDir.value);
}
const gitWinVersion = computed(
() => data.value?.git_latest_rdp_version?.trim() || "—",
);
const gitSshVersion = computed(
() => data.value?.git_latest_ssh_version?.trim() || "—",
);
function sortMark(key: SortKey) {
if (sortBy.value !== key) return "";
return sortDir.value === "asc" ? "↑" : "↓";
@@ -412,3 +433,53 @@ watch(
},
);
</script>
<style scoped>
.hosts-list-meta {
display: flex;
flex-wrap: wrap;
align-items: stretch;
gap: 0.5rem 0.75rem;
margin: 0.35rem 0 1rem;
}
.hosts-list-total {
display: flex;
align-items: center;
gap: 0.5rem;
margin: 0;
line-height: 1.5;
}
.agent-releases-plate {
display: inline-flex;
flex-wrap: wrap;
align-items: baseline;
gap: 0.35rem 0.85rem;
margin: -0.15rem 0 0;
padding: 0.45rem 1rem 0.5rem 1.1rem;
border-radius: 0 0.75rem 0.75rem 0.35rem;
border: 1px solid #2d3a4d;
border-left: 3px solid #58a6ff;
background: linear-gradient(135deg, #1a2332 0%, #151d28 100%);
box-shadow:
0 2px 8px rgba(0, 0, 0, 0.35),
0 1px 0 rgba(88, 166, 255, 0.12) inset;
font-size: 0.9rem;
color: #9aa4b2;
transform: translateY(-1px);
}
.agent-releases-plate__label {
color: #c9d1d9;
font-weight: 500;
}
.agent-releases-plate__item code {
font-size: 0.88em;
color: #79c0ff;
background: rgba(88, 166, 255, 0.08);
padding: 0.1rem 0.35rem;
border-radius: 0.25rem;
}
</style>