feat(app): a new label can be created from the annotation page (#233) - #242
Merged
Conversation
A user who needed a class that did not exist had this path: leave the job, open the Schema tab, publish a version, make a **new batch** — because the old one pins the old version — and re-partition. The `+` in the tool palette now does it in place, and the class is usable in the batch they are already working in. **Three calls, and the order is the design.** Save the pending annotations, then publish the next version, then re-pin the batch (#229). `Workspace` builds the annotator store in a `useMemo` keyed on the schema, so the refetch after the re-pin *rebuilds it* — publish before saving and the user's last few boxes are gone with a success toast on screen, no error and nothing to see. Losing undo history at a save boundary is the page's existing documented behaviour; losing work is not, and the ordering is all that separates them. So the chain is `runAddClass`, a function taking three thunks rather than a body inside a `useCallback` — because behaviour that matters is worth testing without a canvas. `addClass.test.ts` drives it with recorders and asserts the sequence; **flipping save and publish turns four named tests red**, which is acceptance criterion 4 verified by mutation rather than asserted. The version is composed on the **active** version's classes plus the new one, never on the batch's pin. Versions are linear and `create_version` takes the whole contract, so composing on a stale pin would silently delete every class published since — a destructive change nobody asked for. The dialog will not submit before the active version has loaded, for the same reason. `patterns/ClassFields.tsx` is the class form extracted from `SchemaEditor.tsx`, which is what the issue asked for and what stops two forms drifting on which geometries are offered, how a derived colour is shown, and how an attribute's options are typed. It is *fields, not a form* — no submit, no card — because the editor puts them in a draft array and the dialog in a single new class, and only the part that has to agree is shared. `slot` carries the testid identifier, so the editor keeps its `class-name-2` ids and its 301 tests passed unchanged. Three requests are not a transaction. What each failure leaves behind is stated rather than hidden, and the last row is the one worth naming: **if the re-pin refuses, the version exists and the pin has not moved.** That refusal has no flag by design — it means somebody else narrowed the schema past this batch's pin — so the dialog names the Schema tab instead of offering a retry that cannot work. The palette button is absent where a host cannot honour it (`onOpenGallery`'s rule), which is why there is no e2e scenario: the annotator demo has no project behind it, so it renders no button — the criterion's own "else the ui-core screen-test convention". It keeps the canvas's focus like every other palette button, or every chord would be dead until the user clicked the picture again. On success the new class becomes `activeClass`, which lives on the page rather than in the store and so survives the rebuild; its digit hotkey arrives free because the palette order *is* the hotkey order (#46). 322 ui-core vitest, up from 301. Closes #233
…he dialog is open `e2e/annotate.spec.ts` asserts that opening a job makes **no** request to `/schema` — the page is judged against the batch's pinned version, and one that read the active version would offer classes the API then refuses. #233's unconditional `useActiveSchema` broke that, and the test was right to fire. `useActiveSchema` gains an `enabled` parameter, defaulting to on so the rule holds unless a caller says otherwise. The dialog is the one place the active version is the right question, so it is the one place that asks — and only while it is open. Refs #233.
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.
A user who needed a class that did not exist had this path: leave the job, open
the Schema tab, publish a version, make a new batch — because the old one
pins the old version — and re-partition. The
+in the tool palette now does itin place, and the class is usable in the batch they are already working in.
Three calls, and the order is the design. Save the pending annotations, then
publish the next version, then re-pin the batch (#229).
Workspacebuilds theannotator store in a
useMemokeyed on the schema, so the refetch after there-pin rebuilds it — publish before saving and the user's last few boxes are
gone with a success toast on screen, no error and nothing to see. Losing undo
history at a save boundary is the page's existing documented behaviour; losing
work is not, and the ordering is all that separates them.
So the chain is
runAddClass, a function taking three thunks rather than a bodyinside a
useCallback— because behaviour that matters is worth testing withouta canvas.
addClass.test.tsdrives it with recorders and asserts the sequence;flipping save and publish turns four named tests red, which is acceptance
criterion 4 verified by mutation rather than asserted.
The version is composed on the active version's classes plus the new one,
never on the batch's pin. Versions are linear and
create_versiontakes thewhole contract, so composing on a stale pin would silently delete every class
published since — a destructive change nobody asked for. The dialog will not
submit before the active version has loaded, for the same reason.
patterns/ClassFields.tsxis the class form extracted fromSchemaEditor.tsx,which is what the issue asked for and what stops two forms drifting on which
geometries are offered, how a derived colour is shown, and how an attribute's
options are typed. It is fields, not a form — no submit, no card — because the
editor puts them in a draft array and the dialog in a single new class, and only
the part that has to agree is shared.
slotcarries the testid identifier, sothe editor keeps its
class-name-2ids and its 301 tests passed unchanged.Three requests are not a transaction. What each failure leaves behind is stated
rather than hidden, and the last row is the one worth naming: if the re-pin
refuses, the version exists and the pin has not moved. That refusal has no flag
by design — it means somebody else narrowed the schema past this batch's pin — so
the dialog names the Schema tab instead of offering a retry that cannot work.
The palette button is absent where a host cannot honour it (
onOpenGallery'srule), which is why there is no e2e scenario: the annotator demo has no project
behind it, so it renders no button — the criterion's own "else the ui-core
screen-test convention". It keeps the canvas's focus like every other palette
button, or every chord would be dead until the user clicked the picture again.
On success the new class becomes
activeClass, which lives on the page ratherthan in the store and so survives the rebuild; its digit hotkey arrives free
because the palette order is the hotkey order (#46).
322 ui-core vitest, up from 301.
Closes #233