feat(forms): migrate remaining create/edit forms to FormGuard (PMS-518) #356

Merged
nrupard merged 1 commit from feat/PMS-518-remaining-forms into main 2026-06-25 21:12:09 +02:00
Owner

What

Bulk PMS-518 increment: migrates the remaining create/edit form surfaces onto the shared FormGuard, so every form reports its failures together (per-field inline slots) and focuses the first invalid field.

Deferred: the billing and contracts modals are not in this PR - they share files with the still-open #354 (billing New Invoice) and #355 (contracts) and will be a follow-up once those merge, to avoid same-file conflicts.

Forms migrated

  • tickets.rs: Edit Ticket modal, Add Note modal, Request Approval modal (full migrate; the approver XOR rule routes to the banner + note_invalid). Inline onchange editors left as-is (they PUT on change, not form submits).
  • contacts.rs: Company / Contact / Site - focus-first-invalid added; kept their bespoke validate_* validators.
  • assets.rs: New Asset (focus-first, validators kept), Edit Asset modal (Name + focus), Add Credential modal (Type / Username / Password routed through the guard into new inline slots).
  • projects.rs: New Project + Edit Project (focus-first, validators kept), Add Task + Task Edit modals (full migrate - Title/Status get per-field slots).
  • time.rs: Time Entry Edit modal (Work Type / Date via the guard; Hours keeps its free-text parse and reports via note_invalid). The Log Time create form was already migrated.
  • onboarding.rs: First/Last name split into per-field inline slots (was one shared banner message).
  • team.rs: invite Email via [Rule::Required, Rule::Email] into an inline slot.

Strategy

  • Short-circuit handlers (returned on the first failed field) -> converted to report-all via guard.field(...) per field.
  • Already-accumulating handlers (set every field's error, returned at the end) -> kept their bespoke typed validators (they parse-and-return the Decimal/String/date values the body uses) and only added focus-first via FormGuard.

A couple of messages were standardized to the canonical Rule wording so blur-time and submit-time agree (e.g. "Status is required."). Values sent to the server are unchanged (only the required-check is trimmed).

How it was built

Five parallel per-file migrations (one subagent per file), then verified centrally.

Verification

just check parity via the rust-builder image: clippy --all-targets -- -D warnings, fmt --check, cargo check --target wasm32-unknown-unknown - all green.

## What Bulk PMS-518 increment: migrates the remaining create/edit form surfaces onto the shared `FormGuard`, so every form reports its failures together (per-field inline slots) and focuses the first invalid field. > **Deferred:** the billing and contracts **modals** are not in this PR - they share files with the still-open #354 (billing New Invoice) and #355 (contracts) and will be a follow-up once those merge, to avoid same-file conflicts. ## Forms migrated - **tickets.rs**: Edit Ticket modal, Add Note modal, Request Approval modal (full migrate; the approver XOR rule routes to the banner + `note_invalid`). Inline onchange editors left as-is (they PUT on change, not form submits). - **contacts.rs**: Company / Contact / Site - focus-first-invalid added; **kept** their bespoke `validate_*` validators. - **assets.rs**: New Asset (focus-first, validators kept), Edit Asset modal (Name + focus), Add Credential modal (Type / Username / Password routed through the guard into new inline slots). - **projects.rs**: New Project + Edit Project (focus-first, validators kept), Add Task + Task Edit modals (full migrate - Title/Status get per-field slots). - **time.rs**: Time Entry Edit modal (Work Type / Date via the guard; Hours keeps its free-text parse and reports via `note_invalid`). The Log Time create form was already migrated. - **onboarding.rs**: First/Last name split into per-field inline slots (was one shared banner message). - **team.rs**: invite Email via `[Rule::Required, Rule::Email]` into an inline slot. ## Strategy - **Short-circuit handlers** (returned on the first failed field) -> converted to report-all via `guard.field(...)` per field. - **Already-accumulating handlers** (set every field's error, returned at the end) -> kept their bespoke typed validators (they parse-and-return the `Decimal`/`String`/date values the body uses) and only added focus-first via `FormGuard`. A couple of messages were standardized to the canonical `Rule` wording so blur-time and submit-time agree (e.g. "Status is required."). Values sent to the server are unchanged (only the required-check is trimmed). ## How it was built Five parallel per-file migrations (one subagent per file), then verified centrally. ## Verification `just check` parity via the rust-builder image: `clippy --all-targets -- -D warnings`, `fmt --check`, `cargo check --target wasm32-unknown-unknown` - all green.
feat(forms): migrate the remaining create/edit forms to FormGuard (PMS-518)
All checks were successful
Check / fmt + clippy + tests (pull_request) Successful in 15m33s
Create release / Create release from merged PR (pull_request) Has been skipped
f9c37203c1
Bulk per-page migration of the form surfaces that had no in-flight PR (billing and contracts modals are deferred until #354/#355 merge to avoid same-file conflicts). Each form now drives its required fields through the shared FormGuard so failures report together in per-field inline slots and the first invalid field is focused; short-circuit handlers are converted to report-all, already-accumulating handlers (which keep their bespoke typed validators that parse-and-return values the body uses) gain focus-first only.

- tickets.rs: Edit Ticket modal, Add Note modal, Request Approval modal (full migrate; XOR approver rule routes to the banner + note_invalid). Inline onchange editors left as-is (not form submits).
- contacts.rs: Company / Contact / Site forms gain focus-first-invalid (kept their bespoke validate_* validators).
- assets.rs: New Asset (focus-first, kept validators), Edit Asset modal (Name + focus), Add Credential modal (Type/Username/Password through the guard into new inline slots).
- projects.rs: New Project + Edit Project (focus-first, kept validators), Add Task + Task Edit modals (full migrate, Title/Status per-field slots).
- time.rs: Time Entry Edit modal (Work Type/Date via the guard, Hours keeps its free-text parse and reports via note_invalid). Log Time create form already migrated.
- onboarding.rs: First/Last name split into per-field inline slots.
- team.rs: invite Email via [Rule::Required, Rule::Email] into an inline slot.

Standardizes a couple of messages to the canonical Rule wording so blur-time and submit-time agree (e.g. "Status is required."). Values sent to the server are unchanged (only the required-check is trimmed).

Implemented as five parallel per-file migrations; verified centrally. just check parity (rust-builder image): clippy --all-targets -D warnings, fmt --check, cargo check --target wasm32-unknown-unknown all green.

#PMS-518
nrupard deleted branch feat/PMS-518-remaining-forms 2026-06-25 21:12:09 +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!356
No description provided.