Skip to content

fix(ui): prevent sidebar instance reordering and new conversation flicker#213

Merged
karthikmudunuri merged 1 commit intomainfrom
fix/ui-sidebar-reorder-and-new-conversation-flicker
Apr 7, 2026
Merged

fix(ui): prevent sidebar instance reordering and new conversation flicker#213
karthikmudunuri merged 1 commit intomainfrom
fix/ui-sidebar-reorder-and-new-conversation-flicker

Conversation

@karthikmudunuri
Copy link
Copy Markdown
Member

Problem

Two bugs in the chat UI caused a jarring experience:

  1. Sidebar instances reorder on every interaction — When switching between conversations across different instances (e.g. Claude Code and OpenClaw), the sidebar moved the focused instance to the top, causing the list to jump around. This happened because sortAgentGroupsForFocus() prioritized the focused agent and fetchAgents re-ran on every URL change, replacing the agent list with a potentially different order each time.

  2. New conversation creation causes visible flicker — Creating a new conversation briefly flashed the old conversation before showing the new one. The root cause was two separate React Router <Route> elements rendering ChatPage (c/:name? and c/:name/:conversationId). When the URL changed from /c/name to /c/name/conv-id, React Router unmounted and remounted the component, resetting all state and triggering a full re-fetch.

Fix

  • Replace the two chat routes with a single catch-all c/* route so React Router never unmounts ChatPage during navigation.
  • Parse name and conversationId from the wildcard splat param instead of named route params.
  • Always sort sidebar agents alphabetically instead of moving the focused one to the top.
  • Stabilise fetchAgents using refs for URL params so it only runs once on mount, not on every navigation.
  • Update handleNewConversation to insert the new conversation into local state directly instead of calling fetchAgents, eliminating a full re-fetch cycle.
  • Guard applyConversationUpdate so stale WebSocket events don't overwrite the currently selected conversation.

Test plan

  • Added sidebar tests verifying alphabetical order is maintained regardless of focus or input order
  • Added chat page tests for stable instance ordering across conversation switches
  • Added chat page test confirming no flicker when creating a new conversation
  • Updated all existing tests to use the new catch-all route — full suite passes (28 files, 202 tests)

…cker

Two separate bugs caused a jarring experience when switching between
instances or creating new conversations in the chat sidebar:

1. Sidebar instances reordered on every interaction because the old
   sortAgentGroupsForFocus() moved the focused agent to the top and
   fetchAgents re-ran on every URL change, replacing state with a
   potentially different order. Fixed by always sorting alphabetically
   in the Sidebar component and stabilising fetchAgents with refs so
   it only runs on mount.

2. Creating a new conversation caused a visible flicker because React
   Router had two separate Route elements for the chat page (c/:name?
   and c/:name/:conversationId). Navigating from one to the other
   unmounted and remounted ChatPage, resetting all state. Fixed by
   collapsing both routes into a single catch-all (c/*) and parsing
   the name/conversationId from the wildcard param.

Additional fixes:
- handleNewConversation now updates local state directly instead of
  calling fetchAgents, eliminating a full re-fetch cycle.
- applyConversationUpdate only updates selectedConversation if it
  matches the currently viewed conversation, preventing stale
  WebSocket events from overwriting the selection.
@karthikmudunuri karthikmudunuri merged commit 144caff into main Apr 7, 2026
1 check passed
@karthikmudunuri karthikmudunuri deleted the fix/ui-sidebar-reorder-and-new-conversation-flicker branch April 7, 2026 17:55
@gitrank-connector
Copy link
Copy Markdown

👍 GitRank PR Analysis

Score: 20 points

Metric Value
Component Other (1× multiplier)
Severity P2 - Medium (20 base pts)
Final Score 20 × 1 = 20

Eligibility Checks

Check Status
Issue/Bug Fix
Fix Implementation
PR Documented
Tests
Lines Within Limit

Impact Summary

This PR fixes two distinct UI bugs: (1) sidebar instances reordering on every interaction by switching from focus-based sorting to alphabetical sorting and stabilizing the fetchAgents callback, and (2) new conversation creation flicker by consolidating two separate React Router routes into a single catch-all route to prevent component remounting. The fix includes comprehensive test coverage with 166 new test lines and updates to 28 test files, demonstrating thorough validation of the changes.

Analysis Details

Component Classification: This PR affects UI components (sidebar, chat page routing, and state management) but doesn't fit neatly into a single specialized category. The changes span multiple UI layers without a dominant component type, making OTHER the appropriate classification.

Severity Justification: This is a P2 (Medium) severity fix addressing functional bugs with workarounds. While the sidebar reordering and conversation flicker are jarring UX issues that impact user experience, they don't cause data loss, service outages, or security risks. Users can work around these issues by refreshing or manually managing their workflow.

Eligibility Notes: Issue: True - PR clearly describes two specific bugs being fixed. Fix Implementation: True - code changes directly address both problems (route consolidation, alphabetical sorting, ref-based stability). PR Linked: True - detailed problem statement, root cause analysis, and test plan provided. Tests: True - 166 lines of new tests added covering instance ordering, conversation switching, and flicker prevention. Tests Required: True - this is a bug fix in business logic (routing and state management) that requires regression testing to ensure the fixes work and don't introduce new issues.


Analyzed by GitRank 🤖

karthikmudunuri added a commit that referenced this pull request Apr 7, 2026
PR #213 stabilised fetchAgents by moving URL params into refs and
running the effect only on mount. A side-effect was that navigating
to a conversation URL (e.g. from a Discord link) could trigger an
infinite WebSocket reconnection loop when the conversation was not
immediately available in the list response.

Root causes and fixes:

1. fetchAgents auto-created a second conversation when the URL-specified
   one was missing from the list. Now it tries a direct GET for the
   conversation first, and if that also fails it returns early instead
   of auto-creating a duplicate.

2. applyConversationUpdate silently dropped WebSocket events when
   selectedConversation was null (null && ... evaluates to null).
   Changed the guard from (prev && prev.name === conv.name) to
   (!prev || prev.name === conv.name) so the first event properly
   sets the selection.

3. After mount, URL param changes had no way to update the selected
   conversation from already-fetched data. Added a useEffect that
   watches [name, urlConversationId, agents] and syncs the selection.
karthikmudunuri added a commit that referenced this pull request Apr 7, 2026
fix(ui): prevent WebSocket reconnection loop after PR #213

PR #213 stabilised fetchAgents by moving URL params into refs and
running the effect only on mount. A side-effect was that navigating
to a conversation URL (e.g. from a Discord link) could trigger an
infinite WebSocket reconnection loop when the conversation was not
immediately available in the list response.

Root causes and fixes:

1. fetchAgents auto-created a second conversation when the URL-specified
   one was missing from the list. Now it tries a direct GET for the
   conversation first, and if that also fails it returns early instead
   of auto-creating a duplicate.

2. applyConversationUpdate silently dropped WebSocket events when
   selectedConversation was null (null && ... evaluates to null).
   Changed the guard from (prev && prev.name === conv.name) to
   (!prev || prev.name === conv.name) so the first event properly
   sets the selection.

3. After mount, URL param changes had no way to update the selected
   conversation from already-fetched data. Added a useEffect that
   watches [name, urlConversationId, agents] and syncs the selection.
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