feat(ui): success-filled batch bars, and a one-job batch drawn flat - #794
Merged
Conversation
The Progress primitive gains a success variant beside its primary default and takes its ref as a prop. BatchProgressBar draws the batch's annotation as an 8px success fill on a muted track with a border hairline, in the list and the gallery header alike, and a draft row says it is not approved yet rather than counting work it has no jobs for. The job header's bar takes the same variant; ingest and model-download bars keep primary.
The constructor took None for pre_label_run by default, so a route that forgot the read published a batch nobody had pre-labeled. The parameter is now required, as JobOut.of already has it, and every projection does the read.
With exactly one job the gallery renders no accordion and no job-level bar: the job's door, Pre-label and assignee sit under the batch header, followed by the filter, the order, the strip and the grid, and the batch bar is the page's one bar. The assignee reads as a line — Assigned to <name>, or Unassigned — with the name as the control. From two jobs the accordion stays, each header naming its assignee. The pieces both the screen and the accordion mount move to GalleryControls, so JobPanels no longer imports GalleryScreen while GalleryScreen imports it. A closed panel's header carries no aria-controls, since its panel is unmounted, and each job's filter, order and selection are kept by job id so reopening a panel restores them. The view is patched per field at write time: the grid reports its selection from an effect that can run after a filter change, and a whole-view write from it put the old filter back.
The cycle scenario and the gallery specs walk a one-job batch as the flat workspace it now is, and a single-job scenario sits beside the two-job one. The information-architecture rule and the UI reference describe both shapes: one job flat under the header, an accordion from two.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #789
What changed
The annotation progress bar.
Progressgains asuccessvariant beside itsprimarydefault and takes its ref as a prop rather than throughforwardRef.BatchProgressBardraws the batch's annotation as an 8 pxsuccessfill on amutedtrack with aborderhairline, so an empty bar reads as an empty track; the batches list and the gallery header share it, and a draft row says "Not approved yet" instead of counting work it has no jobs for. The job header's bar takes the same variant. Ingest and model-download bars keepprimary, and the styleguide shows the new variant beside the old.A one-job batch draws its job flat. With exactly one job the gallery renders no accordion and no job-level bar: the job's door (Annotate, Continue or View), Pre-label and the assignee sit under the batch header, followed by that job's filter, order, timeline and frames in one bordered panel, and the batch bar is the page's one bar. The assignee reads as a line — Assigned to ‹name›, or Unassigned — with the name itself as the control. From two jobs the accordion stays as it was, each header naming its assignee (Unassigned when nobody has it) and keeping Assign as a button in the open panel.
The accordion's leftovers. The pieces both the screen and the accordion mount — the toolbar, the timeline, the door, the assignee editor and the panel body — move to
screens/GalleryControls.tsx, soJobPanelsno longer importsGalleryScreenwhileGalleryScreenimports it; the import graph is a tree. A closed panel's header carries noaria-controls, since its panel is unmounted and an id pointing at nothing is a broken reference rather than a closed one. Each job's filter, order and selection are kept by job id, so reopening a panel restores them and the other job starts from All. The view is patched per field at write time: the grid reports its selection from an effect that can run after a filter change, and a whole-view write from it put the old filter back.The wire reads what it publishes.
BatchOut.oftookNoneforpre_label_runby default, so a route that forgot the read published a batch nobody had pre-labeled. The parameter is now required, asJobOut.ofalready had it, and every projection does the read — including the membership projection and the page of batches holding an asset.openapi.jsonand the generated client are unchanged.Rules and docs. The information-architecture skill's two rules on the gallery are rewritten (one job flat under the header, an accordion from two; the door is the job's and the header carries the transition; the filled control is the header's step while the batch has one and the navigation column's Annotate once it is open).
docs/content/ui.md's accordion section, its The way in and the pre-label sentence describe both shapes. The sitemap block itself is unchanged: no route, tab or entry point moved, and the open panel is still not in the URL.Revoked guards
No test was deleted or skipped. These asserted the old shape and now assert the same property against the new one:
jobPanels.test"falls back to the default when the open job is no longer in the batch"jobPanels.test"says an unassigned job has nobody rather than nothing"—Unassignedgallery.test"the job panel's way into the annotator" (whole suite)job-panelsjob-workspace; the header holds neither triggergallery.test"the jobs accordion" assignee suitecycle.spec"the job panel is the way in"job-panelsNew guards: the flat single-job structure (vitest and e2e), one progress bar on the page, the filled-control invariant in both directions (none on
in_annotation, exactly the header's step onapproved),aria-controlsonly while a panel exists, a job's filter and order restored on reopen,BatchProgressBar's fill, hairline and draft readout, theProgressvariant and ref, and the batches-list bar's fill and track colours read back in a real browser.Test plan
scripts/check.shin full onc276150: frontend build; annotator 1071, ui-core 1343, app 11 tests; frontend lint; openapi, generated-client and MCP tool-reference drift; version sync;annotator + app e2e (chromium)281 passed;browser cycle, real server (chromium)1 passed. The docs site, whichcheck.shskipped, built by hand: 48 pages, 4422 internal links resolve;docs_links,design_tokensandwire_rostersgates 25/25.python testsstep was red on its first run and green on the re-run — see below.in_annotationgallery, and a two-jobapprovedgallery with one assigned job.A baseline flake, not this branch's
The first
check.shrun failed two tests intests/scripts/test_cooldown_lockfile.py—test_an_interrupted_first_pass_changes_nothingandtest_an_interruption_during_the_snapshot_changes_nothing— withassert 0 == 130: the simulated kill landed after the wrapper had finished, on workerpopen-gw18. Nothing in this diff touchesscripts/cooldown.shortests/scripts/. Both tests pass in isolation on unmodifiedmainat9399430(2 passed in 0.34s) and on this branch (2 passed in 0.10s); the file passes under the configured parallelism four times in a row on each tree (49 passed); and the python step re-run exactly ascheck.shruns it answers4479 passed, 33 skipped in 44.16s. The two tests time a signal against a liveuv add, and lost the race under the full corpus's load.Also fixed
Nothing beyond the scope above. The three items PR #783 recorded as found but not fixed are all in this change, as is the
forwardRefinFeedback.tsx.