Skip to content

fix(apollo-wind): read ISO date strings in date fields instead of crashing - #1339

Merged
BenGSchulz merged 1 commit into
mainfrom
fix/date-fields-iso-values
Oct 15, 2026
Merged

BenGSchulz merged 1 commit into
mainfrom
fix/date-fields-iso-values

Conversation

@BenGSchulz

@BenGSchulz BenGSchulz commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #1338. It edits QuickFormField's utils.ts and quick-form-field.tsx, which that PR also changes.

Summary

Hosts seed MetadataForm date and datetime fields from JSON (schema.initialData, field defaultValue), so values arrive as strings. The HITL quick-form runtime in Flow's debug panel crashes on them today:

  • DateTimePicker threw on any string, including "" (value?.getTime is not a function).
  • DatePicker threw on unparseable strings (Invalid time value).
  • Validation used z.coerce.date(), which guesses at numbers, years and locale strings, and reads "2026-09-23" as UTC midnight: the previous day west of UTC.

Changes:

  • toDateValue helper (src/lib/date-value.ts) accepts only:

    • a valid Date
    • an RFC 3339 date (2026-09-23, read as a local calendar day)
    • an RFC 3339 date-time (2026-09-23T07:00:00.123Z; no offset means local time).

    Anything else is no value: "", null, numbers, digit-only strings, locale strings, expressions. A regex runs before parseISO, which alone accepts reduced forms like "26".

  • The form layer parses. FieldControl and QuickFormField hand the pickers a parsed Date.

  • Validation: z.preprocess(toDateValue, …) wraps the optional/required schema, so an unrecognised value counts as absent rather than "Invalid date". Required date fields now show the required message (including a custom messages.required) instead of zod's generic one.

  • Pickers keep value?: Date. A one-line check treats anything other than a valid Date as no value, so they never throw.

  • DateTimePicker keeps milliseconds when a new day is picked.

  • QuickFormField drops its own parseDateValue in favour of toDateValue.

Behaviour changes

Value Before After
"2026-09-23" Shown and submitted as the previous day west of UTC; crashed DateTimePicker Local Sep 23
ISO date-time Crashed DateTimePicker; fine in DatePicker Shown; submitted with milliseconds kept
"" Crashed DateTimePicker; an optional field blocked submit with "Invalid input" No value
null on a required field Submitted as 1970-01-01 Required message
Expression, locale string, "2026", a number Crashed, or shown and submitted as whatever new Date() made of it No value: optional submits undefined, required shows the required message

Decisions worth a look

  • Don't guess. The standard parsers disagree on ambiguous input (new Date(2026) vs new Date("2026"), parseISO("26")), so only JSON Schema's date / date-time formats are accepted. A host sending another format now gets an empty field, not a guess.
  • Unrecognised values are dropped silently, not flagged as invalid. Surfacing them as a validation error is possible. Deferred until we see confusion, because a required read-only field would then block submit with nothing the user can do.
  • Form state keeps the raw value. A seeded string stays in react-hook-form state until the user picks a date, so rules and watch still see it. Only the control and the submitted data change.
  • Parsing lives in the form layer, not the pickers, so the leaf controls keep a plain Date contract.

Demo

Tested as dev package in hitl-schema to confirm that the runtime form does not crash with a datetime field added.

Before After
hitl-before.mov
hitl-after.mov

Test plan

  • apollo-wind: 2,646 tests pass, typecheck clean, biome clean on changed files
  • toDateValue: ISO dates and date-times (UTC, offsets, local, milliseconds); undefined for each rejected kind of value
  • FieldControl / MetadataForm seeded with "", a locale string and an expression render placeholders without throwing; ISO values show the right date
  • Validation: optional fields submit undefined; required fields (plain and conditionally required) show the required message; milliseconds survive parsing
  • Pickers: non-Date values don't throw; picking a new day keeps milliseconds
  • The new tests fail without the fixes they cover

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Dependency License Review

  • ✅ 1942 package(s) scanned
  • ✅ No license issues found
  • ⚠️ 2 package(s) excluded (see details below)
License distribution
License Packages
MIT 1708
ISC 91
Apache-2.0 56
BSD-3-Clause 28
BSD-2-Clause 23
BlueOak-1.0.0 8
MPL-2.0 4
MIT-0 3
CC0-1.0 3
MIT OR Apache-2.0 2
(MIT OR Apache-2.0) 2
Unlicense 2
LGPL-3.0-or-later 1
Python-2.0 1
CC-BY-4.0 1
(MPL-2.0 OR Apache-2.0) 1
Unknown 1
Artistic-2.0 1
(WTFPL OR MIT) 1
(BSD-2-Clause OR MIT OR Apache-2.0) 1
CC-BY-3.0 1
0BSD 1
(MIT OR CC0-1.0) 1
MIT AND ISC 1
Excluded packages
Package Version License Reason
@img/sharp-libvips-linux-x64 1.3.4 LGPL-3.0-or-later LGPL pre-built binary, not linked
khroma 2.1.0 Unknown MIT per GitHub repo, missing license field in package.json

@BenGSchulz
BenGSchulz added this pull request to stack #1340 October 12, 2026 22:16
@BenGSchulz BenGSchulz added the dev-packages Adds dev package publishing on pushes to this PR label Oct 12, 2026
@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

📦 Dev Packages

🧹 Dev packages cleaned up after PR close.

Last updated: 2026-10-15 14:11:00 PT

@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

📊 Coverage + size by package

Per-package coverage and bundle size on this PR. New-line coverage = of the source lines this PR adds or changes, the % hit by tests.

Package Coverage New-line coverage Packed (gzip) Unpacked vs main
@uipath/apollo-core — — 42.02 MB 50.17 MB ±0
@uipath/apollo-react 51.3% — 7.99 MB 31.45 MB +3.2 KB
@uipath/apollo-ui-icons — — 2.86 MB 6.97 MB ±0
@uipath/apollo-vertex — — — — —
@uipath/apollo-wind 79.0% 100.0% (25/25) 785.2 KB 4.55 MB +3.9 KB
@uipath/ap-chat 85.8% — 40.36 MB 45.58 MB +270 B

"Coverage" is each package's own coverage.include scope (e.g. apollo-core instruments only scripts/). "Packed"/"Unpacked" come from npm pack --dry-run and only cover built packages — "—" means not measured this run (package not affected / not built). "vs main" is the packed (gzipped) delta against the last successful main build (the package-sizes artifact from the Release workflow); "—" there means no main baseline was available this run. The baseline is main's latest build, not this PR's exact merge-base, so it includes any drift since the branch diverged. Packages with no vitest config are omitted.

Base automatically changed from fix/quick-form-field-expressions-disabled to main October 15, 2026 20:37
…shing

Hosts seed MetadataForm date and datetime fields from JSON, so values
arrive as strings. DateTimePicker crashed on any string and DatePicker
on unparseable ones, while z.coerce.date() guessed at numbers, years and
locale strings and read date-only strings as UTC midnight.

A new toDateValue helper accepts only a Date or an RFC 3339 date /
date-time string (date-only as a local calendar day); anything else is
no value. The form layer owns the parsing: FieldControl and
QuickFormField parse before handing a Date to the pickers, and
validation preprocesses with it, so an unrecognised value is absent
rather than "Invalid date". The pickers keep their Date contract and
only guard against non-Date input so they never throw.

DateTimePicker also keeps milliseconds when a new day is picked.
QuickFormField's own parseDateValue is replaced by toDateValue.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@BenGSchulz
BenGSchulz force-pushed the fix/date-fields-iso-values branch from 15fc9d2 to 1d52721 Compare October 15, 2026 20:38
@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Apollo Coded App preview deployments are ready.

Project Status Preview Updated (PT)
apollo-design Ready Preview · Logs Oct 15, 2026, 01:55:30 PM
apollo-docs Ready Preview · Logs Oct 15, 2026, 01:55:30 PM
apollo-landing Ready Preview · Logs Oct 15, 2026, 01:55:30 PM
apollo-vertex Ready Preview · Logs Oct 15, 2026, 01:55:30 PM

@github-actions github-actions Bot added the size:L 100-499 changed lines. label Oct 15, 2026

@dushyant-uipath dushyant-uipath left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve to unblock

@github-actions

Copy link
Copy Markdown
Contributor

Storybook visual diff

⚠️ Visual changes detected: 2 changed (of 150 compared, 148 unchanged). View report

Baseline is the deployed main Storybook, so changes merged to main after this branch was last updated can also appear here. Logs

Updated (PT): Oct 15, 2026, 02:03:10 PM

@BenGSchulz
BenGSchulz merged commit 3b0ddee into main Oct 15, 2026
43 checks passed
@BenGSchulz
BenGSchulz deleted the fix/date-fields-iso-values branch October 15, 2026 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dev-packages Adds dev package publishing on pushes to this PR pkg:apollo-wind size:L 100-499 changed lines.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants