diff --git a/backend/app/version.py b/backend/app/version.py
index 3b96cb9..977bc27 100644
--- a/backend/app/version.py
+++ b/backend/app/version.py
@@ -1,5 +1,5 @@
"""Единый источник версии SAC (API, health, логи, OpenAPI)."""
APP_NAME = "Security Alert Center"
-APP_VERSION = "0.20.32"
+APP_VERSION = "0.20.33"
APP_VERSION_LABEL = f"{APP_NAME} v.{APP_VERSION}"
diff --git a/backend/tests/test_health.py b/backend/tests/test_health.py
index 416dd04..c0e406a 100644
--- a/backend/tests/test_health.py
+++ b/backend/tests/test_health.py
@@ -4,6 +4,6 @@ from app.version import APP_NAME, APP_VERSION, APP_VERSION_LABEL
def test_version_constants():
- assert APP_VERSION == "0.20.32"
+ assert APP_VERSION == "0.20.33"
assert APP_NAME == "Security Alert Center"
- assert APP_VERSION_LABEL == "Security Alert Center v.0.20.32"
+ assert APP_VERSION_LABEL == "Security Alert Center v.0.20.33"
diff --git a/frontend/src/version.ts b/frontend/src/version.ts
index 18ecc97..efcc304 100644
--- a/frontend/src/version.ts
+++ b/frontend/src/version.ts
@@ -1,4 +1,4 @@
/** Fallback до загрузки /health; при релизе держите в sync с backend/app/version.py */
export const APP_NAME = "Security Alert Center";
-export const APP_VERSION = "0.20.32";
+export const APP_VERSION = "0.20.33";
export const APP_VERSION_LABEL = `${APP_NAME} v.${APP_VERSION}`;
diff --git a/frontend/src/views/DashboardView.vue b/frontend/src/views/DashboardView.vue
index ee6b6d2..8276ce4 100644
--- a/frontend/src/views/DashboardView.vue
+++ b/frontend/src/views/DashboardView.vue
@@ -297,6 +297,15 @@
>
qwinsta
+
@@ -333,6 +342,7 @@ import { onMounted, onUnmounted, ref } from "vue";
import {
apiFetch,
getToken,
+ postEventTerminateSession,
type DashboardSummary,
type EventSummary,
} from "../api";
@@ -342,9 +352,11 @@ import { useRdgQwinsta } from "../composables/useRdgQwinsta";
import { useSacVersion } from "../composables/useSacVersion";
import { formatServerName } from "../utils/hostDisplay";
import { hasRdgFlapUi, rdgFlapQwinstaEventId } from "../utils/rdgFlap";
+import { eventSupportsSessionTerminate } from "../utils/sessionActions";
const { appName, appVersion } = useSacVersion();
const { qwinstaLoadingId, qwinstaModal, closeQwinstaModal, runQwinsta, runLogoff } = useRdgQwinsta();
+const sessionTerminateLoadingId = ref(null);
const data = ref(null);
@@ -366,6 +378,22 @@ function formatDt(iso: string) {
}
+async function runSessionTerminate(event: EventSummary) {
+ const label = event.actor_user || event.title;
+ if (!window.confirm(`Завершить сессию пользователя ${label}?`)) return;
+ sessionTerminateLoadingId.value = event.id;
+ try {
+ const res = await postEventTerminateSession(event.id);
+ if (!res.ok) {
+ window.alert(res.message);
+ }
+ } catch (e) {
+ window.alert(e instanceof Error ? e.message : "Ошибка завершения сессии");
+ } finally {
+ sessionTerminateLoadingId.value = null;
+ }
+}
+
function syncLastKnownFromRecent() {