diff --git a/frontend/src/renderer/components/GlobalSettingsForm.tsx b/frontend/src/renderer/components/GlobalSettingsForm.tsx new file mode 100644 index 000000000..89e280e93 --- /dev/null +++ b/frontend/src/renderer/components/GlobalSettingsForm.tsx @@ -0,0 +1,12 @@ +import { DashboardSubhead } from "./DashboardSubhead"; + +// App-wide settings, shown from the sidebar when no project is selected. The +// body is intentionally empty for now; it will be filled in incrementally. +export function GlobalSettingsForm() { + return ( +
+ +
+
+ ); +} diff --git a/frontend/src/renderer/components/Sidebar.test.tsx b/frontend/src/renderer/components/Sidebar.test.tsx index 9b805e4e8..c900aab4e 100644 --- a/frontend/src/renderer/components/Sidebar.test.tsx +++ b/frontend/src/renderer/components/Sidebar.test.tsx @@ -135,6 +135,16 @@ describe("Sidebar", () => { ); }); + it("opens global settings from the footer menu when no project is selected", async () => { + const user = userEvent.setup(); + renderSidebar(); + + await user.click(screen.getAllByLabelText("Settings")[0]); + await user.click(await screen.findByRole("menuitem", { name: "Global settings" })); + + expect(navigateMock).toHaveBeenCalledWith({ to: "/settings" }); + }); + it("always shows action icons and reserves padding for them", () => { renderSidebar(); diff --git a/frontend/src/renderer/components/Sidebar.tsx b/frontend/src/renderer/components/Sidebar.tsx index 83e9a5c41..e321619ed 100644 --- a/frontend/src/renderer/components/Sidebar.tsx +++ b/frontend/src/renderer/components/Sidebar.tsx @@ -91,6 +91,7 @@ function useSelection() { activeSessionId: params.sessionId, goHome: () => void navigate({ to: "/" }), goPrs: () => void navigate({ to: "/prs" }), + goGlobalSettings: () => void navigate({ to: "/settings" }), goSettings: (projectId: string) => void navigate({ to: "/projects/$projectId/settings", params: { projectId } }), goProject: (projectId: string) => void navigate({ to: "/projects/$projectId", params: { projectId } }), goSession: (projectId: string, sessionId: string) => @@ -284,14 +285,17 @@ export function Sidebar({ Search ⌘K - {selection.activeProjectId && ( - <> - - selection.goSettings(selection.activeProjectId!)}> - - + + {selection.activeProjectId ? ( + selection.goSettings(selection.activeProjectId!)}> + + ) : ( + + )} @@ -342,14 +346,17 @@ export function Sidebar({ Search ⌘K - {selection.activeProjectId && ( - <> - - selection.goSettings(selection.activeProjectId!)}> - - + + {selection.activeProjectId ? ( + selection.goSettings(selection.activeProjectId!)}> + + ) : ( + + )} diff --git a/frontend/src/renderer/routeTree.gen.ts b/frontend/src/renderer/routeTree.gen.ts index ffe4cdc41..26cb7f148 100644 --- a/frontend/src/renderer/routeTree.gen.ts +++ b/frontend/src/renderer/routeTree.gen.ts @@ -11,6 +11,7 @@ import { Route as rootRouteImport } from "./routes/__root"; import { Route as ShellRouteImport } from "./routes/_shell"; import { Route as ShellIndexRouteImport } from "./routes/_shell.index"; +import { Route as ShellSettingsRouteImport } from "./routes/_shell.settings"; import { Route as ShellPrsRouteImport } from "./routes/_shell.prs"; import { Route as ShellSessionsSessionIdRouteImport } from "./routes/_shell.sessions.$sessionId"; import { Route as ShellProjectsProjectIdRouteImport } from "./routes/_shell.projects.$projectId"; @@ -26,6 +27,11 @@ const ShellIndexRoute = ShellIndexRouteImport.update({ path: "/", getParentRoute: () => ShellRoute, } as any); +const ShellSettingsRoute = ShellSettingsRouteImport.update({ + id: "/settings", + path: "/settings", + getParentRoute: () => ShellRoute, +} as any); const ShellPrsRoute = ShellPrsRouteImport.update({ id: "/prs", path: "/prs", @@ -55,6 +61,7 @@ const ShellProjectsProjectIdSessionsSessionIdRoute = ShellProjectsProjectIdSessi export interface FileRoutesByFullPath { "/": typeof ShellIndexRoute; "/prs": typeof ShellPrsRoute; + "/settings": typeof ShellSettingsRoute; "/projects/$projectId": typeof ShellProjectsProjectIdRoute; "/sessions/$sessionId": typeof ShellSessionsSessionIdRoute; "/projects/$projectId/settings": typeof ShellProjectsProjectIdSettingsRoute; @@ -62,6 +69,7 @@ export interface FileRoutesByFullPath { } export interface FileRoutesByTo { "/prs": typeof ShellPrsRoute; + "/settings": typeof ShellSettingsRoute; "/": typeof ShellIndexRoute; "/projects/$projectId": typeof ShellProjectsProjectIdRoute; "/sessions/$sessionId": typeof ShellSessionsSessionIdRoute; @@ -72,6 +80,7 @@ export interface FileRoutesById { __root__: typeof rootRouteImport; "/_shell": typeof ShellRouteWithChildren; "/_shell/prs": typeof ShellPrsRoute; + "/_shell/settings": typeof ShellSettingsRoute; "/_shell/": typeof ShellIndexRoute; "/_shell/projects/$projectId": typeof ShellProjectsProjectIdRoute; "/_shell/sessions/$sessionId": typeof ShellSessionsSessionIdRoute; @@ -83,6 +92,7 @@ export interface FileRouteTypes { fullPaths: | "/" | "/prs" + | "/settings" | "/projects/$projectId" | "/sessions/$sessionId" | "/projects/$projectId/settings" @@ -90,6 +100,7 @@ export interface FileRouteTypes { fileRoutesByTo: FileRoutesByTo; to: | "/prs" + | "/settings" | "/" | "/projects/$projectId" | "/sessions/$sessionId" @@ -99,6 +110,7 @@ export interface FileRouteTypes { | "__root__" | "/_shell" | "/_shell/prs" + | "/_shell/settings" | "/_shell/" | "/_shell/projects/$projectId" | "/_shell/sessions/$sessionId" @@ -126,6 +138,13 @@ declare module "@tanstack/react-router" { preLoaderRoute: typeof ShellIndexRouteImport; parentRoute: typeof ShellRoute; }; + "/_shell/settings": { + id: "/_shell/settings"; + path: "/settings"; + fullPath: "/settings"; + preLoaderRoute: typeof ShellSettingsRouteImport; + parentRoute: typeof ShellRoute; + }; "/_shell/prs": { id: "/_shell/prs"; path: "/prs"; @@ -166,6 +185,7 @@ declare module "@tanstack/react-router" { interface ShellRouteChildren { ShellPrsRoute: typeof ShellPrsRoute; + ShellSettingsRoute: typeof ShellSettingsRoute; ShellIndexRoute: typeof ShellIndexRoute; ShellProjectsProjectIdRoute: typeof ShellProjectsProjectIdRoute; ShellSessionsSessionIdRoute: typeof ShellSessionsSessionIdRoute; @@ -175,6 +195,7 @@ interface ShellRouteChildren { const ShellRouteChildren: ShellRouteChildren = { ShellPrsRoute: ShellPrsRoute, + ShellSettingsRoute: ShellSettingsRoute, ShellIndexRoute: ShellIndexRoute, ShellProjectsProjectIdRoute: ShellProjectsProjectIdRoute, ShellSessionsSessionIdRoute: ShellSessionsSessionIdRoute, diff --git a/frontend/src/renderer/routes/_shell.settings.tsx b/frontend/src/renderer/routes/_shell.settings.tsx new file mode 100644 index 000000000..4d07584ec --- /dev/null +++ b/frontend/src/renderer/routes/_shell.settings.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { GlobalSettingsForm } from "../components/GlobalSettingsForm"; + +export const Route = createFileRoute("/_shell/settings")({ + component: GlobalSettingsForm, +});