|
| 1 | +# Learned entries from a legacy-widget rebuild: File Uploader image mode, native-mapped keywords, tab pages, XPath comparands, multi-hop data sources |
| 2 | + |
| 3 | +**From:** a field project (anonymised) |
| 4 | +**Date:** 2026-10-13 |
| 5 | +**Kind:** learning |
| 6 | +**Field evidence:** each entry below was hit while restating 34 pages of an existing app, through |
| 7 | +`bin/exec.sh` (mxbuild delta gate) on mxcli v0.25.0, Mendix 11.14.0 Beta, Classic (Dojo) client, |
| 8 | +toolkit c1efcb3. Error texts are verbatim; module/entity names are genericised. |
| 9 | +**Proposed target:** per entry below (`skills/learned-file-upload-widget.md`, |
| 10 | +`skills/learned-mdl-cannot-express.md`, `skills/learned-page-patterns.md`, `bug-logs/mxcli-bugs.md`) |
| 11 | + |
| 12 | +--- |
| 13 | + |
| 14 | +## 1. File Uploader: image mode fails the build; files mode against a `System.Image` subtype works |
| 15 | + |
| 16 | +Target: `skills/learned-file-upload-widget.md` §7 ("Image mode … was not tested"). |
| 17 | +Status: files mode is ALREADY covered there (PR #139); this adds image mode and the image-preview pattern. |
| 18 | + |
| 19 | +```sql |
| 20 | +fileuploader upPictures ( |
| 21 | + uploadMode: 'images', |
| 22 | + associatedImages: association $currentObject/MyModule.Picture_Asset, |
| 23 | + readOnlyMode: true, |
| 24 | + enableCustomButtons: false |
| 25 | +) |
| 26 | +``` |
| 27 | + |
| 28 | +`mxcli check` passed. mxbuild: `CE0463 The definition of this widget has changed.` on |
| 29 | +`File uploader upPictures`; the gate rolled back (rollback verified by DESCRIBE). The same widget with |
| 30 | +`uploadMode: 'files'` builds clean (finding). |
| 31 | + |
| 32 | +What built clean instead (finding, mxbuild 0 errors): uploads in **files** mode against an entity that |
| 33 | +extends `System.Image` (which extends `FileDocument`), with a separate `dynamicimage` preview beside it; |
| 34 | +read-only picture lists as a `listview` whose template holds a `dynamicimage`. |
| 35 | + |
| 36 | +Also stale: `skills/learned-mdl-cannot-express.md` row 1 still says "A file upload control — nothing … |
| 37 | +⛔ not buildable", which contradicts `learned-file-upload-widget.md`. Suggest pointing that row at the |
| 38 | +File Uploader skill. |
| 39 | + |
| 40 | +Related (finding): the installed FileDropper widget's definition lists `dataFileEntity` and |
| 41 | +`dataContextAssociation` as known properties with no mapping; `check` accepts them, exec does not write |
| 42 | +them, and mxbuild then fails. Upstream ask: refuse unmapped definition properties with MDL-WIDGET07. |
| 43 | + |
| 44 | +## 2. `radiobuttons` and `image` can resolve to NATIVE mobile widgets on a web page |
| 45 | + |
| 46 | +Target: `skills/learned-page-patterns.md` (or the widgets section of `learned-mdl-cannot-express.md`). |
| 47 | +Status: NEW (no toolkit mention). |
| 48 | + |
| 49 | +In this project `DESCRIBE WIDGET TYPE radiobuttons` resolves to `com.mendix.widget.native.radiobuttons`, |
| 50 | +and `check` warns MDL-WIDGET10 that the label is dropped. The project's `image.def.json` maps `image` to |
| 51 | +`com.mendix.widget.native.image.Image`; a probe wrote `image` with no properties. DESCRIBE prints existing |
| 52 | +**web** radio groups with the same `radiobuttons` keyword, so re-running DESCRIBE output writes a native |
| 53 | +widget into a web page (finding for the resolution and the warning; the radiobuttons case was not taken |
| 54 | +through mxbuild). |
| 55 | + |
| 56 | +Rule used: Boolean → `checkbox`, enumeration → `combobox`, images → `dynamicimage`. Before relying on a |
| 57 | +keyword in an existing app, run `DESCRIBE WIDGET TYPE <keyword>` and check the id is a `web` widget. |
| 58 | + |
| 59 | +## 3. Tab pages: `CaptionParams` and `Visible:` pass every gate and are not written |
| 60 | + |
| 61 | +Target: `bug-logs/mxcli-bugs.md` as `## BUG-DRAFT-tabpage-captionparams-visible-dropped:`, plus a row in |
| 62 | +`learned-mdl-cannot-express.md` next to the existing "count badge on a tab" row. |
| 63 | +Status: NEW. (The existing row covers `Badge:`, which `check` refuses; these two are accepted.) |
| 64 | + |
| 65 | +```sql |
| 66 | +tabpage tpDue (Caption: 'Due today or earlier · {1}', CaptionParams: ({1} = DueCount)) { … } |
| 67 | +tabpage tpOther (Caption: 'Unassigned · {1}', Visible: $currentObject/ShowOtherTab) { … } |
| 68 | +``` |
| 69 | + |
| 70 | +`check`, exec and mxbuild all passed, with no MDL-WIDGET07. The stored caption is literal text (the tab |
| 71 | +reads `· {1}`), and the tab page has no visibility setting: `ShowOtherTab` occurs 0 times in the unit. |
| 72 | +Found by a BSON read-back after exec (finding). |
| 73 | + |
| 74 | +Rule: no dynamic captions and no visibility on tab pages; put the count in a line inside the tab, and |
| 75 | +put anything conditional in a container with `Visible:` (container visibility is written correctly). |
| 76 | + |
| 77 | +## 4. DESCRIBE omits module-role visibility and layout-grid row visibility |
| 78 | + |
| 79 | +Target and detail: see the inbox note "Durable rebuild of legacy-widget pages" (same date). Listed |
| 80 | +here so triage sees it among the learned entries. Status: PARTLY (role visibility is known to be |
| 81 | +unwritable; that DESCRIBE also hides it is not recorded). |
| 82 | + |
| 83 | +## 5. Page XPath with a `$currentObject/<association>` comparand → CE0161 (BUG-39 on widgets) |
| 84 | + |
| 85 | +Target: `bug-logs/mxcli-bugs.md` BUG-39 (add a confirmation), `learned-page-patterns.md`. |
| 86 | +Status: PARTLY. BUG-39 records it for microflow retrieves only. |
| 87 | + |
| 88 | +```sql |
| 89 | +combobox cbLevel2 ( |
| 90 | + Attribute: Helper_Level2, |
| 91 | + DataSource: database from "MyModule"."Level2" |
| 92 | + where [MyModule.Level2_Level1 = $currentObject/MyModule.Helper_Level1] |
| 93 | +) |
| 94 | +``` |
| 95 | + |
| 96 | +`check --references` passed; mxbuild: 3 × `CE0161 Error(s) in XPath constraint`, one per cascading combo |
| 97 | +box; rolled back (finding). Studio Pro accepts the same constraint. |
| 98 | + |
| 99 | +Workaround that built: each combo box takes its options from a microflow data source that retrieves the |
| 100 | +parent into a variable and filters on it. |
| 101 | + |
| 102 | +## 6. Two-hop association data source: neither path form is writable → use a microflow data source |
| 103 | + |
| 104 | +Target: `learned-page-patterns.md` (next to the BUG-04 multi-hop ContentParams section), and |
| 105 | +`bug-logs/mxcli-bugs.md` as `## BUG-DRAFT-two-hop-datasource-path:`. |
| 106 | +Status: NEW. BUG-20 (cross-module traversal writing a null `DestinationEntityId`) was fixed in v0.17.0; |
| 107 | +this is a same-module, two-hop path on v0.25.0. |
| 108 | + |
| 109 | +Short form, exactly as DESCRIBE prints it: |
| 110 | + |
| 111 | +```sql |
| 112 | +DataSource: $Parent/MyModule.A_B/MyModule.B_C |
| 113 | +``` |
| 114 | + |
| 115 | +mxcli stored the last segment as an entity: |
| 116 | +`CE1613 The selected entity 'MyModule.B_C' no longer exists.` (5 errors); rolled back. |
| 117 | + |
| 118 | +Full form: |
| 119 | + |
| 120 | +```sql |
| 121 | +DataSource: $Parent/MyModule.A_B/MyModule.B/MyModule.B_C/MyModule.C |
| 122 | +``` |
| 123 | + |
| 124 | +`check` passed; the mxbuild loader crashed: |
| 125 | +`An error occurred when trying to set the 'DestinationEntity' property of a Entity ref step in a Page.` |
| 126 | +(This crash is what exposed the exec.sh gap in the separate inbox note.) |
| 127 | + |
| 128 | +So DESCRIBE output containing such a path is not re-executable. Rule: no multi-hop association path as a |
| 129 | +data-view source; use a microflow data source that retrieves over each association in turn (built clean). |
| 130 | + |
| 131 | +## Not included here |
| 132 | + |
| 133 | +Other cases from the same run (Data grid 2 custom-content column losing its Attribute; XPath through a |
| 134 | +reverse association needing read access mxbuild does not check; names `check --references` does not |
| 135 | +validate) are upstream mxcli material and are left for a separate note. |
0 commit comments