From 9c90657d601faca46c04dc0b1573715058b8f059 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Tue, 14 Apr 2026 15:41:49 +0700 Subject: [PATCH] fix: simplify workspace route navigation --- packages/app/e2e/new-workspace.spec.ts | 82 +++++++++++++++++++ packages/app/src/app/_layout.tsx | 12 +-- .../workspace/[workspaceId]/_layout.tsx | 11 ++- 3 files changed, 88 insertions(+), 17 deletions(-) diff --git a/packages/app/e2e/new-workspace.spec.ts b/packages/app/e2e/new-workspace.spec.ts index db6010842..d760b07ec 100644 --- a/packages/app/e2e/new-workspace.spec.ts +++ b/packages/app/e2e/new-workspace.spec.ts @@ -12,6 +12,7 @@ import { } from "./helpers/new-workspace"; import { createTempGitRepo } from "./helpers/workspace"; import { + expectSidebarWorkspaceSelected, expectWorkspaceHeader, switchWorkspaceViaSidebar, waitForSidebarHydration, @@ -101,6 +102,87 @@ test.describe("New workspace flow", () => { } }); + test("same-project workspaces switch content without requiring refresh", async ({ page }) => { + const serverId = process.env.E2E_SERVER_ID; + if (!serverId) { + throw new Error("E2E_SERVER_ID is not set."); + } + + const repo = await createTempGitRepo("workspace-nav-same-project-"); + + try { + const rootWorkspace = await openProjectViaDaemon(client, repo.path); + const worktreeWorkspace = await createWorktreeViaDaemon(client, { + cwd: repo.path, + slug: `nav-${Date.now()}`, + }); + localWorkspaceIds.add(rootWorkspace.workspaceId); + createdWorktreeIds.add(worktreeWorkspace.workspaceId); + + await gotoAppShell(page); + await waitForSidebarHydration(page); + + await switchWorkspaceViaSidebar({ + page, + serverId, + targetWorkspacePath: rootWorkspace.workspaceId, + }); + await expectWorkspaceHeader(page, { + title: rootWorkspace.workspaceName, + subtitle: rootWorkspace.projectDisplayName, + }); + await expectSidebarWorkspaceSelected({ + page, + serverId, + workspaceId: rootWorkspace.workspaceId, + }); + + await switchWorkspaceViaSidebar({ + page, + serverId, + targetWorkspacePath: worktreeWorkspace.workspaceId, + }); + await expectWorkspaceHeader(page, { + title: worktreeWorkspace.workspaceName, + subtitle: worktreeWorkspace.projectDisplayName, + }); + await expectSidebarWorkspaceSelected({ + page, + serverId, + workspaceId: worktreeWorkspace.workspaceId, + }); + await expectSidebarWorkspaceSelected({ + page, + serverId, + workspaceId: rootWorkspace.workspaceId, + selected: false, + }); + + await switchWorkspaceViaSidebar({ + page, + serverId, + targetWorkspacePath: rootWorkspace.workspaceId, + }); + await expectWorkspaceHeader(page, { + title: rootWorkspace.workspaceName, + subtitle: rootWorkspace.projectDisplayName, + }); + await expectSidebarWorkspaceSelected({ + page, + serverId, + workspaceId: rootWorkspace.workspaceId, + }); + await expectSidebarWorkspaceSelected({ + page, + serverId, + workspaceId: worktreeWorkspace.workspaceId, + selected: false, + }); + } finally { + await repo.cleanup(); + } + }); + test("clicking new workspace redirects, renders header, shows sidebar row, and keeps one draft tab", async ({ page, }) => { diff --git a/packages/app/src/app/_layout.tsx b/packages/app/src/app/_layout.tsx index 66c4a1d7f..c212b7e87 100644 --- a/packages/app/src/app/_layout.tsx +++ b/packages/app/src/app/_layout.tsx @@ -811,17 +811,7 @@ function RootStack() { getId={({ params }) => { const serverId = getRouteParamValue(params?.serverId); const workspaceId = getRouteParamValue(params?.workspaceId); - const openIntent = getRouteParamValue( - params && typeof params === "object" && "open" in params - ? (params as { open?: string | string[] }).open - : undefined, - ); - if (!serverId || !workspaceId) { - return undefined; - } - return openIntent - ? `${serverId}:${workspaceId}:open:${openIntent}` - : `${serverId}:${workspaceId}`; + return serverId && workspaceId ? `${serverId}:${workspaceId}` : undefined; }} /> diff --git a/packages/app/src/app/h/[serverId]/workspace/[workspaceId]/_layout.tsx b/packages/app/src/app/h/[serverId]/workspace/[workspaceId]/_layout.tsx index 336e2bf38..33a98e734 100644 --- a/packages/app/src/app/h/[serverId]/workspace/[workspaceId]/_layout.tsx +++ b/packages/app/src/app/h/[serverId]/workspace/[workspaceId]/_layout.tsx @@ -3,7 +3,6 @@ import { useIsFocused, useNavigation } from "@react-navigation/native"; import { useGlobalSearchParams, useLocalSearchParams, - usePathname, useRouter, useRootNavigationState, } from "expo-router"; @@ -13,7 +12,6 @@ import { WorkspaceScreen } from "@/screens/workspace/workspace-screen"; import { buildHostWorkspaceRoute, decodeWorkspaceIdFromPathSegment, - parseHostWorkspaceRouteFromPathname, parseWorkspaceOpenIntent, type WorkspaceOpenIntent, } from "@/utils/host-routes"; @@ -85,7 +83,6 @@ function HostWorkspaceLayoutContent() { const rootNavigationState = useRootNavigationState(); const consumedIntentRef = useRef(null); const [intentConsumed, setIntentConsumed] = useState(false); - const pathname = usePathname(); const params = useLocalSearchParams<{ serverId?: string | string[]; workspaceId?: string | string[]; @@ -93,9 +90,11 @@ function HostWorkspaceLayoutContent() { const globalParams = useGlobalSearchParams<{ open?: string | string[]; }>(); - const parsedWorkspaceRoute = parseHostWorkspaceRouteFromPathname(pathname); - const serverId = parsedWorkspaceRoute?.serverId ?? ""; - const workspaceId = parsedWorkspaceRoute?.workspaceId ?? ""; + const serverId = getParamValue(params.serverId); + const workspaceValue = getParamValue(params.workspaceId); + const workspaceId = workspaceValue + ? (decodeWorkspaceIdFromPathSegment(workspaceValue) ?? "") + : ""; const openValue = getParamValue(globalParams.open); useEffect(() => {