feat: edit one element end-to-end — sidecar schemas, generated form, canonical save, live preview #20

Merged
dominik.polakovics merged 4 commits from afk/3 into main 2026-07-12 02:51:31 +02:00

First true editing tracer bullet: a param edit travels from a schema-generated form through validation and the #2 round-trip engine onto disk, and the Hugo preview picks it up via LiveReload.

What's in here

  • internal/element — sidecar schema package: discovers editor/elements/*.yaml|yml (one file per shortcode), strict-validates them (unknown types, malformed files, bad defaults → actionable per-file errors while valid sidecars keep loading), and validates/coerces edited param values into content-engine types. Nine v1 field types: text, textarea, link, image, select, checkbox, number, color, date. Importable without the server; goccy/go-yaml promoted to a direct dependency.
  • internal/serverGET /api/elements (schemas + load errors, loaded fresh per request), GET /api/page (parsed tree; shares the /api/debug/tree implementation), POST /api/page/save (locate shortcode by child-index path with 409 on drift, server-authoritative validation returning 422 field errors, non-schema params preserved, atomic same-dir temp+rename write of only that page's file in canonical form). server.New now takes the site dir.
  • web/ — Elements pane with a crude page-path input (real navigation is #4), shortcode list derived from the parsed tree, sidecar load errors listed verbatim; Edit pane renders a form generated purely from the schema (labels, defaults, required markers, select options — zero element-specific branches), client-side validation inline, server 422 errors mapped per field, save button + saved indicator, post-save tree swap keeping the selection.
  • testdata/sitehero (inline) and notice (block, markdown body) element types covering all nine field types, with visible templates and a canonical homepage using both.

Acceptance criteria → evidence

  • Sidecars discovered/validated with actionable errors listed in the UI: internal/element load tests (17 error cases), /api/elements broken-sidecar test, schema-errors UI section + test
  • Schemas served via API: TestElementsHappyPath (sorted, arrays never null)
  • Form generated purely from schema, all nine types: FormPane renderer + vitest coverage (types, defaults, required, options)
  • Save round-trips through the #2 engine, rewrites only that page's file canonically: TestSavePageHappyPath (byte-exact expected file, site-dir snapshot diff, unknown params survive, empty optional removed, integral numbers stay ints) — also verified against a live harness
  • Preview reflects the change without manual reload: verified live — save triggered Change detected, rebuilding site, preview served the new value, LiveReload script present, no Hugo restart
  • Validation blocks save and shows inline: server 422 {errors:[{param,msg}]} + client mirror, tested on both sides
  • Two element types on the sample site: hero + notice, Hugo build verified

Full suite green: go vet ./..., go test ./..., npx tsc --noEmit, npm test (15), npm run build, plus a live end-to-end save exercised over HTTP.

Closes #3

First true editing tracer bullet: a param edit travels from a schema-generated form through validation and the #2 round-trip engine onto disk, and the Hugo preview picks it up via LiveReload. ## What's in here - **`internal/element`** — sidecar schema package: discovers `editor/elements/*.yaml|yml` (one file per shortcode), strict-validates them (unknown types, malformed files, bad defaults → actionable per-file errors while valid sidecars keep loading), and validates/coerces edited param values into content-engine types. Nine v1 field types: text, textarea, link, image, select, checkbox, number, color, date. Importable without the server; `goccy/go-yaml` promoted to a direct dependency. - **`internal/server`** — `GET /api/elements` (schemas + load errors, loaded fresh per request), `GET /api/page` (parsed tree; shares the `/api/debug/tree` implementation), `POST /api/page/save` (locate shortcode by child-index path with 409 on drift, server-authoritative validation returning 422 field errors, non-schema params preserved, atomic same-dir temp+rename write of only that page's file in canonical form). `server.New` now takes the site dir. - **`web/`** — Elements pane with a crude page-path input (real navigation is #4), shortcode list derived from the parsed tree, sidecar load errors listed verbatim; Edit pane renders a form generated purely from the schema (labels, defaults, required markers, select options — zero element-specific branches), client-side validation inline, server 422 errors mapped per field, save button + saved indicator, post-save tree swap keeping the selection. - **`testdata/site`** — `hero` (inline) and `notice` (block, markdown body) element types covering all nine field types, with visible templates and a canonical homepage using both. ## Acceptance criteria → evidence - Sidecars discovered/validated with actionable errors listed in the UI: `internal/element` load tests (17 error cases), `/api/elements` broken-sidecar test, `schema-errors` UI section + test - Schemas served via API: `TestElementsHappyPath` (sorted, arrays never null) - Form generated purely from schema, all nine types: FormPane renderer + vitest coverage (types, defaults, required, options) - Save round-trips through the #2 engine, rewrites only that page's file canonically: `TestSavePageHappyPath` (byte-exact expected file, site-dir snapshot diff, unknown params survive, empty optional removed, integral numbers stay ints) — also verified against a live harness - Preview reflects the change without manual reload: verified live — save triggered `Change detected, rebuilding site`, preview served the new value, LiveReload script present, no Hugo restart - Validation blocks save and shows inline: server 422 `{errors:[{param,msg}]}` + client mirror, tested on both sides - Two element types on the sample site: hero + notice, Hugo build verified Full suite green: `go vet ./...`, `go test ./...`, `npx tsc --noEmit`, `npm test` (15), `npm run build`, plus a live end-to-end save exercised over HTTP. Closes #3
Load per-shortcode editor schemas from editor/elements/*.yaml (label,
icon, group, version, body policy, placement, params with nine v1 field
types), with strict per-file validation producing actionable errors
while valid sidecars keep loading. Validate and coerce edited param
values into content-engine types (string | bool | int64 | float64).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0175UHGnFtuHMf2rdWaxZc7B
Two element types with shortcode templates and sidecar schemas covering
all nine v1 field types, plus a canonical homepage using both so the
end-to-end edit flow is demonstrable. The hero template consumes .Inner
because Hugo only accepts the canonical self-closed call form when the
template evaluates it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0175UHGnFtuHMf2rdWaxZc7B
GET /api/elements serves sidecar schemas (with load errors) fresh from
disk; GET /api/page shares the /api/debug/tree implementation; POST
/api/page/save locates a shortcode by child-index path, validates
values against the schema (422 with field errors), preserves non-schema
params, and atomically rewrites only that page's file in canonical
form. The handler now takes the site dir and derives content/ and
editor/elements/.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0175UHGnFtuHMf2rdWaxZc7B
feat(web): schema-generated element form with element list and save flow
All checks were successful
ci / build-and-test (pull_request) Successful in 1m4s
2f4b28b2d3
The Elements pane lists a page's shortcodes from the parsed tree (crude
page-path input; real navigation is #4) and surfaces sidecar load
errors. The Edit pane renders a form generated purely from the element
schema — all nine field types, defaults, required markers, select
options — with client-side validation mirrored inline, server 422 field
errors mapped onto fields, and the post-save tree swapped in so the
selection survives.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0175UHGnFtuHMf2rdWaxZc7B
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!20
No description provided.