webui: fix IDLE/DISCONNECTED oscillation by replacing initialLoadComplete misuse
Fix DataManager session_ended handler that caused rapid status switching
between IDLE and DISCONNECTED when sessions ended.
Issue Description:
When a session ended, the UI's sketch-call-status component would rapidly
oscillate between IDLE and DISCONNECTED states, suggesting continued
connection attempts despite the session being over.
Root Cause Analysis:
The primary issue was session_ended handler improperly firing initialLoadComplete
event, confusing timeline component state management. The initialLoadComplete event
was added for newsessions functionality but broke assumptions in regular sketch
sessions. The timeline component expects initialLoadComplete to signal new page
loads, not ended sessions.
When fired for ended sessions, this caused UI re-render cycles and state confusion
that interfered with connection status display, creating the oscillation effect.
Implementation Changes:
- Added sessionDataReady event type for ended session data readiness
- Modified session_ended handler to emit sessionDataReady instead of
initialLoadComplete for ended sessions
- Preserved initialLoadComplete semantics for active session data loading
- Added clarifying comment to existing isSessionEnded guard in connect()
Security & Compatibility:
- No security implications, purely UI state management fix
- Newsessions component unaffected (doesn't use initialLoadComplete)
- Timeline component behavior restored to expected state
- All existing event handling preserved
This fix eliminates the connection status oscillation while maintaining
proper separation of concerns between live session loading and ended
session display states.
Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: scd1b437c8ae7c381k
diff --git a/webui/src/data.ts b/webui/src/data.ts
index 247a9cb..9d24444 100644
--- a/webui/src/data.ts
+++ b/webui/src/data.ts
@@ -7,7 +7,8 @@
| "dataChanged"
| "connectionStatusChanged"
| "initialLoadComplete"
- | "sessionEnded";
+ | "sessionEnded"
+ | "sessionDataReady";
/**
* Connection status types
@@ -56,6 +57,7 @@
this.eventListeners.set("connectionStatusChanged", []);
this.eventListeners.set("initialLoadComplete", []);
this.eventListeners.set("sessionEnded", []);
+ this.eventListeners.set("sessionDataReady", []);
// Check connection status periodically
setInterval(() => this.checkConnectionStatus(), 5000);
@@ -73,6 +75,7 @@
* Connect to the SSE stream
*/
private connect(): void {
+ // Don't attempt to connect if the session has ended
if (this.isSessionEnded) {
console.log("Skipping connection attempt - session has ended");
return;
@@ -208,9 +211,12 @@
state: this.timelineState,
newMessages: [],
});
- this.emitEvent("initialLoadComplete", {
+ // Emit sessionDataReady for components that need to know the ended session data is ready
+ // (like newsessions), but don't emit initialLoadComplete as that's for live session loads
+ this.emitEvent("sessionDataReady", {
messageCount: this.messages.length,
expectedCount: this.messages.length,
+ isEndedSession: true,
});
});
}