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(() => {