fix: hide ????????? after session terminate (0.3.8)
Persist session_terminated in event details, expose in API, and update Events/Dashboard UI. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -189,6 +189,7 @@ export interface EventSummary {
|
||||
rdg_flap_qwinsta_event_id?: number | null;
|
||||
rdg_access_path?: string | null;
|
||||
rdg_qwinsta_enabled?: boolean;
|
||||
session_terminated?: boolean;
|
||||
}
|
||||
|
||||
export interface AgentCommandResponse {
|
||||
|
||||
@@ -14,3 +14,19 @@ export function eventSupportsSessionTerminate(event: Pick<EventSummary, "type">)
|
||||
WINDOWS_SESSION_EVENT_TYPES.has(event.type)
|
||||
);
|
||||
}
|
||||
|
||||
export function showEventSessionTerminateButton(
|
||||
event: Pick<EventSummary, "type" | "session_terminated">,
|
||||
): boolean {
|
||||
return eventSupportsSessionTerminate(event) && !event.session_terminated;
|
||||
}
|
||||
|
||||
export function markEventSessionTerminatedInList(
|
||||
items: EventSummary[] | undefined,
|
||||
eventId: number,
|
||||
): void {
|
||||
const item = items?.find((row) => row.id === eventId);
|
||||
if (item) {
|
||||
item.session_terminated = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/** Fallback до загрузки /health; при релизе держите в sync с backend/app/version.py */
|
||||
export const APP_NAME = "Security Alert Center";
|
||||
export const APP_VERSION = "0.3.7";
|
||||
export const APP_VERSION = "0.3.8";
|
||||
export const APP_VERSION_LABEL = `${APP_NAME} v.${APP_VERSION}`;
|
||||
|
||||
@@ -299,7 +299,7 @@
|
||||
Обрыв RDS
|
||||
</button>
|
||||
<button
|
||||
v-if="eventSupportsSessionTerminate(e)"
|
||||
v-if="showEventSessionTerminateButton(e)"
|
||||
type="button"
|
||||
class="secondary dash-qwinsta-btn"
|
||||
:disabled="sessionTerminateLoadingId === e.id"
|
||||
@@ -342,6 +342,7 @@ import { onMounted, onUnmounted, ref } from "vue";
|
||||
|
||||
import {
|
||||
apiFetch,
|
||||
ApiError,
|
||||
getToken,
|
||||
postEventTerminateSession,
|
||||
type DashboardSummary,
|
||||
@@ -353,7 +354,7 @@ import RdgQwinstaModal from "../components/RdgQwinstaModal.vue";
|
||||
import { useRdgQwinsta } from "../composables/useRdgQwinsta";
|
||||
import { formatServerName } from "../utils/hostDisplay";
|
||||
import { hasRdgFlapUi, rdgQwinstaEventId } from "../utils/rdgFlap";
|
||||
import { eventSupportsSessionTerminate } from "../utils/sessionActions";
|
||||
import { markEventSessionTerminatedInList, showEventSessionTerminateButton } from "../utils/sessionActions";
|
||||
|
||||
const { qwinstaLoadingId, qwinstaModal, closeQwinstaModal, runQwinsta, runLogoff } = useRdgQwinsta();
|
||||
const sessionTerminateLoadingId = ref<number | null>(null);
|
||||
@@ -386,8 +387,13 @@ async function runSessionTerminate(event: EventSummary) {
|
||||
const res = await postEventTerminateSession(event.id);
|
||||
if (!res.ok) {
|
||||
window.alert(res.message);
|
||||
} else {
|
||||
markEventSessionTerminatedInList(data.value?.recent_events, event.id);
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof ApiError && e.status === 409) {
|
||||
markEventSessionTerminatedInList(data.value?.recent_events, event.id);
|
||||
}
|
||||
window.alert(e instanceof Error ? e.message : "Ошибка завершения сессии");
|
||||
} finally {
|
||||
sessionTerminateLoadingId.value = null;
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
Обрыв RDS
|
||||
</button>
|
||||
<button
|
||||
v-if="eventSupportsSessionTerminate(e)"
|
||||
v-if="showEventSessionTerminateButton(e)"
|
||||
type="button"
|
||||
class="secondary events-qwinsta-btn"
|
||||
:disabled="sessionTerminateLoadingId === e.id"
|
||||
@@ -106,7 +106,7 @@
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { useSacLiveEventStream } from "../composables/useSacLiveEventStream";
|
||||
import { apiFetch, postEventTerminateSession, type EventListResponse, type EventSummary } from "../api";
|
||||
import { apiFetch, ApiError, postEventTerminateSession, type EventListResponse, type EventSummary } from "../api";
|
||||
import RdgAccessBadge from "../components/RdgAccessBadge.vue";
|
||||
import RdgFlapBadge from "../components/RdgFlapBadge.vue";
|
||||
import RdgQwinstaModal from "../components/RdgQwinstaModal.vue";
|
||||
@@ -120,7 +120,7 @@ import {
|
||||
type EventsListState,
|
||||
} from "../utils/eventsListQuery";
|
||||
import { formatServerName } from "../utils/hostDisplay";
|
||||
import { eventSupportsSessionTerminate } from "../utils/sessionActions";
|
||||
import { markEventSessionTerminatedInList, showEventSessionTerminateButton } from "../utils/sessionActions";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
@@ -227,8 +227,13 @@ async function runSessionTerminate(event: EventSummary) {
|
||||
const res = await postEventTerminateSession(event.id);
|
||||
if (!res.ok) {
|
||||
window.alert(res.message);
|
||||
} else {
|
||||
markEventSessionTerminatedInList(data.value?.items, event.id);
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof ApiError && e.status === 409) {
|
||||
markEventSessionTerminatedInList(data.value?.items, event.id);
|
||||
}
|
||||
window.alert(e instanceof Error ? e.message : "Ошибка завершения сессии");
|
||||
} finally {
|
||||
sessionTerminateLoadingId.value = null;
|
||||
|
||||
Reference in New Issue
Block a user