Skip to content

Fix sidebar flickering and reconnecting toast loop#66

Merged
JoshuaAFerguson merged 2 commits into
mainfrom
claude/fix-sidebar-flickering-01GuuznEcY7nFxSJQtztkSCZ
Nov 17, 2025
Merged

Fix sidebar flickering and reconnecting toast loop#66
JoshuaAFerguson merged 2 commits into
mainfrom
claude/fix-sidebar-flickering-01GuuznEcY7nFxSJQtztkSCZ

Conversation

@JoshuaAFerguson

Copy link
Copy Markdown
Member

No description provided.

Issue: Sidebar constantly flickering and WebSocket repeatedly disconnecting

Root Causes:
1. EnhancedWebSocketStatus countdown timer updated every second
   - setCountdown() called every 1000ms causing re-renders
   - Re-renders propagated through component tree to Layout
   - Caused sidebar to flicker with CSS transitions
2. WebSocket backend missing ping/pong keepalive
   - Connections timed out due to inactivity
   - Triggered reconnection attempts and countdown display

Solutions:
1. UI Fix - Remove per-second countdown updates
   - Changed countdown timer to set initial value only
   - Removed setInterval that updated every second
   - Now shows "Reconnecting... (attempt X/10)" without ticking countdown
   - Status still updates when reconnection attempt changes
   - Prevents thousands of unnecessary re-renders

2. Backend Fix - Add WebSocket ping/pong keepalive
   - writePump(): Send ping every 30 seconds to keep connection alive
   - readPump(): Set 60s read deadline and pong handler
   - Reset deadlines on any message activity
   - Prevents idle connection timeouts

Technical Details:
- UI: EnhancedWebSocketStatus.tsx countdown effect simplified
- UI: LinearProgress changed from determinate to indeterminate
- UI: Static "~Xs" display instead of live countdown
- Backend: Added time.NewTicker for 30s ping interval
- Backend: Added SetReadDeadline(60s) and SetPongHandler
- Backend: Added SetWriteDeadline(10s) for write operations

Result: Sidebar only re-renders on actual navigation or status changes,
not every second. WebSocket stays connected indefinitely.

Files Changed:
- ui/src/components/EnhancedWebSocketStatus.tsx
- api/internal/websocket/hub.go
Issue: The WebSocket status indicator's spinning circle constantly restarts,
making the UI appear glitchy and distracting to users.

Root Cause:
The CircularProgress component in EnhancedWebSocketStatus was being recreated
on every render because getStatusIcon() returned a new React element each time.
Even though the component was memoized, any prop change (like latency updating
every 10 seconds) would trigger a re-render, creating a new CircularProgress
element and restarting its animation.

Solution:
- Added useMemo to memoize the status icon
- Icon only recreates when connection status actually changes
  (isConnected, reconnectAttempts, or maxReconnectAttempts change)
- Latency updates no longer cause the spinner to restart
- Removed duplicate getStatusIcon() function

Technical Details:
- Added useMemo import to React imports
- Created statusIcon memoized value with proper dependencies
- Updated Chip and Popover to use statusIcon instead of getStatusIcon()
- Removed redundant getStatusIcon() function

Result: The CircularProgress spinner animation now runs smoothly without
restarting, even when other component props update. This provides a much
better user experience when WebSocket is reconnecting.

Files Changed:
- ui/src/components/EnhancedWebSocketStatus.tsx
@JoshuaAFerguson JoshuaAFerguson merged commit d26972f into main Nov 17, 2025
7 of 23 checks passed
@JoshuaAFerguson JoshuaAFerguson deleted the claude/fix-sidebar-flickering-01GuuznEcY7nFxSJQtztkSCZ branch November 17, 2025 19:52
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