fix(frontend): auto-close WinRM update success panel after 30s (0.20.24)
Remote action log dock closes on successful fallback; no duplicate inline message.
This commit is contained in:
@@ -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.23"
|
APP_VERSION = "0.20.24"
|
||||||
APP_VERSION_LABEL = f"{APP_NAME} v.{APP_VERSION}"
|
APP_VERSION_LABEL = f"{APP_NAME} v.{APP_VERSION}"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "sac-ui",
|
"name": "sac-ui",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.11.1",
|
"version": "0.11.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { reactive } from "vue";
|
import { reactive } from "vue";
|
||||||
import {
|
import {
|
||||||
ApiError,
|
ApiError,
|
||||||
fetchHost,
|
fetchHost,
|
||||||
@@ -23,11 +23,29 @@ export const hostRemoteActionLog = reactive({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const POLL_MS = 1500;
|
const POLL_MS = 1500;
|
||||||
|
const SUCCESS_AUTO_CLOSE_MS = 30_000;
|
||||||
|
|
||||||
|
let successAutoCloseTimer: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|
||||||
function sleep(ms: number): Promise<void> {
|
function sleep(ms: number): Promise<void> {
|
||||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearSuccessAutoCloseTimer() {
|
||||||
|
if (successAutoCloseTimer != null) {
|
||||||
|
clearTimeout(successAutoCloseTimer);
|
||||||
|
successAutoCloseTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleSuccessAutoClose() {
|
||||||
|
clearSuccessAutoCloseTimer();
|
||||||
|
successAutoCloseTimer = setTimeout(() => {
|
||||||
|
hostRemoteActionLog.open = false;
|
||||||
|
successAutoCloseTimer = null;
|
||||||
|
}, SUCCESS_AUTO_CLOSE_MS);
|
||||||
|
}
|
||||||
|
|
||||||
function applyJobToModal(job: HostRemoteActionJobStatus) {
|
function applyJobToModal(job: HostRemoteActionJobStatus) {
|
||||||
hostRemoteActionLog.title = job.title || hostRemoteActionLog.title;
|
hostRemoteActionLog.title = job.title || hostRemoteActionLog.title;
|
||||||
hostRemoteActionLog.message = job.message || hostRemoteActionLog.message;
|
hostRemoteActionLog.message = job.message || hostRemoteActionLog.message;
|
||||||
@@ -39,6 +57,9 @@ function finishModal(job: HostRemoteActionJobStatus) {
|
|||||||
hostRemoteActionLog.ok = job.ok ?? job.status === "success";
|
hostRemoteActionLog.ok = job.ok ?? job.status === "success";
|
||||||
applyJobToModal(job);
|
applyJobToModal(job);
|
||||||
hostRemoteActionLog.open = true;
|
hostRemoteActionLog.open = true;
|
||||||
|
if (hostRemoteActionLog.ok) {
|
||||||
|
scheduleSuccessAutoClose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function pollRemoteJob(hostId: number): Promise<HostRemoteActionJobStatus> {
|
async function pollRemoteJob(hostId: number): Promise<HostRemoteActionJobStatus> {
|
||||||
@@ -83,6 +104,7 @@ export async function runHostRemoteAction(
|
|||||||
title: string,
|
title: string,
|
||||||
kind: HostRemoteActionKind,
|
kind: HostRemoteActionKind,
|
||||||
): Promise<HostRemoteActionJobStatus | null> {
|
): Promise<HostRemoteActionJobStatus | null> {
|
||||||
|
clearSuccessAutoCloseTimer();
|
||||||
hostRemoteActionLog.open = true;
|
hostRemoteActionLog.open = true;
|
||||||
hostRemoteActionLog.loading = true;
|
hostRemoteActionLog.loading = true;
|
||||||
hostRemoteActionLog.ok = null;
|
hostRemoteActionLog.ok = null;
|
||||||
@@ -116,6 +138,7 @@ export async function runHostRemoteAction(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function closeHostRemoteActionLog() {
|
export function closeHostRemoteActionLog() {
|
||||||
|
clearSuccessAutoCloseTimer();
|
||||||
hostRemoteActionLog.open = false;
|
hostRemoteActionLog.open = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.23";
|
export const APP_VERSION = "0.20.24";
|
||||||
export const APP_VERSION_LABEL = `${APP_NAME} v.${APP_VERSION}`;
|
export const APP_VERSION_LABEL = `${APP_NAME} v.${APP_VERSION}`;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<template>
|
<template>
|
||||||
<p><RouterLink to="/hosts">← Хосты</RouterLink></p>
|
<p><RouterLink to="/hosts">← Хосты</RouterLink></p>
|
||||||
<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>
|
||||||
@@ -623,9 +623,11 @@ async function runAgentFallback() {
|
|||||||
const job = await runHostRemoteAction(hostId.value, title, "fallback");
|
const job = await runHostRemoteAction(hostId.value, title, "fallback");
|
||||||
if (job) {
|
if (job) {
|
||||||
agentControlOk.value = job.ok ?? false;
|
agentControlOk.value = job.ok ?? false;
|
||||||
agentControlMessage.value = job.message || "";
|
|
||||||
if (job.ok) {
|
if (job.ok) {
|
||||||
|
agentControlMessage.value = "";
|
||||||
await loadHost();
|
await loadHost();
|
||||||
|
} else {
|
||||||
|
agentControlMessage.value = job.message || "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user