Replaces the always-text-input cell editor with a per-property
widget factory keyed off the row's JSON Schema (form.yaml). The
table view now picks the right editor for each cell automatically:
strings get text inputs, enums get dropdowns, integers get number
inputs with min/max, dates get date pickers, booleans get
checkboxes, multi-select arrays get a multi-select. Cells whose
schema is a complex type (nested object, generic array, oneOf /
anyOf / allOf) can't be inline-edited and punt to the row's
form-mode editor on Enter / double-click.
Schema discovery:
context.js walkServer fetches <currentdir>/form.yaml as a
companion to <currentdir>/table.yaml — same file the form-mode
renderer already loads, just from the table view's perspective.
Best-effort: a directory with table.yaml but no form.yaml still
renders as a sortable/filterable table; cells just fall back to
plain text inputs without per-property hints. The schema is
exposed as ctx.rowSchema and consumed by the editor's
propertySchemaFor() helper, which walks dot-separated field
names through schema.properties to locate each column's
property schema.
Editor factory (editor.js):
- propertySchemaFor(col) — schema lookup keyed by col.field.
- isComplexSchema(s) — true for nested object, generic array,
oneOf/anyOf/allOf. Multi-select-friendly arrays
(string-enum + uniqueItems) are NOT complex; they get an
inline multi-select widget.
- makeWidget(propSchema, col, initialValue) — dispatches to one
of the widget builders below based on schema type / format /
enum + column-spec hints (col.format / col.enum) for tables
without a form.yaml.
Widget builders, each returning {element, getValue, focus}:
- widgetText — plain <input type=text>, default fallback.
- widgetTextarea — for string with maxLength > 200 (long
narrative fields).
- widgetTyped(type) — typed inputs the browser can help validate;
used for date / date-time / email.
- widgetNumber — <input type=number> with min/max/step
derived from schema.minimum/maximum/
multipleOf. Integer schemas force step=1.
getValue returns Number, not string, so
the draft buffer holds the right type for
JSON serialization later.
- widgetCheckbox — <input type=checkbox>; getValue returns
bool. initial value coerces from "true"/
true string-or-bool.
- widgetSelect — <select> with empty placeholder + one
option per enum choice; getValue returns
the chosen string or null.
- widgetMultiSelect — <select multiple> with size = min(6, N);
getValue returns the array of selected
values (preserves order in the option list).
Complex-type cells:
isComplexSchema(propSchema) → enterEdit calls navigateToRowForm,
which routes to row.url (already the <id>.yaml.html re-edit URL
the row tracker holds). Phase 5 may swap this for an inline
side-panel mount of form-mode in the same bundle, but the
current navigate-out path delivers the same eventual UX without
needing the side-panel scaffolding.
Type-aware draft equality:
The pre-Phase-2 commit treated every value as a string and
compared via String() equality, which would mark any number-
column edit dirty even when the user re-typed the same number.
The new sameValue() helper handles bool/object via JSON-string
equality and falls back to loose string compare so 42 == "42"
isn't a false dirty. Drafts hold typed values (number, bool,
array) instead of all strings, so when Phase 3 wires the row PUT
the body shape matches the JSON Schema the server validates
against without an additional coercion pass.
Tests (tests/tables.spec.js — 7 new specs, total 22 in the
table view, all 27 in the file):
- enum column edits via select dropdown — verifies the empty
placeholder + 3 enum options render and the chosen value
displays back in the cell.
- integer column gives a number input with min/max — verifies
the type/min/max/step attributes derive from the schema, AND
the draft buffer holds typeof === 'number'.
- boolean column gives a checkbox — verifies type=checkbox and
the draft holds true after Space-toggle. (Toggle via Space,
not Playwright's .check() helper, to dodge the click+blur
race a focused-checkbox-inside-grid-cell hits.)
- format:date column gives a date input — verifies type=date
and the existing value pre-populates as YYYY-MM-DD.
- multi-select enum-array column gives a multi-select.
- complex (object) column navigates to the row form on edit —
verifies no inline editor mounts AND the navigate seam
receives the row's URL.
- no rowSchema → falls back to plain text editor — verifies the
best-effort behavior for directories with only table.yaml.
Bundle size: 124 KB → 127 KB (+3 KB for the factory + widget
builders).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|---|---|---|
| .forgejo | ||
| archive | ||
| browse | ||
| classifier | ||
| form | ||
| helm | ||
| landing | ||
| mdedit | ||
| pandoc | ||
| shared | ||
| tables | ||
| tests | ||
| transmittal | ||
| zddc | ||
| .gitignore | ||
| AGENTS.md | ||
| ARCHITECTURE.md | ||
| build | ||
| CLAUDE.md | ||
| deploy | ||
| dev-server | ||
| freshen-channel | ||
| LICENSE.txt | ||
| package.json | ||
| playwright.config.js | ||
| README.md | ||
| SECURITY.md | ||
Zero Day Document Control (ZDDC)
The Universal Distributed Filing Cabinet
ZDDC is an information management convention plus a small set of single-file HTML tools. Every deliverable's filename encodes its tracking number, revision, status, and title; every transmittal folder is date-prefixed and self-describing. A plain shared folder becomes a fully searchable, auditable archive — no server, no database, no software required to read it.
The name "Zero Day Document Control" comes from the convention itself — adopt it on day zero of a project, with no setup time. The tools are optional interfaces around the structure; the structure works without them.
For end users: https://zddc.varasys.io/ introduces the project, links to all tool channels (stable / beta / alpha), and prints copy-paste shell snippets to install on a self-hosted deployment.
Tools
| Tool | What it does |
|---|---|
| Archive Browser | Browse, search, and filter a project archive folder. Group by transmittal, export selections as ZIP. |
| Transmittal Creator | Self-contained HTML transmittal records with SHA-256 checksums and optional digital signatures. |
| Document Classifier | Spreadsheet-like bulk-renamer that copy/pastes with Excel and writes back to disk. |
| Markdown Editor | Browser-based markdown editor with YAML front matter, TOC, and direct local file access. |
| Form Renderer | Schema-driven *.form.yaml editor — every form spec auto-mounts an editable form at <name>.form.html. |
| Tables | Read-only grid view of a directory of YAML files with sort + filter; click row → edit in the form renderer. Declared per-directory in .zddc. |
Each tool is published in three channels (stable, beta, alpha) as static files served from https://zddc.varasys.io/releases/. Local use: download a .html file from releases/ and open it in a browser. Server use: run zddc-server — the current-stable build of every tool is baked into the binary at compile time, so a fresh deployment Just Works with zero config. Tools auto-appear at folder-name-driven paths (archive everywhere; classifier in Incoming/Working/Staging; mdedit in Working; transmittal in Staging). Override per-directory by writing an apps: entry in any .zddc file (channel/version/URL/path). URL overrides are fetched once and cached in <ZDDC_ROOT>/_app/; drop a real .html file at any path to override entirely.
File-naming convention
The full specification — filename format, tracking numbers, revision rules, status codes, folder naming, and the transmittal workflow — lives at https://zddc.varasys.io/reference.html.
Quick example: 123456-EL-SPC-2623_A (IFR) - Specification For Switchgear.pdf
Build & develop
git clone https://codeberg.org/VARASYS/ZDDC.git && cd ZDDC
sh build.sh # build all tools (writes to dist/ only)
sh archive/build.sh # build one tool
sh archive/build.sh --release # cut stable; auto-bumps patch from last tag
sh archive/build.sh --release 0.1.0 # explicit version
sh archive/build.sh --release alpha # cut alpha (mutable channel, no tag)
sh archive/build.sh --release beta # cut beta
npm install && npx playwright install chromium && npm test # tests
./dev-server start # cache-busting HTTP on :8000
Authoritative build/release docs are in AGENTS.md. Architecture notes (single-file rationale, JS module pattern, security model) are in ARCHITECTURE.md. zddc-server (optional Go HTTP server with ACL and a virtual archive index) is in zddc/README.md. Example Helm charts for deploying zddc-server (production + dev) are under helm/.
Contributing
ZDDC is an open source project hosted on Codeberg at https://codeberg.org/VARASYS/ZDDC. Bug reports, feature requests, and pull requests welcome.
ZDDC is designed for zero configuration to start and minimal configuration overall — feature proposals are filtered through that lens.
License
GNU Affero General Public License v3.0. Free to use, modify, and distribute, including commercially, under the terms of the license. Provided "as is" without warranty.