From af837a1098b83e693eddf7a68aab7fef66af765b Mon Sep 17 00:00:00 2001 From: Nathan Wong <20381195+thelogicmatrix@users.noreply.github.com> Date: Tue, 3 Nov 2026 17:43:55 +0800 Subject: [PATCH] fix(web): working threads stay in the shelf when the window comes back Returning to the window resubscribes the shell, which marks it synchronizing until the server's completion marker arrives. The sidebar counted a connected environment whose shell was not live as disconnected, so every working thread left the Working shelf and slid back in moments later. Only connection phases past the first attempt now count as disconnected. Co-Authored-By: Claude Opus 5.5 --- apps/web/src/components/Sidebar.logic.test.ts | 26 +++++++++---------- apps/web/src/components/Sidebar.logic.ts | 7 ++--- apps/web/src/components/Sidebar.tsx | 9 +------ 3 files changed, 15 insertions(+), 27 deletions(-) diff --git a/apps/web/src/components/Sidebar.logic.test.ts b/apps/web/src/components/Sidebar.logic.test.ts index 669c805492bcc..e6e8e4948729f 100644 --- a/apps/web/src/components/Sidebar.logic.test.ts +++ b/apps/web/src/components/Sidebar.logic.test.ts @@ -970,20 +970,18 @@ describe("Working shelf (beta)", () => { }); it.each([ - ["connected", true, false], - ["connected", false, true], - ["connecting", false, false], - ["reconnecting", false, true], - ["offline", false, true], - ["error", false, true], - ["unsupported", false, true], - ["available", false, true], - ] as const)( - "lists threads outside the shelf on a %s environment: %s", - (phase, shellIsLive, disconnected) => { - expect(isSidebarEnvironmentDisconnected(phase, shellIsLive)).toBe(disconnected); - }, - ); + // Returning to the window resyncs the shell on a healthy connection, so a + // connected environment holds its rows in the shelf whatever the shell is doing. + ["connected", false], + ["connecting", false], + ["reconnecting", true], + ["offline", true], + ["error", true], + ["unsupported", true], + ["available", true], + ] as const)("lists threads outside the shelf on a %s environment: %s", (phase, disconnected) => { + expect(isSidebarEnvironmentDisconnected(phase)).toBe(disconnected); + }); it("lists a running thread outside the shelf while its environment is disconnected", () => { const thread = { ...idle, runtime, environmentId: localEnvironmentId }; diff --git a/apps/web/src/components/Sidebar.logic.ts b/apps/web/src/components/Sidebar.logic.ts index 55cf694c2b79e..921bd91ebf717 100644 --- a/apps/web/src/components/Sidebar.logic.ts +++ b/apps/web/src/components/Sidebar.logic.ts @@ -186,11 +186,8 @@ export function resolveSidebarThreadSection(input: { } // Keep cached placement on the first connection attempt, matching mobile's threadRouteIsHydrating. -export function isSidebarEnvironmentDisconnected( - phase: EnvironmentConnectionPhase, - shellIsLive: boolean, -): boolean { - return phase !== "connecting" && (phase !== "connected" || !shellIsLive); +export function isSidebarEnvironmentDisconnected(phase: EnvironmentConnectionPhase): boolean { + return phase !== "connecting" && phase !== "connected"; } export function belongsInSidebarWorkingShelf( diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx index cbf0191a7f40f..b0511e13c0a22 100644 --- a/apps/web/src/components/Sidebar.tsx +++ b/apps/web/src/components/Sidebar.tsx @@ -1,4 +1,3 @@ -import { liveShellEnvironmentIdsAtom } from "../state/shell"; import { attachSidebarTree } from "../lib/sidebarTree"; import { type EnvironmentId, type ScopedProjectRef } from "@t3tools/contracts"; import type { EnvironmentServerConfig } from "@t3tools/client-runtime/connection"; @@ -442,15 +441,9 @@ function useSidebarThreads(input: { const workingShelfEnabled = useClientSettings((s) => s.sidebarWorkingShelfEnabled) && folderGroups === null; const environmentConnections = useEnvironmentConnectionSummaries(); - const liveShellEnvironmentIds = useAtomValue(liveShellEnvironmentIdsAtom); const disconnectedEnvironmentIds = new Set( environmentConnections - .filter((environment) => - isSidebarEnvironmentDisconnected( - environment.connectionState, - liveShellEnvironmentIds.has(environment.environmentId), - ), - ) + .filter((environment) => isSidebarEnvironmentDisconnected(environment.connectionState)) .map((environment) => environment.environmentId), ); const inboxReturnsVersion = useSyncExternalStore(