feat(frontend): git agent versions plate on Hosts list (0.20.32)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -27,7 +27,11 @@ from app.services.host_remote_actions import (
|
|||||||
run_ssh_monitor_update_action,
|
run_ssh_monitor_update_action,
|
||||||
start_host_remote_action,
|
start_host_remote_action,
|
||||||
)
|
)
|
||||||
from app.services.agent_update_settings import get_effective_agent_update_config
|
from app.services.agent_update_settings import (
|
||||||
|
PRODUCT_RDP,
|
||||||
|
PRODUCT_SSH,
|
||||||
|
get_effective_agent_update_config,
|
||||||
|
)
|
||||||
from app.services.agent_host_config import get_host_agent_settings, update_host_agent_config
|
from app.services.agent_host_config import get_host_agent_settings, update_host_agent_config
|
||||||
from app.services.host_sessions import (
|
from app.services.host_sessions import (
|
||||||
HostSessionRow,
|
HostSessionRow,
|
||||||
@@ -165,6 +169,8 @@ def list_hosts(
|
|||||||
page_size=page_size,
|
page_size=page_size,
|
||||||
latest_agent_versions=latest_map,
|
latest_agent_versions=latest_map,
|
||||||
reference_agent_versions=reference_map,
|
reference_agent_versions=reference_map,
|
||||||
|
git_latest_rdp_version=git_release.versions.get(PRODUCT_RDP) or None,
|
||||||
|
git_latest_ssh_version=git_release.versions.get(PRODUCT_SSH) or None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,14 @@ class HostListResponse(BaseModel):
|
|||||||
default_factory=dict,
|
default_factory=dict,
|
||||||
description="Эталон для «устарела»: max(git latest, min, max в fleet)",
|
description="Эталон для «устарела»: max(git latest, min, max в fleet)",
|
||||||
)
|
)
|
||||||
|
git_latest_rdp_version: str | None = Field(
|
||||||
|
None,
|
||||||
|
description="Последняя версия rdp-login-monitor из git (version.txt / main)",
|
||||||
|
)
|
||||||
|
git_latest_ssh_version: str | None = Field(
|
||||||
|
None,
|
||||||
|
description="Последняя версия ssh-monitor из git (version.txt / main)",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class EventSummary(BaseModel):
|
class EventSummary(BaseModel):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""Единый источник версии SAC (API, health, логи, OpenAPI)."""
|
"""Единый источник версии SAC (API, health, логи, OpenAPI)."""
|
||||||
|
|
||||||
APP_NAME = "Security Alert Center"
|
APP_NAME = "Security Alert Center"
|
||||||
APP_VERSION = "0.20.31"
|
APP_VERSION = "0.20.32"
|
||||||
APP_VERSION_LABEL = f"{APP_NAME} v.{APP_VERSION}"
|
APP_VERSION_LABEL = f"{APP_NAME} v.{APP_VERSION}"
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ from app.version import APP_NAME, APP_VERSION, APP_VERSION_LABEL
|
|||||||
|
|
||||||
|
|
||||||
def test_version_constants():
|
def test_version_constants():
|
||||||
assert APP_VERSION == "0.20.31"
|
assert APP_VERSION == "0.20.32"
|
||||||
assert APP_NAME == "Security Alert Center"
|
assert APP_NAME == "Security Alert Center"
|
||||||
assert APP_VERSION_LABEL == "Security Alert Center v.0.20.31"
|
assert APP_VERSION_LABEL == "Security Alert Center v.0.20.32"
|
||||||
|
|||||||
@@ -286,6 +286,9 @@ export interface HostListResponse {
|
|||||||
latest_agent_versions?: Record<string, string>;
|
latest_agent_versions?: Record<string, string>;
|
||||||
/** Эталон для «устарела»: max(git latest, min, max в fleet) */
|
/** Эталон для «устарела»: max(git latest, min, max в fleet) */
|
||||||
reference_agent_versions?: Record<string, string>;
|
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 {
|
export interface ProblemSummary {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/** Fallback до загрузки /health; при релизе держите в sync с backend/app/version.py */
|
/** Fallback до загрузки /health; при релизе держите в sync с backend/app/version.py */
|
||||||
export const APP_NAME = "Security Alert Center";
|
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}`;
|
export const APP_VERSION_LABEL = `${APP_NAME} v.${APP_VERSION}`;
|
||||||
|
|||||||
@@ -19,10 +19,24 @@
|
|||||||
<p v-if="error" class="error">{{ error }}</p>
|
<p v-if="error" class="error">{{ error }}</p>
|
||||||
<p v-else-if="loading">Загрузка…</p>
|
<p v-else-if="loading">Загрузка…</p>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<p>
|
<div class="hosts-list-meta">
|
||||||
|
<p class="hosts-list-total">
|
||||||
Всего: {{ data?.total ?? 0 }}
|
Всего: {{ data?.total ?? 0 }}
|
||||||
<span v-if="live" class="live-badge">live</span>
|
<span v-if="live" class="live-badge">live</span>
|
||||||
</p>
|
</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">
|
<table class="hosts-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -242,6 +256,13 @@ function setSort(key: SortKey) {
|
|||||||
saveHostsSortPrefs(sortBy.value, sortDir.value);
|
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) {
|
function sortMark(key: SortKey) {
|
||||||
if (sortBy.value !== key) return "";
|
if (sortBy.value !== key) return "";
|
||||||
return sortDir.value === "asc" ? "↑" : "↓";
|
return sortDir.value === "asc" ? "↑" : "↓";
|
||||||
@@ -412,3 +433,53 @@ watch(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
</script>
|
</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>
|
||||||
|
|||||||
Reference in New Issue
Block a user