Keep composer autocomplete visible after route hops (#1851)

* fix(app): keep composer autocomplete visible after route hops

Workspace callers now express only the target workspace. The navigation helper chooses whether to pop to a mounted host route or fall back, and active-workspace tracking ignores stale hidden route params while app-wide routes are foregrounded.

* test(app): address workspace navigation review

* fix(app): parse decoded legacy workspace routes

* fix(app): ignore decoded legacy tab routes

* test(app): use canonical offline workspace route
This commit is contained in:
Mohamed Boudra
2026-07-01 21:55:17 +02:00
committed by GitHub
parent 48d07dedb5
commit d3e8f77914
19 changed files with 196 additions and 103 deletions
@@ -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,
},
]);
@@ -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,
});
}
@@ -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;
}
@@ -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 }]);
});
});