diff --git a/docs/expo-router.md b/docs/expo-router.md index abfe85b24..af5ce6792 100644 --- a/docs/expo-router.md +++ b/docs/expo-router.md @@ -47,18 +47,27 @@ dynamic params exist before any nested workspace leaf is selected. ## App-Wide Route Hops -When app-wide routes such as `/new` navigate back into a host workspace, use -`navigateToHostWorkspaceRoute()` instead of calling `router.dismissTo()` with the -leaf workspace URL. +When app-wide routes such as `/new`, `/settings`, or `/sessions` navigate back +into a host workspace, express only the destination with `navigateToWorkspace()`. +Do not make the caller branch on its current route. The root stack owns `h/[serverId]`; the host stack owns `workspace/[workspaceId]/index`. Repeated global-route hops must `POP_TO` the -root host route and pass the nested workspace screen, or Expo Router can append -extra hidden workspace deck entries. +root host route and pass the nested workspace screen when a host route is +already mounted, or Expo Router can append extra hidden workspace deck entries. +The workspace navigation helper inspects the mounted navigation state to make +that decision; if no host route is mounted yet, it falls back to ordinary route +navigation. Those hidden entries are not harmless: composer floating panels can measure against the wrong deck and disappear offscreen. +Hidden host routes may keep their local params while an app-wide route is +foregrounded. Active-workspace observers must prefer the current pathname and +only use local param fallback during cold mount (`/` or empty pathname), or a +hidden workspace can overwrite the remembered workspace before Settings or +History returns. + ## Params Required dynamic params belong to the matched route. @@ -112,8 +121,7 @@ Before landing route changes: - [ ] Did you change `packages/app/src/app`? Re-read this file. - [ ] Did you touch remembered workspace restore? Keep root on `/h/[serverId]`. -- [ ] Did an app-wide route return to a workspace? Use - `navigateToHostWorkspaceRoute()`. +- [ ] Did any route return to a workspace? Use `navigateToWorkspace()`. - [ ] Did you add a route? Register it in the layout that directly owns it. - [ ] Did `useLocalSearchParams()` lose a required param? Fix the route tree. - [ ] Did native show a blank screen without a crash? Suspect route ownership diff --git a/packages/app/e2e/composer-autocomplete.spec.ts b/packages/app/e2e/composer-autocomplete.spec.ts index b813c605a..c8b19b31c 100644 --- a/packages/app/e2e/composer-autocomplete.spec.ts +++ b/packages/app/e2e/composer-autocomplete.spec.ts @@ -5,7 +5,7 @@ import { seedMockAgentWorkspace, type MockAgentWorkspace, } from "./helpers/mock-agent"; -import { expectWorkspaceTabVisible } from "./helpers/archive-tab"; +import { expectWorkspaceTabVisible, openSessions } from "./helpers/archive-tab"; import { daemonWsRoutePattern } from "./helpers/daemon-port"; import { getServerId } from "./helpers/server-id"; import { switchWorkspaceViaSidebar } from "./helpers/workspace-ui"; @@ -153,6 +153,13 @@ async function openAppWideNewWorkspace(page: Page): Promise { await page.waitForURL((url) => url.pathname === "/new", { timeout: 30_000 }); } +async function openSettingsThenBackToWorkspace(page: Page): Promise { + await page.getByTestId("sidebar-settings").filter({ visible: true }).first().click(); + await expect(page).toHaveURL(/\/settings\/general$/, { timeout: 30_000 }); + await page.getByTestId("settings-back-to-workspace").click(); + await page.waitForURL((url) => url.pathname.includes("/workspace/"), { timeout: 30_000 }); +} + async function expectSingleCurrentWorkspaceDeckEntry( page: Page, input: { expectedDeckEntryCount: number; serverId: string; workspaceId: string }, @@ -351,7 +358,7 @@ function expectPopoverDoesNotDisappearAfterFirstVisible(frames: PopoverFrame[]): } test.describe("Composer autocomplete", () => { - test("stays visible after returning from the app-wide new workspace route", async ({ page }) => { + test("stays visible after returning from app-wide routes", async ({ page }) => { await installListCommandsStub(page); const serverId = getServerId(); const sessions: MockAgentWorkspace[] = []; @@ -384,10 +391,28 @@ test.describe("Composer autocomplete", () => { await openAppWideNewWorkspace(page); await switchWorkspaceViaSidebar({ page, serverId, workspaceId: second.workspaceId }); await expectComposerVisible(page, { timeout: 30_000 }); + await expectSingleCurrentWorkspaceDeckEntry(page, { + expectedDeckEntryCount: 2, + serverId, + workspaceId: second.workspaceId, + }); - await openAppWideNewWorkspace(page); + await openSettingsThenBackToWorkspace(page); + await expectComposerVisible(page, { timeout: 30_000 }); + await expectSingleCurrentWorkspaceDeckEntry(page, { + expectedDeckEntryCount: 2, + serverId, + workspaceId: second.workspaceId, + }); + + await openSessions(page); await switchWorkspaceViaSidebar({ page, serverId, workspaceId: third.workspaceId }); await expectComposerVisible(page, { timeout: 30_000 }); + await expectSingleCurrentWorkspaceDeckEntry(page, { + expectedDeckEntryCount: sessions.length, + serverId, + workspaceId: third.workspaceId, + }); await openAppWideNewWorkspace(page); await switchWorkspaceViaSidebar({ page, serverId, workspaceId: first.workspaceId }); diff --git a/packages/app/e2e/workspace-navigation-regression.spec.ts b/packages/app/e2e/workspace-navigation-regression.spec.ts index 9c27a92c7..d1fccbdc3 100644 --- a/packages/app/e2e/workspace-navigation-regression.spec.ts +++ b/packages/app/e2e/workspace-navigation-regression.spec.ts @@ -256,9 +256,7 @@ test.describe("Workspace navigation regression", () => { await ws.close({ code: 1008, reason: "Blocked cold offline workspace route test." }); }); - await page.goto( - `/h/${encodeURIComponent(serverId)}/workspace/${encodeURIComponent("/tmp/paseo-missing-workspace")}`, - ); + await page.goto(buildHostWorkspaceRoute(serverId, "/tmp/paseo-missing-workspace")); await expectHostConnectingOrOffline(page); await expectMenuButtonVisible(page); diff --git a/packages/app/src/app/_layout.tsx b/packages/app/src/app/_layout.tsx index 0d32b7184..9b9cc8b88 100644 --- a/packages/app/src/app/_layout.tsx +++ b/packages/app/src/app/_layout.tsx @@ -134,14 +134,13 @@ const HostRuntimeBootstrapContext = createContext({ function PushNotificationRouter() { const router = useRouter(); - const pathname = usePathname(); const lastHandledIdRef = useRef(null); const openNotification = useStableEvent((data: Record | undefined) => { const target = resolveNotificationTarget(data); const serverId = target.serverId; const agentId = target.agentId; if (serverId && agentId) { - navigateToAgent({ serverId, agentId, currentPathname: pathname, pin: true }); + navigateToAgent({ serverId, agentId, pin: true }); return; } diff --git a/packages/app/src/app/h/[serverId]/agent/[agentId].tsx b/packages/app/src/app/h/[serverId]/agent/[agentId].tsx index 180e588ef..39193bc16 100644 --- a/packages/app/src/app/h/[serverId]/agent/[agentId].tsx +++ b/packages/app/src/app/h/[serverId]/agent/[agentId].tsx @@ -1,5 +1,5 @@ import { useEffect, useRef } from "react"; -import { useLocalSearchParams, usePathname, useRouter, type Href } from "expo-router"; +import { useLocalSearchParams, useRouter, type Href } from "expo-router"; import { HostRouteBootstrapBoundary } from "@/components/host-route-bootstrap-boundary"; import { useSessionStore } from "@/stores/session-store"; import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime"; @@ -17,7 +17,6 @@ export default function HostAgentReadyRoute() { function HostAgentReadyRouteContent() { const router = useRouter(); - const pathname = usePathname(); const params = useLocalSearchParams<{ serverId?: string; agentId?: string; @@ -53,10 +52,9 @@ function HostAgentReadyRouteContent() { navigateToAgent({ serverId, agentId, - currentPathname: pathname, }); } - }, [agentId, pathname, resolvedWorkspaceId, router, serverId]); + }, [agentId, resolvedWorkspaceId, router, serverId]); useEffect(() => { if (redirectedRef.current) { @@ -96,7 +94,6 @@ function HostAgentReadyRouteContent() { serverId, agentId, workspaceId, - currentPathname: pathname, }); return; } @@ -114,7 +111,7 @@ function HostAgentReadyRouteContent() { return () => { cancelled = true; }; - }, [agentId, client, isConnected, pathname, router, serverId]); + }, [agentId, client, isConnected, router, serverId]); return null; } diff --git a/packages/app/src/components/sidebar-workspace-list.tsx b/packages/app/src/components/sidebar-workspace-list.tsx index 99f4c369e..4086cd384 100644 --- a/packages/app/src/components/sidebar-workspace-list.tsx +++ b/packages/app/src/components/sidebar-workspace-list.tsx @@ -1749,14 +1749,13 @@ function WorkspaceRowItem({ isDragging = false, dragHandleProps, }: WorkspaceRowItemProps) { - const currentPathname = usePathname(); const handlePress = useCallback(() => { if (!workspace.serverId) { return; } onWorkspacePress?.(); - navigateToWorkspace(workspace.serverId, workspace.workspaceId, { currentPathname }); - }, [currentPathname, onWorkspacePress, workspace.serverId, workspace.workspaceId]); + navigateToWorkspace(workspace.serverId, workspace.workspaceId); + }, [onWorkspacePress, workspace.serverId, workspace.workspaceId]); return ( { if (!workspace.serverId) return; onWorkspacePress?.(); - navigateToWorkspace(workspace.serverId, workspace.workspaceId, { currentPathname }); - }, [currentPathname, onWorkspacePress, workspace.serverId, workspace.workspaceId]); + navigateToWorkspace(workspace.serverId, workspace.workspaceId); + }, [onWorkspacePress, workspace.serverId, workspace.workspaceId]); if (!workspaceEntry) return null; diff --git a/packages/app/src/hooks/use-command-center.ts b/packages/app/src/hooks/use-command-center.ts index 3af93495f..60ba70297 100644 --- a/packages/app/src/hooks/use-command-center.ts +++ b/packages/app/src/hooks/use-command-center.ts @@ -1,6 +1,6 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import type { TextInput } from "react-native"; -import { router, usePathname, type Href } from "expo-router"; +import { router, type Href } from "expo-router"; import { useTranslation } from "react-i18next"; import { useKeyboardShortcutsStore } from "@/stores/keyboard-shortcuts-store"; import { keyboardActionDispatcher } from "@/keyboard/keyboard-action-dispatcher"; @@ -136,7 +136,6 @@ function resolveActionShortcutKeys( export function useCommandCenter() { const { t } = useTranslation(); - const pathname = usePathname(); const { overrides } = useKeyboardShortcutOverrides(); const open = useKeyboardShortcutsStore((s) => s.commandCenterOpen); const setOpen = useKeyboardShortcutsStore((s) => s.setCommandCenterOpen); @@ -223,10 +222,9 @@ export function useCommandCenter() { navigateToAgent({ serverId: agent.serverId, agentId: agent.id, - currentPathname: pathname, }); }, - [pathname, setOpen], + [setOpen], ); const openProjectPicker = useOpenProjectPicker(); diff --git a/packages/app/src/hooks/use-keyboard-shortcuts.ts b/packages/app/src/hooks/use-keyboard-shortcuts.ts index b0c8c787e..0f427c573 100644 --- a/packages/app/src/hooks/use-keyboard-shortcuts.ts +++ b/packages/app/src/hooks/use-keyboard-shortcuts.ts @@ -120,7 +120,7 @@ export function useKeyboardShortcuts({ serverId: action.serverId, workspaceId: action.workspaceId, }; - navigateToWorkspace(action.serverId, action.workspaceId, { currentPathname: pathname }); + navigateToWorkspace(action.serverId, action.workspaceId); return true; case "navigate-last-workspace": return navigateToLastWorkspace(); diff --git a/packages/app/src/navigation/workspace-route-navigation.test.ts b/packages/app/src/navigation/workspace-route-navigation.test.ts new file mode 100644 index 000000000..868dc13af --- /dev/null +++ b/packages/app/src/navigation/workspace-route-navigation.test.ts @@ -0,0 +1,80 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; +import type { NavigationContainerRefWithCurrent } from "@react-navigation/native"; +import { + navigateToHostWorkspaceRoute, + registerWorkspaceRouteNavigationRef, +} from "./workspace-route-navigation"; + +function createNavigationRef(rootState: unknown, options: { ready?: boolean } = {}) { + const dispatch = vi.fn(); + const navigationRef = { + current: { + isReady: () => options.ready ?? true, + getRootState: () => rootState, + dispatch, + }, + } as unknown as NavigationContainerRefWithCurrent; + + return { navigationRef, dispatch }; +} + +describe("navigateToHostWorkspaceRoute", () => { + beforeEach(() => { + vi.clearAllMocks(); + registerWorkspaceRouteNavigationRef({ + current: null, + } as unknown as NavigationContainerRefWithCurrent)(); + }); + + it("falls back to route navigation when no host route is mounted yet", () => { + const { navigationRef, dispatch } = createNavigationRef({ + key: "root-stack", + routeNames: ["index", "settings/[section]", "h/[serverId]"], + routes: [{ key: "settings-general", name: "settings/[section]" }], + }); + registerWorkspaceRouteNavigationRef(navigationRef); + const dismissTo = vi.fn(); + + navigateToHostWorkspaceRoute("/h/server-1/workspace/workspace-a", { dismissTo }); + + expect(dispatch).not.toHaveBeenCalled(); + expect(dismissTo).toHaveBeenCalledWith("/h/server-1/workspace/workspace-a"); + }); + + it("pops to the mounted host route and targets the requested workspace", () => { + const { navigationRef, dispatch } = createNavigationRef({ + key: "root-stack", + routeNames: ["index", "settings/[section]", "h/[serverId]"], + routes: [ + { + key: "host-server-1", + name: "h/[serverId]", + params: { serverId: "server-1" }, + }, + { key: "settings-general", name: "settings/[section]" }, + ], + }); + registerWorkspaceRouteNavigationRef(navigationRef); + const dismissTo = vi.fn(); + + navigateToHostWorkspaceRoute("/h/server-1/workspace/workspace-a", { dismissTo }); + + expect(dismissTo).not.toHaveBeenCalled(); + expect(dispatch).toHaveBeenCalledWith({ + type: "POP_TO", + target: "root-stack", + payload: { + name: "h/[serverId]", + params: { + serverId: "server-1", + screen: "workspace/[workspaceId]/index", + params: { + serverId: "server-1", + workspaceId: "workspace-a", + }, + pop: true, + }, + }, + }); + }); +}); diff --git a/packages/app/src/navigation/workspace-route-navigation.ts b/packages/app/src/navigation/workspace-route-navigation.ts index fc72a577e..a717f157b 100644 --- a/packages/app/src/navigation/workspace-route-navigation.ts +++ b/packages/app/src/navigation/workspace-route-navigation.ts @@ -8,13 +8,17 @@ import { const ROOT_HOST_ROUTE_NAME = "h/[serverId]"; const HOST_WORKSPACE_ROUTE_NAME = "workspace/[workspaceId]/index"; +interface NavigateToHostWorkspaceRouteDeps { + dismissTo(route: string): void; +} + +const defaultNavigateToHostWorkspaceRouteDeps: NavigateToHostWorkspaceRouteDeps = { + dismissTo: (route) => router.dismissTo(route as Href), +}; + let rootNavigationRef: NavigationContainerRefWithCurrent | null = null; -interface NavigateToHostWorkspaceRouteOptions { - popToExistingHostRoute?: boolean; -} - export function registerWorkspaceRouteNavigationRef( ref: NavigationContainerRefWithCurrent, ): () => void { @@ -26,33 +30,38 @@ export function registerWorkspaceRouteNavigationRef( }; } -function findStackKeyWithRouteName(state: unknown, routeName: string): string | null { +function findStackKeyWithMountedRouteName(state: unknown, routeName: string): string | null { if (!state || typeof state !== "object") { return null; } const candidate = state as { key?: unknown; - routeNames?: unknown; routes?: unknown; }; - if ( - typeof candidate.key === "string" && - Array.isArray(candidate.routeNames) && - candidate.routeNames.includes(routeName) - ) { - return candidate.key; - } if (!Array.isArray(candidate.routes)) { return null; } + if ( + typeof candidate.key === "string" && + candidate.routes.some( + (route) => + !!route && typeof route === "object" && (route as { name?: unknown }).name === routeName, + ) + ) { + return candidate.key; + } + for (const route of candidate.routes) { if (!route || typeof route !== "object") { continue; } - const childKey = findStackKeyWithRouteName((route as { state?: unknown }).state, routeName); + const childKey = findStackKeyWithMountedRouteName( + (route as { state?: unknown }).state, + routeName, + ); if (childKey) { return childKey; } @@ -69,7 +78,7 @@ function dispatchHostWorkspacePopTo(route: string): boolean { } const rootState = navigation.getRootState(); - const target = findStackKeyWithRouteName(rootState, ROOT_HOST_ROUTE_NAME); + const target = findStackKeyWithMountedRouteName(rootState, ROOT_HOST_ROUTE_NAME); if (!target) { return false; } @@ -99,11 +108,11 @@ function dispatchHostWorkspacePopTo(route: string): boolean { export function navigateToHostWorkspaceRoute( route: string, - options: NavigateToHostWorkspaceRouteOptions = {}, + deps: NavigateToHostWorkspaceRouteDeps = defaultNavigateToHostWorkspaceRouteDeps, ): void { - if (options.popToExistingHostRoute && dispatchHostWorkspacePopTo(route)) { + if (dispatchHostWorkspacePopTo(route)) { return; } - router.dismissTo(route as Href); + deps.dismissTo(route); } diff --git a/packages/app/src/screens/new-workspace-screen.tsx b/packages/app/src/screens/new-workspace-screen.tsx index 40c7e6114..5e4d1faa0 100644 --- a/packages/app/src/screens/new-workspace-screen.tsx +++ b/packages/app/src/screens/new-workspace-screen.tsx @@ -1147,7 +1147,6 @@ function submitWorkspaceDraft(input: SubmitDraftInput): void { navigateToPreparedWorkspaceTab({ serverId, workspaceId, - currentPathname: "/new", target: submission.target, }); useDraftStore.getState().clearDraftInput({ draftKey, lifecycle: "sent" }); @@ -1994,7 +1993,7 @@ export function NewWorkspaceScreen({ ensureWorkspace, serverId: selectedServerId, navigate: (targetServerId, workspaceId) => - navigateToWorkspace(targetServerId, workspaceId, { currentPathname: "/new" }), + navigateToWorkspace(targetServerId, workspaceId), }); return; } diff --git a/packages/app/src/stores/navigation-active-workspace-store/index.ts b/packages/app/src/stores/navigation-active-workspace-store/index.ts index 78c508add..dc4ebedb4 100644 --- a/packages/app/src/stores/navigation-active-workspace-store/index.ts +++ b/packages/app/src/stores/navigation-active-workspace-store/index.ts @@ -20,10 +20,6 @@ import { navigateToHostWorkspaceRoute } from "@/navigation/workspace-route-navig export type { ActiveWorkspaceSelection } from "@/stores/last-workspace-selection"; -interface NavigateToWorkspaceOptions { - currentPathname?: string | null; -} - const lastWorkspaceSelectionStorage: LastWorkspaceSelectionStorage = { read: () => AsyncStorage.getItem(LAST_WORKSPACE_SELECTION_STORAGE_KEY), write: (value) => AsyncStorage.setItem(LAST_WORKSPACE_SELECTION_STORAGE_KEY, value), @@ -33,13 +29,7 @@ const lastWorkspaceSelectionStore = createLastWorkspaceSelectionStore( lastWorkspaceSelectionStorage, ); -function shouldPopToExistingHostRoute(options: NavigateToWorkspaceOptions): boolean { - // Only /new needs POP_TO to avoid hidden deck entries; regular workspace switches - // should use router navigation so route observers like the sidebar selection update. - return options.currentPathname === "/new"; -} - -function navigateDeps(options: NavigateToWorkspaceOptions): NavigateToWorkspaceDeps { +function navigateDeps(): NavigateToWorkspaceDeps { return { getSessionWorkspaces: (serverId) => useSessionStore.getState().sessions[serverId]?.workspaces, getSessionAgents: (serverId) => @@ -49,9 +39,7 @@ function navigateDeps(options: NavigateToWorkspaceOptions): NavigateToWorkspaceD }, rememberLastWorkspace: (selection) => lastWorkspaceSelectionStore.remember(selection), navigateToRoute: (route) => { - navigateToHostWorkspaceRoute(route, { - popToExistingHostRoute: shouldPopToExistingHostRoute(options), - }); + navigateToHostWorkspaceRoute(route); stripHostWorkspaceRouteEchoSearchFromBrowserUrlAfterCommit(); }, }; @@ -69,17 +57,13 @@ export function getIsLastWorkspaceSelectionHydrated(): boolean { return lastWorkspaceSelectionStore.isHydrated(); } -export function navigateToWorkspace( - serverId: string, - workspaceId: string, - options: NavigateToWorkspaceOptions = {}, -) { - navigateToWorkspacePure(serverId, workspaceId, navigateDeps(options)); +export function navigateToWorkspace(serverId: string, workspaceId: string) { + navigateToWorkspacePure(serverId, workspaceId, navigateDeps()); } export function navigateToLastWorkspace(): boolean { return navigateToLastWorkspacePure({ - ...navigateDeps({}), + ...navigateDeps(), getLastWorkspaceSelection: () => lastWorkspaceSelectionStore.getSelection(), }); } diff --git a/packages/app/src/stores/navigation-active-workspace-store/navigation.test.ts b/packages/app/src/stores/navigation-active-workspace-store/navigation.test.ts index 097189a7f..e2f8aab93 100644 --- a/packages/app/src/stores/navigation-active-workspace-store/navigation.test.ts +++ b/packages/app/src/stores/navigation-active-workspace-store/navigation.test.ts @@ -115,6 +115,18 @@ describe("workspace navigation", () => { }); }); + it("ignores stale workspace route params while an app-wide route is active", () => { + const selection = parseActiveWorkspaceSelection({ + pathname: "/settings/general", + params: { + serverId: "server-1", + workspaceId: "workspace-a", + }, + }); + + expect(selection).toBeNull(); + }); + it("navigates to the last workspace once a route observation has been remembered", () => { const { deps, navigations } = createLastSelectionDeps(null); diff --git a/packages/app/src/stores/navigation-active-workspace-store/navigation.ts b/packages/app/src/stores/navigation-active-workspace-store/navigation.ts index 03be5571e..17c7c96b3 100644 --- a/packages/app/src/stores/navigation-active-workspace-store/navigation.ts +++ b/packages/app/src/stores/navigation-active-workspace-store/navigation.ts @@ -58,10 +58,16 @@ function parseWorkspaceSelectionFromRouteParams(params: { export function parseActiveWorkspaceSelection( input: RouteSelectionInput, ): ActiveWorkspaceSelection | null { - return ( - parseHostWorkspaceRouteFromPathname(input.pathname) ?? - parseWorkspaceSelectionFromRouteParams(input.params) - ); + const routeSelection = parseHostWorkspaceRouteFromPathname(input.pathname); + if (routeSelection) { + return routeSelection; + } + + if (input.pathname !== "/" && input.pathname !== "") { + return null; + } + + return parseWorkspaceSelectionFromRouteParams(input.params); } export function navigateToWorkspace( diff --git a/packages/app/src/utils/navigate-to-agent/resolve.test.ts b/packages/app/src/utils/navigate-to-agent/resolve.test.ts index e061ea050..4f0a31af2 100644 --- a/packages/app/src/utils/navigate-to-agent/resolve.test.ts +++ b/packages/app/src/utils/navigate-to-agent/resolve.test.ts @@ -69,7 +69,6 @@ describe("resolveNavigateToAgent", () => { serverId: SERVER_ID, workspaceId: WORKSPACE_ID, target: { kind: "agent", agentId: AGENT_ID }, - currentPathname: undefined, pin: true, }, ]); @@ -107,7 +106,6 @@ describe("resolveNavigateToAgent", () => { serverId: SERVER_ID, workspaceId: WORKSPACE_ID, target: { kind: "agent", agentId: AGENT_ID }, - currentPathname: undefined, pin: undefined, }, ]); diff --git a/packages/app/src/utils/navigate-to-agent/resolve.ts b/packages/app/src/utils/navigate-to-agent/resolve.ts index 61188d4b0..6298608ef 100644 --- a/packages/app/src/utils/navigate-to-agent/resolve.ts +++ b/packages/app/src/utils/navigate-to-agent/resolve.ts @@ -8,7 +8,6 @@ export interface NavigateToAgentInput { // Used as the workspace target when the agent is not yet in the session store // (cold deep-links). Otherwise the workspace is read from the store. workspaceId?: string | null; - currentPathname?: string | null; pin?: boolean; } @@ -54,7 +53,6 @@ export function resolveNavigateToAgent( serverId: input.serverId, workspaceId, target: { kind: "agent", agentId: input.agentId }, - currentPathname: input.currentPathname, pin: input.pin, }); } diff --git a/packages/app/src/utils/prepare-workspace-tab.ts b/packages/app/src/utils/prepare-workspace-tab.ts index ee116ff3b..ae76e96b5 100644 --- a/packages/app/src/utils/prepare-workspace-tab.ts +++ b/packages/app/src/utils/prepare-workspace-tab.ts @@ -12,9 +12,7 @@ export interface PrepareWorkspaceTabInput { pin?: boolean; } -export interface NavigateToPreparedWorkspaceTabInput extends PrepareWorkspaceTabInput { - currentPathname?: string | null; -} +export type NavigateToPreparedWorkspaceTabInput = PrepareWorkspaceTabInput; export interface PrepareWorkspaceTabDeps { openTabFocused: (workspaceKey: string, target: WorkspaceTabTarget) => string | null; @@ -22,11 +20,7 @@ export interface PrepareWorkspaceTabDeps { } export interface NavigateToPreparedWorkspaceTabDeps extends PrepareWorkspaceTabDeps { - navigateToWorkspace: ( - serverId: string, - workspaceId: string, - options: { currentPathname?: string | null }, - ) => void; + navigateToWorkspace: (serverId: string, workspaceId: string) => void; } function getPreparedTarget(target: WorkspaceTabTarget): WorkspaceTabTarget { @@ -61,8 +55,6 @@ export function navigateToPreparedWorkspaceTab( deps: NavigateToPreparedWorkspaceTabDeps, ): string { const route = prepareWorkspaceTab(input, deps); - deps.navigateToWorkspace(input.serverId, input.workspaceId, { - currentPathname: input.currentPathname, - }); + deps.navigateToWorkspace(input.serverId, input.workspaceId); return route; } diff --git a/packages/app/src/utils/workspace-navigation.test.ts b/packages/app/src/utils/workspace-navigation.test.ts index af08350ab..2b3c60a7c 100644 --- a/packages/app/src/utils/workspace-navigation.test.ts +++ b/packages/app/src/utils/workspace-navigation.test.ts @@ -19,7 +19,6 @@ interface RecordedPin { interface RecordedNavigation { serverId: string; workspaceId: string; - currentPathname?: string | null; } function createFakeLayout() { @@ -42,12 +41,8 @@ function createFakeNavigator() { const navigations: RecordedNavigation[] = []; return { navigations, - navigateToWorkspace: ( - serverId: string, - workspaceId: string, - options: { currentPathname?: string | null }, - ) => { - navigations.push({ serverId, workspaceId, currentPathname: options.currentPathname }); + navigateToWorkspace: (serverId: string, workspaceId: string) => { + navigations.push({ serverId, workspaceId }); }, }; } @@ -89,8 +84,6 @@ describe("prepareWorkspaceTab", () => { expect(layout.openedTabs).toEqual([ { key: "server-1:/repo/worktree", target: { kind: "agent", agentId: AGENT_ID } }, ]); - expect(navigator.navigations).toEqual([ - { serverId: SERVER_ID, workspaceId: WORKSPACE_ID, currentPathname: undefined }, - ]); + expect(navigator.navigations).toEqual([{ serverId: SERVER_ID, workspaceId: WORKSPACE_ID }]); }); });