Skip to content

fix: write, describe and alter a date picker's DateFormat (#968) - #976

Merged
ako merged 12 commits into
mainfrom
fix/968-datepicker-format
Oct 4, 2026
Merged

ako merged 12 commits into
mainfrom
fix/968-datepicker-format

Conversation

@ako

@ako ako commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Closes #968. Same bug as mendixlabs#1263.

What was wrong

datepicker d (…, DateFormat: Time) and DateFormat: Custom, CustomDateFormat: '…' passed check and were stored as FormattingInfo{DateFormat: Date, CustomDateFormat: ''}. There were three drops: the builder never read the properties, the writer hard-coded newFormattingInfo(), and describe never printed them. check said nothing because validateStaticWidgetUnknownProps skipped the dynamic-text format keys on every widget type, not just dynamictext.

Measured first

  • Studio Pro-authored pickers: TestApp WorkflowCommons.WorkflowEndedUserTask and Snip_Workflow_Detail store DateFormat: DateTime plus a leftover CustomDateFormat ('dd/MM/yyyh, HH:mm'). Studio Pro keeps the pattern when you switch the format away from Custom.
  • mxbuild (mx check, 11.13, PedApp scratch copy) for each value:
    • Date, Time, DateTime, Custom+pattern, and DateTime+pattern: no errors.
    • Custom with an empty pattern: CE0493 "Date format is custom but no format string is specified."
  • Text box: it binds no DateTime attributes (CE2421, MDL-WIDGET39), so only its numeric formatting means anything.

Changes

  • Syntax: pages.DatePicker.FormattingInfo replaces a DateFormat string that nothing read. sdk/pages/formatting.go holds the canonical DateFormat values and the per-widget property list, shared by the builder and the mutator.

  • Spelling (additive, ADR-0011): the PascalCase widget-property form of the existing format (dateFormat:, customDateFormat:) keys:

    • date picker: DateFormat, CustomDateFormat
    • text box: DecimalPrecision, GroupDigits
  • Builder and check: mdl/executor/input_formatting.go uses one validator for both the builder and the check, reported as MDL-WIDGET18. It refuses:

    • an unknown DateFormat
    • a CustomDateFormat with no DateFormat (it would never apply)
    • Custom with no pattern (CE0493)
    • a negative precision, or a non-bool GroupDigits

    A pattern beside an explicit non-Custom DateFormat is accepted, because Studio Pro stores that combination.

  • Writer: formattingInfoToGen(x.FormattingInfo) for both DatePicker and TextBox. A nil value is byte-identical to before.

  • Describe: prints only non-default values. A leftover pattern is printed together with its DateFormat, so describe's output passes check.

  • alter page … set: DateFormat / CustomDateFormat / DecimalPrecision / GroupDigits work through setWidgetFormattingMut. It refuses an invalid value, Custom with no pattern, and a key on the wrong widget type.

  • MDL-WIDGET07: the format-key exemption is now per type. DateFormat: on a textarea or text box now warns instead of passing silently.

  • Dynamic-text parameter format (…): customDateFormat beside an explicit dateFormat: DateTime is no longer refused. Before this, check on describe's own output for TestApp's Snip_Workflow_CommentsAndAttachments failed with MDL-WIDGET18.

  • MCP backend: inputWidget now sends an authored formattingInfo, in the same shape the template parameters use. Not verified against a live Studio Pro MCP.

  • Docs: syntax help (features_page.go), create-page skill widgets.md, MDL_QUICK_REFERENCE.md, CHANGELOG, and a finding in mdl-executor.jsonl.

Format-property audit

  • Text box DecimalPrecision/GroupDigits: had the same drop; fixed here.
  • Dynamic text: per-parameter format (…) already round-tripped; the false refusal is fixed here.
  • Reference selector: has a FormattingInfo, but MDL has no builder or writer for it, so there is nothing to drop. Not covered.
  • Legacy grid column: has a FormattingInfo; not authorable from MDL.

Test plan

  • go test ./mdl/executor/ ./mdl/backend/... ./sdk/pages/ ./cmd/mxcli/ ./mdl/visitor/: pass.
  • New tests:
    • mdl/backend/modelsdk/widget_formatting_write_test.go: BSON layer, with a defaults control.
    • mdl/executor/input_formatting_pedapp_test.go: on PedApp, exec → stored unit FormattingInfo per widget → describe prints the values → re-exec the describe output writes no file (GetPut) → control: an edited description is written. Plus alter set, and each refusal leaves the page unchanged.
    • mdl/executor/input_formatting_test.go: check, via ValidateWidgetProperties on parsed MDL.
    • dynamictext_format_test.go: the leftover-pattern case.
  • TestApp harness (-tags integration): with WorkflowEndedUserTask and Snip_Workflow_Detail removed from the allowlist, their GetPut diff no longer contains any FormattingInfo/DateFormat path. The date-time pickers keep DateTime and their pattern. Both still break GetPut on unrelated losses (see follow-ups), so their allowlist entries stay. TestTestAppRoundTrip subtests for the four affected documents pass.
  • mx check evidence: the probe page on a PedApp copy (Date/Time/DateTime/Custom/leftover-pattern pickers and a text box with precision 4 and grouping) shows no errors for these widgets except CE0493 on the deliberate Custom+empty picker. That picker is what drove the refusal.
  • Revert checks: each of these was reverted on its own, and the named test failed with the reported symptom:
    • writer datepicker → DateFormat = Date, want Time
    • writer textbox → 2/false, want 4/true
    • builder → stored Date
    • describe → describe should print DateFormat: Time
    • validateInputFormatting call → no MDL-WIDGET18
    • WIDGET07 per-type exemption → no warning on textarea/textbox
    • param leftover-pattern relaxation → MDL-WIDGET18 on describe-shaped input
    • mutator case → alter set error
  • make build, make check-conformance, make lint, make check-findings, make check-mdl, make check-skill-mdl, make sync-skills: pass.

Follow-ups (not in this PR)

  • Input-widget ReadOnlyStyle is a silent drop on textbox, textarea and datepicker. The writer hard-codes Inherit, and describe and the builder ignore it (checkbox and dataview already handle it). This is now the only remaining loss on the TestApp date-picker pages, along with textarea NumberOfLines/Autocomplete and a button's OutputMappings on Snip_Workflow_Detail. Until it is fixed, a Studio Pro date-time picker's unit does not yet pass GetPut end to end; its format does.
  • The dynamic-text customDateFormat describe does not escape ' (formatParamFormatSuffix writes '+cdf+'). A Java date pattern with literal text ('at') would not round-trip.
  • alter page … set (CustomDateFormat: '') on a Custom picker is not refused. Only the DateFormat side checks CE0493, because properties are applied one at a time.

🤖 Generated with Claude Code

ako and others added 12 commits October 4, 2026 14:53
…ash index

Compares every Unit.ContentsHash with base64(SHA-256) of its .mxunit and
reports mismatches, missing files and orphan files; --repair rewrites the
mismatched hashes in one transaction under the writer's Studio Pro guard.
exec and docker check warn when the index disagrees (~0.2 s on 900 units).

Part of #972 (item 1).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Studio Pro 11.13 fails with "Unable to find 'system' property in 'system'"
when the branch has no upstream or git reports dubious ownership. docker
check, run --local and diag -p now warn with the remedy. Never fatal;
silent outside a repo, on a detached HEAD, under CI or with
MXCLI_NO_GIT_WARNINGS=1.

Part of #972 (item 3).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Part of #972.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lone (#970)

theme create --from wrote a design's base palette into the base theme's
alt-variant mixin, so a light ground and ink landed in a dark palette
whose other surfaces stayed dark. Without a block for that variant the
mixin is now left as the base ships it and create prints a note.

Also: applyTokens matched the indent with \s*, which under (?m) swallowed
the preceding newline, putting the first token on the @mixin line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ace' (#970)

An unscoped create translations reaches the whole project, Marketplace
modules (and their Atlas templates/building blocks) included; a module
update replaces those. The default is kept (ADR-0011: what a committed
script writes does not change in place). The run now warns with a
per-module count, and the additive clause 'without marketplace' (create
and describe) keeps the run out of Marketplace modules and reports the
entries it left alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
watchAndApply held a bare *WebClientWatcher. A bundler that exited was never
restarted, so every later page change failed with "watcher exited"; a failed
incremental build (ENOTDIR on web/pages mid-rewrite, measured on 11.13 after
adding an entity) dropped the change and the next one too; and
ensureClientServed's recovery ran a one-shot production bundle in the same
web/ directory while the watcher was still running.

bundlerSupervisor now owns the bundler: EnsureAlive restarts an exited one
with backoff, AwaitRebuild retries a failed incremental rebuild once with a
fresh bundler, and a recovery re-bundle replaces the bundler (stop and reap,
then start) instead of running beside it. The bundle-build limit is
configurable (--web-client-timeout, MXCLI_WEB_CLIENT_TIMEOUT) and a timeout
prints the tail of web-client-build.log. A change that restarts the runtime
says that browser sessions were dropped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After each apply watchAndApply moved its change baseline to the source's
current mtime, so an exec or save that landed during the build was folded
into the baseline and never rebuilt. Keep the baseline at the mtime the build
settled on; the build writes nothing under the watched source.

Found while reproducing #971.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A date picker's DateFormat / CustomDateFormat passed check, was stored as
the default Date, and was never described, so describe -> exec turned a
Studio Pro date-time picker into a date-only one (mendixlabs#1263).
The builder now reads them into the picker's FormattingInfo, the writer
stores it, describe prints non-default values, alter page set changes them,
and check refuses an unknown value, a pattern with no DateFormat and Custom
with no pattern (mxbuild CE0493) as MDL-WIDGET18. A text box's
DecimalPrecision / GroupDigits had the same drop and is fixed with it.

The unknown-property exemption for the dynamic-text format keys now applies
to dynamictext only, and a dynamic-text parameter's customDateFormat beside
an explicit non-Custom dateFormat (stored by Studio Pro) is accepted.

Closes #968

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and quick reference (#968)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-dark' into c25-974

# Conflicts:
#	CHANGELOG.md
@ako
ako merged commit aa8069f into main Oct 4, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Date picker DateFormat / CustomDateFormat silently dropped on write and not described (also mendixlabs/mxcli#1263)

1 participant