Skip to content

feat(v2-ui): v2 frontend vertical slice — schemas, records, search, reference review#230

Open
JonnyTran wants to merge 29 commits into
developfrom
feat/v2-frontend-slice
Open

feat(v2-ui): v2 frontend vertical slice — schemas, records, search, reference review#230
JonnyTran wants to merge 29 commits into
developfrom
feat/v2-frontend-slice

Conversation

@JonnyTran

Copy link
Copy Markdown
Member

Summary

First v2 UI vertical slice — schemas → records → search → annotation → reference review — built as an isolated v2/ DDD module in extralit-frontend/, consuming the shipped /api/v2 surface and producing the reference-agnostic ProjectionReviewForm.

Implements Tasks 4–17 of docs/superpowers/plans/2026-07-10-v2-frontend-vertical-slice.md (Tasks 1–3 landed earlier). Executed task-by-task with TDD.

What's included

Domain + infrastructure (v2/)

  • Entities: Schema, SchemaVersion, ColumnMeta, Question, V2Record, RecordsPage, SearchCriteria, ReferenceReview/ReviewCell/ReviewRecord, SuggestionHint, widget mapping + adapters.
  • Repositories (hand-written on the shared axios instance, DTOs typed from the committed OpenAPI snapshot): SchemaRepository, V2RecordRepository, AnnotationRepository, ProjectionRepository; response value double-wrap/unwrap; two-shape 422 normalizer.
  • Use-cases: get-schemas/settings/records, search, rebuild-index, get-reference-review (5-endpoint assembly with the name↔id join), submit/save-draft/discard.
  • A v2/ ts-injecty DI container loaded after v1's in plugins/3.di.ts; reference-keyed Pinia storage.

Pages & components

  • /schemas, /schemas/[id] (records table + FTS search + status filter), /schemas/[id]/settings (read-only inspector + rebuild-index), /references/[...reference] (review page).
  • Pure ProjectionReviewForm (record cards → per-type widget dispatch, provenance badges, not-applicable + orphaned-value surfacing) and a lean ~300-LOC V2TableEditor tabulator wrapper.
  • schemas.* / review.* i18n families (en; fallback covers de/es/ja).

Reuse-don't-fork

  • Four Argilla leaf widgets git mv'd to components/base/inputs/, v1 wrappers re-pointed — no copy-paste.

e2e (e2e/v2/)

  • Dedicated Playwright v2 project (isolated from legacy specs), CDP-remote-chromium fixture, deterministic Python seed script, and 5 seam-gating scenarios (bearer auth, slashed-DOI encoding, suggestion→response loop, draft lifecycle, search freshness). Response-mutating specs use per-spec isolated records.

Verification

  • npm run test — 861 passing
  • npm run lint (eslint --quiet) — clean
  • npx nuxi typecheck — 0 errors
  • npm run gen:api:types — no OpenAPI types drift
  • ✅ Import-boundary audit — v2/ imports only the allowed v1 seams; v1 never imports v2/
  • ⏸️ Live e2e — gated to CI / a live-stack session (local Playwright chromium can't launch on the dev host; specs need a seeded backend + remote chromium)

9 roborev review findings were surfaced and fixed during implementation (all closed) — including a real V2TableEditor self-emit rebuild bug and the e2e shared-record isolation issue.

Notes / follow-ups (deferred per plan §ledger)

  • Seam-C server behavior (draft/discard projection) is asserted by the draft-lifecycle e2e spec but not yet verified against a live stack — if a draft projects, that spec fails and surfaces the server bug.
  • Column filters derived from columns_cache, span questions, Queue UI (Phase 5), and v1 retirements (Phase 6) are out of scope.

JonnyTran added 29 commits July 10, 2026 06:21
Roborev job 131 (Low): dtypeDefaultEditor matched pandas interval[...] as a
number via the broad 'int' prefix — now requires a digit (int64/uint8/float32).
QuestionType intentionally omits the API's 'span' variant (rejected on write);
documented at the type and cast site.
Roborev job 133 (Low): add SchemaRepository.getSchema URL+mapping assertion and
a GetSchemaSettingsUseCase test verifying all three repo calls fire and the
{ schema, versions, questions } shape is returned.
The pager lived inside the results-only v-else, so advancing onto an empty page
(approximate totals let 'next' run one page past the last full page) hid all
controls and stranded the user with currentOffset advanced. Move the pager
outside the results branch and show it whenever currentOffset > 0, so 'previous'
stays available to recover.
… 140)

Mirror useSchemasViewModel: a rejected getSettings fetch now sets loadFailed and
renders the schemas.loadError branch instead of a blank page (both isLoading and
settings were falsy). Adds a test asserting loadFailed toggles on rejection.
…upsert (roborev job 143)

Add ProjectionRepository.test.ts asserting the percent-encoded slashed-DOI URL
(seam B) with workspace_id params and the full ProjectionView->DTO mapping, plus
an upsertResponse(null, 'discarded') case asserting the { values: null } body.
Add a two-schema projection case asserting each ReviewRecord resolves against its
own schema — distinct schemaName, cells (questions), and context fields — exercising
the schemaId-keyed contexts/records/version maps that single-schema tests can't.
The emitting boolean reset synchronously before the async watcher, so every
committed cell edit rebuilt the tabulator and lost focus. Replace it with a
last-emitted-value signature guard (flush-timing independent) and split the
watchers so column/editable changes always rebuild while the value-echo doesn't.
Adds mount-level tests asserting a committed edit does not rebuild but an external
modelValue change does; mock now records construction count and stores handlers.
…job 150)

Add ReviewCellInput.test.ts with stubs that emit on-selected/on-reorder after
mutating their bound options, exercising the adapter-invocation handlers: single
label -> scalar, multi label -> array (multiple flag), rating -> number, ranking
-> [{value,rank}]. Previously only the text path ran end-to-end (leaves stubbed inert).
…slashed-DOI scenarios

Note: live e2e run is gated to CI or a live-stack session — local Playwright
chromium can't launch on the Orin host and the specs need a seeded backend on
:6900 + remote chromium (ccui:9222), both unavailable here. Statically verified:
ruff on the seed script, playwright --list resolves the v2 project and both specs,
config/fixtures parse.
…cenarios

Live run gated to CI / live-stack session (Orin chromium + seeded :6900 backend
unavailable here). Scenario 4 (draft-lifecycle) is itself the seam-C gate: the
plan's curl-based seam-C server check requires the live stack, so it's pending —
if a draft projects, this spec fails and surfaces the server bug per §10.3.
Statically verified: playwright --list collects all 5 v2 specs.
…v job 153)

The /schemas list renders for the auto-selected (first) workspace, so asserting
the seeded schema flaked when another workspace sorted ahead of e2e-v2. Pre-seed
the persisted selection (localStorage extralit-selected-workspace-id) with the
seeded workspace id via addInitScript so saveWorkspaces() restores it deterministically.
Type-friction only, no logic change: bridge the opaque columns_cache cast through
unknown, cast tabulator editor:false (runtime-valid, absent from @types) and the
mock's static test hooks, and cast empty-tuple mock.calls indexing. npx nuxi
typecheck now reports 0 errors; full suite (861) still green.
…(roborev job 154)

review-loop and draft-lifecycle both mutated the shared seed record's response,
racing under fullyParallel and — since draft-lifecycle sorts first and leaves a
submitted response — breaking review-loop's clean-Suggestion precondition in
serial order. Add createIsolatedRecord (own reference + seeded suggestion via the
API) so each mutating spec runs on its own record: parallel-safe and order-independent.
@JonnyTran JonnyTran requested a review from a team as a code owner July 12, 2026 18:26
@JonnyTran JonnyTran requested a review from a team as a code owner July 12, 2026 18:26
@vercel

vercel Bot commented Jul 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
extralit-frontend Ready Ready Preview, Comment Jul 12, 2026 6:27pm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant