diff --git a/apps/fabro-web/app/router.test.tsx b/apps/fabro-web/app/router.test.tsx
index 2901413f5..89def916e 100644
--- a/apps/fabro-web/app/router.test.tsx
+++ b/apps/fabro-web/app/router.test.tsx
@@ -33,9 +33,9 @@ describe("browser router", () => {
expect(paths).not.toContain("/setup/complete");
});
- test("exposes the resources settings page", () => {
+ test("exposes the monitoring settings page", () => {
const paths = collectPaths(routes);
- expect(paths).toContain("/settings/resources");
+ expect(paths).toContain("/settings/monitoring");
});
});
diff --git a/apps/fabro-web/app/router.tsx b/apps/fabro-web/app/router.tsx
index c3c13b9b5..fd41edaba 100644
--- a/apps/fabro-web/app/router.tsx
+++ b/apps/fabro-web/app/router.tsx
@@ -40,7 +40,7 @@ import * as SettingsModels from "./routes/settings-models";
import * as SettingsSandboxes from "./routes/settings-sandboxes";
import * as SettingsSecrets from "./routes/settings-secrets";
import * as SettingsSecretsNew from "./routes/settings-secrets-new";
-import * as SettingsResources from "./routes/settings-resources";
+import * as SettingsMonitoring from "./routes/settings-monitoring";
import * as SettingsSecurity from "./routes/settings-security";
import * as SettingsStorage from "./routes/settings-storage";
import * as SettingsLiveEvents from "./routes/settings-live-events";
@@ -142,15 +142,16 @@ export const routes: RouteObject[] = [
}),
route("settings", Settings, {
children: [
- indexRoute(SettingsGeneral),
- route("integrations", SettingsIntegrations),
+ indexRoute(SettingsModels),
route("models", SettingsModels),
+ route("integrations", SettingsIntegrations),
route("sandboxes", SettingsSandboxes),
+ route("security", SettingsSecurity),
route("secrets", SettingsSecrets),
route("secrets/new", SettingsSecretsNew),
- route("security", SettingsSecurity),
+ route("server", SettingsGeneral),
route("storage", SettingsStorage),
- route("resources", SettingsResources),
+ route("monitoring", SettingsMonitoring),
route("live-events", SettingsLiveEvents),
],
}),
diff --git a/apps/fabro-web/app/routes/settings-general.tsx b/apps/fabro-web/app/routes/settings-general.tsx
index 1d4838683..470a7e7fb 100644
--- a/apps/fabro-web/app/routes/settings-general.tsx
+++ b/apps/fabro-web/app/routes/settings-general.tsx
@@ -21,7 +21,7 @@ import {
} from "../components/settings-panel";
export function meta() {
- return [{ title: "General settings — Fabro" }];
+ return [{ title: "Server settings — Fabro" }];
}
const DESCRIPTION = (
diff --git a/apps/fabro-web/app/routes/settings-resources.test.tsx b/apps/fabro-web/app/routes/settings-monitoring.test.tsx
similarity index 93%
rename from apps/fabro-web/app/routes/settings-resources.test.tsx
rename to apps/fabro-web/app/routes/settings-monitoring.test.tsx
index f8c225bc8..10227b98a 100644
--- a/apps/fabro-web/app/routes/settings-resources.test.tsx
+++ b/apps/fabro-web/app/routes/settings-monitoring.test.tsx
@@ -21,14 +21,14 @@ mock.module("../lib/queries", () => ({
useSystemResources: () => ({ data: systemResources }),
}));
-const { default: SettingsResources } = await import("./settings-resources");
+const { default: SettingsMonitoring } = await import("./settings-monitoring");
const mountedRenderers: TestRenderer.ReactTestRenderer[] = [];
-function renderSettingsResources() {
+function renderSettingsMonitoring() {
let renderer: TestRenderer.ReactTestRenderer | undefined;
act(() => {
- renderer = TestRenderer.create();
+ renderer = TestRenderer.create();
});
mountedRenderers.push(renderer!);
return renderer!;
@@ -103,7 +103,7 @@ function sampleServerSettings(maxConcurrentRuns = 8): ServerSettings {
} as unknown as ServerSettings;
}
-describe("SettingsResources route", () => {
+describe("SettingsMonitoring route", () => {
beforeEach(() => {
teardownReactTestEnv = setupReactTestEnv();
systemInfo = { runs: { active: 3, total: 12 } };
@@ -126,7 +126,7 @@ describe("SettingsResources route", () => {
test("renders loaded resource data", () => {
systemResources = sampleResources();
- const renderer = renderSettingsResources();
+ const renderer = renderSettingsMonitoring();
const text = textContent(renderer.toJSON());
expect(text).toContain("18%");
@@ -148,7 +148,7 @@ describe("SettingsResources route", () => {
},
});
- const renderer = renderSettingsResources();
+ const renderer = renderSettingsMonitoring();
expect(textContent(renderer.toJSON())).toContain("Collecting sample");
});
@@ -179,7 +179,7 @@ describe("SettingsResources route", () => {
},
});
- const renderer = renderSettingsResources();
+ const renderer = renderSettingsMonitoring();
const text = textContent(renderer.toJSON());
expect(text).toContain("Unsupported");
@@ -192,7 +192,7 @@ describe("SettingsResources route", () => {
notes: ["Memory is scoped to the current container."],
});
- const renderer = renderSettingsResources();
+ const renderer = renderSettingsMonitoring();
expect(textContent(renderer.toJSON())).toContain(
"Memory is scoped to the current container.",
diff --git a/apps/fabro-web/app/routes/settings-resources.tsx b/apps/fabro-web/app/routes/settings-monitoring.tsx
similarity index 98%
rename from apps/fabro-web/app/routes/settings-resources.tsx
rename to apps/fabro-web/app/routes/settings-monitoring.tsx
index 8d6409adc..b058e6d27 100644
--- a/apps/fabro-web/app/routes/settings-resources.tsx
+++ b/apps/fabro-web/app/routes/settings-monitoring.tsx
@@ -17,13 +17,13 @@ import {
} from "../components/settings-panel";
export function meta() {
- return [{ title: "Resources — Fabro" }];
+ return [{ title: "Monitoring — Fabro" }];
}
const DESCRIPTION =
"Server-visible run concurrency, CPU, memory, and storage filesystem usage for this Fabro process.";
-export default function SettingsResources() {
+export default function SettingsMonitoring() {
const resourcesQuery = useSystemResources();
const resources = resourcesQuery.data;
diff --git a/apps/fabro-web/app/routes/settings.tsx b/apps/fabro-web/app/routes/settings.tsx
index f4c0e1758..c577262c7 100644
--- a/apps/fabro-web/app/routes/settings.tsx
+++ b/apps/fabro-web/app/routes/settings.tsx
@@ -1,12 +1,12 @@
import {
BoltIcon,
+ ChartBarSquareIcon,
CircleStackIcon,
Cog6ToothIcon,
CpuChipIcon,
CubeTransparentIcon,
KeyIcon,
PuzzlePieceIcon,
- ServerStackIcon,
ShieldCheckIcon,
} from "@heroicons/react/24/outline";
import { Link, Outlet, useLocation, useMatches } from "react-router";
@@ -25,28 +25,19 @@ type NavItem = {
match: (pathname: string) => boolean;
};
+type NavSection = { type: "section"; key: string; label: string };
+
type NavDivider = { type: "divider"; key: string };
-type NavEntry = NavItem | NavDivider;
+type NavEntry = NavItem | NavSection | NavDivider;
const navItems: NavEntry[] = [
- {
- name: "General",
- href: "/settings",
- icon: Cog6ToothIcon,
- match: (p) => p === "/settings",
- },
+ { type: "section", key: "general", label: "General" },
{
name: "Models",
href: "/settings/models",
icon: CpuChipIcon,
- match: (p) => p.startsWith("/settings/models"),
- },
- {
- name: "Sandboxes",
- href: "/settings/sandboxes",
- icon: CubeTransparentIcon,
- match: (p) => p.startsWith("/settings/sandboxes"),
+ match: (p) => p === "/settings" || p.startsWith("/settings/models"),
},
{
name: "Integrations",
@@ -55,10 +46,10 @@ const navItems: NavEntry[] = [
match: (p) => p.startsWith("/settings/integrations"),
},
{
- name: "Secrets",
- href: "/settings/secrets",
- icon: KeyIcon,
- match: (p) => p.startsWith("/settings/secrets"),
+ name: "Sandboxes",
+ href: "/settings/sandboxes",
+ icon: CubeTransparentIcon,
+ match: (p) => p.startsWith("/settings/sandboxes"),
},
{
name: "Security",
@@ -66,6 +57,19 @@ const navItems: NavEntry[] = [
icon: ShieldCheckIcon,
match: (p) => p.startsWith("/settings/security"),
},
+ {
+ name: "Secrets",
+ href: "/settings/secrets",
+ icon: KeyIcon,
+ match: (p) => p.startsWith("/settings/secrets"),
+ },
+ { type: "section", key: "administration", label: "Administration" },
+ {
+ name: "Server",
+ href: "/settings/server",
+ icon: Cog6ToothIcon,
+ match: (p) => p.startsWith("/settings/server"),
+ },
{
name: "Storage",
href: "/settings/storage",
@@ -73,12 +77,12 @@ const navItems: NavEntry[] = [
match: (p) => p.startsWith("/settings/storage"),
},
{
- name: "Resources",
- href: "/settings/resources",
- icon: ServerStackIcon,
- match: (p) => p.startsWith("/settings/resources"),
+ name: "Monitoring",
+ href: "/settings/monitoring",
+ icon: ChartBarSquareIcon,
+ match: (p) => p.startsWith("/settings/monitoring"),
},
- { type: "divider", key: "after-storage" },
+ { type: "divider", key: "after-administration" },
{
name: "Live Events",
href: "/settings/live-events",
@@ -88,7 +92,7 @@ const navItems: NavEntry[] = [
];
function isLink(entry: NavEntry): entry is NavItem {
- return entry.type !== "divider";
+ return entry.type !== "divider" && entry.type !== "section";
}
function classNames(...classes: Array) {
@@ -115,7 +119,7 @@ export default function SettingsLayout() {