You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(pages): ALTER PAGE can set conditional Visible/Editable expressions (Issue 627)
ALTER PAGE had the same conditional-visibility gap as CREATE: `SET Visible =
[Name != ''] ON ctn` parsed the `[...]` as a propertyValueV3 array, which the
mutator's Visible handler (string/bool only) silently ignored — reporting
"Altered page" while doing nothing.
- Grammar: targeted `VISIBLE/EDITABLE EQUALS xpathConstraint` alternatives on
alterPageAssignment (before the generic rule), so a bracketed RHS on Visible/
Editable is captured as an expression rather than an array. `Visible = false`
and other properties are unaffected.
- Visitor: buildAlterPageAssignment routes these to VisibleIf/EditableIf via the
shared buildConditionalExpression ($currentObject rooting, idempotent).
- Mutator: new VisibleIf/EditableIf cases in setRawWidgetPropertyMut build the
ConditionalVisibility/EditabilitySettings node (setWidgetConditionalSettingMut)
with Studio Pro's sub-field set, replacing the null slot. Editability on a
non-input widget is rejected with a clear error. Shared mutator → both engines.
Verified on 11.11.0: `mx check` = 0 errors on both engines for `SET Visible =
[Name != '']` and `SET Editable = [Active]`; expressions written as
`$currentObject/…`; DESCRIBE round-trips; misuse (Editable on a container) errors.
Tests: visitor (Visible/Editable rooting), mutator (node built / non-input
rejected). Bug-test extended with an ALTER section. Docs: alter-page skill,
fix-issue symptom-table row.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: .claude/skills/fix-issue.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -48,7 +48,7 @@ to the symptom table below, so the next similar issue costs fewer reads.
48
48
| CE0463 on a `datagrid` whose column uses `ColumnWidth: manual` + `Size: N` — Studio Pro resets the column `size` to `1`| The MDL `ColumnWidth:` keyword isn't mapped to the schema `width` enum, so `width` stays at its `autoFill` default; `size` only applies when `width=manual`, so the value is inconsistent. Regression from the Stream B keyword-path consolidation (the deleted `datagrid_builder.go` did `colPropString(col.Properties, "ColumnWidth", "autoFill")`) |`mdl/executor/widget_defs.go``itemPropertyAliases`| Add the MDL→schema alias under `[datagrid]["columns"]`: `"width": {"ColumnWidth"}`. Bump `WidgetDefGeneratorVersion` so stale `.def.json` regenerate. General rule when a column/object-list property's MDL keyword differs from the `.mpk` schema key (not just case), add it to `itemPropertyAliases`; cross-check against the pre-B3 `datagrid_builder.go``colProp*` calls for any other dropped mappings |
49
49
| Nightly `mx check` reports `CE0117 "Error(s) in expression." at Log message activity 'Log message (warning)'` on Mendix 10.24.19+ but not 10.24.16 or 11.x | Mendix 10.24.19 tightened expression validation: `toString(<string>)` is now a type error (toString expects a non-string input). An example called `toString($OrderNumber)` where `$OrderNumber` was already a string parameter | The offending `log warning ... with ({1} = toString($stringVar))` — find via `~/.mxcli/mxbuild/{ver}/modeler/mx check`, then bisect with `drop microflow ...` until CE0117 disappears | Remove the redundant `toString()` wrapper around already-string values. Only wrap non-string values (integers, decimals, dates, enums) in `toString()`. The Mendix 11.x parser is more lenient and lets this slide, but 10.24.19+ rejects it |
50
50
| A page-level property can't be set — `ALTER PAGE X { SET PopupWidth = 800; }` (or any page-level prop other than Title/Url) fails with `unsupported page-level property: …` | The page-level SET handler only special-cased a couple of properties; everything else fell through to the default error | `mdl/backend/pagemutator/mutator.go` → `applyPageLevelSetMut` (shared by both engines) | Add a `case` writing the field at the top level of the Forms$Page doc via `dSetOrAppend` with the on-disk BSON type (int64 for PopupWidth/PopupHeight, bool for PopupResizable — verify against a Studio Pro page with `mxcli bson dump --format bson`). Page-level prop names are **case-sensitive**. For DESCRIBE roundtrip, emit the values back in the CREATE PAGE header. CREATE-time support: add a generic `IDENTIFIER COLON propertyValueV3` to `pageHeaderPropertyV3` (regen grammar), recognize the keys in `parsePageHeaderV3` (`applyGenericPageHeaderProp`, error on unknown), carry `*int`/`*bool` on `CreatePageStmtV3`, default to 600/600/false in `buildPageV3`, and have both writers honour `page.Popup*` (legacy `sdk/mpr/writer_pages.go` int64; codec `mdl/backend/modelsdk/page_write.go` int32 via gen — tolerated by mx check). The MCP backend has its **own** `mcpPageMutator` (pg content tree, not raw BSON) — page-level SET there reaches `SetWidgetProperty("")`; map it or reject honestly (it rejects, pending a `pg_read_page` probe of the pop-up keys). Issue #661 |
51
-
| `Visible: [Attr != '']` / `Editable: […]` on a widget (CONTAINER, textbox, …) → CE0117 "Error(s) in expression." in Studio Pro on the legacy engine, and silently *ignored* on the modelsdk engine | Two bugs (NOT BSON structure): (1) the expression was emitted with a bare attribute reference (`Name != ''`) — a Mendix client expression must root attributes in the widget data context (`$currentObject/Name != ''`); (2) the modelsdk codec hardcoded `ConditionalVisibilitySettings` to null, dropping the expression entirely | `mdl/visitor/visitor_page_v3.go` → `buildConditionalExpression`/`conditionalExprToString`; `mdl/backend/modelsdk/widget_write.go` → `applyWidgetBase` + TypeDefaults | (1) For `VISIBLE`/`EDITABLE` xpath constraints, build the xpath AST and serialize via `conditionalExprToString`, which prefixes bare `IdentifierExpr` / non-variable-rooted `XPathPathExpr` with `$currentObject/` (leaves `$…`-rooted paths, literals, functions, enum qualified-names untouched). Do **not** apply this to datasource `where` clauses (those are real XPath). (2) In `applyWidgetBase`, type-assert `SetConditionalVisibilitySettings`/`SetConditionalEditabilitySettings` and emit a settings element when the model has one; register `Forms$ConditionalVisibilitySettings`/`…EditabilitySettings` TypeDefaults (`NullFields: Attribute,SourceVariable`; `MandatoryLists: Conditions[,ModuleRoles]`) so the null-when-unset slots stay null (the encoder only fills NullFields when not already emitted). Verify both engines with `mx check` = 0 errors. Issue #627 |
51
+
| `Visible: [Attr != '']` / `Editable: […]` on a widget (CONTAINER, textbox, …) → CE0117 "Error(s) in expression." in Studio Pro on the legacy engine, and silently *ignored* on the modelsdk engine | Two bugs (NOT BSON structure): (1) the expression was emitted with a bare attribute reference (`Name != ''`) — a Mendix client expression must root attributes in the widget data context (`$currentObject/Name != ''`); (2) the modelsdk codec hardcoded `ConditionalVisibilitySettings` to null, dropping the expression entirely | `mdl/visitor/visitor_page_v3.go` → `buildConditionalExpression`/`conditionalExprToString`; `mdl/backend/modelsdk/widget_write.go` → `applyWidgetBase` + TypeDefaults | (1) For `VISIBLE`/`EDITABLE` xpath constraints, build the xpath AST and serialize via `conditionalExprToString`, which prefixes bare `IdentifierExpr` / non-variable-rooted `XPathPathExpr` with `$currentObject/` (leaves `$…`-rooted paths, literals, functions, enum qualified-names untouched). Do **not** apply this to datasource `where` clauses (those are real XPath). (2) In `applyWidgetBase`, type-assert `SetConditionalVisibilitySettings`/`SetConditionalEditabilitySettings` and emit a settings element when the model has one; register `Forms$ConditionalVisibilitySettings`/`…EditabilitySettings` TypeDefaults (`NullFields: Attribute,SourceVariable`; `MandatoryLists: Conditions[,ModuleRoles]`) so the null-when-unset slots stay null (the encoder only fills NullFields when not already emitted). **ALTER PAGE** had the same gap (`SET Visible = [expr]` parsed as a `propertyValueV3` array and silently no-op'd): add `VISIBLE/EDITABLE EQUALS xpathConstraint` alternatives to `alterPageAssignment` (regen grammar), route to `VisibleIf`/`EditableIf` in `buildAlterPageAssignment` (reusing `buildConditionalExpression`), and add `VisibleIf`/`EditableIf` cases to `setRawWidgetPropertyMut` (`mdl/backend/pagemutator/mutator.go`) that build the settings node via `setWidgetConditionalSettingMut` (rejecting editability on non-input widgets). The shared mutator covers both engines. Verify both engines with `mx check` = 0 errors. Issue #627 |
52
52
| Mendix can't resolve the microflow named in `CREATE ODATA CLIENT (ConfigurationMicroflow: microflow X.Y)` / `ErrorHandlingMicroflow:` — error names the literal string `"MICROFLOW X.Y"` as the missing microflow | Case-mismatched prefix strip: visitor emits uppercase `"MICROFLOW "` from `odataValueText`, but `extractMicroflowRef` only trimmed lowercase `"microflow "`, so the keyword survived into BSON |`mdl/executor/cmd_odata.go` → `extractMicroflowRef`| Use a case-insensitive strip: `if strings.EqualFold(ref[:10], "microflow ") { return ref[10:] }`. Whenever a value goes from a visitor that emits a keyword-prefixed form to an executor that strips it, the strip must match the case the visitor produces — grep visitor files for `"MICROFLOW " +`/`"ENTITY " +`/etc. when adding a new property. Issue #573|
53
53
|`describe`/catalog reports a numeric BSON field (Length, MinOccurs, MaxOccurs, MaxLength, FractionDigits, TotalDigits, Interval, NumberOfPagesToClose, …) as `0` / `unlimited` even though Studio Pro shows a real value | BSON numeric width mismatch — Studio Pro writes the field as `int64`, but the parser asserted `raw["X"].(int32)` so the type assertion failed silently and the field defaulted to its zero value |`sdk/mpr/parser_*.go` — grep for the field name; the fix point is the narrow assertion | Replace narrow type assertions on BSON numeric fields with the existing `extractInt(raw["X"])` helper (`sdk/mpr/parser.go`). It handles int32/int64/int/float64. When a non-zero default must survive a missing field, gate with `if _, ok := raw["X"]; ok { … = extractInt(...) }`. Sweep `grep -n '\.(int32)' sdk/mpr/parser_*.go` and ignore matches whose comment says "marker" (BSON-array-prefix probes are intentional). Issues #583, #585|
54
54
| Studio Pro shows a dropdown / property as its default value even though MDL set it explicitly (e.g. CREATE ODATA CLIENT with `ConfigurationMicroflow:` set, but the "Configuration source" dropdown reads "Constants only") | The BSON key mxcli writes isn't what Studio Pro reads — either the key name is wrong, or multiple dropdown options actually share a single field discriminated by something other than the key name (return type of a referenced microflow, sibling property, etc.) | The `serializeXxx` function in `sdk/mpr/writer_*.go` for the affected document type | (1) Ask the user to duplicate the offending object in Studio Pro and **explicitly pick each dropdown option** on the duplicate(s). An unconfigured duplicate just looks like "Constants only" and tells you nothing about which field the option uses. (2) Re-dump the duplicates from `mprcontents/**/*.mxunit` **after every Studio Pro change** — cached `/tmp/svc-*.json` files go stale the instant the user edits the project (see [[feedback-refresh-bson-dumps]]). (3) Diff against mxcli's output to find the renamed key. (4) Don't assume one-state-per-key. The OData "Configuration microflow" / "Headers microflow" case stores BOTH options in the single `ConfigurationMicroflow` BSON field — Studio Pro picks the dropdown label from the referenced microflow's return type. When a discriminator like that exists, have both MDL keywords write to the same model field. Issues #573, #587 and 2026-05-27 unify-config-microflow fix |
> `Editable`) attach a per-object expression. Bare attributes are rooted in the
101
+
> widget data context automatically: `[Name != '']` becomes
102
+
> `$currentObject/Name != ''` (paths you write with `$currentObject/…`/`$Param/…`
103
+
> pass through). Setting `Editable` on a non-input widget is rejected. This mirrors
104
+
> CREATE PAGE's `visible: [...]` — see the create-page skill for enum-value rules.
105
+
99
106
**Pluggable widget properties** use quoted names to set values in the widget's `Object.Properties[]`. Boolean values are stored as `"yes"`/`"no"` in BSON.
100
107
101
108
**Column property names are case-insensitive** in MDL — `set caption = …` and `set Caption = …` both work. The internal BSON keys are dictated by the widget schema and stay case-sensitive on the storage side.
0 commit comments