fix(mobile): reconnects no longer shift the thread list - #5372
Conversation
The environment connection status rendered as a row above the thread
list, so every reconnect pushed the rows down and popped them back.
The brand/title slot in the header now doubles as the status surface:
while an environment is unavailable the lockup ("Threads" on the iPad
sidebar) fades to a spinner plus status label in place, and fades back
on reconnect. Nothing is inserted into the list, so its geometry never
moves. An 800ms debounce keeps sub-second blips invisible entirely.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d61499f. Configure here.
| {status.label} | ||
| </Text> | ||
| </Pressable> | ||
| </StatusFadeIn> |
There was a problem hiding this comment.
Status labels overflow header actions
Medium Severity
When WorkspaceConnectionTitle displays a connection status with grow, the inner Pressable and its label don't properly constrain their width. This allows long status messages to overflow and overlap adjacent header controls, as flex: 1 and minWidth: 0 are not effectively applied to the content.
Reviewed by Cursor Bugbot for commit d61499f. Configure here.
ApprovabilityVerdict: Needs human review PR is marked WIP and introduces a new component with meaningful UI behavior changes (relocating connection status display). An unresolved comment identifies a potential layout overflow issue in the new component. You can customize Macroscope's approvability policy. Learn more. |
Adopts the two upstream commits after #378: reconnects no longer shift the mobile thread list (pingdotgg#5372) and the v0.0.32 release prep. pingdotgg#5372 moves connection status out of the lists into the header title slot (WorkspaceConnectionTitle / getConnectionAwareBrandHeaderOptions) and deletes WorkspaceConnectionStatus. The fork rendered that status in four places across HomeScreen and ThreadNavigationSidebar — exactly the row-shifting this fixes — so those in-list surfaces are removed and the header slots adopted. The auto-merge left one dangling {connectionStatus} in HomeScreen whose definition upstream had deleted; typecheck caught it. Fork surfaces kept around the new title: - multi-environment selection: HomeScreen keeps its selectedEnvironmentIds label derivation and environmentLabelById (BoardScreen consumes it) instead of upstream's single selectedEnvironmentId. - board mode: ThreadNavigationSidebar keeps its board branch, board-specific solid header, and board-gated search bar, with upstream's connection-aware brand slot merged into the same header options. - HomeRouteScreen keeps the fork's in-flow HomeHeader as title owner rather than also restoring upstream's native-stack title, which would surface the connection status twice. Adversarial review caught two holes in the first pass, both fixed here: getConnectionAwareBrandHeaderOptions hardcodes the brand lockup and "Threads", so spreading it over the fork's list-mode titles silently replaced "Board" / "Projects"; and iOS Home has its own IosHomeHeader owning the native title, so dropping upstream's route-level options left that path with no status surface at all. The helper now takes an optional title/brand, and both the sidebar and IosHomeHeader pass their mode title through it. Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
Adopts the two upstream commits after #378: reconnects no longer shift the mobile thread list (pingdotgg#5372) and the v0.0.32 release prep. pingdotgg#5372 moves connection status out of the lists into the header title slot (WorkspaceConnectionTitle / getConnectionAwareBrandHeaderOptions) and deletes WorkspaceConnectionStatus. The fork rendered that status in four places across HomeScreen and ThreadNavigationSidebar — exactly the row-shifting this fixes — so those in-list surfaces are removed and the header slots adopted. The auto-merge left one dangling {connectionStatus} in HomeScreen whose definition upstream had deleted; typecheck caught it. Fork surfaces kept around the new title: - multi-environment selection: HomeScreen keeps its selectedEnvironmentIds label derivation and environmentLabelById (BoardScreen consumes it) instead of upstream's single selectedEnvironmentId. - board mode: ThreadNavigationSidebar keeps its board branch, board-specific solid header, and board-gated search bar, with upstream's connection-aware brand slot merged into the same header options. - HomeRouteScreen keeps the fork's in-flow HomeHeader as title owner rather than also restoring upstream's native-stack title, which would surface the connection status twice. Adversarial review caught two holes in the first pass, both fixed here: getConnectionAwareBrandHeaderOptions hardcodes the brand lockup and "Threads", so spreading it over the fork's list-mode titles silently replaced "Board" / "Projects"; and iOS Home has its own IosHomeHeader owning the native title, so dropping upstream's route-level options left that path with no status surface at all. The helper now takes an optional title/brand, and both the sidebar and IosHomeHeader pass their mode title through it. A second review pass caught one more surface — the custom (Android split) sidebar large title still hardcoded "Threads" — plus the status offset being applied to caller-supplied titles that lack the brand lockup's inset. Both fixed, and mobileSurfaceExistence now asserts every adopting surface passes its own list-mode title (that assertion fails on the pre-fix tree). Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
Adopts pingdotgg#5581 (drag pinned threads into your own order) on top of the pingdotgg#5372 merge already on this branch. Pinned rows now sort by the user's arranged pinOrderKey on every platform, which is deliberately independent of the fork's thread-grouping preference: that preference still orders the active rows, but a pin is an explicit arrangement and upstream documents the sort as identical everywhere so mixed-version fleets cannot disagree. Server capability gates dragging only, never the sort. SidebarV2 keeps the fork's environment/ownership filters around the new pinned block and gains upstream's reorderablePinnedKeys. Welds the auto-merge produced, all caught by typecheck or tests: - useThreadActions.ts: upstream's ThreadPinReorderUnsupportedError landed inside the fork's clearPerThreadClientState, leaving it unclosed. - threadListV2.ts: two `for (const thread of ...)` headers stacked on one loop body; the pinned block takes upstream's order-key sort. - useThreadListActions.ts: duplicate threadEnvironment import plus local copies of helpers this fork imports from threadActionMessages. - HomeRouteScreen: upstream's single-environment onEnvironmentChange handler does not exist in this fork's multi-select screen. - projector.pinned.test.ts indexed state.threads[0]; this fork's read model keys threads by id in a HashMap. - Six migration-ledger fixtures pinned the tail at 37; upstream's 038 ProjectionThreadsPinOrderKey extends it. Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
Adopts pingdotgg#5581 (drag pinned threads into your own order) on top of the pingdotgg#5372 merge already on this branch. Pinned rows now sort by the user's arranged pinOrderKey on every platform, which is deliberately independent of the fork's thread-grouping preference: that preference still orders the active rows, but a pin is an explicit arrangement and upstream documents the sort as identical everywhere so mixed-version fleets cannot disagree. Server capability gates dragging only, never the sort. SidebarV2 keeps the fork's environment/ownership filters around the new pinned block and gains upstream's reorderablePinnedKeys. Welds the auto-merge produced, all caught by typecheck or tests: - useThreadActions.ts: upstream's ThreadPinReorderUnsupportedError landed inside the fork's clearPerThreadClientState, leaving it unclosed. - threadListV2.ts: two `for (const thread of ...)` headers stacked on one loop body; the pinned block takes upstream's order-key sort. - useThreadListActions.ts: duplicate threadEnvironment import plus local copies of helpers this fork imports from threadActionMessages. - HomeRouteScreen: upstream's single-environment onEnvironmentChange handler does not exist in this fork's multi-select screen. - projector.pinned.test.ts indexed state.threads[0]; this fork's read model keys threads by id in a HashMap. - Six migration-ledger fixtures pinned the tail at 37; upstream's 038 ProjectionThreadsPinOrderKey extends it. Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
## What's Changed * fix(mobile): reconnects no longer shift the thread list by @t3dotgg in pingdotgg/t3code#5372 * feat(web): drag pinned threads into your own order by @t3dotgg in pingdotgg/t3code#5581 **Full Changelog**: pingdotgg/t3code@v0.0.33-nightly.20260807.1025...v0.0.33-nightly.20260807.1026 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.33-nightly.20260807.1026
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit 6d70e6d)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
## What's Changed * fix(mobile): reconnects no longer shift the thread list by @t3dotgg in pingdotgg/t3code#5372 * feat(web): drag pinned threads into your own order by @t3dotgg in pingdotgg/t3code#5581 * chore(ci): vouch StiensWout by @t3-code[bot] in pingdotgg/t3code#5637 * feat(desktop): remember recently used sites in the Browser panel by @chrisdeeming in pingdotgg/t3code#5270 * chore: vouch chrisdeeming by @t3-code[bot] in pingdotgg/t3code#5641 * feat(web): make sidebar artwork theme-aware by @maria-rcks in pingdotgg/t3code#5636 * fix(web): reconnect the composer seam for remote non-Git projects by @caezium in pingdotgg/t3code#5633 * fix(web): show Stop button while input is pending by @ipanasenko in pingdotgg/t3code#5554 * feat(web): fold plan mode and token-by-token output into Legacy features by @t3dotgg in pingdotgg/t3code#5664 * feat: sidebar v2 is now the default sidebar by @t3dotgg in pingdotgg/t3code#5672 * fix(server): stop PR status lookups amplifying GitHub rate limits by @t3dotgg in pingdotgg/t3code#5673 * fix(web): delay transient reconnect warnings by @t3-code[bot] in pingdotgg/t3code#5670 * fix(web): inherit terminal size in simple typography by @chrisdeeming in pingdotgg/t3code#5628 * fix(server): stop the reaper from silently killing live background subagents by @t3dotgg in pingdotgg/t3code#5677 * fix(desktop): zoom shortcuts no longer die when the preview browser has focus by @t3dotgg in pingdotgg/t3code#5691 * feat(mobile): one sheet for model and thread settings by @t3dotgg in pingdotgg/t3code#5625 * feat(usage): usage page reading provider transcripts across environments by @t3dotgg in pingdotgg/t3code#5684 * fix(web): usage chart no longer makes Claude look like the bigger spender by @t3dotgg in pingdotgg/t3code#5697 * fix(web): persist diff view mode by @leorivastech in pingdotgg/t3code#5731 * feat(web): show how many subagents are running at a glance by @t3dotgg in pingdotgg/t3code#5745 * fix(web): add missing cursor-pointer styling to dropdowns and interactive buttons by @naMqe-h in pingdotgg/t3code#5716 * fix(server): stop Claude resume handshakes from completing turns that never ran by @gfsaaser24 in pingdotgg/t3code#5710 * chore: vouch gfsaaser24 by @t3dotgg in pingdotgg/t3code#5761 * chore: vouch saphid by @t3dotgg in pingdotgg/t3code#5763 * fix(server): stop Codex threads with queued follow-ups by @t3dotgg in pingdotgg/t3code#5762 * fix(web): usage page loses the cost quality panel, gains a back button by @t3dotgg in pingdotgg/t3code#5756 * feat(server): agents can now open the images you paste into chat by @t3dotgg in pingdotgg/t3code#5757 * fix(web): pinned reorder no longer reshuffles while writes land by @t3dotgg in pingdotgg/t3code#5767 * feat(web): overhaul project settings into a real settings page by @t3dotgg in pingdotgg/t3code#5768 * fix(web): usage totals no longer jump while devices report in by @t3dotgg in pingdotgg/t3code#5772 * fix(server): settle no longer leaves monitors and dev servers running by @t3dotgg in pingdotgg/t3code#5774 * feat: pick worktree or current checkout per project by @t3dotgg in pingdotgg/t3code#5766 * fix(web): sidebar rows show the branch again, not a truncated plan step by @t3dotgg in pingdotgg/t3code#5776 * feat(server): vp run migrate-dev-db seeds worktree dev dbs with real data by @t3dotgg in pingdotgg/t3code#5773 * feat(web): keep unsent drafts one click away in the sidebar by @t3dotgg in pingdotgg/t3code#5777 * feat(web): project icons can be chosen manually by @t3dotgg in pingdotgg/t3code#5775 * fix(server): one greedy agent process no longer takes down the whole server by @t3dotgg in pingdotgg/t3code#5788 * ci: label-gated hosted-web preview deploys by @t3dotgg in pingdotgg/t3code#5465 * Add cross-platform mobile usage dashboard by @juliusmarminge in pingdotgg/t3code#5743 * fix(web): preserve desktop route during Clerk auth by @wobsoriano in pingdotgg/t3code#5770 * fix(web): match create theme and import theme buttons to the standard outline style by @UtkarshUsername in pingdotgg/t3code#5860 * fix(server): favicon resolution no longer pins the event loop by @murenovich in pingdotgg/t3code#5538 * fix(shared): bound the file-link label so bracket runs stop rescanning by @tsouth89 in pingdotgg/t3code#5782 * fix(web): thread title button no longer eats the drag area by @nathangerday in pingdotgg/t3code#5857 * fix(web): unify usage page chrome by @t3-code[bot] in pingdotgg/t3code#5823 * fix(shell): add ~/.local/bin to the Windows CLI resolver so native-installed providers are found by @arhxam in pingdotgg/t3code#5074 * fix(web): match settings search shortcut styling to command palette's by @UtkarshUsername in pingdotgg/t3code#5841 * fix(mobile): long-pressing a thread row no longer navigates into the thread by @juliusmarminge in pingdotgg/t3code#5901 * fix(server): usage no longer double-counts forked Codex sessions by @t3dotgg in pingdotgg/t3code#5887 * fix(server): sandbox user-provided SVGs by @t3dotgg in pingdotgg/t3code#5916 * fix(web): match usage titlebar text styling by @t3-code[bot] in pingdotgg/t3code#5897 * Move project settings to contextual project routes by @juliusmarminge in pingdotgg/t3code#5923 * Retain thread sidebar data when navigating to /settings so back navigation is instant by @juliusmarminge in pingdotgg/t3code#5930 * Automate production mobile EAS releases by @juliusmarminge in pingdotgg/t3code#5609 * Add settings and usage breadcrumbs by @juliusmarminge in pingdotgg/t3code#5929 * fix(web): correct model picker trigger padding by @Chrono-byte in pingdotgg/t3code#5935 * fix(web): show worktree icon in sidebar v2 by @tris203 in pingdotgg/t3code#5909 * fix(web): enable restore defaults after theme mix changes by @Lucenx9 in pingdotgg/t3code#5928 * fix(web): trait menu closes after you pick a level by @t3dotgg in pingdotgg/t3code#5879 * fix(web): align project name with headline by @carterwsmith in pingdotgg/t3code#5864 * fix(web): update pills use readable theme foregrounds by @chrisdeeming in pingdotgg/t3code#5938 * fix(web): use themed confirmation dialogs by @StiensWout in pingdotgg/t3code#5624 * fix(web): use import/export-appropriate icons for theme buttons by @UtkarshUsername in pingdotgg/t3code#5964 * fix(mobile): detect PowerShell cmdlet errors in work log rows by @myacoub91 in pingdotgg/t3code#5726 * fix(mobile): stop Android user bubbles with code blocks from overlapping by @Brechard in pingdotgg/t3code#5659 * fix(mobile): parse EAS fingerprint JSON by @juliusmarminge in pingdotgg/t3code#5991 ## New Contributors * @chrisdeeming made their first contribution in pingdotgg/t3code#5270 * @wobsoriano made their first contribution in pingdotgg/t3code#5770 * @murenovich made their first contribution in pingdotgg/t3code#5538 * @tsouth89 made their first contribution in pingdotgg/t3code#5782 * @nathangerday made their first contribution in pingdotgg/t3code#5857 * @carterwsmith made their first contribution in pingdotgg/t3code#5864 * @myacoub91 made their first contribution in pingdotgg/t3code#5726 **Full Changelog**: pingdotgg/t3code@v0.0.32...v0.0.33 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.33


When an environment reconnected on mobile, the connection status appeared as a row above the thread list. Every reconnect pushed all the rows down, then popped them back when it resolved. Jarring, and it happens constantly.
Now the header's brand slot doubles as the status surface. While an environment is unavailable, the T3 Code lockup ("Threads" on the iPad sidebar) fades to a spinner plus a status label in the same place, then fades back on reconnect. Nothing is inserted into the list, so its geometry never moves.
An 800ms debounce gates the swap, so the sub-second blips that make up most reconnects now show nothing at all. Offline and error states get a wifi-slash icon instead of the spinner, and tapping the status still opens environment settings the way the old pill did.
Covers every surface the old pill lived on: iPhone Home (both the liquid-glass and pre-glass header paths), Android Home, and the iPad sidebar in both native and custom chrome. The pill component is deleted; its display logic stays in
workspace-connection-status.tswith tests extended for the new presentation helper.Testing
vp test runinapps/mobile: 611 passingpackages/contracts/src/orchestration.tserror reproduces on cleanmain, unrelated to this branch)Simulator verification
📹 Full-quality 9-second simulator recording
Written by Claude Opus 5 (1M context) in T3 Code.
Note
Low Risk
UI-only mobile header/list layout change with no auth, data, or API changes; main risk is header animation/native chrome edge cases; the iPhone path is now verified in an iOS 26.5 Simulator.
Overview
Reconnects used to insert a connection status pill above the thread list, which pushed rows down and back on every blip. That pill is removed; status now lives in the header brand/title slot via new
WorkspaceConnectionTitle, so list geometry stays fixed.While disconnected (after an 800ms debounce), the T3 Code lockup or “Threads” title is replaced in place by a tappable label (spinner for reconnect/sync, wifi-slash for offline/errors) that still opens environment settings.
getConnectionAwareBrandHeaderOptionswires this into iOS nav headers; Android home header and iPad sidebar (native + custom chrome) use the same component. SharedbrandTitleOffsetkeeps status aligned with the brand.workspace-connection-status.tsgainsworkspaceConnectionStatusPresentation(label + whether to show progress); tests cover it.onOpenEnvironmentsmoves fromHomeScreentoHomeHeader/ route header options.Reviewed by Cursor Bugbot for commit d61499f. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Move connection status display from thread list into the header title area
WorkspaceConnectionStatuscomponent (rendered insideHomeScreenandThreadNavigationSidebarPane) with a newWorkspaceConnectionTitlecomponent that swaps the header brand area to show connection status during reconnects.getConnectionAwareBrandHeaderOptionsto wireWorkspaceConnectionTitleinto native stack headers, with platform-specific placement (iOS native glass vs. Android).useDelayedConnectionStatus, which suppresses status changes shorter than 800ms so brief reconnects don't flash the UI.unstable_headerLeftItemsfor alignment.Macroscope summarized d61499f.