Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/AppShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export function AppShell() {
const [projectTrustDialogOpen, setProjectTrustDialogOpen] = useState(false);
const [projectTrustBusy, setProjectTrustBusy] = useState(false);
const [projectTrustError, setProjectTrustError] = useState<string | null>(null);
const [sidebarOpen, setSidebarOpen] = useState(true);
const [sidebarOpen, setSidebarOpen] = useState(() => !initialNavigation.sidebarCollapsed);
const [rightPanelOpen, setRightPanelOpen] = useState(false);
const [mobileToolbarMoreOpen, setMobileToolbarMoreOpen] = useState(false);
const [mobileSidebarReady, setMobileSidebarReady] = useState(false);
Expand Down
104 changes: 96 additions & 8 deletions lib/initial-navigation.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@ async function loadSubject() {

test("uses cwd instead of session when both parameters are present", async () => {
const { getInitialNavigation } = await loadSubject();
const result = getInitialNavigation(new URLSearchParams({
cwd: " /work/project ",
session: "saved-session",
}));
const result = getInitialNavigation(
new URLSearchParams({
cwd: " /work/project ",
session: "saved-session",
}),
);

assert.deepEqual(result, {
requestedCwd: "/work/project",
sessionId: null,
sidebarCollapsed: false,
});
});

Expand All @@ -23,16 +26,18 @@ test("restores session when cwd is absent", async () => {

assert.deepEqual(
getInitialNavigation(new URLSearchParams({ session: "saved-session" })),
{ requestedCwd: null, sessionId: "saved-session" },
{ requestedCwd: null, sessionId: "saved-session", sidebarCollapsed: false },
);
});

test("treats an empty cwd as absent", async () => {
const { getInitialNavigation } = await loadSubject();

assert.deepEqual(
getInitialNavigation(new URLSearchParams({ cwd: " ", session: "saved-session" })),
{ requestedCwd: null, sessionId: "saved-session" },
getInitialNavigation(
new URLSearchParams({ cwd: " ", session: "saved-session" }),
),
{ requestedCwd: null, sessionId: "saved-session", sidebarCollapsed: false },
);
});

Expand All @@ -41,6 +46,89 @@ test("preserves a URL-encoded Windows path", async () => {

assert.deepEqual(
getInitialNavigation(new URLSearchParams("cwd=C%3A%5CProjects%5Cpi-web")),
{ requestedCwd: "C:\\Projects\\pi-web", sessionId: null },
{
requestedCwd: "C:\\Projects\\pi-web",
sessionId: null,
sidebarCollapsed: false,
},
);
});

test("keeps the sidebar open when no sidebar parameter is present", async () => {
const { getInitialNavigation } = await loadSubject();

assert.deepEqual(getInitialNavigation(new URLSearchParams()), {
requestedCwd: null,
sessionId: null,
sidebarCollapsed: false,
});
});

test("collapses the sidebar for sidebar=collapsed", async () => {
const { getInitialNavigation } = await loadSubject();

assert.deepEqual(
getInitialNavigation(new URLSearchParams({ sidebar: "collapsed" })),
{
requestedCwd: null,
sessionId: null,
sidebarCollapsed: true,
},
);
});

test("collapses the sidebar when combined with a cwd parameter", async () => {
const { getInitialNavigation } = await loadSubject();

assert.deepEqual(
getInitialNavigation(
new URLSearchParams({ cwd: "/work/project", sidebar: "collapsed" }),
),
{
requestedCwd: "/work/project",
sessionId: null,
sidebarCollapsed: true,
},
);
});

test("collapses the sidebar when combined with a session parameter", async () => {
const { getInitialNavigation } = await loadSubject();

assert.deepEqual(
getInitialNavigation(
new URLSearchParams({ session: "saved-session", sidebar: "collapsed" }),
),
{
requestedCwd: null,
sessionId: "saved-session",
sidebarCollapsed: true,
},
);
});

test("ignores any other sidebar value", async () => {
const { getInitialNavigation } = await loadSubject();

assert.deepEqual(
getInitialNavigation(new URLSearchParams({ sidebar: "expanded" })),
{
requestedCwd: null,
sessionId: null,
sidebarCollapsed: false,
},
);
});

test("parses a URL-encoded sidebar parameter", async () => {
const { getInitialNavigation } = await loadSubject();

assert.deepEqual(
getInitialNavigation(new URLSearchParams("sidebar=collapsed%20")),
{
requestedCwd: null,
sessionId: null,
sidebarCollapsed: false,
},
);
});
6 changes: 5 additions & 1 deletion lib/initial-navigation.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
export interface InitialNavigation {
requestedCwd: string | null;
sessionId: string | null;
sidebarCollapsed: boolean;
}

export function getInitialNavigation(searchParams: Pick<URLSearchParams, "get">): InitialNavigation {
export function getInitialNavigation(
searchParams: Pick<URLSearchParams, "get">,
): InitialNavigation {
const requestedCwd = searchParams.get("cwd")?.trim() || null;

return {
requestedCwd,
sessionId: requestedCwd ? null : searchParams.get("session"),
sidebarCollapsed: searchParams.get("sidebar") === "collapsed",
};
}