Pluggable widget generation, warm local dev loop, ALTER PAGE INSERT INTO, and widget-authoring fixes#774
Merged
Conversation
The prompt block used a triple-backtick ```text fence containing a nested ```bash fence. mdBook's parser treated the inner closing ``` as closing the outer block, so everything after the curl example rendered as prose instead of inside the prompt code block. Switch the outer fence to four backticks (the pattern already used elsewhere in the site) so the nested fence is literal. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
CE0463 remediation in the synced skills told agents to run `mx update-widgets` directly. On an MPRv2 project (an `mprcontents/`-folder project — everything `mxcli new` creates) that command silently rewrites the project to single-file v1 and deletes `mprcontents/`, corrupting a git working tree, breaking a running `mxcli run --local` loop, and sometimes leaving Studio Pro unable to open the project. This actually bit a warm-loop app-generation run (CE0463 on Image widgets → agent ran `mx update-widgets` per the skill). With PR mendixlabs#764 (issue mendixlabs#763) merged, `mxcli docker check`/`build` snapshot and restore the v2 storage around the widget normalization, so they are the safe remediation. Point every CE0463/update-widgets mention at those commands and warn that bare `mx update-widgets` is only safe on a v1 project or a throwaway diagnostic copy. - create-page.md, custom-widgets.md, migrate-design-prototype.md, download-marketplace-content.md (user-synced): steer to docker check/build, warn about the v2->v1 deletion. - debug-bson.md (dev): fix the "safety net"/"quick workaround" framing; add a "use a COPY" caution to the reference-extraction blocks. - fix-issue.md: add a symptom-table row for the mprcontents/ data-loss class (issue mendixlabs#763 / PR mendixlabs#764). Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
Authoring an Image widget on any Mendix 11.7+ project and running `mx check` (without `mx update-widgets`) reported CE0463 "the definition of this widget has changed". The documented remedy — `mx update-widgets` — rewrites an MPRv2 project to v1 and deletes mprcontents/ (issue mendixlabs#763), so this stale default quietly funnelled users into data loss. Root cause (found by ruling out every other theory empirically): the embedded image.json carried a spurious default value — a WidgetValue.Image pointing at `Atlas_Core.Content.Mendix` (Atlas's Mendix logo), captured when the template was extracted from a project that had it set. The installed 11.12 Image widget expects that field empty, so MxBuild flags the definition as changed. It was NOT a version stamp, Type $IDs, property order, or missing properties — those were all disproven (a passing datagrid is reordered by update-widgets too, and authoring with a "correct" extracted template + stableIds still failed). Fix: clear the default to "" in both engine templates. Verified: the widget now passes `mx check --no-update-widgets` with 0 errors on Mendix 11.12.1. Adds a bug-test repro and a fix-issue.md symptom row documenting the order-independent before/after-update-widgets diff method used to isolate it (reusable for the rest of this CE0463 class, incl. DataGrid2 mendixlabs#600). Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…n defaults The dirty-template guard (from the ComboBox fix, 827bffd) only flagged concrete entity/attribute/flow refs in a template's Object — which is exactly why the Image dirty default (WidgetValue.Image = "Atlas_Core.Content.Mendix", fixed in 549c44f) shipped and caused CE0463. Extend `dirtyBindings` to also flag image-asset refs, page refs, and configured client actions (Action != Forms$NoAction) on a WidgetValue — the broader dirty-default class the tolerance spike identified. - Scans BOTH engines' template sets (modelsdk embed + sdk sibling on disk), so a regression in either fails the build. - Non-vacuous: detect-dirt cases for all four classes (entity/image/page/action) + a clean-is-clean case guarding against false positives (an empty DataSource slot on a data widget is legitimate and must not flag). - Verified it catches the real Image regression (reintroducing the stale default fails the test; clean passes). Kept WidgetValue-scoped (false-positive-free) rather than any-node: a broader scan surfaces a configured delete Forms$ActionButton baked into datagrid.json, but that nested-Forms-widget dirt is an unverified object-list-widget issue (mendixlabs#600 / Open Question 1) — documented as a lead in the proposal, not flagged here. Updates PROPOSAL_multi_version_pluggable_widgets.md: Image recorded as the second cleaned template (Phase 1), the guard marked built+broadened, the before/after-update-widgets diagnosis method recorded, and the datagrid ActionButton captured as a mendixlabs#600 lead. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…[email protected] schema drift Verified pluggable-widget CE0463 directly against cached mxbuild 10.24.19 / 11.10.0 / 11.12.1: - DataGrid2 is clean across all three versions (attribute columns — the exact mendixlabs#600 repro — plus custom content, filters, and selection). mendixlabs#600 was filed on v0.11.0 and is resolved on HEAD. Corrects an earlier note that claimed DataGrid2 custom-content still failed on 11.12.1; that was a test-syntax artifact (Content: showContentAs), not a defect. - Gallery custom content fails CE0463 on 10.24 (clean on 11.10/11.12). The before/after-update-widgets subtree diff shows it is within-key PropertyType DEFINITION drift (pagingPosition enum values + default changed, a Category renamed, a Type/order shift), not a dirty default and not merely nested. augmentFromMPK reconciles key presence but not within-key definition changes. Frames the fix (deeper augment reconciling full PropertyType from the .mpk vs per-version templates) and notes this generalises — DataGrid2 will drift the same way on a far-enough version, so the deeper-augment fix future-proofs it. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…n mxcli-version bug The latest mendixlabs#600 report (mxcli v0.16.0, Mendix 11.12.0, "still present") is reproduced-by-diagnosis: the user updated Data Widgets from the marketplace (bundled 3.4.0 → 3.10.0), and that newer schema drifts from the 11.6 template exactly like [email protected] — within-key PropertyType definition changes that augmentFromMPK's key-presence reconciliation misses. Material facts established this session: - mxcli widget code is IDENTICAL v0.16.0→HEAD (only Image fix + guard differ), so no mxcli upgrade fixes the reporter's CE0463. - All BUNDLED Data Widgets versions ([email protected], [email protected]/11.12) reconcile and pass; a marketplace-updated newer widget is what drifts. Corrects the prior "DataGrid2 is clean across all three versions" to "clean with the bundled Data Widgets" and confirms the deeper-augment fix is the reporter's actual bug, not a Gallery-only concern. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…E0463 drift) augmentFromMPK reconciled property-KEY presence (add/remove) and enum OPTION SETS, but not the rest of a matched PropertyType's definition. When a project's installed widget is updated past the embedded 11.6 template (e.g. Data Widgets 3.4.0 → 3.10.0 from the marketplace — the mendixlabs#600 case), the schema drifts WITHIN existing keys: - DefaultValue goes stale: reconcileEnumValues rebuilds Gallery pagingPosition's options to {below,above} but the default stays "bottom" — a value the installed widget no longer defines, so the PropertyType is inconsistent → CE0463. - Category drifts (General::Pagination → General::Items across 5 Gallery props). - Caption drifts. Add reconcilePropertyMetadata: for every PropertyType whose key the installed .mpk defines, overwrite Category, Caption, and ValueType.DefaultValue from the .mpk (only non-empty .mpk values, so a template value is never clobbered by a blank). The .mpk is authoritative for a freshly-created instance — this is what update-widgets does. Verified: after this pass, every [email protected] PropertyType matches update-widgets' output exactly (was: Category + pagingPosition DefaultValue drift). Existing widget tests green; DataGrid2 + Gallery still 0 errors on 11.12.0 (no regression). This is the likely complete fix for the mendixlabs#600 DataGrid2-with-updated-Data-Widgets case (that drift is PropertyType metadata). [email protected] additionally drifts in its datasource structure (Forms$GridSortBar.SortItems, CustomWidgetXPathSource. SourceVariable) — a separate codec-TypeDefaults axis, tracked in the proposal. modelsdk (default) engine only; the legacy sdk engine lacks even reconcileEnumValues. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…fixed Records the root-cause split from the key-indexed PropertyType diff: Axis 1 (within-key PropertyType metadata — Category/DefaultValue/Caption) fixed in 8b65f06 and verified to make every [email protected] PropertyType match update-widgets; Axis 2 (datasource structure — GridSortBar.SortItems / XPathSource.SourceVariable, a codec TypeDefaults gap) remaining. Notes Axis 1 alone likely closes the mendixlabs#600 DataGrid2 case, since DataGrid2 does not hit the datasource axis that Gallery does. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
… PropertyType order Two remaining axes of the object-list within-key drift (after the metadata fix 8b65f06), both needed to make [email protected] pass end-to-end without update-widgets: 1. Datasource structure (codec TypeDefaults, widget_write.go): a pluggable-widget XPath datasource always serializes SourceVariable as null when unbound, and its GridSortBar always emits an empty SortItems list (marker 2). An older embedded template omits both; a project whose installed widget expects them (Data Widgets updated past the 11.6 template) reports CE0463. Register the defaults for CustomWidgets$CustomWidgetXPathSource (NullFields: SourceVariable) and Forms$GridSortBar (MandatoryListMarkers: SortItems=2). 2. PropertyType order (augment.go): augment adds/removes/reconciles by KEY but kept the template's original order. When the installed widget reordered its properties across versions (Gallery 3.x moved pagingPosition ahead of showTotalCount), the emitted Type's PropertyType order != the installed widget -> CE0463. The WidgetType's PropertyType order IS checked (unlike the WidgetObject's Properties order, which Studio Pro tolerates). reorderPropertyTypes sorts the top-level PropertyTypes to the .mpk declaration order; Object<->Type refs are by $ID so reordering the Type list is safe. Verified end-to-end: [email protected] (previously CE0463) now 0 errors with NO update-widgets. Full regression clean — DataGrid2 (attribute + filter + custom-content) and Gallery both 0 errors on 10.24 / 11.10 / 11.12.0 / 11.12.1. Unit + executor + both widget-engine suites green. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…10.24 green Marks Axis 2 (datasource TypeDefaults + PropertyType order) fixed in 10b5bcf. [email protected] now passes mx check with 0 errors and no update-widgets; full regression clean across 10.24/11.10/11.12.0/11.12.1 for DataGrid2 and Gallery. Remaining: fold into widget-version-matrix.sh as a gate; mendixlabs#600 DataGrid2 end-to-end validation awaits a Data Widgets 3.10.0 project. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…ecessary but not sufficient End-to-end validation against the reporter's exact stack (marketplace Data Widgets 3.10.0 swapped into a Mendix 11.12.0 project): a DataGrid2 authored with the fixed binary STILL reports CE0463. Isolated from the Atlas template pages, the installed 3.10.0 schema differs from the 11.6-era template across far more than the three fixed axes reconcile — AllowUpload (79), ValueType.Type (15), Translations (14), DefaultValue (13), Required (7), EnumerationValues (7), AllowedTypes (4), and more. Corrects the earlier claim that Axis 1 alone would close mendixlabs#600: augment's key-presence + metadata/enum/order reconciliation scales to a MODERATE drift ([email protected], fully fixed) but not to a LARGE version jump (DataGrid2 11.6-era -> 3.10.0). The Phase-1 "56=56 for ComboBox" measurement held only because that was a small delta. Records the two paths to close the large-drift case, both now testable against real DW 3.10.0: (a) full-ValueType augment (overwrite the entire ValueType from the .mpk; recommended), or (b) per-version templates (fallback). Notes marketplace download now makes the version matrix a feasible standing gate. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…lope is mxbuild-only End-to-end reproduction of the mendixlabs#600 stack (DW 3.10.0 over bundled 3.4.0 in an 11.12.0 project, DataGrid2 authored with mxcli, isolated from the Atlas template pages) with an order-independent, ID-masked before/after-update-widgets subtree diff proves the parser/template/augment approach is structurally capped below large version jumps: - Nested-column PropertyKey sets are already identical before/after (augment adds every new 3.10.0 key correctly). - Residual drift is dominated by fields ABSENT from the widget XML source: AllowUpload (x105), DesignProperties, LabelTemplate, and a mxbuild-COMPUTED Required (XML declares 3 required="true"; mxbuild emits 54). - update-widgets on the same copy takes the grid CE0463 -> 0. Since these fields are not derivable from the .mpk, no augment (including the proposed full-ValueType path a) can reproduce a version-faithful WidgetType. A speculative reconcileValueTypeSchema was implemented and reverted (setting Required from the XML attr would mis-set the 51 computed keys to false). Revised path forward: delegate the envelope to mxbuild's own update-widgets made v2-safe (adopt mendixlabs PR mendixlabs#764), keep the moderate-drift augment as-is. Records the rejected approach inline in augment.go and updates the proposal Open Question #1. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…ly (mendixlabs#600) update-widgets is fully generic — it has no per-widget knowledge, so everything needed to reconcile a widget across a large version jump is derivable from the widget package plus the generic metamodel defaults. This reworks augment to do the same, closing the DEFINITION side of the [email protected] CE0463: the emitted CustomWidgetType is now byte-identical (canonically) to mxbuild's update-widgets output for the mendixlabs#600 reporter's exact stack (DW 3.10.0 on Mendix 11.12.0). Parser (mpk): - Required defaults to TRUE when the XML omits required= (Mendix pluggable-widget spec default; mxbuild emits Required=true for every property without the attr). Defaulting missing->false caused within-key drift on augment-added keys. - Parse <returnType type=.../> (expression props) and <translations> (shipped caption localizations). - Nested (object-list) child properties now inherit their propertyGroup caption chain as Category, matching how mxbuild derives nested categories. Augment: - reconcileValueTypesFromMPK: overwrite each matched PropertyType's ValueType scalars (Type, Required, DefaultValue, AllowedTypes, IsList, DataSourceProperty) from the .mpk; when a Type changes (wrong-typed exemplar clone), reset the matching Object WidgetValue so it stays schema-consistent; normalize the mutually-exclusive type-specific fields (EnumerationValues cleared on non-enum, ReturnType built only for Expression) so stale clone data cannot survive. - reconcilePropertyMetadata also reconciles Description. - completeValueTypeEnvelope emits the generic AllowUpload envelope default (mxbuild writes it on every ValueType; the 11.6-era template predates it). - reorderPropertyTypes now recurses into nested ObjectTypes. Verified end-to-end: definition diff vs update-widgets output = 0; no regression on bundled Data Widgets (3.4.0/3.0.0) across 11.12.0 / 11.10.0 / 10.24. Note the instance-side envelope (Forms$Appearance.DesignProperties, CustomWidget. LabelTemplate, Object-side translations) is not yet emitted; see follow-up. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…jected, editor-logic boundary Corrects the earlier (wrong) "only mxbuild can produce the envelope" conclusion: the WidgetType IS generically reproducible and is now byte-identical to update-widgets output (committed c7fe714). Records the instance-side investigation: - The residual CE0463 (definition matching) is textTemplate default-template instantiation in the WidgetObject. Even a minimal DataGrid2 reproduces it. - Which textTemplates get a default template is config-conditional applicability (aria labels always; clearSelectionButtonLabel/loadMoreButtonCaption/ singleSelectionColumnLabel only when their feature is active) — a distinction mxbuild derives from the widget's editor code, NOT the declarative XML (the null-vs-populated property defs are structurally identical). always-populate closes 9->3, Required-gate 3->9; neither matches because the rule isn't declarative. - The Object-from-definition rebuild was tried and REJECTED: it discards the byte-exact extracted template Object and regressed bundled DataGrid2 0->1 on both 11.12.0 and 10.24. Path forward for the instance last-mile: v2-safe update-widgets (mendixlabs#764) on top of mxcli's now-correct definition — the applicability logic lives in the widget's compiled editor code, which mxbuild executes and mxcli cannot. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…nce-default mechanism
Upgrades the instance last-mile finding from inference to confirmed, with the
concrete evidence: the widget .mpk ships Datagrid.editorConfig.js whose
getProperties() calls hidePropertyIn/hidePropertiesIn conditionally on the
instance's values. The verbatim hides for the three always-null properties are
present ("Multi"!==selection hides clearSelectionButtonLabel; "loadMore"!==
pagination hides loadMoreButtonCaption; singleSelectionColumnLabel conditional),
mapping 1:1 onto the measured null-vs-populated pattern. Always-populated props
(selectRowLabel, cancelExportLabel) appear 0x in editorConfig.js. A hidden
property does not get its default template instantiated — so the applicability
rule is imperative JS keyed on instance config, not declarative XML.
Adds path (d): execute editorConfig.js in-process via a Go JS engine (goja) as a
research spike for a no-mxbuild-dependency path; kept deferred behind the
recommended (c) v2-safe update-widgets (mendixlabs#764).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…d2 CE0463 (mendixlabs#574) Automates what the hand-transcribed widgetVisibilityRules table did for VideoPlayer/Timeline: a static extractor lifts a widget's compiled editorConfig.js property-hide logic (hidePropertyIn/hidePropertiesIn) into declarative WidgetVisibilityRules, which the builder's existing ApplyPropertyVisibility consumes to null the TextTemplate of properties the widget hides under the current config. This is the instance last-mile that the definition reconciliation (c7fe714) could not reach — the applicability logic lives in the widget's editor JS, not the declarative .mpk XML. Extractor (mdl/executor/editorconfig_extract.go): - Recognizes the dominant getProperties idioms: "V"===/!==ref && hide, ref && hide, ref || hide, ref ? hide : … — with scoped alias resolution (var r=e.selection) so minified single-letter identifiers don't leak across functions. - Skips object-list-nested hides and compound/ternary-nested guards (boundary check), degrading safely to "not hidden" rather than emitting a partial rule. - Reports coverage stats. On the real DW 3.10.0 Datagrid.editorConfig.js: 9/28 hide calls lifted (12 nested, 7 complex) — including the three that drive mendixlabs#600. Wiring: built-in widgets (DataGrid2/Gallery) skip .def.json generation, so rules are resolved on the fly from the project's installed .mpk editorConfig at build time (mpk.ReadEditorConfig + resolveWidgetVisibilityRules, cached), then applied. Object-side textTemplate defaults are populated with the .mpk's shipped caption translations (fixes CE4899 required-textTemplate) and the visibility pass nulls the hidden ones afterward. Result: minimal DataGrid2 on Mendix 11.12.0 + Data Widgets 3.10.0 (the mendixlabs#600 stack) → 0 errors (was CE0463). No regression on bundled Data Widgets across 11.12.0 / 11.10.0 / 10.24. Remaining: the full repro's nested textfilter widgets (separate widget type) still show 1 CE0463 — same mechanism, follow-up. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…ditions (mendixlabs#574) A WidgetVisibilityRule keyed on a Selection-typed property (DataGrid2 itemSelection = None/Single/Multi) was evaluated against the wrong WidgetValue field: currentPrimitiveValues read only PrimitiveValue, but a selection value lives in the `Selection` field. The condition therefore saw "" and mis-fired — e.g. singleSelectionColumnLabel was nulled even under Selection:Single, leaving 1 CE0463 on the full mendixlabs#600 repro (DataGrid2 with Selection:Single + column textfilters) while the minimal case passed. currentPrimitiveValues now reads the field appropriate to each property's ValueType (Selection→`Selection`, else `PrimitiveValue`). Result: the full DataGrid2 repro on Mendix 11.12.0 + Data Widgets 3.10.0 → 0 errors. Bundled DW (11.12.0 / 10.24) minimal+full still 0. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
mendixlabs#574) Piece 2 of the editorConfig visibility work. Generation (2a): GenerateDefJSON now lifts propertyVisibility from the widget's installed editorConfig.js (extractVisibilityRulesFromMPK) and writes it into the generated .def.json, superseding the hand-transcribed widgetVisibilityRules table for any widget whose editor config parses. Built-in widgets (DataGrid2/ Gallery) still resolve rules at build time from the installed .mpk. Check (2b): a new MDL-WIDGET10 warning fires when a property the user set on a pluggable widget is hidden under that widget's current configuration — the editorConfig suppresses it, so Studio Pro ignores the value. Rules come from the .def.json or are resolved on the fly from editorConfig for built-ins (registry now carries the project path). Conservative: only warns when the property is explicitly set AND the hiding condition's value is determinable from the MDL or a mapping default, so it never guesses. Config-aware end-to-end: DataGrid2 with Selection:None + ClearSelectionButtonLabel warns; Selection:Multi does not. No regression: DataGrid2 3.10.0 minimal+repro and bundled DW still 0 CE0463. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…LVED via editorConfig extractor Updates Open Question #1 to record the landed outcome (was still framing the instance last-mile as needing v2-safe update-widgets / a goja spike): - The static editorConfig.js extractor (4b8c4f5) + selection-value fix (666a65b) close the DataGrid2 CE0463 natively in mxcli — 0 errors on the mendixlabs#600 stack (11.12.0 + DW 3.10.0), minimal and full, no bundled regression. No mxbuild/ update-widgets dependency needed for DataGrid2. - Phase 2 (458c52a): extraction moved into .def.json generation; rules wired into check as the config-aware MDL-WIDGET10 warning. - Marks paths (c) update-widgets and (d) goja as superseded (c kept as fallback for widgets the static extractor can't fully lift); records coverage (9/28 DataGrid hide-calls) and the JS-AST / LLM-property-card follow-ups. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…lter build path (mendixlabs#574) The Data Widgets 3.10.0 package ships 9 widgets (DataGrid2, Gallery, DropdownSort, SelectionHelper, TreeNode/outline-tree, and 4 filters: Date/Dropdown/Number/Text), all with editorConfig.js. The extractor recognized DataGrid only; the rest use guard forms it skipped. Extractor generalization: - Strip ANY `<ident>.` namespace prefix (D./M./j./A.), not just `_.` — the minifier names it per widget. - Strip a leading `return` keyword (getProperties' first statement is `return <cond> && hide…`, minified `return"none"===…`). - Handle grouping parens `cond && ( hide, … )` for the first hide in a group. Coverage now (was 0 for everything but DataGrid): DataGrid 9/28, Gallery 5/13, TreeNode 4/7, DropdownFilter 5/13, DateFilter 3/5, Number/TextFilter 2-3, Selection Helper 1/2. Remaining skips are grouped-subsequent and compound guards (safely skipped, not mis-lifted); a real JS AST would lift those. Filter build path: BuildFilterWidget went through a separate path that never applied visibility, so a filter's hidden textTemplate stayed populated -> CE0463. Factored the nulling into widgetobj.ApplyVisibilityRules (engine-agnostic), added VisibilityRules to FilterWidgetSpec, and the executor now resolves+passes them. Result: DataGrid2 3.10.0 (minimal+repro) and bundled DW still 0; Text/Number/Date filters 0. The Dropdown filter still shows 1 CE0463 — a SEPARATE definition-drift issue (its nested filter-options ObjectType drifts ~30 Type/28 ObjectType fields from 3.10.0), i.e. the DataGrid-class definition reconciliation applied to the dropdown filter, not a visibility/extractor gap. Tracked as follow-up. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…Widgets + filter path Records the filter/multi-widget work (da30bab): the DW 3.10.0 package ships 9 widgets (DataGrid2, Gallery, DropdownSort, SelectionHelper, TreeNode, 4 filters), all with editorConfig; the extractor now handles all of them (coverage table) after generalising namespace/return/grouping-paren guard forms. Filter build path wired via widgetobj.ApplyVisibilityRules → Text/Number/Date filters at 0. Adds the open items: the Dropdown filter's separate ~1529-line definition drift (nested filter-options ObjectType — a definition-reconciliation follow-up, not a visibility gap), and TreeNode's dynamic-structure guards that need a JS AST. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…x into definition-drift follow-up (mendixlabs#574) Verified the pluggable-widget scripts in mdl-examples/ against mx check on fresh 11.12.0 projects: 8 of 9 report 0 CE0463 via the generic editorConfig visibility path. The 9th (112-combobox) is documented version drift — the embedded 2.5.0 template restructures ~3351 definition lines from the newer installed ComboBox — same class as the DropdownFilter ddf drift, now folded into the definition-reconciliation follow-up. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…endixlabs#112 CE0463 A ComboBox created on a fresh 11.12.x project raised CE0463 even though the project ships ComboBox 2.5.0 (the same version as mxcli's embedded template), so it was never a version jump. Two generic definition-drift causes the augment reconciliation didn't cover: 1. System-property order. ComboBox declares <systemProperty> Label/Visibility/ Editability inline mid-list (Editability group mixes a systemProperty ahead of a regular property). mxbuild emits the WidgetType PropertyTypes in that declared order and CE0463 checks it, but the .mpk parser split system properties into a separate list and reorderPropertyTypes pushed them to the end. DataGrid2/Gallery declare no inline system properties, so they were unaffected — which is why they passed and ComboBox didn't. The parser now preserves the full declared order (regular + system interleaved) via WidgetDefinition.AllTopLevel, built from a document-ordered custom UnmarshalXML on propertyGroup; reorderPropertyTypes ranks by it. 2. <returnType assignableTo="../staticAttribute"/>. ComboBox's staticDataSourceValue expression derives its return type from another property. The parser read only <returnType type=...> and emitted a null ReturnType where mxbuild emits WidgetReturnType{Type:None, AssignableTo}. Now parsed and emitted. Both fixes are generic (no ComboBox-specific code). After them the emitted CustomWidgetType is byte-identical (ID-masked) to mx update-widgets output for the mendixlabs#112 stack, and mx check reports 0 errors. No regression: DataGrid2/Gallery/filters (incl. DropdownFilter) stay at 0 CE0463 on 11.12.1. Adds mpk parser tests for the interleaved system-property order and the assignableTo return type. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…neric order + assignableTo fixes) Corrects the earlier '~3351-line large version jump' framing (an ID-unmasked diff artifact): ComboBox on a fresh 11.12.1 project ships 2.5.0 = the embedded template version, so no version jump. Masked drift was 243 lines from two generic causes (inline system-property order + returnType assignableTo), both now fixed; emitted WidgetType is byte-identical to update-widgets. DropdownFilter is also clean on bundled DW. Only the 3.10.0-marketplace nested object-list axis remains open. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…overed format Adds a CLI command that surfaces what mxcli knows about a pluggable widget: its expected properties (key, type, caption, category, required, default, enum options, nested object-list children) and its dynamic property rules (which properties the widget's editor hides under which configuration), lifted from the widget package's editorConfig.js. - Resolve by MDL keyword (COMBOBOX, DATAGRID2, GALLERY, …) or full widget id. - With -p, properties + rules come from the widget package installed in the project (widgets/*.mpk) — the version-accurate discovered format, including marketplace widgets mxcli has no built-in def for. Without -p, from the embedded template. - --format json for machine consumption; text output groups by category and marks system properties, showing the declared order (so e.g. ComboBox's Label/Visibility/ Editability appear at their real mid-list position). - Reports editorConfig extraction coverage (recognized / total hide-rules). Exports executor.WidgetVisibilityRules / ExtractWidgetVisibilityStats for the CLI. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
Adds docs-site guide 'Pluggable Widgets Across Versions' explaining how mxcli keeps widget definitions version-correct (embedded template + reconcile against the project .mpk + editorConfig dynamic rules, no update-widgets needed) and documents the `mxcli widget list` / `mxcli widget describe` inspection commands with text and JSON examples. Wires it into SUMMARY.md, cross-links the internals Widget Template System page, and notes the command in the CLAUDE.md feature table. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…gine routing DataGrid2 page-building is already fully on the generic pluggable engine (columns as an ObjectListMapping, per-column filters as item slots) — buildDataGridV3 was removed in the v0.12.0 consolidation. Correct the comments that still implied a hand-coded DataGrid builder: - cmd_pages_builder_v3.go: DATAGRID has no switch case; it falls through to the registry + buildPluggable (generic engine), not a hand-coded builder. - 189-datagrid2-column-textfilter.mdl: describe the actual filter-slot routing (generic engine ItemSlots on page build; buildColumnSpecFromAST/BuildFilterWidget on the ALTER PAGE path), not the removed buildDataGridV3. Add an 'Object-Lists and DataGrid2 Columns' section to the Pluggable Widget Engine internals page and note that the only remaining hand-coded DataGrid2 path is ALTER PAGE column insert/replace (a tracked follow-up). No functional change. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
Badge `value`, TreeNode `headerCaption`, and Timeline `title`/`description`/`timeIndication` (all textTemplate properties) were silently dropped by the page writer (MDL-WIDGET01): GenerateDefJSON emitted a texttemplate PropertyMapping only when a friendly MDL alias was hand-registered (PieChart/HeatMap only), so every other top-level textTemplate had no mapping and its caption was discarded. Emit a texttemplate mapping for every top-level textTemplate property, keyed by its own name so it's authorable as `value:`/`title:`/`headerCaption:`. The engine now skips the texttemplate write when the value is unset, so emitting the mapping never nulls a widget's default caption — it only enables authoring. Registered aliases (PieChart seriesName) are still carried. Bump WidgetDefGeneratorVersion 10->11 so existing projects regenerate their defs. Verified on Mendix 11.12.1: Badge/TreeNode/Timeline captions persist, no MDL-WIDGET01, mx check 0 errors, MPR v2 preserved. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
A pluggable widget child slot authored as `container <slotName> { ... }`
(e.g. TreeNode `container children`, Timeline `container customTitle`) was
silently dropped: applyChildSlots matched a child block to a slot by the child's
Type ("container") against the slot keyword, so it never matched the slot named
after the container and fell through to the discarded default widgets. Only the
bare-keyword form (`children { ... }`) matched.
Route a `container <slotName>` to the slot whose keyword matches the container's
NAME (mirroring the object-list item-slot matcher); the bare-keyword form still
matches by Type. Verified: TreeNode `children` slot content persists, mx check
0 errors, MPR v2 preserved.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…rules The editorConfig visibility extractor skips compound/ternary guards (e.g. Timeline's `customVisualization ? hidePropertiesIn([title,description, timeIndication])`), and RefreshWidgetDefinitions overwrote the hand-authored fallback table with the (incomplete) extracted rules. So Timeline title/ description/timeIndication lost their visibility rules and their hidden textTemplates were emitted as empty ClientTemplates instead of null → CE0463 on custom-visualization timelines. Merge instead of overwrite: extracted rules win on conflict (version-specific), hand-authored rules fill the keys the extractor misses. Bump generator version 11->12 to regenerate existing defs. Verified: Timeline customVisualization=true now nulls the hidden captions (mx check 0 errors), and customVisualization=false still keeps them visible. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…E0463 in v2 Charts (Pie/Column/Line/Bar/Area) have no embedded template, so they are built by GenerateFromMPK. That path drifted from mxbuild's WidgetType in three ways, all checked by CE0463, so every chart instance failed mx check in an MPR v2 project (only mx update-widgets cleared it, downgrading v2->v1): 1. It omitted the widget's declared <systemProperty> entries (Name, TabIndex, Visibility). Now emitted in their declared document position as System-typed PropertyTypes (via the .mpk's AllTopLevel order), with no Object WidgetProperty. 2. It left each ValueType's schema-derived fields empty (enum option sets, expression returnType, selectionTypes, multiline). GenerateFromMPK now runs the same .mpk reconciliation augment applies to template-based widgets. 3. The .mpk parser read helpUrl/studioCategory as XML attributes; Mendix declares them as elements. Also parse the multiline attr and <selectionType> elements. Result: the emitted WidgetType is byte-identical to update-widgets output for Pie/Column/Line/Bar/Area on Mendix 11.12.1 — 0 CE0463, MPR v2 preserved. No regression on template-based widgets (ComboBox, DataGrid2) or the reconcile path. Known remaining: TimeSeries has a nested-series textTemplate that serializes as an empty ClientTemplate instead of null (object-side, same class as the Timeline visibility nulling but nested in an object-list item) — separate follow-up. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
A datasource constrained two associations away with the natural shorthand database from Travel.Activity where [Travel.Day_Activity/Travel.Trip_Day = $Trip] failed with CE1613 'The selected entity Travel.Trip_Day no longer exists': Mendix XPath requires the intermediate entity between two association hops (Assoc1/Entity/Assoc2), and mxcli stored the shorthand verbatim so mxbuild read the second association as an entity. buildDataSourceV3 now expands consecutive association segments, inserting the intermediate entity resolved from each association's target (resolveAssociationDestination). Safe by construction: only runs of slash-joined qualified names anchored at an association from the datasource entity are touched, and an entity is inserted only between two segments that both resolve as associations — so the already-correct full form, single-hop constraints, and attribute paths are returned verbatim. Verified against the reporter's Travel schema: the two-hop Timeline datasource resolves, mx check 0 errors. Known related (separate): attribute-over-association shorthand ([Assoc/Attribute = x], needs [Assoc/Entity/Attribute = x]) is not yet expanded. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…erColor) A TimeSeries/LineChart with a default 'line' series tripped CE0463: the series' markerColor textTemplate was serialized as an empty Forms$ClientTemplate, but Studio Pro stores it as null when the property is hidden. chartSeriesTextTemplateVisible honored only the dataSet (static/dynamic) gate and missed the item-level editorConfig gates — markerColor is hidden unless lineStyle == 'lineWithMarkers' (default 'line'), and fillColor unless enableFillArea is truthy (default true). Add chartSeriesTextTemplateHiddenByItemConfig, mirroring the widget's hideNestedPropertiesIn rules, so a hidden series textTemplate serializes as null rather than an empty ClientTemplate. Verified: default TimeSeries line -> 0 errors, lineStyle 'lineWithMarkers' keeps markerColor visible, full chart example (all types) 0 errors. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…time JSON.parse)
A ColumnChart with a static series passed mx check but failed to render with a
client-side JSON.parse('Unexpected end of JSON input'). The object-list-item
builder emitted an unset String property as a single space " " instead of "".
The chart client feeds customSeriesOptions / customLayout / customConfigurations
to JSON.parse behind an empty-guard (value !== "" ? value : "{}"); a lone
space passes that guard, so the client runs JSON.parse(" ") and throws. mx check
doesn't execute the client, so it stayed green. A Pie (widget-level datasource,
no series object-list) was unaffected — the top-level String path already emitted
"".
Leave an unset String empty, matching Studio Pro and the top-level path, so the
client's empty-guard turns it into "{}". Verified: series customSeriesOptions is
now "" (was " "), zero space-valued primitives; mx check 0 errors and no
CE0463 regression across charts / DataGrid2 / Gallery.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…er's children
ALTER PAGE could only INSERT BEFORE/AFTER a sibling widget, so there was no way to
fill an EMPTY container or add a widget to a container/dataview without an existing
sibling to anchor to. Add:
alter page Mod.Page { insert into containerName { <widgets> } }
which appends the widgets as the last children of the named container. Full-stack:
grammar (INSERT INTO), visitor (Position "INTO"), executor (children take the
target's own entity context, e.g. a dataview's entity), and both mutators
(pagemutator for MPR files, MCP for live Studio Pro). An empty container omits its
Widgets list, so it is created with the Mendix widget-list marker and written back
into the parent (the bson.D grows). Simple containers are supported (DivContainer,
Container, DataView, GroupBox, ScrollContainerRegion, Section); LayoutGrid and
TabContainer have no single child list and give a clear error pointing to
INSERT BEFORE/AFTER inside the target column/tab.
Verified on 11.12.1: insert into an empty container, append to a non-empty one, and
insert a data-bound widget into a dataview — mx check 0 errors. Unit test for the
mutator INTO path + error case; doctype example; skill / quick-reference / syntax
help updated.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
…iation The `test-integration` suite (TestMxCheck_DoctypeScripts) started failing once the multi-version pluggable-widget reconciliation landed. Two showcase scripts regressed — both because reconciliation stopped masking genuine widget incompleteness, not because of a defect in the generated BSON: 32-pluggable-widget-object-lists-v010.mdl (modelsdk): the OL09 HeatMap only set its SCALECOLOR entries and never bound a data series, so mx check reported CE0642 "Property 'Series'/'Value attribute' is required". Reconciling the HeatMap definition to the installed .mpk correctly marks those required (the old embedded template understated it). Complete the example with the widget-level DataSource / HorizontalAxisAttribute / VerticalAxisAttribute / ValueAttribute binding, mirroring the passing HeatMap in 34-chart-widget-examples.mdl — the object-list showcase now demonstrates a complete, deployable heat map. 17-custom-widget-examples.mdl (both engines): the IMAGE showcases author bare/default static-image-mode Image widgets to demonstrate the IMAGE keyword's basic/dimensions/onclick syntax. MDL exposes no property to bind a static image resource (only imageUrl mode), so a default Image is legitimately "No image selected." — exactly what a freshly-dropped Image shows in Studio Pro. It previously passed only because a stale Atlas_Core.Content.Mendix template default masked it; that default caused CE0463 and was removed in the Image CE0463 fix. Whitelist the message for this script via scriptKnownCEErrors (now documented to also accept a message substring where an error carries no CE code), matching the existing syntax-showcase-limitation pattern. Verified on Mendix 11.12.1: all three previously-failing subtests pass; mendixlabs#32 retains only the globally-tolerated Maps CE0463. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
govulncheck (the vuln-scan step in Build, Test & Lint) flags GO-2026-5970, "Infinite loop on invalid input" in golang.org/x/text, reachable via catalog.Catalog.Query → sql.Rows.Columns → norm.Form and mpr.OpenWithOptions → sql.Open → norm.Form. The advisory is fixed in golang.org/x/text v0.39.0; bump the (indirect) requirement to it. go mod tidy also nudges the transitive golang.org/x/sync v0.20.0 → v0.21.0. Build is clean. This gate lives in the same CI job as the doctype integration tests, so it only surfaced once those passed; the fix greens the job and, once merged, main. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
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.
Summary
This bundles six merged PRs from ako/mxcli into upstream. Together they make pluggable-widget generation version-correct without mx update-widgets, add a Docker-free warm dev loop, extend ALTER PAGE with INSERT INTO, and close a batch of widget-authoring gaps found while authoring real marketplace widgets against MPR v2 projects.
Every change was verified on Mendix 11.12.1 with mx check (0 errors, MPR v2 preserved), and the widget fixes each ship a runnable repro under mdl-examples/bug-tests/.
What’s included
A Docker-free, ~1s edit→test loop for Mendix apps plus the provisioning that makes a fresh/reaped web session testable.
• Long-lived mxbuild --serve (warm ~1s builds vs ~30–60s one-shot), restartRequired-driven hot reload_model vs restart+DDL.
• Standalone JVM runtime boot (no Docker), web-client rollup bundling (the serve Deploy target skips web/dist), --watch incremental bundler, Playwright screenshots (deep-link + authenticated).
• --ensure-db provisions local Postgres + app DB; --setup non-blocking bring-up wired into a Claude Code SessionStart hook by mxcli init; empty-repo bootstrap prompt.
Makes pluggable-widget generation version-correct across Mendix versions with no per-widget hardcoding and no dependency on mx update-widgets.
• Definition-side reconciliation against the installed .mpk (per-ValueType scalars, enum option sets, per-property metadata, AllowUpload envelope), full declared PropertyType ordering including inline system properties.
• editorConfig.js static extractor lifts getProperties visibility idioms into declarative rules so config-hidden textTemplate defaults are nulled exactly as Studio Pro does.
• DataGrid2 @ Data Widgets 3.10.0 / Mendix 11.12 and ComboBox reach byte-identical definitions vs update-widgets → 0 CE0463.
• New mxcli widget describe inspects a widget’s discovered format (properties, types, enums, dynamic visibility rules); --format json.
• textTemplate content persisted for generated-def widgets (Badge value, TreeNode headerCaption, Timeline title/description/timeIndication were silently dropped).
• Container-wrapped child slots routed by name (container children { … }, container customTitle { … }).
• Visibility fallback merged, not overwritten (extracted wins, hand-authored fallback fills gaps).
• Generated-widget definitions reconciled — Charts (no embedded template) now emit declared system props in order + run the same .mpk reconciliation; Pie/Column/Line/Bar/Area build byte-identical to update-widgets, no v2→v1 downgrade.
• Multi-hop association XPath expanded to include the intermediate entity (Assoc1/Entity/Assoc2) → avoids CE1613.
• Hidden chart-series textTemplates nulled (TimeSeries markerColor/fillColor honor item-level editorConfig gates).
Unset chart-series String properties were emitted as a single space " " instead of "". The chart client feeds customSeriesOptions/customLayout/customConfigurations to JSON.parse behind a value !== "" ? value : "{}" guard; a lone space slips the guard and throws JSON.parse(" "). Now emits "" (schema default), matching Studio Pro. Passed mx check before but failed at runtime.
ALTER PAGE … { insert into { … } } appends widgets as a container’s children — the only way to fill an empty container or add a child without an existing sibling to anchor to.
• Full-stack: grammar → AST/visitor (Position = "INTO") → executor (children take the target’s own entity context, e.g. a dataview’s entity) → both the MPR-file pagemutator and live-Studio-Pro mcp mutator.
• Empty containers omit the Widgets list, so it’s created with the Mendix widget-list marker and the grown bson.D written back into its parent.
• Scope: simple containers (DivContainer, Container, DataView, GroupBox, ScrollContainerRegion, Section). LayoutGrid/TabContainer return a clear error pointing to INSERT BEFORE/AFTER.
Testing
• go build ./... clean; go test ./... green except cmd/mxcli/docker TestServeIntegration, a live-mxbuild serve integration test that fails identically on the base branch (stale local fixture: test project v11.6.3 vs cached mxbuild v11.12.1), unrelated to and untouched by these changes.
• Each widget fix verified on a fresh Mendix 11.12.1 project via mx check (0 errors, mprcontents/ intact); charts and the XPath fix reproduced from real project scripts.
• Repro scripts under mdl-examples/bug-tests/; doctype example for INSERT INTO; unit tests for mpk declared-order parsing, the editorConfig extractor, and the mutator INTO path.
• Docs: docs-site pages, MDL_QUICK_REFERENCE.md, alter-page skill, and mxcli syntax help (page + snippet) updated.
Notes
• No sdk/mpr write imports added to the executor; new mutation goes through the backend abstraction.
• Generated ANTLR parser files are not committed (regenerated by make).
🤖 Generated with Claude Code