Files
urapt/urapt-web/src/components/common/root-guard.tsx
T
owen 39525bd5f0 Add urapt-web: web UI for urapt-server instances
A Vite + React 18 + TypeScript SPA, same-origin with the API (no CORS,
no Go server changes). Full management parity with the urapt CLI:

- First-run setup (admin bootstrap via needs_setup), login/logout
- Repositories: list, create, tabbed detail (overview edit/delete,
  members CRUD, distributions/components/architectures manager,
  package list + .deb upload + detail + delete, apt-config panel)
- API tokens: show-once creation + revoke
- Admin users: toggle admin / delete
- Settings + dark mode

Stack: Tailwind + shadcn/ui (New York), React Router v7 (lazy routes),
TanStack Query v5, Zustand, Vitest. Hand-written typed API client
mirroring shared/api + shared/models. Dev proxy forwards /api + /apt
to a local urapt-server; deploy behind nginx/Caddy (see urapt-web/README).
2026-06-28 18:42:46 -05:00

40 lines
1.2 KiB
TypeScript

import { Navigate } from "react-router-dom";
import { FullPageSpinner } from "@/components/common/spinner";
import { AppShell } from "@/components/app-shell";
import { useAuthStore } from "@/stores/auth";
import { useMe, useServerInfo } from "@/hooks/use-server";
/**
* Root guard: boots server info + current session before rendering the app
* shell. Redirects to /setup on first run and /login when unauthenticated.
*/
export function RootGuard() {
const token = useAuthStore((s) => s.token);
const serverInfo = useServerInfo();
const me = useMe(!!token);
if (serverInfo.isLoading || serverInfo.isPending) {
return <FullPageSpinner label="Connecting to urapt…" />;
}
// First-run setup takes priority: no admin exists yet.
if (serverInfo.data?.needs_setup) {
return <Navigate to="/setup" replace />;
}
if (!token) {
return <Navigate to="/login" replace />;
}
if (me.isLoading || me.isPending) {
return <FullPageSpinner label="Loading session…" />;
}
// Token present but invalid (401 already cleared the store; handle races).
if (me.isError || !me.data) {
return <Navigate to="/login" replace />;
}
return <AppShell />;
}