Skip to content

feat(web): show session status indicators in sidebar#1701

Open
Jesse-XIE wants to merge 1 commit intoMoonshotAI:mainfrom
Jesse-XIE:feat/session-status-indicator
Open

feat(web): show session status indicators in sidebar#1701
Jesse-XIE wants to merge 1 commit intoMoonshotAI:mainfrom
Jesse-XIE:feat/session-status-indicator

Conversation

@Jesse-XIE
Copy link
Copy Markdown
Contributor

@Jesse-XIE Jesse-XIE commented Apr 1, 2026

Related Issue

no

Description

Add visual dot indicators after the timestamp in the session list:

State Indicator Description
busy 🟢 Green pulsing dot Session is actively running (matches bottom status indicator animation)
unread 🔵 Blue static dot Session completed a turn while user was viewing another session
idle No dot Default state

Track unread sessions via busy→idle transitions from both WebSocket status events and API refresh polling. Clear unread on session select.

image

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked the related issue, if any.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have run make gen-changelog to update the changelog.
  • I have run make gen-docs to update the user documentation.

Open with Devin

Related Issue

no

Description

Add visual dot indicators after the timestamp in the session list:

State Indicator Description
busy 🟢 Green pulsing dot Session is actively running (matches bottom status indicator animation)
unread 🔵 Blue static dot Session completed a turn while user was viewing another session
idle No dot Default state

Track unread sessions via busy→idle transitions from both WebSocket status events and API refresh polling. Clear unread on session select.

image

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked the related issue, if any.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have run make gen-changelog to update the changelog.
  • I have run make gen-docs to update the user documentation.

Open with Devin

Add visual dot indicators after the timestamp in the session list:
- busy: green pulsing dot (animate-pulse)
- unread: blue static dot (completed while user was viewing another session)
- idle: no dot (default)

Track unread sessions via busy→idle transitions from both WebSocket
status events and API refresh polling. Clear unread on session select.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 35262d2aab

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +365 to +369
setUnreadSessionIds((prev) => {
if (!prev.has(sessionId)) return prev;
const next = new Set(prev);
next.delete(sessionId);
return next;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clear unread when selection changes from any path

Unread state is currently cleared only in the sidebar click handler, so programmatic selection paths (for example URL restore in App, or auto-selection after deleting the current session in useSessions.deleteSession) bypass this logic. When that happens, a session can stay marked unread even while it is the active session, leaving a stale blue indicator. Clearing unread based on selectedSessionId changes (instead of only click events) would keep the indicator consistent.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment on lines +306 to +313
// Mark as unread when a non-selected session finishes (becomes non-busy)
if (status.state !== "busy" && status.sessionId !== selectedSessionId) {
setUnreadSessionIds((prev) => {
const next = new Set(prev);
next.add(status.sessionId);
return next;
});
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 handleSessionStatus marks unread on any non-busy status instead of only busy→non-busy transitions

The unread marking logic in handleSessionStatus at line 307 marks a session as unread whenever status.state !== "busy" for a non-selected session, without checking whether the previous state was "busy". This differs from the useEffect at web/src/App.tsx:284-287 which correctly checks prevState === "busy" && state !== "busy" to detect transitions only.

In the current architecture this code is effectively dead — the WebSocket connects per-session to the selected session, so status.sessionId !== selectedSessionId is always false. However, if the backend or architecture ever changes to deliver cross-session status events through a single WebSocket, this would cause false-positive unread badges: any non-busy status (e.g., an idle status with reason: "config_update", or a stopped session that was never busy) would incorrectly mark the session as unread, and the unread dot would reappear even after the user has cleared it by clicking the session.

Prompt for agents
In web/src/App.tsx, the unread marking inside handleSessionStatus (lines 306-313) should track the previous state to only mark as unread on busy→non-busy transitions, matching the useEffect logic at lines 274-300. Since handleSessionStatus is called per-event (not on batch session updates), you'd need to consult prevSessionStatusRef to check the previous state:

1. Read the previous state from prevSessionStatusRef.current.get(status.sessionId)
2. Only add to unreadSessionIds if the previous state was "busy" AND the new state is not "busy"
3. Update prevSessionStatusRef.current with the new state

Alternatively, since this code path currently never fires (WebSocket is per-session, so status.sessionId always equals selectedSessionId), consider removing this block entirely and relying solely on the useEffect at lines 274-300 for unread detection.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant