fix: simplify workspace route navigation
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
|||||||
} from "./helpers/new-workspace";
|
} from "./helpers/new-workspace";
|
||||||
import { createTempGitRepo } from "./helpers/workspace";
|
import { createTempGitRepo } from "./helpers/workspace";
|
||||||
import {
|
import {
|
||||||
|
expectSidebarWorkspaceSelected,
|
||||||
expectWorkspaceHeader,
|
expectWorkspaceHeader,
|
||||||
switchWorkspaceViaSidebar,
|
switchWorkspaceViaSidebar,
|
||||||
waitForSidebarHydration,
|
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 ({
|
test("clicking new workspace redirects, renders header, shows sidebar row, and keeps one draft tab", async ({
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
|
|||||||
@@ -811,17 +811,7 @@ function RootStack() {
|
|||||||
getId={({ params }) => {
|
getId={({ params }) => {
|
||||||
const serverId = getRouteParamValue(params?.serverId);
|
const serverId = getRouteParamValue(params?.serverId);
|
||||||
const workspaceId = getRouteParamValue(params?.workspaceId);
|
const workspaceId = getRouteParamValue(params?.workspaceId);
|
||||||
const openIntent = getRouteParamValue(
|
return serverId && workspaceId ? `${serverId}:${workspaceId}` : undefined;
|
||||||
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}`;
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen name="h/[serverId]/agent/[agentId]" options={{ gestureEnabled: false }} />
|
<Stack.Screen name="h/[serverId]/agent/[agentId]" options={{ gestureEnabled: false }} />
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { useIsFocused, useNavigation } from "@react-navigation/native";
|
|||||||
import {
|
import {
|
||||||
useGlobalSearchParams,
|
useGlobalSearchParams,
|
||||||
useLocalSearchParams,
|
useLocalSearchParams,
|
||||||
usePathname,
|
|
||||||
useRouter,
|
useRouter,
|
||||||
useRootNavigationState,
|
useRootNavigationState,
|
||||||
} from "expo-router";
|
} from "expo-router";
|
||||||
@@ -13,7 +12,6 @@ import { WorkspaceScreen } from "@/screens/workspace/workspace-screen";
|
|||||||
import {
|
import {
|
||||||
buildHostWorkspaceRoute,
|
buildHostWorkspaceRoute,
|
||||||
decodeWorkspaceIdFromPathSegment,
|
decodeWorkspaceIdFromPathSegment,
|
||||||
parseHostWorkspaceRouteFromPathname,
|
|
||||||
parseWorkspaceOpenIntent,
|
parseWorkspaceOpenIntent,
|
||||||
type WorkspaceOpenIntent,
|
type WorkspaceOpenIntent,
|
||||||
} from "@/utils/host-routes";
|
} from "@/utils/host-routes";
|
||||||
@@ -85,7 +83,6 @@ function HostWorkspaceLayoutContent() {
|
|||||||
const rootNavigationState = useRootNavigationState();
|
const rootNavigationState = useRootNavigationState();
|
||||||
const consumedIntentRef = useRef<string | null>(null);
|
const consumedIntentRef = useRef<string | null>(null);
|
||||||
const [intentConsumed, setIntentConsumed] = useState(false);
|
const [intentConsumed, setIntentConsumed] = useState(false);
|
||||||
const pathname = usePathname();
|
|
||||||
const params = useLocalSearchParams<{
|
const params = useLocalSearchParams<{
|
||||||
serverId?: string | string[];
|
serverId?: string | string[];
|
||||||
workspaceId?: string | string[];
|
workspaceId?: string | string[];
|
||||||
@@ -93,9 +90,11 @@ function HostWorkspaceLayoutContent() {
|
|||||||
const globalParams = useGlobalSearchParams<{
|
const globalParams = useGlobalSearchParams<{
|
||||||
open?: string | string[];
|
open?: string | string[];
|
||||||
}>();
|
}>();
|
||||||
const parsedWorkspaceRoute = parseHostWorkspaceRouteFromPathname(pathname);
|
const serverId = getParamValue(params.serverId);
|
||||||
const serverId = parsedWorkspaceRoute?.serverId ?? "";
|
const workspaceValue = getParamValue(params.workspaceId);
|
||||||
const workspaceId = parsedWorkspaceRoute?.workspaceId ?? "";
|
const workspaceId = workspaceValue
|
||||||
|
? (decodeWorkspaceIdFromPathSegment(workspaceValue) ?? "")
|
||||||
|
: "";
|
||||||
const openValue = getParamValue(globalParams.open);
|
const openValue = getParamValue(globalParams.open);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user