feat(forms): component-owned field validation + shared validator set (PMS-516) #350
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/PMS-516-form-validation-layer"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Foundation for the PMS-515 form-validation epic. Gives the shared field components their own validation and adds a single shared validator module, so forms stop hand-rolling ~76 ad-hoc validation strings with divergent messages.
Changes
src/utils/validation.rs(new): aRuleenum (Required,MinLen/MaxLen,Email,Uuid,Number{min,max,max_decimals},Custom) +validate(value, label, rules) -> Option<String>returning the first failing rule's label-parameterised message. Pure and unit-tested (13 cases). Ships the broadly-applicable rules; domain-specific ones (phone E.164, postal, ISO country, H:MM) move onto shared rules as forms adopt them in PMS-518, withCustomas the interim escape hatch.components/form.rs:Input,Textarea,Select, andDateField(viaInput) take arules: Vec<Rule>prop and self-validate once the field is touched (on blur, then live on subsequent input so the message clears as the value is corrected), driving the existing inlineerrorslot. An expliciterrorprop still overrides, so a serverfield_message(...)lands in the same slot.DateFielddoc that still claimedrequiredsets the native HTML attribute (MAPPS-277 removed it).Non-breaking / opt-in
rulesdefaults to empty, so every existing call site behaves exactly as before (empty rules -> no computed error -> theerrorprop alone drives the slot, identical to the old code) until a form opts in during PMS-518.PartialEqonRuleis hand-written (comparingCustomviastd::ptr::fn_addr_eq) to satisfy-D unpredictable_function_pointer_comparisonswhile keeping the enum usable in DioxusProps.Scope boundary
This is the component layer + validator module. Submit-time enforcement (forcing untouched fields to validate, blocking submit, focusing the first invalid field) is the separate submit guard in PMS-517; migrating the ~30 forms and deleting the bespoke validators is PMS-518.
Checkboxis deferred (boolean value, different rule shape, no form needs it yet).Verification
just checkparity via the rust-builder image:clippy --all-targets -- -D warnings,fmt --check,cargo test --lib validation(30 passed),cargo check --target wasm32-unknown-unknown- all green.Acceptance criteria (PMS-516)
required+ typed rules themselves and surface in the inline slot (on blur; submit-time forcing is PMS-517).pattern-style viaCustom.errorprop still overrides for server field errors.form.rsdocs corrected (incl. the staleDateFieldcomment).just checkgreen.Foundation for the PMS-515 epic. Adds src/utils/validation.rs: a Rule enum (Required, MinLen/MaxLen, Email, Uuid, Number{min,max,max_decimals}, and a Custom escape hatch) plus validate(value, label, rules) that returns the first failing rule's label-parameterised message, with unit tests. This is the single place to express the common field rules so forms stop hand-rolling ~76 ad-hoc strings with divergent messages. Wires the rule into the shared field components (Input, Textarea, Select, and DateField via Input): each takes a rules: Vec<Rule> prop and validates its value once the field is touched (on blur, then live on subsequent input so the error clears as it is fixed), driving its existing inline error slot. An explicit error prop (e.g. a server field_message) still overrides the rule message, so server errors land in the same slot. Non-breaking and opt-in: rules defaults to empty, so every existing call site behaves exactly as before (empty rules -> no computed error -> the error prop alone drives the slot, identical to the old code) until a form adopts rules during the PMS-518 migration. Submit-time enforcement (forcing untouched fields to validate, blocking submit, focusing the first invalid field) is the separate submit guard in PMS-517; this commit delivers the component layer and the validator module it calls. Also corrects the stale DateField doc that still claimed required sets the native HTML attribute (MAPPS-277 removed it). Checkbox is intentionally left for later: its value is boolean, not a string, so a "must be checked" rule has a different shape and no form needs it yet. just check parity (rust-builder image): clippy --all-targets -D warnings, fmt --check, cargo test --lib validation (30 passed), cargo check --target wasm32-unknown-unknown all green. #PMS-516