Files
biggus-dickus/web/src/app.tsx
T
logaritmisk ada5d06dad feat(web): deep-linkable field selection via /fields/:key (#72)
FieldsPage kept the selected field definition in component state, so
reload lost the selection, fields couldn't be linked/shared, and
back/forward didn't navigate selections — inconsistent with
/vocabularies/:id and /objects/:id.

Move selection into the URL: the route becomes /fields/:key?
(optional segment), FieldList selection navigates, cancel/done
navigates back to /fields, and the page derives the selected def from
the already-cached field-defs query. An unknown or stale key (e.g.
after deleting the selected field) falls back to the create form.

Tests: deep link opens the locked edit form, select→cancel round-trips
through the URL, unknown key falls back to create.

Closes #72

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 13:44:02 +02:00

93 lines
3.3 KiB
TypeScript

import { lazy, Suspense } from "react";
import { createBrowserRouter, createRoutesFromElements, Navigate, Outlet, Route, RouterProvider } from "react-router-dom";
import { NavigationBridge } from "./shell/navigation-bridge";
import { RequireAuth } from "./auth/require-auth";
import { LoginPage } from "./auth/login-page";
import { AppShell } from "./shell/app-shell";
import { ObjectsPage } from "./objects/objects-page";
import { ObjectDetail } from "./objects/object-detail";
import { SearchPage } from "./search/search-page";
import { SelectSearchPrompt } from "./search/select-search-prompt";
import { VocabulariesPage } from "./vocab/vocabularies-page";
import { VocabularyTerms } from "./vocab/vocabulary-terms";
import { SelectVocabularyPrompt } from "./vocab/select-vocabulary-prompt";
import { AuthoritiesPage } from "./authorities/authorities-page";
import { FormSkeleton, ListSkeleton } from "@/components/ui/skeletons";
const ObjectNewPage = lazy(() =>
import("./objects/object-new-page").then((m) => ({ default: m.ObjectNewPage })),
);
const ObjectEditForm = lazy(() =>
import("./objects/object-edit-form").then((m) => ({ default: m.ObjectEditForm })),
);
const FieldsPage = lazy(() =>
import("./fields/fields-page").then((m) => ({ default: m.FieldsPage })),
);
function RootLayout() {
return (
<>
<NavigationBridge />
<Outlet />
</>
);
}
const router = createBrowserRouter(
createRoutesFromElements(
<Route element={<RootLayout />}>
<Route path="/login" element={<LoginPage />} />
<Route element={<RequireAuth />}>
<Route element={<AppShell />}>
<Route
path="/objects/new"
element={
<Suspense fallback={<div className="mx-auto max-w-2xl"><FormSkeleton /></div>}>
<ObjectNewPage />
</Suspense>
}
/>
<Route path="/objects" element={<ObjectsPage />}>
<Route path=":id" element={<ObjectDetail />} />
<Route
path=":id/edit"
element={
<Suspense fallback={<div className="mx-auto max-w-2xl"><FormSkeleton /></div>}>
<ObjectEditForm />
</Suspense>
}
/>
</Route>
<Route path="/vocabularies" element={<VocabulariesPage />}>
<Route index element={<SelectVocabularyPrompt />} />
<Route path=":id" element={<VocabularyTerms />} />
</Route>
<Route path="/search" element={<SearchPage />}>
<Route index element={<SelectSearchPrompt />} />
<Route path=":id" element={<ObjectDetail />} />
</Route>
<Route path="/authorities" element={<Navigate to="/authorities/person" replace />} />
<Route path="/authorities/:kind" element={<AuthoritiesPage />} />
<Route
path="/fields/:key?"
element={
<Suspense fallback={<ListSkeleton />}>
<FieldsPage />
</Suspense>
}
/>
<Route path="/" element={<Navigate to="/objects" replace />} />
</Route>
</Route>
<Route path="*" element={<Navigate to="/objects" replace />} />
</Route>,
),
);
export function App() {
return <RouterProvider router={router} />;
}