Skip to content

fix(alter-page): refuse widgets at a DataGrid2 column target, see into a customContent cell - #195

Merged
ako merged 3 commits into
mainfrom
claude/mxcli-unit-test-perf-n7ggx8
Aug 20, 2026
Merged

fix(alter-page): refuse widgets at a DataGrid2 column target, see into a customContent cell#195
ako merged 3 commits into
mainfrom
claude/mxcli-unit-test-perf-n7ggx8

Conversation

@ako

@ako ako commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Fixes the two defects reported as mendixlabs#935. Verified on Mendix 10.24.20.105674 (the reported version) and 11.13.0.

1. A dotted column target still corrupted the page (the crash)

mendixlabs#891 fixed the bare form — insert after NextRunAt { … } — by refusing it and pointing authors at grid.NextRunAt. That form skips the guard entirely, because the target is legitimate. What is wrong is the pairing: the executor routes an all-column body to InsertColumns/ReplaceColumn, and anything else fell through to the generic widget path and was serialized into the grid's column list. So the fix for mendixlabs#891 named the route to the same unloadable document:

alter page Sample.Order_Overview {
  insert after grid1.OrderNo { container ctnStray { dynamictext txtStray (content: '!') } }
};
ERROR: System.InvalidCastException: Unable to cast object of type
'…LayoutWidgets.DivContainers.DivContainer' to type '…CustomWidgets.WidgetObject'

mx check aborts on load, before reaching a single check. Refusing at the pairing covers INSERT (before/after/into) and REPLACE at once. The column is resolved first, so a mistyped name still reports not-found with the available names rather than the refusal.

Measured on 10.24: Altered page then a load abort, before. Refused, and the project still checks at 0 errors, after.

2. A widget inside a customContent cell bound nothing

The entity-context walk descended into a pluggable widget's own widget properties but not into an object-list item's — a DataGrid2 column keeps its cell widgets one level deeper, at Objects[].Properties[content].Value.Widgets. That is the descent findInWidgetChildren gained in mendixlabs#834; this second walk never learned it.

That is what makes it bite: mendixlabs#834 made those widgets addressable, so targeting the container by its own name is the recommended way to edit a cell — and it built every binding with an empty entity context. An association-navigating ContentParams path then could not resolve into AttributeRef + EntityRef steps and was stored as the attribute name:

mx check:      [CE1613] "The selected attribute
               'Sample.Order_Customer/Sample.Customer_Country/CountryName' no longer exists."
describe page: ContentParams: [{1} = Customer_Country/CountryName]   -- first hop silently gone

CREATE PAGE got the identical page right, which is what made this read as a storage bug rather than a context bug.

The walk also never read a pluggable widget's datasource at all, so the grid's own entity was invisible even one level up. Both readers now share entityFromEntityRef, which also gives the pluggable one the IndirectEntityRef (association) case the plain one already had.

The descent is keyed on the BSON shape, not on the columns property key, so Accordion groups and PopupMenu items are covered by the same code rather than tying the walk to one widget.

Measured on 10.24: CE1613 before, 0 errors after, with the two-hop path round-tripping through describe.

On the issue's repro

The steps as written do not reproduce — the crash needs a non-column body. The bare-name variant does crash on a build from the reported nightly (2026-07-20) and is refused today, so if that is what was actually run, mendixlabs#891 had already fixed it. Both live defects above are reproduced from a clean project and fixed here.

Controls

  • Fix 2 is guarded by five unit tests that fail with the reported "" before the fix, including a false-positive control: a nearer DataView must still shadow the grid, and a widget outside every bound container must still report no entity.
  • Fix 1's unit test is deliberately not claimed as its own control — reverting the guard makes it nil-deref in the fixture rather than reproduce the symptom. The honest control there is the CLI plus mx check against a real 10.24 project, which is what was measured.
  • Existing mdl-examples/doctype-tests/33-alter-page-examples.mdl uses dotted targets throughout with column … bodies and is unaffected (re-run against a real project).

Changes

  • mdl/backend/pagemutator/mutator.gorefuseWidgetsAtColumnTarget wired into InsertWidget/ReplaceWidget; object-list descent in findEntityContextInChildren; new widgetOwnEntity and shared entityFromEntityRef
  • mdl/backend/pagemutator/mutator_entity_context_test.go (new) — five tests for the entity walk
  • mdl/backend/pagemutator/mutator_column_addressing_test.go — three tests for the new guard, driven through the exported methods so deleting a call site fails
  • mdl-examples/bug-tests/935-alter-page-widgets-at-column-target.mdl, 935-customcontent-column-entity-context.mdl (new, the second re-runnable)
  • .claude/skills/fix-issue.md — symptom row appended

go test ./..., make lint-go and make check-mdl are green.

🤖 Generated with Claude Code

https://claude.ai/code/session_018hifgRSawfaRWXS44YKtSJ


Generated by Claude Code

claude and others added 3 commits August 19, 2026 23:04
…Content cell

Two defects reported as mendixlabs#935, both verified on Mendix
10.24.20.105674 (the reported version) and 11.13.0.

**1. A dotted column target still corrupted the page (the crash).**

mendixlabs#891 fixed the BARE form — `insert after NextRunAt { … }` — by refusing it
and pointing authors at `grid.NextRunAt`. That form skips the guard
entirely, because the target is legitimate. What is wrong is the pairing:
the executor routes an all-`column` body to InsertColumns/ReplaceColumn,
and anything else fell through to the generic widget path and was
serialized into the grid's COLUMN list. So the fix for mendixlabs#891 named the
route to the same unloadable document:

  System.InvalidCastException: Unable to cast object of type
  '…LayoutWidgets.DivContainers.DivContainer' to type
  '…CustomWidgets.WidgetObject'

mx check aborts on load, before reaching a single check. Refusing at the
pairing covers INSERT (before/after/into) and REPLACE at once. The column
is resolved first, so a mistyped name still reports not-found with the
available names rather than the refusal.

Measured: "Altered page" then a load abort, before. Refused, and the
project still checks at 0 errors, after.

**2. A widget inside a customContent cell bound nothing.**

The entity-context walk descended into a pluggable widget's own widget
properties but not into an object-list ITEM's — a DataGrid2 column keeps
its cell widgets one level deeper, at Objects[].Properties[content].Value
.Widgets. That is the descent findInWidgetChildren gained in mendixlabs#834; this
second walk never learned it, so ALTER PAGE could FIND those widgets (and
mendixlabs#834's fix made that the recommended way to edit a cell) while building
their bindings with an empty entity context.

An association-navigating ContentParams path then could not resolve into
AttributeRef + EntityRef steps and was stored as the attribute NAME:
CE1613 at build time, and a describe that silently dropped the first hop.
CREATE PAGE got the identical page right, which is what made this read as
a storage bug rather than a context bug.

The walk also never read a pluggable widget's datasource at all, so the
grid's own entity was invisible even one level up. Both readers now share
entityFromEntityRef, which also gives the pluggable one the
IndirectEntityRef (association) case the plain one already had.

The descent is keyed on the BSON shape, not on the "columns" property
key, so Accordion groups and PopupMenu items are covered by the same code.

Measured: CE1613 before, 0 errors after, with the two-hop path
round-tripping through describe.

Note on the controls: reverting fix 1 makes its unit test nil-deref in the
fixture rather than reproduce the symptom, so the honest control there is
the CLI plus mx check, run against a real 10.24 project. Fix 2's five
tests do fail with the reported "" before the fix, including a
false-positive control (a nearer DataView must still shadow the grid, and
a widget outside every bound container must still report no entity).

Repros: mdl-examples/bug-tests/935-alter-page-widgets-at-column-target.mdl
and 935-customcontent-column-entity-context.mdl.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018hifgRSawfaRWXS44YKtSJ
@ako
ako merged commit 57823ec into main Aug 20, 2026
7 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.

2 participants