ZDDC/tables
ZDDC f9ba493145 feat(tables): row context-menu opens the form, not raw YAML
Replace "Edit YAML" with "Edit row" — navigates to row.url, which
is already the schema-driven form-mode editor URL. The form handler
unwraps virtual-view URLs server-side so SSR and rollup rows route
to their per-party canonical paths automatically; no client-side
URL rewriting needed.

This fills the gap where row-click only opens the form for
complex-type cells (objects, arrays) — for plain scalars it enters
inline edit mode. Right-click → Edit row is now the discoverable
way to reach the full form for any row.

Raw YAML editing remains available via the browse tool directly
(navigate to the file's parent folder and click it in the tree).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 08:43:45 -05:00
..
css feat(tables): explicit Save button + clearer dirty-row marker 2026-05-19 08:38:35 -05:00
js feat(tables): row context-menu opens the form, not raw YAML 2026-05-19 08:43:45 -05:00
sample feat(tables): new sortable/filterable grid tool for directories of YAML files 2026-05-05 20:32:01 -05:00
build.sh feat(tables): Export CSV button in the table toolbar 2026-05-19 07:00:23 -05:00
README.md feat(tables): new sortable/filterable grid tool for directories of YAML files 2026-05-05 20:32:01 -05:00
template.html feat(tables): explicit Save button + clearer dirty-row marker 2026-05-19 08:38:35 -05:00

ZDDC Tables

← Back to ZDDC

Render a directory of YAML files as a sortable, filterable table — read-only, with click-row → edit-in-form integration. Backed by zddc-server's form handler so the table view and the form editor are two sides of the same data.

Anchor use case. A Master Deliverables List (MDL) under Archive/<Party>/MDL/, where each .yaml file is one expected deliverable. Multiple parties keep their own MDLs side by side; the table aggregates within a single party's directory.

How it works

  • Storage is file-per-row YAML — one *.yaml file in a directory per table row. Concurrent edits don't collide on a shared blob, every row has independent git history, and per-row ACL inherits from the cascading .zddc chain.
  • Discovery is .zddc-declarative. Drop a tables: entry in the directory's .zddc to register the table; no file-presence auto-mount, no phantom tables from rogue YAML drops.
  • Rendering is server-side: zddc-server reads every *.yaml under the rows directory, normalizes them into a JSON list, and inlines the list into the page on render. The browser does sorting, filtering, and click-row navigation locally — no further server round-trips for those.
  • Editing is delegated to the existing form tool. Each row's click target is the form's re-edit URL (<dir>/<name>/<basename>.yaml.html), which zddc-server already serves via the form handler. The table itself never writes.

Setup (for an MDL at Archive/Acme/MDL/)

Archive/Acme/
├── .zddc                 # declares: tables: { MDL: ./MDL.table.yaml }
├── MDL.table.yaml        # column spec + rows path + row schema reference
├── MDL.form.yaml         # JSON Schema for one row (used by both the table and the form editor)
└── MDL/
    ├── D-001.yaml        # one row
    ├── D-002.yaml        # one row
    └── ...

Visit Archive/Acme/MDL.table.html and the table renders. Visit Archive/Acme/MDL.form.html to add a new row (the form handler creates a YAML in MDL/).

.zddc declaration

tables:
  MDL: ./MDL.table.yaml

The map key (MDL) becomes the URL stem and must match both the rows directory name and the form spec name. v1 enforces this with a load-time spec-validation error.

Table spec (MDL.table.yaml)

title: Master Deliverables List
description: Optional description shown above the table.
rowSchema: ./MDL.form.yaml         # path to the row's JSON Schema (form-spec format)
rows: ./MDL                        # directory of *.yaml row files (non-recursive in v1)
columns:
  - field: id                      # top-level key OR JSON Pointer (e.g. /nested/path)
    title: ID
    width: 7em
    sort: asc                      # default sort key (overridden by defaults.sort below)
  - field: title
    title: Deliverable
  - field: dueDate
    title: Due
    format: date                   # date | datetime | number | bool
  - field: status
    title: Status
    enum: [pending, submitted, accepted, rejected]   # constrains values + enables enum filter
defaults:
  sort:
    - { field: dueDate, dir: asc }
  filter:
    status: [pending, submitted]   # initial filter state; clear with the toolbar button

Columns are explicit — the renderer does not auto-derive from the row schema. Pick the subset you want to display.

ACL behavior

  • The page-level read check uses the cascade at the spec directory; a caller without r gets a 403.
  • Per-row "edit" affordance is recomputed against the row's own parent dir. If the user has w there, the row is clickable; otherwise it's plain text. Hard enforcement remains on the form-handler side (the form's POST will refuse a write the cascade denies).
  • Issued/Received archive folders are server-enforced WORM. The decider strips w/d/a from non-admin grants under those subtrees, so an MDL placed inside Issued/ shows every row as read-only with no special-casing in the table tool.

v1 limits

  • Read-only grid; click-row opens the form editor. Inline cell editing is a v2 candidate (would PUT each edit through the new file API in zddc/internal/handler/fileapi.go).
  • One directory of *.yaml per table; cross-directory aggregation (Archive/*/MDL/*.yaml as one combined view) is not yet supported.
  • No virtualization — large tables (>1000 rows) will be slow.
  • No multi-row bulk operations, no add-row UI inside the table (use the form editor at <name>.form.html).
  • .zddc tables: declarations are direct-lookup only; no upward cascade. Each directory hosting a table needs its own declaration.

Build & develop

sh tables/build.sh                       # build (writes tables/dist/tables.html)
sh tables/build.sh --release alpha       # cut alpha
sh ./build                               # full lockstep build (all tools + zddc-server)

(cd zddc && go test ./internal/handler/... ./internal/zddc/...)
npx playwright test --project=tables

Authoritative architecture and build docs are in ../AGENTS.md and ../ARCHITECTURE.md.