From c0d27a775485aec21792d8011b6fbf008200cd18 Mon Sep 17 00:00:00 2001 From: Nicolas Varrot Date: Thu, 12 Feb 2026 11:36:31 +0000 Subject: [PATCH] feat: add unread message indicators on sidebar sessions Show a cyan dot on sessions that received new messages while viewing a different session. The dot clears when switching to that session. --- src/components/Sidebar.tsx | 3 +++ src/hooks/useGateway.ts | 21 ++++++++++++++++++++- src/types/index.ts | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 8fc1378..1b44747 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -147,6 +147,9 @@ export function Sidebar({ sessions, activeSession, onSwitch, open, onClose }: Pr {s.isActive && ( )} + {s.hasUnread && !isActive && ( + + )}
diff --git a/src/hooks/useGateway.ts b/src/hooks/useGateway.ts index e8ba502..e045630 100644 --- a/src/hooks/useGateway.ts +++ b/src/hooks/useGateway.ts @@ -41,6 +41,7 @@ export function useGateway() { useEffect(() => { activeSessionRef.current = activeSession; }, [activeSession]); const currentRunIdRef = useRef(null); const [activeSessions, setActiveSessions] = useState>(new Set()); + const [unreadSessions, setUnreadSessions] = useState>(new Set()); const handleAgentEvent = useCallback((payload: JsonPayload) => { if (payload?.stream !== 'tool') return; @@ -241,7 +242,18 @@ export function useGateway() { } } - if (evtSession !== activeSessionRef.current) return; + if (evtSession !== activeSessionRef.current) { + // Mark non-active sessions as unread when they receive a final message + if (state === 'final' && evtSession) { + setUnreadSessions(prev => { + if (prev.has(evtSession)) return prev; + const next = new Set(prev); + next.add(evtSession); + return next; + }); + } + return; + } if (state === 'delta') { const text = extractText(message); @@ -358,6 +370,12 @@ export function useGateway() { setActiveSession(key); activeSessionRef.current = key; setMessages([]); + setUnreadSessions(prev => { + if (!prev.has(key)) return prev; + const next = new Set(prev); + next.delete(key); + return next; + }); loadHistory(key); }, [loadHistory]); @@ -388,6 +406,7 @@ export function useGateway() { const enrichedSessions = sessions.map(s => ({ ...s, isActive: activeSessions.has(s.key), + hasUnread: unreadSessions.has(s.key), })); return { diff --git a/src/types/index.ts b/src/types/index.ts index 516bc8d..550f6d4 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -20,6 +20,7 @@ export interface Session { label?: string; messageCount?: number; isActive?: boolean; + hasUnread?: boolean; totalTokens?: number; contextTokens?: number; inputTokens?: number;