feat(engine): 'insertable: false' element sidecar flag; apply to the html element #103

Merged
dominik.polakovics merged 1 commit from afk/90 into main 2026-07-18 03:37:54 +02:00

A new optional boolean element sidecar flag, default true. insertable: false removes an element from the web insert picker and makes the server refuse inserts of it (defense in depth), while already-placed instances remain fully visible, editable, movable, and rendering in preview/publish — unlike hidden: true, which also suppresses tree rows and blocks duplicates.

Changes

  • engine (internal/element): Schema.Insertable *bool (insertable,omitempty on the wire; nil = absent = insertable, so the default-true flag stays distinguishable from an explicit false). Strict sidecar parse rejects non-boolean values with insertable must be a boolean. Godoc updated.
  • server (internal/server): the insert handler refuses insertable: false elements with 422 — element %q is not insertable: its sidecar sets insertable: false; already-placed instances remain editable. Duplicate and move are deliberately unaffected; tests pin that duplicating a placed instance still succeeds and that an absent flag still inserts.
  • web (web/src): allowedElements and emptyPickerReason filter insertable !== false (the slot-cell picker goes through allowedElements too, so both picker paths are covered). Tree rendering (isHiddenNode/flattenChildren) is untouched, pinned by inverse tests.
  • scaffold: editor/elements/html.yaml sets insertable: false and drops its stale "picker-hiding flag will follow" comment; scaffold/site/AGENTS.md documents the flag next to the sidecar schema (per the CLAUDE.md same-change rule).

Verification

  • go test ./..., go vet ./..., gofmt clean; web: vitest 795/795 across 40 files, npm run build green.
  • Exercised end-to-end against a freshly scaffolded site under harness serve: /api/elements carries "insertable":false only for html; POST insert of html → 422 with the message above; insert of text → 200; duplicate of a hand-placed html instance → 200 with a fresh uid; the Hugo preview renders the placed raw HTML verbatim; and in a real Chromium the Insert-element dialog omits Raw HTML while the placed instance stays a visible, editable tree row.

Closes #90

A new optional boolean element sidecar flag, default true. `insertable: false` removes an element from the web insert picker and makes the server refuse inserts of it (defense in depth), while already-placed instances remain fully visible, editable, movable, and rendering in preview/publish — unlike `hidden: true`, which also suppresses tree rows and blocks duplicates. ## Changes - **engine** (`internal/element`): `Schema.Insertable *bool` (`insertable,omitempty` on the wire; nil = absent = insertable, so the default-true flag stays distinguishable from an explicit `false`). Strict sidecar parse rejects non-boolean values with `insertable must be a boolean`. Godoc updated. - **server** (`internal/server`): the insert handler refuses `insertable: false` elements with 422 — `element %q is not insertable: its sidecar sets insertable: false; already-placed instances remain editable`. Duplicate and move are deliberately unaffected; tests pin that duplicating a placed instance still succeeds and that an absent flag still inserts. - **web** (`web/src`): `allowedElements` and `emptyPickerReason` filter `insertable !== false` (the slot-cell picker goes through `allowedElements` too, so both picker paths are covered). Tree rendering (`isHiddenNode`/`flattenChildren`) is untouched, pinned by inverse tests. - **scaffold**: `editor/elements/html.yaml` sets `insertable: false` and drops its stale "picker-hiding flag will follow" comment; `scaffold/site/AGENTS.md` documents the flag next to the sidecar schema (per the CLAUDE.md same-change rule). ## Verification - `go test ./...`, `go vet ./...`, gofmt clean; web: vitest 795/795 across 40 files, `npm run build` green. - Exercised end-to-end against a freshly scaffolded site under `harness serve`: `/api/elements` carries `"insertable":false` only for `html`; POST insert of `html` → 422 with the message above; insert of `text` → 200; duplicate of a hand-placed `html` instance → 200 with a fresh uid; the Hugo preview renders the placed raw HTML verbatim; and in a real Chromium the Insert-element dialog omits Raw HTML while the placed instance stays a visible, editable tree row. Closes #90
feat(engine): 'insertable: false' element sidecar flag; apply to the html element
All checks were successful
ci / build-and-test (pull_request) Successful in 7m6s
0ba8de7b91
A new optional boolean sidecar flag, default true. insertable: false
removes an element from the web insert picker and makes the server refuse
inserts of it (defense in depth), while already-placed instances remain
fully visible, editable, movable, and rendering in preview/publish —
unlike hidden: true, which suppresses tree rows and blocks duplicates too.

- engine: Schema.Insertable *bool (nil = absent = insertable), strict
  parse with 'insertable must be a boolean' on invalid values; godoc
- server: insert handler rejects insertable:false with 422; duplicate and
  move deliberately unaffected, pinned by tests
- web: allowedElements/emptyPickerReason filter insertable !== false
  (slot picker shares the path); tree rendering untouched, pinned by tests
- scaffold: html.yaml sets insertable: false and drops its stale
  'picker-hiding flag will follow' comment; AGENTS.md documents the flag

Closes #90

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Author
Owner

This was generated by AI while landing a PR.

Validation verdict: PASS.

Verification signal relied on: the green Forgejo Actions run ci / build-and-test (success, 7m6s) — full go vet / go test ./... / go build and the web vitest suite (incl. the picker-filter and server-refusal tests). Not re-run.

Checked:

  • Merges cleanly into current main (base includes the just-landed #102; no conflict).
  • Title is Conventional Commits (feat(engine): …); body carries Closes #90 on afk/90.
  • Schema.Insertable *bool with insertable,omitempty distinguishes absent / true / false on the wire; normalizeOptionalBool rejects non-boolean values with insertable must be a boolean.
  • Server insert handler 422s an insertable: false element (defense in depth); duplicate and move handlers deliberately untouched, so placed instances stay editable and movable.
  • Web allowedElements and emptyPickerReason both filter insertable !== false (the slot-cell picker routes through allowedElements); tree rendering untouched, so placed instances stay visible.
  • html.yaml sets insertable: false and drops the stale "picker-hiding flag will follow" comment.
  • Contract surfaces per CLAUDE.md: scaffold/site/AGENTS.md documents the flag in the sidecar-schema section, godoc (doc.go) updated.

No blockers. Awaiting a free-text merge go-ahead before merging.

> *This was generated by AI while landing a PR.* **Validation verdict: PASS.** Verification signal relied on: the green Forgejo Actions run `ci / build-and-test` (success, 7m6s) — full `go vet` / `go test ./...` / `go build` and the web vitest suite (incl. the picker-filter and server-refusal tests). Not re-run. Checked: - Merges cleanly into current `main` (base includes the just-landed #102; no conflict). - Title is Conventional Commits (`feat(engine): …`); body carries `Closes #90` on `afk/90`. - `Schema.Insertable *bool` with `insertable,omitempty` distinguishes absent / true / false on the wire; `normalizeOptionalBool` rejects non-boolean values with `insertable must be a boolean`. - Server insert handler 422s an `insertable: false` element (defense in depth); duplicate and move handlers deliberately untouched, so placed instances stay editable and movable. - Web `allowedElements` and `emptyPickerReason` both filter `insertable !== false` (the slot-cell picker routes through `allowedElements`); tree rendering untouched, so placed instances stay visible. - `html.yaml` sets `insertable: false` and drops the stale "picker-hiding flag will follow" comment. - Contract surfaces per CLAUDE.md: `scaffold/site/AGENTS.md` documents the flag in the sidecar-schema section, godoc (`doc.go`) updated. No blockers. Awaiting a free-text merge go-ahead before merging.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Cloonar/deckle!103
No description provided.