fix: platform-specific placeholder in agent update log modal (v0.5.13)

Windows WinRM updates no longer show the Linux /var/log/update_script.log hint while output is still empty.
This commit is contained in:
2026-07-13 17:18:49 +10:00
parent 91be282ec6
commit 3475c1811b
8 changed files with 62 additions and 8 deletions
+1 -1
View File
@@ -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.5.12" APP_VERSION = "0.5.13"
APP_VERSION_LABEL = f"{APP_NAME} v.{APP_VERSION}" APP_VERSION_LABEL = f"{APP_NAME} v.{APP_VERSION}"
@@ -67,8 +67,6 @@ import { fetchHostRemoteJob, type HostRemoteActionJobStatus } from "../api";
const LOG_POLL_MS = 1500; const LOG_POLL_MS = 1500;
const AUTO_CLOSE_MS = 30_000; const AUTO_CLOSE_MS = 30_000;
const PLACEHOLDER =
"Ожидание лога с хоста…\n(обновление /var/log/update_script.log)";
const props = defineProps<{ const props = defineProps<{
hostId: number; hostId: number;
@@ -78,6 +76,7 @@ const props = defineProps<{
ok: boolean | null; ok: boolean | null;
message: string; message: string;
output: string; output: string;
logPlaceholder: string;
logVisible: boolean; logVisible: boolean;
sessionStartedAt: string; sessionStartedAt: string;
}>(); }>();
@@ -135,7 +134,7 @@ const displayMessage = computed(() => {
const displayOutput = computed(() => { const displayOutput = computed(() => {
const text = (polledOutput.value || props.output).trim(); const text = (polledOutput.value || props.output).trim();
return text || PLACEHOLDER; return text || props.logPlaceholder;
}); });
function stopPoll() { function stopPoll() {
@@ -10,6 +10,7 @@
:ok="entry.ok" :ok="entry.ok"
:message="entry.message" :message="entry.message"
:output="entry.output" :output="entry.output"
:log-placeholder="entry.logPlaceholder"
:log-visible="entry.logVisible" :log-visible="entry.logVisible"
:session-started-at="entry.sessionStartedAt" :session-started-at="entry.sessionStartedAt"
@close="closeHostRemoteActionLog(entry.id)" @close="closeHostRemoteActionLog(entry.id)"
@@ -22,6 +22,8 @@ export type HostRemoteActionLogEntry = {
title: string; title: string;
message: string; message: string;
output: string; output: string;
/** Текст в окне лога, пока output с сервера ещё пустой */
logPlaceholder: string;
/** ISO-время открытия окна — отсекаем stale success от прошлого job */ /** ISO-время открытия окна — отсекаем stale success от прошлого job */
sessionStartedAt: string; sessionStartedAt: string;
}; };
@@ -189,6 +191,7 @@ async function executeRemoteAction(
export async function pollHostRemoteAction( export async function pollHostRemoteAction(
hostId: number, hostId: number,
title: string, title: string,
logPlaceholder?: string,
): Promise<HostRemoteActionJobStatus | null> { ): Promise<HostRemoteActionJobStatus | null> {
const existingPromise = hostRunningPromises.get(hostId); const existingPromise = hostRunningPromises.get(hostId);
if (existingPromise) { if (existingPromise) {
@@ -209,6 +212,7 @@ export async function pollHostRemoteAction(
title, title,
message: "Выполняется на удалённом хосте…", message: "Выполняется на удалённом хосте…",
output: "", output: "",
logPlaceholder: logPlaceholder || "Ожидание лога с хоста…",
sessionStartedAt: new Date().toISOString(), sessionStartedAt: new Date().toISOString(),
}; };
hostRemoteActionLogs.push(entry); hostRemoteActionLogs.push(entry);
@@ -240,6 +244,7 @@ export async function runHostRemoteAction(
hostId: number, hostId: number,
title: string, title: string,
kind: HostRemoteActionKind, kind: HostRemoteActionKind,
logPlaceholder?: string,
): Promise<HostRemoteActionJobStatus | null> { ): Promise<HostRemoteActionJobStatus | null> {
const existingPromise = hostRunningPromises.get(hostId); const existingPromise = hostRunningPromises.get(hostId);
if (existingPromise) { if (existingPromise) {
@@ -260,6 +265,7 @@ export async function runHostRemoteAction(
title, title,
message: "Запуск на сервере SAC…", message: "Запуск на сервере SAC…",
output: "", output: "",
logPlaceholder: logPlaceholder || "Ожидание лога с хоста…",
sessionStartedAt: new Date().toISOString(), sessionStartedAt: new Date().toISOString(),
}; };
hostRemoteActionLogs.push(entry); hostRemoteActionLogs.push(entry);
+34
View File
@@ -58,3 +58,37 @@ export function remoteActionTitleForHost(host: HostSummary): string {
} }
return `Обновление ssh-monitor (SSH): ${label}`; return `Обновление ssh-monitor (SSH): ${label}`;
} }
const LOG_PLACEHOLDER_SSH_UPDATE =
"Ожидание лога с хоста…\n(обновление /var/log/update_script.log)";
const LOG_PLACEHOLDER_WINRM =
"Ожидание вывода с хоста…\n(WinRM: Deploy-LoginMonitor.ps1)";
const LOG_PLACEHOLDER_GENERIC = "Ожидание лога с хоста…";
export function remoteActionLogPlaceholder(
host: Pick<HostSummary, "os_family" | "product"> | null | undefined,
kind: HostRemoteActionKind | null,
): string {
if (kind === "ssh-update") {
return LOG_PLACEHOLDER_SSH_UPDATE;
}
if (host && isWindowsAgentHost(host)) {
return LOG_PLACEHOLDER_WINRM;
}
if (kind === "fallback") {
return LOG_PLACEHOLDER_SSH_UPDATE;
}
return LOG_PLACEHOLDER_GENERIC;
}
export function remoteActionLogPlaceholderFromTitle(title: string): string {
if (/winrm/i.test(title)) {
return LOG_PLACEHOLDER_WINRM;
}
if (/ssh-monitor|\/var\/log\/update_script/i.test(title)) {
return LOG_PLACEHOLDER_SSH_UPDATE;
}
return LOG_PLACEHOLDER_GENERIC;
}
+1 -1
View File
@@ -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.5.12"; export const APP_VERSION = "0.5.13";
export const APP_VERSION_LABEL = `${APP_NAME} v.${APP_VERSION}`; export const APP_VERSION_LABEL = `${APP_NAME} v.${APP_VERSION}`;
+4 -1
View File
@@ -315,6 +315,7 @@ import {
import { import {
isLinuxAgentHost, isLinuxAgentHost,
remoteActionKindForHost, remoteActionKindForHost,
remoteActionLogPlaceholder,
remoteActionTitleForHost, remoteActionTitleForHost,
type AgentGitVersions, type AgentGitVersions,
} from "../utils/hostAgentUpgrade"; } from "../utils/hostAgentUpgrade";
@@ -638,7 +639,7 @@ async function runRequestAgentUpdate() {
async function runAgentFallback() { async function runAgentFallback() {
agentControlMessage.value = ""; agentControlMessage.value = "";
const title = isWindowsHost.value ? "Обновление через WinRM" : "Fallback SSH (ssh-monitor)"; const title = isWindowsHost.value ? "Обновление через WinRM" : "Fallback SSH (ssh-monitor)";
const job = await runHostRemoteAction(hostId.value, title, "fallback"); const job = await runHostRemoteAction(hostId.value, title, "fallback", remoteActionLogPlaceholder(host.value, "fallback"));
if (job) { if (job) {
agentControlOk.value = job.ok ?? false; agentControlOk.value = job.ok ?? false;
if (job.ok) { if (job.ok) {
@@ -706,6 +707,7 @@ async function runAgentUpdate() {
hostId.value, hostId.value,
"Обновление ssh-monitor (SSH)", "Обновление ssh-monitor (SSH)",
"ssh-update", "ssh-update",
remoteActionLogPlaceholder(host.value, "ssh-update"),
); );
if (job?.ok) { if (job?.ok) {
const detail = await fetchHost(hostId.value); const detail = await fetchHost(hostId.value);
@@ -728,6 +730,7 @@ async function runAgentUpgradeFromCell() {
hostId.value, hostId.value,
remoteActionTitleForHost(host.value), remoteActionTitleForHost(host.value),
kind, kind,
remoteActionLogPlaceholder(host.value, kind),
); );
if (job?.ok) { if (job?.ok) {
const detail = await fetchHost(hostId.value); const detail = await fetchHost(hostId.value);
+13 -2
View File
@@ -135,6 +135,8 @@ import { isAgentVersionOutdated } from "../utils/agentVersion";
import { import {
isGitAgentUpgradeAvailable, isGitAgentUpgradeAvailable,
remoteActionKindForHost, remoteActionKindForHost,
remoteActionLogPlaceholder,
remoteActionLogPlaceholderFromTitle,
remoteActionTitleForHost, remoteActionTitleForHost,
} from "../utils/hostAgentUpgrade"; } from "../utils/hostAgentUpgrade";
import { import {
@@ -289,7 +291,12 @@ async function startAgentUpgrade(h: HostSummary) {
} }
const kind = remoteActionKindForHost(h); const kind = remoteActionKindForHost(h);
if (!kind) return; if (!kind) return;
void runHostRemoteAction(h.id, remoteActionTitleForHost(h), kind); void runHostRemoteAction(
h.id,
remoteActionTitleForHost(h),
kind,
remoteActionLogPlaceholder(h, kind),
);
} }
function openHost(id: number) { function openHost(id: number) {
@@ -450,7 +457,11 @@ interface HostDeleteResponse {
async function onManualAddStarted(payload: { hostId: number; title: string }) { async function onManualAddStarted(payload: { hostId: number; title: string }) {
await loadHosts(); await loadHosts();
void pollHostRemoteAction(payload.hostId, payload.title); void pollHostRemoteAction(
payload.hostId,
payload.title,
remoteActionLogPlaceholderFromTitle(payload.title),
);
} }
async function confirmDelete(h: HostSummary) { async function confirmDelete(h: HostSummary) {