feat(forms): preview the client's view from the builder #494

Merged
longjacksonle merged 2 commits from feat/PMS-744-form-preview into main 2026-08-08 06:31:33 +02:00

Closes PMS-744.

The ask

"After setting a form, is it possible to show a preview of what it looks like for the creator, easy to manage."

It makes sense, and the gap is real. The builder describes a form in editor terms (reference names, field types, conditional rules) and never showed the result. The only way to see what a client receives was to issue a real request link, which is single-use, expires in seven days, emails an actual client, and adds a row to that client's link history. So in practice nobody looked, and the third screenshot on the ticket, a client page with one field, is the first time anyone saw it.

What this adds

A Preview button beside Cancel and Save in the form editor, opening the client's view of the form.

Three decisions worth stating:

It renders through the real component. The first commit lifts the client page's title, description, field list and submit button into RequestFormBody, and the preview calls that, on the client page's own background. A preview built from a second copy of the markup would drift from the page it claims to show, and a preview that lies is worse than none: it invites an operator to sign off on a form they have not actually seen.

It reads the live editor state, not the saved definition. The question is asked while editing, so the answer covers unsaved changes.

It is live, not a picture. Typing into it exercises the required_if rules exactly as a client will hit them, which is the part of a definition hardest to hold in your head from the rule editor alone.

Rows the client would never receive are dropped rather than drawn: a field with no reference name (the server rejects that save anyway) and a rule missing any of its three parts (it cannot fire). Options are carried only for a choice list, so stale values left behind by switching a field's type back to text do not show up. An unnamed draft previews as "Untitled form", and an unlabelled field shows its reference name, which is what the client would actually get.

The submit button renders but does nothing. Removing it would misrepresent the page, since the client sees one; wiring it would need a token this form does not have. The preview says so in one line above the card.

Verification

cargo check --all-targets, cargo clippy --all-targets (clean), cargo fmt --all --check (clean), cargo test --lib (267 passed).

Three new unit tests cover the mapping: incomplete fields and rules are dropped, the fallbacks fire where a client would otherwise see a gap, and only a choice list carries options.

Considered and not done

A Preview action on each definition row, next to Edit and Send. It would be a third link in a narrow Actions column for a case already covered by Edit then Preview, and the row cannot preview unsaved work, which is the more useful moment. Easy to add later if the row turns out to be where people reach for it.

Closes PMS-744. ## The ask "After setting a form, is it possible to show a preview of what it looks like for the creator, easy to manage." It makes sense, and the gap is real. The builder describes a form in editor terms (reference names, field types, conditional rules) and never showed the result. The only way to see what a client receives was to issue a real request link, which is single-use, expires in seven days, emails an actual client, and adds a row to that client's link history. So in practice nobody looked, and the third screenshot on the ticket, a client page with one field, is the first time anyone saw it. ## What this adds A **Preview** button beside Cancel and Save in the form editor, opening the client's view of the form. Three decisions worth stating: **It renders through the real component.** The first commit lifts the client page's title, description, field list and submit button into `RequestFormBody`, and the preview calls that, on the client page's own background. A preview built from a second copy of the markup would drift from the page it claims to show, and a preview that lies is worse than none: it invites an operator to sign off on a form they have not actually seen. **It reads the live editor state, not the saved definition.** The question is asked while editing, so the answer covers unsaved changes. **It is live, not a picture.** Typing into it exercises the `required_if` rules exactly as a client will hit them, which is the part of a definition hardest to hold in your head from the rule editor alone. Rows the client would never receive are dropped rather than drawn: a field with no reference name (the server rejects that save anyway) and a rule missing any of its three parts (it cannot fire). Options are carried only for a choice list, so stale values left behind by switching a field's type back to text do not show up. An unnamed draft previews as "Untitled form", and an unlabelled field shows its reference name, which is what the client would actually get. The submit button renders but does nothing. Removing it would misrepresent the page, since the client sees one; wiring it would need a token this form does not have. The preview says so in one line above the card. ## Verification `cargo check --all-targets`, `cargo clippy --all-targets` (clean), `cargo fmt --all --check` (clean), `cargo test --lib` (267 passed). Three new unit tests cover the mapping: incomplete fields and rules are dropped, the fallbacks fire where a client would otherwise see a gap, and only a choice list carries options. ## Considered and not done A Preview action on each definition row, next to Edit and Send. It would be a third link in a narrow Actions column for a case already covered by Edit then Preview, and the row cannot preview unsaved work, which is the more useful moment. Easy to add later if the row turns out to be where people reach for it.
The title, description, ordered fields and submit button rendered inline in the page. `RequestFormBody` lifts them out unchanged, with the caller owning the answer and error signals.

Groundwork for PMS-744: the builder's preview has to render through this exact component. A preview assembled from a second copy of the markup would drift from the real page, and a preview that lies is worse than none, because it invites an operator to sign off on a form they have not actually seen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011myibMMwyb6za3GVWJGkiX
feat(forms): preview the client's view from the builder
All checks were successful
Check / fmt + clippy + tests (pull_request) Successful in 1m33s
Create release / Create release from merged PR (pull_request) Has been skipped
60544b10cb
PMS-744: the builder describes a form in editor terms (reference names, types, conditional rules) and never showed what a client receives. Checking meant issuing a real request link, which is single-use, expires in seven days, and emails an actual client, so in practice nobody checked.

Preview sits with Cancel and Save, because that is the moment the question arises, and it reads the live editor state rather than the saved definition, so it answers for unsaved edits. It renders through `RequestFormBody` on the client page's own background: what is shown is what is sent.

The preview is live, not a picture. Typing into it exercises the `required_if` rules exactly as a client will hit them, which is the part of a definition hardest to hold in your head from the rule editor alone.

Rows the client would never receive are dropped: a field with no reference name (the server would reject that save) and a rule missing any of its three parts (it cannot fire). Options are carried only for a choice list, so values left behind by switching a field's type back to text do not appear. The submit button renders but is inert: removing it would misrepresent the page, and wiring it would need a token this form does not have.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011myibMMwyb6za3GVWJGkiX
longjacksonle scheduled this pull request to auto merge when all checks succeed 2026-08-08 06:31:18 +02:00
longjacksonle deleted branch feat/PMS-744-form-preview 2026-08-08 06:31:34 +02:00
Sign in to join this conversation.
No reviewers
No labels
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
psa-systems/mokosh-apps!494
No description provided.