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


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.