You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Centralize extract and user-profile route resolution
Move URL parsing, GraphQL entity resolution, and reactive-var population
for /extracts/:extractId and /users/:slug into CentralRouteManager,
matching the pattern already used for corpus, document, thread, and
labelset routes.
Why
---
ExtractDetailRoute and UserProfileRoute were each parsing useParams,
running their own RESOLVE_* / GET_USER queries, and writing the
corresponding entity reactive vars (openedExtract, ad-hoc local state).
This duplicated the four-phase flow documented in
docs/frontend/routing_system.md and made it possible for components to
race CentralRouteManager (e.g. ExtractDetail's back handler clearing
openedExtract while Phase 1 was still settling).
A few smaller violations were cleaned up at the same time:
- views/Corpuses.tsx used window.history.replaceState to strip a
?create=true query param; replaced with React Router navigate so the
routing system stays in sync.
- LabelSetDetailPage and LabelSetLandingRoute called openedLabelset(null)
in handlers that already navigate to a browse route, where Phase 1
clears the var.
What changed
------------
Routing system:
- cache.ts: added openedUser (typed OpenedUserProfile) and tightened
the openedExtract docstring to reflect manager-only ownership.
- navigationUtils.ts: parseRoute now recognizes /users/:slug and
/extracts/:extractId.
- CentralRouteManager.tsx: added GET_USER lazy query, a Phase 1 user
branch, and openedUser(null) clears alongside the existing entity
reset paths.
Route components became dumb consumers:
- ExtractDetailRoute.tsx (89 -> 56 lines)
- UserProfileRoute.tsx (68 -> 51 lines)
- New ProfileRedirect.tsx handles /profile -> /users/<current-slug>
using backendUserObj. This is auth-driven, not URL-driven, so it
legitimately lives outside CentralRouteManager.
- App.tsx wires /profile to ProfileRedirect.
Cleanups:
- views/ExtractDetail.tsx back handler no longer writes openedExtract.
- LabelSet handlers no longer write openedLabelset.
Tests
-----
- 8 new parseRoute tests covering /users/:slug and /extracts/:extractId.
- 3 new CentralRouteManager tests: user resolution success, user
not-found error path, extract-by-id resolution. Existing fixtures
updated to reset the new vars in beforeEach.
- New centralRouteDiscipline.test.ts: static regression test that
grep-walks frontend/src and fails if any production file outside
CentralRouteManager.tsx and cache.ts SETs the 15 routing-owned
reactive vars. This caught three openedLabelset writes during
development that were also fixed.
- New e2e/user-and-extract-routes.spec.ts: deep-links /users/<slug>,
verifies /profile redirects, and exercises the dumb-consumer error
path on /extracts/<unknown-id>.
- Added /users/admin to the helpers.ts VIEWS catalog so the existing
login-and-navigation walk also covers the user route.
Pre-existing typecheck failure resolved
---------------------------------------
CamlDirectiveRenderer.tsx failed tsc because the installed
@os-legal/caml-react@0.0.1 d.ts files lack the resolveImageSrc prop that
the declared semver (^0.1.0) source already exposes. Added a narrow
local type widening with a comment so tsc compiles cleanly until the
lockfile is refreshed; runtime behavior is unchanged.
Verification
------------
- yarn tsc --noEmit: clean.
- yarn lint: clean.
- yarn vitest run for the three updated/new test files: 140/140
passing (24 manager, 115 navigationUtils, 1 discipline regression).
- E2E specs deferred to CI (frontend-e2e.yml).
0 commit comments