Loading panel/src/App.tsx +3 −13 Changes for panel/src/App.tsx: 3 added lines, 13 removed lines. Original line number Diff line number Diff line Loading @@ -7,14 +7,12 @@ import { RequireAuth } from "@/components/RequireAuth"; import { Login } from "@/pages/Login"; import { ChangePassword } from "@/pages/ChangePassword"; import { Dashboard } from "@/pages/Dashboard"; import { MyServers } from "@/pages/MyServers"; import { ServersPage } from "@/pages/servers/ServersPage"; import { ServerConsole } from "@/pages/ServerConsole"; import { ServerPlayers } from "@/pages/ServerPlayers"; import { ServerBackups } from "@/pages/ServerBackups"; import { Account } from "@/pages/Account"; import { ServerAdmin } from "@/pages/admin/ServerAdmin"; import { ImageAdmin } from "@/pages/admin/ImageAdmin"; import { FleetTable } from "@/pages/ops/FleetTable"; // Three UX surfaces over two Zero-Trust tiers (DESIGN-WEB-3SIDES): // / User-Side — app-tier, every authenticated principal Loading @@ -41,7 +39,7 @@ export default function App() { <Route element={<AppShell />}> {/* User-Side — app-tier */} <Route index element={<Dashboard />} /> <Route path="servers" element={<MyServers />} /> <Route path="servers" element={<ServersPage />} /> <Route path="servers/:name" element={<ServerConsole />} /> <Route path="servers/:name/players" element={<ServerPlayers />} /> <Route path="servers/:name/backups" element={<ServerBackups />} /> Loading @@ -51,18 +49,10 @@ export default function App() { /admin has no landing page; redirect to the first concrete view so the section root and any stale bookmarks land somewhere useful. */} <Route path="admin" element={<RequireAdmin />}> <Route index element={<Navigate to="/admin/servers" replace />} /> <Route path="servers" element={<ServerAdmin />} /> <Route index element={<Navigate to="/admin/images" replace />} /> <Route path="images" element={<ImageAdmin />} /> </Route> {/* SysAdmin-Side — admin-tier (platform observability). Same redirect treatment as /admin — fleet is the meaningful view. */} <Route path="ops" element={<RequireAdmin />}> <Route index element={<Navigate to="/ops/fleet" replace />} /> <Route path="fleet" element={<FleetTable />} /> </Route> <Route path="*" element={<Navigate to="/" replace />} /> </Route> </Route> Loading panel/src/i18n/resources/en-US/navigation.json +2 −5 Changes for panel/src/i18n/resources/en-US/navigation.json: 2 added lines, 5 removed lines. Original line number Diff line number Diff line { "dashboard": "Dashboard", "my_servers": "My servers", "my_servers": "Servers", "account": "Account", "admin_section": "Admin", "admin_servers": "Servers", "admin_images": "Images", "sysadmin_section": "SysAdmin", "sysadmin_fleet": "Fleet" "admin_images": "Images" } panel/src/i18n/resources/zh-CN/navigation.json +2 −5 Changes for panel/src/i18n/resources/zh-CN/navigation.json: 2 added lines, 5 removed lines. Original line number Diff line number Diff line { "dashboard": "仪表盘", "my_servers": "我的服务器", "my_servers": "服务器", "account": "账户", "admin_section": "管理", "admin_servers": "服务器", "admin_images": "镜像", "sysadmin_section": "系统管理", "sysadmin_fleet": "全平台服务器" "admin_images": "镜像" } panel/src/lib/nav.test.ts +2 −2 Changes for panel/src/lib/nav.test.ts: 2 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -19,9 +19,9 @@ describe("visibleSections", () => { expect(visibleSections(false)[0].id).toBe("user"); }); it("shows User-Side, Admin-Side and SysAdmin-Side to an admin", () => { it("shows User-Side and Admin-Side to an admin", () => { const ids = visibleSections(true).map((s) => s.id); expect(ids).toEqual(["user", "admin", "ops"]); expect(ids).toEqual(["user", "admin"]); }); it("keeps the User-Side section ungated so it survives both branches", () => { Loading panel/src/lib/nav.ts +1 −12 Changes for panel/src/lib/nav.ts: 1 added line, 12 removed lines. Original line number Diff line number Diff line Loading @@ -2,9 +2,7 @@ import { LayoutDashboard, Server, UserRound, ServerCog, Boxes, Network, type LucideIcon, } from "lucide-react"; Loading @@ -28,7 +26,7 @@ export interface NavItem { } export interface NavSection { id: "user" | "admin" | "ops"; id: "user" | "admin"; /** Section heading key; null renders no heading (User-Side flat list). */ titleKey: string | null; /** When true the section is shown only to admins (is_admin === true). */ Loading @@ -52,18 +50,9 @@ export const NAV_SECTIONS: NavSection[] = [ titleKey: "admin_section", adminOnly: true, items: [ { to: "/admin/servers", key: "admin_servers", icon: ServerCog }, { to: "/admin/images", key: "admin_images", icon: Boxes }, ], }, { id: "ops", titleKey: "sysadmin_section", adminOnly: true, items: [ { to: "/ops/fleet", key: "sysadmin_fleet", icon: Network }, ], }, ]; /** Loading Loading
panel/src/App.tsx +3 −13 Changes for panel/src/App.tsx: 3 added lines, 13 removed lines. Original line number Diff line number Diff line Loading @@ -7,14 +7,12 @@ import { RequireAuth } from "@/components/RequireAuth"; import { Login } from "@/pages/Login"; import { ChangePassword } from "@/pages/ChangePassword"; import { Dashboard } from "@/pages/Dashboard"; import { MyServers } from "@/pages/MyServers"; import { ServersPage } from "@/pages/servers/ServersPage"; import { ServerConsole } from "@/pages/ServerConsole"; import { ServerPlayers } from "@/pages/ServerPlayers"; import { ServerBackups } from "@/pages/ServerBackups"; import { Account } from "@/pages/Account"; import { ServerAdmin } from "@/pages/admin/ServerAdmin"; import { ImageAdmin } from "@/pages/admin/ImageAdmin"; import { FleetTable } from "@/pages/ops/FleetTable"; // Three UX surfaces over two Zero-Trust tiers (DESIGN-WEB-3SIDES): // / User-Side — app-tier, every authenticated principal Loading @@ -41,7 +39,7 @@ export default function App() { <Route element={<AppShell />}> {/* User-Side — app-tier */} <Route index element={<Dashboard />} /> <Route path="servers" element={<MyServers />} /> <Route path="servers" element={<ServersPage />} /> <Route path="servers/:name" element={<ServerConsole />} /> <Route path="servers/:name/players" element={<ServerPlayers />} /> <Route path="servers/:name/backups" element={<ServerBackups />} /> Loading @@ -51,18 +49,10 @@ export default function App() { /admin has no landing page; redirect to the first concrete view so the section root and any stale bookmarks land somewhere useful. */} <Route path="admin" element={<RequireAdmin />}> <Route index element={<Navigate to="/admin/servers" replace />} /> <Route path="servers" element={<ServerAdmin />} /> <Route index element={<Navigate to="/admin/images" replace />} /> <Route path="images" element={<ImageAdmin />} /> </Route> {/* SysAdmin-Side — admin-tier (platform observability). Same redirect treatment as /admin — fleet is the meaningful view. */} <Route path="ops" element={<RequireAdmin />}> <Route index element={<Navigate to="/ops/fleet" replace />} /> <Route path="fleet" element={<FleetTable />} /> </Route> <Route path="*" element={<Navigate to="/" replace />} /> </Route> </Route> Loading
panel/src/i18n/resources/en-US/navigation.json +2 −5 Changes for panel/src/i18n/resources/en-US/navigation.json: 2 added lines, 5 removed lines. Original line number Diff line number Diff line { "dashboard": "Dashboard", "my_servers": "My servers", "my_servers": "Servers", "account": "Account", "admin_section": "Admin", "admin_servers": "Servers", "admin_images": "Images", "sysadmin_section": "SysAdmin", "sysadmin_fleet": "Fleet" "admin_images": "Images" }
panel/src/i18n/resources/zh-CN/navigation.json +2 −5 Changes for panel/src/i18n/resources/zh-CN/navigation.json: 2 added lines, 5 removed lines. Original line number Diff line number Diff line { "dashboard": "仪表盘", "my_servers": "我的服务器", "my_servers": "服务器", "account": "账户", "admin_section": "管理", "admin_servers": "服务器", "admin_images": "镜像", "sysadmin_section": "系统管理", "sysadmin_fleet": "全平台服务器" "admin_images": "镜像" }
panel/src/lib/nav.test.ts +2 −2 Changes for panel/src/lib/nav.test.ts: 2 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -19,9 +19,9 @@ describe("visibleSections", () => { expect(visibleSections(false)[0].id).toBe("user"); }); it("shows User-Side, Admin-Side and SysAdmin-Side to an admin", () => { it("shows User-Side and Admin-Side to an admin", () => { const ids = visibleSections(true).map((s) => s.id); expect(ids).toEqual(["user", "admin", "ops"]); expect(ids).toEqual(["user", "admin"]); }); it("keeps the User-Side section ungated so it survives both branches", () => { Loading
panel/src/lib/nav.ts +1 −12 Changes for panel/src/lib/nav.ts: 1 added line, 12 removed lines. Original line number Diff line number Diff line Loading @@ -2,9 +2,7 @@ import { LayoutDashboard, Server, UserRound, ServerCog, Boxes, Network, type LucideIcon, } from "lucide-react"; Loading @@ -28,7 +26,7 @@ export interface NavItem { } export interface NavSection { id: "user" | "admin" | "ops"; id: "user" | "admin"; /** Section heading key; null renders no heading (User-Side flat list). */ titleKey: string | null; /** When true the section is shown only to admins (is_admin === true). */ Loading @@ -52,18 +50,9 @@ export const NAV_SECTIONS: NavSection[] = [ titleKey: "admin_section", adminOnly: true, items: [ { to: "/admin/servers", key: "admin_servers", icon: ServerCog }, { to: "/admin/images", key: "admin_images", icon: Boxes }, ], }, { id: "ops", titleKey: "sysadmin_section", adminOnly: true, items: [ { to: "/ops/fleet", key: "sysadmin_fleet", icon: Network }, ], }, ]; /** Loading