Skip to content

Add form events that run declarative actions - #58

Merged
Ziinc merged 38 commits into
mainfrom
claude/project-thread-cc7r2r
Oct 12, 2026
Merged

Ziinc merged 38 commits into
mainfrom
claude/project-thread-cc7r2r

Conversation

@Ziinc

@Ziinc Ziinc commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Zn · project thread

  • Forms bind an action to on load, on current, before update and after update (PRD §17.4); a failing before update action vetoes the save
  • Events section in form properties; Rust checks flag missing actions; config version 5 for Form.events (siblings adding nested fields will need to rebase onto 5)
  • App QA spec scripts/screenshot/specs/form-events.spec.tsx captures the designer, on load, veto and after update

🤖 Generated with Claude Code

https://claude.ai/code/session_01Tafn1n7Y2WYuRXBsW3r2Fo

…ator

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GbiHdEqFVn5g9qhRXNvbiX
…uilds

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GbiHdEqFVn5g9qhRXNvbiX
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GbiHdEqFVn5g9qhRXNvbiX
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GbiHdEqFVn5g9qhRXNvbiX
…p criteria to DuckDB

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JeeNa946LqRHZZjLxBERLz
- PRD §4.5 billing model (per app, org pays, annual = 2 months free, no
  trial, USD from a Singapore sole proprietorship) and §20.3 per-app access.
- Migration: app_collaborators, app_capabilities(_for), capability-based RLS,
  plans.annual_price_cents (check = 10x monthly), subscriptions.billing_interval,
  org_billing_customers.
- Edge Functions: app-access-update; billing-checkout takes interval and
  bills the org's single customer; webhook resolves plan and interval from
  the price; admin checks share app_capabilities_for.
- Website: Access tab, capability-gated read-only tabs, Monthly/Annual toggle
  on Billing and Pricing.
- service-qa contract and UI specs, Deno tests, decision records.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FnMtGVhp92898pMda24XBU
…ects they became

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JeeNa946LqRHZZjLxBERLz
Forms bind a declarative action to each event (PRD §17.4). Before update
vetoes the save when its action fails; after update reports a failure
without undoing the save. Config version 5 adds Form.events.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tafn1n7Y2WYuRXBsW3r2Fo
@github-actions

github-actions Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Continuous forms repeat the form's grid per record and save rows in place;
split forms show the list above the selected record. Detail views can show a
first/previous/next/last/new bar that walks the list's order. An openForm step
can open a popup and wait for its saved record or a closeForm value.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nu61xuJiarU1GUM2djPXyj
Running sums accumulate a field or calculated value over the rows or group
instances printed so far, over the enclosing group or the whole report.
Text components take conditional formatting rules (bold, text gray, fill)
evaluated with the component's value. A chart component draws bar, line,
area, pie, donut and scatter charts with the dashboard chart data and
geometry, as one chart item of paths and text that preview and PDF draw
alike.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCUeHtApaLW2nLJEdDErJd
src/reports/ matches the reports/ ignore rule, so new files there need
git add -f.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCUeHtApaLW2nLJEdDErJd
An older build would drop Form.navigationBar on save and reject the
continuous and split modes, so it must refuse these documents.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nu61xuJiarU1GUM2djPXyj
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tafn1n7Y2WYuRXBsW3r2Fo
Related lists now open child forms that show their own related lists, up to
three levels below the opened form; validation rejects deeper chains and
loops, the designer only offers forms that fit, and Runtime guards the depth.

Reports gain a subreport component that prints another report inside a band,
linked by child and parent fields, for invoices and statements. Layout
expands it into ordinary band instances so pagination stays deterministic.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FZkDyoVBe41qkCf1KCJfn6
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nu61xuJiarU1GUM2djPXyj
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JeeNa946LqRHZZjLxBERLz
The root .gitignore entry reports/ also matches src/reports/, so the new file
was left out of the previous commit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FZkDyoVBe41qkCf1KCJfn6
Field settings on each entity layer formats on text and JSON columns:
sanitized rich text, attachment files stored in the record store's hidden
_ixtable_attachments table and read through DuckDB, multi-select JSON
arrays, and Access-style input masks checked on entry. Forms, lists, the
datasheet, and table-sourced reports use them; the table designer edits
them. Decision record in docs/decisions/field-formats.md.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QWgr5aR41RSBVb1dYrZR12
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCUeHtApaLW2nLJEdDErJd
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QWgr5aR41RSBVb1dYrZR12
Embedded forms skipped their related lists, which kept nesting at one level.
The depth guard in RelatedRecords now limits nesting instead.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FZkDyoVBe41qkCf1KCJfn6

Ziinc commented Oct 10, 2026

Copy link
Copy Markdown
Contributor Author

Test (windows-latest) failed two integration tests on f62b08c:

  • persistence.test.tsx › "keeps the last valid archive when recovered work is invalid, then discards it": the "Recover unsaved work" dialog was still showing.
  • shell.test.tsx › "undoes and redoes saved-query edits…": the "Query name" textbox was not found after clicking New query (line 144).

Neither test opens a form or uses an event, and both pass on macOS for this same commit. This PR's integration test also passes on macOS. I think these are Windows timing failures, but that is not confirmed yet. I'll re-run the failed job once when this run finishes. If they fail again, I'll treat them as real and investigate.


Generated by Claude Code

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QWgr5aR41RSBVb1dYrZR12
Also label chart components 'bar chart: amount' on the canvas and call
the unchanged condition style 'As is' so it fits its select.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCUeHtApaLW2nLJEdDErJd
…nd filter styling

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JeeNa946LqRHZZjLxBERLz
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tafn1n7Y2WYuRXBsW3r2Fo
… not overlap

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FnMtGVhp92898pMda24XBU
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FZkDyoVBe41qkCf1KCJfn6
claude added 11 commits October 11, 2026 05:44
…eenshots

A row saved by leaving it showed its old value: the page re-read after the
save could land after the rows remounted. Rows now key on their record and
take new stored values unless they hold unsaved edits, so the new-record row
also keeps what was typed. A fixed actions column keeps fields aligned.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nu61xuJiarU1GUM2djPXyj
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	src/reports/data.ts
#	src/runtime/RelatedList.tsx
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Ziinc
Ziinc marked this pull request as ready for review October 12, 2026 22:48
@Ziinc
Ziinc merged commit 814017f into main Oct 12, 2026
13 checks passed

This branch was successfully deployed

1 active deployment
preview — 8de6557b Deployed Oct 12, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants