Mobile was silently dropping two event types the gateway emits. This adds parsing + UI surfacing for both, bringing mobile to parity with desktop (which shows gateway errors as red toasts). - `error` (backend crash) -> WsEvent.GatewayError, surfaced in the existing error banner (mirrors how RpcError is handled). - `background.complete` (scheduled job finished) -> WsEvent.BackgroundComplete, surfaced as a non-blocking snackbar in ChatScreen. Changes: - WsEvent.kt: add GatewayError(message?) + BackgroundComplete(data?) sealed subtypes. - EventParser.kt: handle "error" + "background.complete"; unknowns still fall through to Unknown (no behavior change for existing event types). - ChatWsEventReducer.kt: onGatewayError (sets errorMessage, clears loading) + onBackgroundComplete (sets backgroundCompleteMessage); mirrors onRpcError. - ChatViewModel.kt: backgroundCompleteMessage state field, clearBackgroundComplete(), handleWsEvent branches (ViewModel owns the snackbar trigger). - ChatScreen.kt: pass backgroundCompleteMessage to ChatLifecycleEffects + a LaunchedEffect that shows the snackbar and calls clearBackgroundComplete(). - EventParserTest.kt: cover both new events (incl. missing-message case). Pure additive; sealed class + exhaustive when() preserved. Verified: compileDebugKotlin + ktlintCheck green; EventParserTest passes. Closes #527 Co-authored-by: M57 <m57@hermes-control.app>
This commit is contained in:
1 parent
480d29e481
commit
cf893585b1
6 files changed
+160
No files matched your search
@@ -423,6 +423,61 @@ class EventParserTest {
|
||||
assertEquals(mapOf("session_id" to "sess-1"), (event as WsEvent.SessionUpdated).data)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testParseGatewayError_returnsGatewayErrorEvent() {
|
||||
val response =
|
||||
createJsonRpcResponse(
|
||||
jsonrpc = "2.0",
|
||||
id = null,
|
||||
result = null,
|
||||
error = null,
|
||||
method = "event",
|
||||
params = mapOf("type" to "error", "payload" to mapOf("message" to "boom")),
|
||||
)
|
||||
val event = EventParser.parse(response, "")
|
||||
assertTrue(event is WsEvent.GatewayError)
|
||||
assertEquals("boom", (event as WsEvent.GatewayError).message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testParseGatewayError_missingMessage_returnsNullMessage() {
|
||||
val response =
|
||||
createJsonRpcResponse(
|
||||
jsonrpc = "2.0",
|
||||
id = null,
|
||||
result = null,
|
||||
error = null,
|
||||
method = "event",
|
||||
params = mapOf("type" to "error", "payload" to mapOf<String, String>()),
|
||||
)
|
||||
val event = EventParser.parse(response, "")
|
||||
assertTrue(event is WsEvent.GatewayError)
|
||||
assertEquals(null, (event as WsEvent.GatewayError).message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testParseBackgroundComplete_returnsBackgroundCompleteEvent() {
|
||||
val response =
|
||||
createJsonRpcResponse(
|
||||
jsonrpc = "2.0",
|
||||
id = null,
|
||||
result = null,
|
||||
error = null,
|
||||
method = "event",
|
||||
params =
|
||||
mapOf(
|
||||
"type" to "background.complete",
|
||||
"payload" to mapOf("label" to "nightly backup"),
|
||||
),
|
||||
)
|
||||
val event = EventParser.parse(response, "")
|
||||
assertTrue(event is WsEvent.BackgroundComplete)
|
||||
assertEquals(
|
||||
"nightly backup",
|
||||
(event as WsEvent.BackgroundComplete).data?.get("label"),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testParseUnknownType_returnsUnknownEvent() {
|
||||
val response =
|
||||
|
||||
Reference in new issue
Block a user