fix: hide session terminate after SAC marks event terminated

Read session_terminated from API and update UI after successful logoff.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
PTah
2026-06-24 14:45:36 +10:00
parent 47842e0ef3
commit d794d7dc48
4 changed files with 20 additions and 5 deletions
@@ -63,6 +63,7 @@ data class EventSummary(
@SerialName("rdg_flap_qwinsta_event_id") val rdgFlapQwinstaEventId: Long? = null,
@SerialName("rdg_access_path") val rdgAccessPath: String? = null,
@SerialName("rdg_qwinsta_enabled") val rdgQwinstaEnabled: Boolean = false,
@SerialName("session_terminated") val sessionTerminated: Boolean = false,
)
@Serializable
@@ -91,6 +92,7 @@ data class EventDetail(
@SerialName("rdg_flap_qwinsta_event_id") val rdgFlapQwinstaEventId: Long? = null,
@SerialName("rdg_access_path") val rdgAccessPath: String? = null,
@SerialName("rdg_qwinsta_enabled") val rdgQwinstaEnabled: Boolean = false,
@SerialName("session_terminated") val sessionTerminated: Boolean = false,
val details: JsonElement? = null,
val raw: JsonElement? = null,
val payload: JsonElement? = null,
@@ -183,7 +183,11 @@ fun EventDetailScreen(repo: SacRepository, id: Long, onBack: () -> Unit) {
terminateMessage = null
try {
val res = repo.withAuth { it.postEventTerminateSession(id) }
if (!res.ok) terminateMessage = res.message
if (!res.ok) {
terminateMessage = res.message
} else {
data = data?.copy(sessionTerminated = true)
}
} catch (e: Exception) {
terminateMessage = if (e is HttpException) SacRepository.parseError(e) else e.message
} finally {
@@ -207,6 +207,7 @@ fun EventsScreen(repo: SacRepository, onOpen: (Long) -> Unit) {
var terminateLoadingId by remember { mutableStateOf<Long?>(null) }
var terminateConfirm by remember { mutableStateOf<EventSummary?>(null) }
var terminateError by remember { mutableStateOf<String?>(null) }
var locallyTerminatedIds by remember { mutableStateOf(setOf<Long>()) }
val dateMode by repo.session.dateTimeDisplayMode.collectAsStateWithLifecycle(
initialValue = DateTimeDisplayMode.SLASH,
)
@@ -230,7 +231,11 @@ fun EventsScreen(repo: SacRepository, onOpen: (Long) -> Unit) {
terminateError = null
try {
val res = repo.withAuth { it.postEventTerminateSession(target.id) }
if (!res.ok) terminateError = res.message
if (!res.ok) {
terminateError = res.message
} else {
locallyTerminatedIds = locallyTerminatedIds + target.id
}
} catch (e: Exception) {
terminateError = if (e is HttpException) SacRepository.parseError(e) else e.message
} finally {
@@ -268,7 +273,9 @@ fun EventsScreen(repo: SacRepository, onOpen: (Long) -> Unit) {
itemQwinsta = { rdgQwinstaEventId(it) != null },
onQwinsta = { qwinsta.openFor(it, scope) },
qwinstaLoading = qwinsta.loading,
itemTerminate = { eventSupportsSessionTerminate(it) },
itemTerminate = {
eventSupportsSessionTerminate(it) && it.id !in locallyTerminatedIds
},
onTerminate = { terminateConfirm = it },
terminateLoadingId = terminateLoadingId,
onOpen = onOpen,
@@ -12,10 +12,12 @@ private val LINUX_SESSION_EVENT_TYPES = setOf(
private val WINDOWS_SESSION_EVENT_TYPES = setOf("rdp.login.success")
fun eventSupportsSessionTerminate(event: EventSummary): Boolean =
event.type in LINUX_SESSION_EVENT_TYPES || event.type in WINDOWS_SESSION_EVENT_TYPES
(event.type in LINUX_SESSION_EVENT_TYPES || event.type in WINDOWS_SESSION_EVENT_TYPES) &&
!event.sessionTerminated
fun eventSupportsSessionTerminate(event: EventDetail): Boolean =
event.type in LINUX_SESSION_EVENT_TYPES || event.type in WINDOWS_SESSION_EVENT_TYPES
(event.type in LINUX_SESSION_EVENT_TYPES || event.type in WINDOWS_SESSION_EVENT_TYPES) &&
!event.sessionTerminated
fun sessionTerminateLabel(event: EventSummary): String =
event.actorUser?.takeIf { it.isNotBlank() } ?: event.title