Fix workspace navigation regression on web (#772)
Centralize workspace navigation behind a small route-derived API so the workspace shell reads active selection from the current Expo Router route instead of a separately synchronized store.
Remove the stale layout-driven active-workspace write that regressed web after 02e5b564.
This commit is contained in:
@@ -13,6 +13,18 @@ vi.hoisted(() => {
|
||||
(globalThis as unknown as { __DEV__: boolean }).__DEV__ = false;
|
||||
});
|
||||
|
||||
const pathnameState = vi.hoisted(() => ({
|
||||
value: "/",
|
||||
}));
|
||||
|
||||
vi.mock("expo-router", () => ({
|
||||
router: {
|
||||
dismissTo: vi.fn(),
|
||||
},
|
||||
useLocalSearchParams: () => ({}),
|
||||
usePathname: () => pathnameState.value,
|
||||
}));
|
||||
|
||||
import {
|
||||
createSidebarWorkspaceEntry,
|
||||
type SidebarProjectEntry,
|
||||
@@ -28,12 +40,7 @@ import type { HostProfile } from "@/types/host-connection";
|
||||
import { useSessionStore, type WorkspaceDescriptor } from "@/stores/session-store";
|
||||
import { useSidebarOrderStore } from "@/stores/sidebar-order-store";
|
||||
import { useWorkspaceFields } from "@/stores/session-store-hooks";
|
||||
import {
|
||||
activateNavigationWorkspaceSelection,
|
||||
syncNavigationActiveWorkspace,
|
||||
useIsNavigationProjectActive,
|
||||
useIsNavigationWorkspaceSelected,
|
||||
} from "@/stores/navigation-active-workspace-store";
|
||||
import { useActiveWorkspaceSelection } from "@/stores/navigation-active-workspace-store";
|
||||
|
||||
vi.mock("@react-native-async-storage/async-storage", () => ({
|
||||
default: {
|
||||
@@ -222,10 +229,11 @@ function ProjectActiveProbe({
|
||||
project: SidebarProjectEntry;
|
||||
counts: RenderCounts;
|
||||
}): null {
|
||||
useIsNavigationProjectActive({
|
||||
serverId,
|
||||
workspaceIds: project.workspaces.map((entry) => entry.workspaceId),
|
||||
});
|
||||
const activeSelection = useActiveWorkspaceSelection();
|
||||
const isActive =
|
||||
activeSelection?.serverId === serverId &&
|
||||
project.workspaces.some((entry) => entry.workspaceId === activeSelection.workspaceId);
|
||||
void isActive;
|
||||
incrementRecord(counts.projectSelection, project.projectKey);
|
||||
return null;
|
||||
}
|
||||
@@ -239,7 +247,10 @@ function WorkspaceSelectionProbe({
|
||||
workspaceId: string;
|
||||
counts: RenderCounts;
|
||||
}): null {
|
||||
useIsNavigationWorkspaceSelected({ serverId, workspaceId });
|
||||
const activeSelection = useActiveWorkspaceSelection();
|
||||
const selected =
|
||||
activeSelection?.serverId === serverId && activeSelection.workspaceId === workspaceId;
|
||||
void selected;
|
||||
incrementRecord(counts.rowSelection, workspaceId);
|
||||
return null;
|
||||
}
|
||||
@@ -304,12 +315,16 @@ async function renderProbe(counts: RenderCounts): Promise<{ root: Root; containe
|
||||
document.body.appendChild(container);
|
||||
const root = createRoot(container);
|
||||
await act(async () => {
|
||||
root.render(<SidebarFrameProbe counts={counts} />);
|
||||
renderSidebarFrame(root, counts);
|
||||
});
|
||||
resetCounts(counts);
|
||||
return { root, container };
|
||||
}
|
||||
|
||||
function renderSidebarFrame(root: Root, counts: RenderCounts) {
|
||||
root.render(<SidebarFrameProbe counts={counts} />);
|
||||
}
|
||||
|
||||
describe("sidebar workspace render isolation", () => {
|
||||
let root: Root | null = null;
|
||||
let container: HTMLElement | null = null;
|
||||
@@ -328,7 +343,7 @@ describe("sidebar workspace render isolation", () => {
|
||||
container?.remove();
|
||||
container = null;
|
||||
act(() => {
|
||||
syncNavigationActiveWorkspace({ current: null });
|
||||
pathnameState.value = "/";
|
||||
getHostRuntimeStore().syncHosts([]);
|
||||
useSessionStore.getState().clearSession(SERVER_ID);
|
||||
useSidebarOrderStore.setState({
|
||||
@@ -417,7 +432,7 @@ describe("sidebar workspace render isolation", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("isolates active selection updates to affected row and project boolean probes", async () => {
|
||||
it("updates active selection probes from the active workspace route", async () => {
|
||||
const counts: RenderCounts = {
|
||||
frame: 0,
|
||||
headers: {},
|
||||
@@ -427,29 +442,28 @@ describe("sidebar workspace render isolation", () => {
|
||||
};
|
||||
|
||||
act(() => {
|
||||
activateNavigationWorkspaceSelection({
|
||||
serverId: SERVER_ID,
|
||||
workspaceId: "a-one",
|
||||
});
|
||||
pathnameState.value = `/h/${SERVER_ID}/workspace/a-one`;
|
||||
});
|
||||
({ root, container } = await renderProbe(counts));
|
||||
|
||||
act(() => {
|
||||
activateNavigationWorkspaceSelection({
|
||||
serverId: SERVER_ID,
|
||||
workspaceId: "b-two",
|
||||
});
|
||||
pathnameState.value = `/h/${SERVER_ID}/workspace/b-two`;
|
||||
if (root) {
|
||||
renderSidebarFrame(root, counts);
|
||||
}
|
||||
});
|
||||
|
||||
expect(counts.frame).toBe(0);
|
||||
expect(counts.headers).toEqual({});
|
||||
expect(counts.rows).toEqual({});
|
||||
expect(counts.frame).toBe(1);
|
||||
expect(counts.projectSelection).toEqual({
|
||||
"project-a": 1,
|
||||
"project-b": 1,
|
||||
});
|
||||
expect(counts.rowSelection).toEqual({
|
||||
"a-main": 1,
|
||||
"a-one": 1,
|
||||
"a-two": 1,
|
||||
"b-main": 1,
|
||||
"b-one": 1,
|
||||
"b-two": 1,
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user