Skip to content

Typed design properties: registry-driven value types + check validation - #36

Merged
ako merged 1 commit into
mainfrom
feature/typed-design-properties
Jul 26, 2026
Merged

Typed design properties: registry-driven value types + check validation#36
ako merged 1 commit into
mainfrom
feature/typed-design-properties

Conversation

@ako

@ako ako commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Implements the "typed design properties" requirement (previously deferred P2 in PROPOSAL_atlas_design_system.md:433 / open question in page-styling-support.md:402).

The problem

Design properties were written fully free-form. A flat value always serialized as an option, so a ColorPicker/ToggleButtonGroup property got the wrong BSON $Type for Studio Pro's Appearance tab, and a typo'd key or value — both case-sensitive — passed mxcli check and only failed later.

Root cause found along the way

The theme registry (themesource/*/web/design-properties.jsontheme_reader.go) already carried per-widget allowed keys/types/values, but nothing used it on the write/validate paths. Reason: resolveDesignPropsKey upper-cased the MDL keyword while the lookup map is lowercase-keyed, so container never resolved to DivContainer. That left resolveDesignPropertyValueType as dead code and made show design properties <widget> report "not found" for valid widgets. Fixed to lower-case the lookup.

What's implemented

  • Write pathastDesignPropToValue now resolves each flat value's type from the registry (ColorPicker/ToggleButtonGroupcustom), falling back to option when there's no project/themesource (backward compatible; on/off/compound unchanged).

  • Check (-p only, when themesource defines properties) — new ValidateDesignProperties walks page/snippet/alter-page widget trees and warns:

    • MDL-WIDGET11 — unknown design-property key for the widget (with a case-sensitivity "did you mean" hint, or the list of valid keys).
    • MDL-WIDGET12 — value not allowed; the message lists the allowed values (case-sensitive) — the fastest fix for a casing typo.

    Both are warnings, not errors — a newer theme may legitimately add keys/values (forward-compat). Compound entries and widgets with no type-specific metadata (e.g. pluggable) are skipped to avoid false positives.

  • LSP — caches the theme registry once per session (no per-keystroke file I/O) and surfaces the same diagnostics.

Answering "does the error list the allowed values?"

Yes — MDL-WIDGET12 prints Allowed values (case-sensitive): … from the registry, mirroring show design properties.

Tests & docs

  • Executor unit tests: registry-driven value typing; MDL-WIDGET11/12 incl. the allowed-values list and the wrong-case hint; unknown-widget skip; backward-compat (no metadata → option).
  • Example typed-design-properties.mdl; theme-styling.md validation section; fix-issue.md symptom row.

Scoped deliberately to entity/widget design-property typing; the Atlas-first migration-skill update is a separate docs PR.

🤖 Generated with Claude Code


Generated by Claude Code

@ako
ako force-pushed the feature/typed-design-properties branch 2 times, most recently from c664d48 to 2adb077 Compare July 26, 2026 05:00
Design properties were written fully free-form: a flat value always
serialized as an option, so a ColorPicker/ToggleButtonGroup property got
the wrong BSON $Type for Studio Pro's Appearance tab, and a typo'd key or
value (both case-sensitive) sailed through mxcli check.

Root cause of why the existing theme registry was unused: resolveDesignPropsKey
upper-cased the MDL keyword but the lookup map is lowercase-keyed, so
`container` never resolved to `DivContainer`. That left resolveDesignPropertyValueType
as dead code and also made `show design properties <widget>` report "not
found" for valid widgets. Fixed to lower-case the lookup.

- Write path: astDesignPropToValue now takes the widget's theme properties
  and resolves each flat value's type from metadata (ColorPicker /
  ToggleButtonGroup -> custom), falling back to option when no project /
  themesource (backward compatible).
- Check (-p only, when themesource defines properties): new
  ValidateDesignProperties walks page/snippet/alter-page widget trees and
  warns on MDL-WIDGET11 (unknown key, with a case-sensitivity hint / the
  list of valid keys) and MDL-WIDGET12 (invalid value, listing the allowed
  values). Warnings, not errors, for forward-compat with newer themes.
  Compound entries and widgets without type-specific metadata are skipped.
- LSP: caches the theme registry once per session (no per-keystroke I/O)
  and surfaces the same diagnostics.

Adds executor unit tests, an example, and theme-styling / symptom-table docs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
@ako
ako force-pushed the feature/typed-design-properties branch from 2adb077 to 8744867 Compare July 26, 2026 05:18
@ako
ako merged commit 8db91bc into main Jul 26, 2026
1 of 3 checks passed
ako pushed a commit that referenced this pull request Jul 29, 2026
A pass-through view column (a bare source-attribute ref like `select c.Name as
X`) inherits the source attribute's length verbatim, and Mendix requires the
declared length to match EXACTLY — declaring an unbounded `string` (or a
different `string(N)`) against a `string(100)` source fails the build with CE6770
"View Entity out of sync". MDL031's length check previously covered only DERIVED
columns (cast/case → 200); the references-mode validator compared pass-through
strings with `typesCompatible`, whose `>=` rule only guards truncation, so the
mismatch slipped through.

`validateViewEntityTypes` now checks pass-through string columns with
`passthroughStringLengthMismatch` (exact match), reporting the source entity/attr
and inherited length. `col.SourceAttr` is set only for a bare attribute ref, so
aggregates/derived expressions are unaffected.

References-mode only (needs the domain model to resolve the source length).
Test `TestPassthroughStringLengthMismatch`; example
mdl-examples/bug-tests/ledger-36-view-passthrough-length.mdl. Verified on a real
Mendix 11.12.1 project: `string`→CE6770 flagged, `string(100)`→clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
ako pushed a commit that referenced this pull request Jul 29, 2026
…ll gaps (FINDINGS #42/#36/#23/#48/#47)

- #42 DESCRIBE WORKFLOW dropped the `with (...)` param mappings: the modelsdk read
  path built a CallMicroflowTask with only Microflow+Outcomes and never populated
  ParameterMappings, so describe→drop→exec silently lost the mapping (which nothing
  then reports). Added microflowParamMappingsFromGen and wired it into both the
  CallMicroflowTask and CallMicroflowActivity read cases; the legacy sdk/mpr parser
  already read them. Round-trip test added; verified `describe workflow` now emits
  `call microflow M.ACT_Do with (Item = '$workflowContext')`.
- #36 SEC005 lint suggested `ALTER PROJECT SECURITY STRICT MODE ON`, a statement the
  parser doesn't implement. Strict mode is Studio Pro-only — the suggestion now says
  so instead of naming an unrunnable command.
- #23 documented `create or modify association` (the idempotent form) in the
  domain-model skill: plain `create association` is not idempotent and its failure
  aborts the rest of the script.
- #48 documented `set task outcome $Task '<Outcome>'` (there is no `complete task`)
  and the other workflow task statements in write-workflows.
- #47 documented that System-module enumerations are read from the runtime, not the
  .mpr, so mxcli can't resolve them — constrain on an attribute instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
ako pushed a commit that referenced this pull request Jul 31, 2026
…t (TraceOps #36)

`mxcli oql` is the documented way to verify data, but it could not query a
`mxcli run --local` app: the local runtime booted the JVM with no system
properties, so /dev/preview_execute_oql was never mounted (docker mode passes
-Dmendix.live-preview=enabled + -Dmendix.running.locally.by.studiopro=true via
docker-compose; the local boot did not), and `mxcli oql` failed with "Action
not found" — silently 0 rows. Before that, the admin password was
undiscoverable: run --local never printed it and oql errored with "admin
password required".

- LocalRuntimeOptions.jvmArgs() now always passes the two live-preview -D flags
  (run --local is always DTAPMode=D, matching docker mode).
- resolveM2EEDefaults falls back to defaultLocalAdminPass when nothing else
  supplies a token (the admin API is loopback-only), so oql works against a
  local run with zero configuration.
- The "Action not found" hint now branches to cover the --local case.
- The run --local banner prints a ready-to-copy `mxcli oql` line.

Tests: TestJVMArgs, updated TestResolveM2EEDefaults_Defaults.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
ako added a commit that referenced this pull request Aug 1, 2026
…-spike-emta6h

TraceOps #31#36: oql reaches run --local, lint widget flow refs, view-entity docs
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.

2 participants