fix(forms): validate only rendered fields so create forms can submit#25
Merged
Conversation
SchemaForm passed the full insert schema to zodResolver while omitting fields like companyId from rendering. companyId is required by every tenant-scoped insert schema and bound server-side, so submit failed validation on a field with no rendered error slot: clicking save did nothing, silently, on every CrudPage create form (assets, suppliers, risks, incidents, ...). Reported by a user on the asset step. - resolver now validates schema minus the omitted keys (mask filtered against the shape; Zod v4 omit throws on unknown keys) - asset date columns tightened to z.iso.date().nullable() so forms render native date inputs and Postgres never sees ''::date or free- text dates; empty date inputs and defaults are null, not "" - asset mutations surface server errors as toasts instead of nothing - add missing accessManagement / privilegedAccountCount labels and descriptions in all 10 asset locale files
simonorzel26
added a commit
that referenced
this pull request
Jul 20, 2026
…mps, global mutation error toasts (#26) Follow-up sweep after #25 for the same bug classes across all forms: - isoDateColumns(table) helper derives z.iso.date() overrides from drizzle table metadata and is spread into every insert schema whose table has pg date columns (18 schemas). Forms render date pickers, Postgres never receives '' or free-text dates, and notNull date columns (exercise/ audit scheduledDate, managementReview reviewDate) become properly required. nullish (not nullable) preserves drizzle-zod's absent-key semantics — this also fixes a #25 regression where asset.create 400d server-side because the omitted lastVulnScanDate/lastBackupTestDate keys were absent from the payload. - z.date() timestamp fields (incident discoveredAt/occurredAt etc.) get real Date objects from the date input instead of strings that could never validate; introspection marks them via FieldMeta.jsDate. - companyCertificationCreateSchema date regexes replaced with z.iso.date() so those fields render date pickers too. - Global MutationCache onError toasts any tRPC mutation failure that has no local handler; the AssetsPage-local handler from #25 is superseded.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
User report (2026-07-17, asset step of the journey): filling out Asset hinzufügen and clicking Speichern does nothing. Reproduced in Firefox and Edge — browser-independent.
Root cause:
SchemaFormpasses the full insert schema tozodResolverwhileCrudPageomits fields likecompanyIdfrom rendering.companyIdis.notNull()with no default on every tenant-scoped table, so validation fails on every submit — on a field that has no rendered error slot.handleSubmithas no invalid-handler, so nothing visible happens. This silently broke create on all 13 CrudPage forms (assets, suppliers, risks, incidents, patches, …). Edit worked, becausedefaultValuescarry the existing row'scompanyId.Fix
schema.omit(omitted keys)— exactly the fields the form renders. Mask is filtered against the shape (Zod v4.omit()throws on unknown keys). Server keeps bindingcompanyIdfrom session, unchanged.datecolumns (lastPatchDate,lastVulnScanDate,lastBackupTestDate,endOfLife) tightened toz.iso.date().nullable(): forms now render native date inputs, empty dates arenull(not"", which Postgres rejects as''::date), and free-text dates like17.07.2026get a visible client-side error instead of a server 500.accessManagement/privilegedAccountCountlabels + descriptions (CIR 2024/2690 points 11.2/11.3) in all 10 asset locale files.Verification
Scripted the exact reported payload through the fixed pipeline:
companyIdno longer validated client-sidelastPatchDate/endOfLifeintrospect asdate→ native date pickers, optional17.07.2026rejected with a field-level errornameerrors on the rendered field onlyactivatedAterrors on main are a local cross-worktree artifact, see CI)🤖 Generated with Claude Code