Skip to content

feat: dashboard UX — shortcuts, reconnect, per-project sessions - #14

Merged
aterrylu merged 1 commit into
mainfrom
terry/dashboard-ux-improvements
Mar 10, 2026
Merged

feat: dashboard UX — shortcuts, reconnect, per-project sessions#14
aterrylu merged 1 commit into
mainfrom
terry/dashboard-ux-improvements

Conversation

@aterrylu

@aterrylu aterrylu commented Mar 9, 2026

Copy link
Copy Markdown
Owner

Summary

  • Keyboard shortcuts: Ctrl+B toggles sidebar (VSCode-style, captured even when terminal is focused), Ctrl+O forwards to Claude Code for show-details view
  • WebSocket auto-reconnect: Exponential backoff (1s→10s max) on unexpected disconnects, immediate reconnect on tab visibility change — fixes stale terminal after idle/tab switch
  • Per-project new session: Hover a project in sidebar to see + button that starts a session in that project's directory. createSession now accepts optional workingDirectory

Test plan

  • Ctrl+B toggles sidebar from anywhere (terminal focused or not)
  • Ctrl+O in active session triggers Claude Code details view
  • Switch tabs for ~60s, return — terminal should auto-reconnect without page refresh
  • Hover project name in sidebar → green + appears → click starts session in that project dir
  • Top-level + still creates session at ~

🤖 Generated with Claude Code

- Ctrl+B toggles sidebar (VSCode-style, intercepted even in terminal)
- Ctrl+O passes through to Claude Code for show-details
- Auto-reconnect WebSocket with exponential backoff on disconnect
- Reconnect on tab visibility change (browser suspend recovery)
- Per-project "+" button to start sessions in project directory
- createSession now accepts optional workingDirectory

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
// Reconnect when tab regains focus (browser may have killed the WS)
const handleVisibility = () => {
if (
document.visibilityState === "visible" &&

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟡 Warning

Problem: handleVisibility can trigger connect() while a pending reconnectTimer is still queued. If the WS dropped while the tab was hidden, the timer was already scheduled — then visibility fires and calls connect() immediately, then the timer fires and calls connect() again. The second call overwrites wsRef.current, leaving the first socket as a zombie writing duplicate data into the terminal.

Why it matters: User returns to tab, gets reconnected, sees output — then a second WebSocket fires ~1s later and starts writing duplicate/interleaved terminal data. Hard to reproduce reliably, but definitely possible.

Suggested fix:

const handleVisibility = () => {
  if (
    document.visibilityState === "visible" &&
    wsRef.current?.readyState !== WebSocket.OPEN &&
    wsRef.current?.readyState !== WebSocket.CONNECTING
  ) {
    if (reconnectTimer) {
      clearTimeout(reconnectTimer);
      reconnectTimer = null;
    }
    retryDelay = 1000;
    connect();
  }
};

@nox-0x nox-0x left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Solid UX wins — reconnect logic, per-project sessions, and keyboard shortcuts all look clean. One warning left inline: handleVisibility needs to clear the pending reconnectTimer before calling connect() to avoid a double-socket race that could write duplicate output to the terminal. Easy one-liner fix, not blocking merge.

@aterrylu
aterrylu merged commit e99e0d3 into main Mar 10, 2026
1 check failed
@aterrylu
aterrylu deleted the terry/dashboard-ux-improvements branch March 10, 2026 06:04
aterrylu added a commit that referenced this pull request Mar 10, 2026
…F-003)

Add a ChatGPT-style conversation view for browsing Claude Code session
transcripts. User messages appear as right-aligned bubbles, assistant
messages flow freely on the left with an avatar. Tool calls render as
expandable blocks with status indicators and tool-specific summaries.

Architecture: Parser (provider-specific) → RenderItem[] (stable contract)
→ Renderer (swappable). ClaudeCodeParser handles JSONL format with
cross-message tool_use/tool_result pairing.

New packages/routes:
- core: RenderItem types, SessionParser interface, ClaudeCodeParser
- server: GET /api/conversation/:sessionId endpoint
- dashboard: ConversationView, ToolCallBlock, ThinkingBlock components

Also fixes TS errors from PR #14 (Sidebar onClick signature, sessionId null check).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

2 participants