fix(routing): render a 404 page for unmatched routes (v0.52.3)

The top-level catch-all silently redirected unknown paths to "/", and the
nested /admin/*, /p/:projectId/*, and /docs/* route groups had no catch-all
(invalid subpaths rendered a blank pane). Add a shared NotFound component and
wire it into all four route groups so a bad/typo'd URL shows a clear 404 with
a link home. Client-side 404 UI (SPA still serves HTTP 200).

Patch 0.52.2 → 0.52.3; CHANGELOG updated. Caught by the operator on PPE.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ben Stull
2026-06-08 20:14:25 -07:00
parent 7bcf784d06
commit 948ee88160
7 changed files with 60 additions and 5 deletions
+2
View File
@@ -29,6 +29,7 @@ import {
} from '../api.js'
import { EVENTS, track } from '../lib/analytics.js'
import { entryPath, useProjectId } from '../lib/entryPaths'
import NotFound from './NotFound.jsx'
// v0.17.0 — roadmap item #16. The max length the backend enforces
// (Pydantic body bound + `invites.CUSTOM_MESSAGE_MAX_LENGTH`); kept
@@ -82,6 +83,7 @@ export default function Admin({ viewer }) {
{isSiteOwner && <Route path="retired" element={<RetiredTab />} />}
<Route path="audit" element={<AuditTab />} />
<Route path="permissions" element={<PermissionsTab />} />
<Route path="*" element={<NotFound message="That admin page doesn't exist." />} />
</Routes>
</div>
</div>
+21
View File
@@ -0,0 +1,21 @@
// Client-side 404 for routes that don't match. An SPA serves index.html
// for every non-API path (HTTP 200), so an unknown URL would otherwise
// render blank or, worse, silently bounce home. This surfaces a clear
// "page not found" instead. Used by the top-level router and by the
// nested /admin, /p/:projectId, and /docs route groups so an invalid
// subpath (e.g. /admin/users/allowlist/graduation) lands here too.
import { Link } from 'react-router-dom'
export default function NotFound({ message }) {
return (
<div className="not-found" role="alert">
<h1 className="not-found-code">404</h1>
<p className="not-found-message">
{message || "We couldn't find that page."}
</p>
<p className="not-found-actions">
<Link to="/">Return to the catalog</Link>
</p>
</div>
)
}