feat: copy/paste per-class auto-annotate overrides as YAML (REQ-186, REQ-190)
Copy now emits YAML instead of the one-line "class <name> conf ..." text: one
block per selected class, fields named after the row labels, globals resolved
into the block, a name quoted only when YAML would misread it.
Paste reads the clipboard back and fills the overrides for the classes selected
in that modal, naming any it ignored — an override for a deselected class would
otherwise ride along in class_params unseen. container diffs go out as one
PATCH /projects/{id} and revert together if the save is rejected.
Parsing is parseClassYaml, a strict subset reader for exactly what Copy emits,
so no YAML dependency: any malformed line throws with its line number and
applies nothing. Values must look like numbers, not merely start like them —
parseFloat would have taken "0.5abc" as 0.5.
Both are real buttons with Lucide icons plus a status line reporting the
outcome, and both live in the shared table so the mass modal carries them too.
This commit is contained in:
1 parent
4f15335092
commit
4575c46f4c
8 files changed
+344
-49
No files matched your search
+35
-6
@@ -466,12 +466,41 @@ Two columns inside one dialog (920 px wide, max 96 vw / 90 vh, scrollable).
|
||||
unmarked classes are governed by IoU alone. Toggling is optimistic
|
||||
`PATCH /projects/{id} { containers: { [classId]: bool } }` into `project_classes.container`
|
||||
with revert on rejection — preview and batch job read the same stored flag.
|
||||
- **Copy (REQ-186)** — small right-aligned ghost button above the overrides block; label
|
||||
`Copy`, flips to `Copied` for 1.5 s inside an `aria-live` span, and on failure silently
|
||||
stays `Copy`. One line per selected class, e.g.
|
||||
`class sack conf 0.4 iou 0.6 minbox 0.005 maxbox 1 container false` — an empty input copies the
|
||||
global value. Present in the engine-chooser modal **and** the mass modal (shared
|
||||
component).
|
||||
- **Copy / Paste YAML (REQ-186, REQ-190)** — a small right-aligned toolbar above the overrides
|
||||
block: two real buttons, `Copy YAML` and `Paste YAML`, each an inline SVG icon (Lucide copy /
|
||||
clipboard-paste, no emoji) plus its label, `btn` styling at `0.76rem`, both disabled while a
|
||||
paste is in flight. A `role="status"` line beside them carries the outcome — `Copied`,
|
||||
`Pasted 3 classes`, `Pasted 2 classes — ignored crane`, or the failure in `--danger` — success
|
||||
text clears itself after 2 s, a failure stays until the next action.
|
||||
Copy puts one YAML block per selected class on the clipboard:
|
||||
|
||||
```yaml
|
||||
# auto-annotate per-class overrides
|
||||
sack:
|
||||
conf: 0.4
|
||||
iou: 0.6
|
||||
minbox: 0.005
|
||||
maxbox: 1
|
||||
container: false
|
||||
```
|
||||
|
||||
Field names are the row labels as written on screen; a name is quoted only when YAML would
|
||||
misread it (`"weird: name":`). An empty input copies the global value, so the block is a
|
||||
complete configuration, not a diff.
|
||||
Paste reads the clipboard and fills the overrides for the classes **selected in this modal**;
|
||||
an unselected class is named in the status line and never written. Numbers merge per field.
|
||||
`container` is saved to the server like ticking the box by hand (one PATCH for all changed
|
||||
classes, reverted together on rejection, and the status line says the flags were not saved).
|
||||
Parsing is strict and **atomic**: `#` comments (whole lines, or trailing on a value), `class:`
|
||||
at the left margin, `key: value` indented under it, numbers in 0–1 written as numbers
|
||||
(`0.5abc` is a typo, not `0.5`), `container` `true|false|yes|no|1|0`; a list item, a nested
|
||||
map, a top-level scalar, an unknown key, a malformed number, an out-of-range value or a
|
||||
key before any class throws `line N: …` and applies **nothing**. A class repeated in the same
|
||||
document merges rather than replacing. Where the browser blocks the clipboard read — the
|
||||
app on plain http over a LAN address, or the permission prompt refused — the status line says
|
||||
so rather than doing nothing.
|
||||
Both buttons live in the shared per-class table, so they exist in the engine-chooser modal
|
||||
**and** the mass modal.
|
||||
- `ClassPromptPanel`:
|
||||
- Target-class chips. Without SAM3 a chip is a simple toggle.
|
||||
- **With SAM3 a chip is two buttons**: the *name* selects-and-activates, the `×` deselects.
|
||||
|
||||
Reference in new issue
Block a user