feat: paste overrides through a reviewable dialog, any origin (REQ-190)

navigator.clipboard.readText() only exists in a secure context, so on plain http
over a LAN address it is absent, not merely refused — the previous one-click
paste could never work there. A keyboard paste into a focused textarea is an
ordinary user gesture and is not gated, so paste now opens a dialog: the YAML
goes in a textarea, prefilled only when the browser allows the read.

Nothing is written until Apply, and Apply stays disabled while the text does not
parse, so a typo cannot be clicked through. A live line names the classes the
block matched, the container flags it would flip and the classes it would ignore.
Esc closes and returns focus to the button; Enter is left to the textarea,
because YAML needs newlines.

planPaste() produces that review line and applyPasted() does the writing, keeping
the selected-classes-only rule and the single batched container PATCH.
This commit is contained in:
asus committed 2026-10-05 14:41:22 +07:00
1 parent 4575c46f4c
commit 3eeb529e3d
6 files changed
+229 -84

No files matched your search

+6 -3
View File
@@ -368,9 +368,12 @@ selected class's effective settings (per-class override where set, else the glob
container = the checkbox state) on the clipboard as **YAML** — one block per class, fields
named after the row labels (`conf`, `iou`, `minbox`, `maxbox`, `container`), through
`clipboard.js`'s `copyText` (Clipboard API with an `execCommand` fallback for insecure
contexts) — read-only, no network, no setting changed. **Paste** reads the clipboard back
(`readClipboardText`, no legacy fallback, so a blocked read is reported) and fills the
overrides for the classes selected in this modal; `container` diffs go out as one
contexts) — read-only, no network, no setting changed. **Paste** opens `PasteYamlDialog` — a textarea plus a live review line, nothing written until
Apply, and Apply disabled while the text does not parse. It prefills from the clipboard when
the browser allows a read and otherwise waits for Ctrl+V, which is what makes paste work on
plain http on a LAN address (`readText` needs a secure origin; a keyboard paste does not).
`planPaste()` in `ClassParamsTable.jsx` is what produces that review line; `applyPasted()`
writes it. `container` diffs go out as one
`PATCH /api/projects/{id} { containers: { classId: bool } }` and revert together on
rejection. Parsing is `parseClassYaml` in the same file — a strict subset reader for exactly
what Copy emits, no YAML dependency, all-or-nothing with a `line N: …` error. Because