fix(pages): four silent page changes — list view Editable, data view footer addressing, page-variable input binding, pluggable REPLACE passthrough - #917
Merged
Conversation
… reporting success with nothing stored (mendixlabs#1214) A list view / data view stores Editable as a boolean; the setter only wrote strings, so `set Editable = true on lvRows` returned nil. The stored value's type now decides the vocabulary (true/false vs Always/Never), the input enum is canonicalised, anything else is refused, and EditableIf writes the Conditional enum beside its settings element as CREATE does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…627) The fluent API's AttributeModifier.Apply() rebuilt the attribute with raw == nil and kept only its $ID, so the codec minted GUID = $ID - the mendixlabs#1119 data-loss class. The write guard refused it, leaving the API unusable on any Studio Pro-authored attribute. Carry the stored raw bytes and export level via carryStoredAttribute, now shared with the entity rewrite's carryAttributeIdentity. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…#528, mendixlabs#293) A data view's footer is a region: its widgets live in the data view's FooterWidgets and the footer has no stored Name, so the name a script wrote and describe's invented footer1 both named nothing ALTER could find. - ALTER PAGE: <dv>.footer resolves as a region; INSERT INTO appends, REPLACE swaps the whole content (a describe-style footer { } block is unwrapped), DROP empties it. A not-found names the footer addresses the page has. - REPLACE may reuse the names of the widgets it removes (the target's descendants), which was refused as a duplicate. - A name on a data view footer is MDL-DEPR005 (unstored widget name), like a layout grid row's; describe prints footer { } unnamed. The AST is identical, so writes do not change. Docs/examples/skills rewritten. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MoveEntity scanned only the plain associations of the source unit, so a cross-association created by an earlier move was invisible: moving its second endpoint left a ParentPointer naming an element absent from its unit and Studio Pro could not open the project. Handle the three shapes: convert back to a plain association when both endpoints share a module (raw transform, GUID carried), let an own cross-association travel with its FROM entity, and re-point a cross-association in another module. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…endixlabs#849) Studio Pro does not reload the model from disk, so a write mxcli makes while the project is open is silently discarded by Studio Pro's next save. The writer now refuses any write that would reach storage while Studio Pro's <project>.mpr.lock is beside the .mpr (matched without regard to case, as Studio Pro lower-cases it). Reads and writes elided as no-ops are never refused; exec --force or MXCLI_ALLOW_STUDIO_PRO_OPEN=1 override. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…its mappings and its commit option (#571) create published rest service wrote only the path's {name} placeholders as operation parameters, each a String: a query or body microflow parameter failed mx check with CE0350, an Integer {id} with CE6539. import mapping, export mapping and commit parsed and were thrown away. - Parameters are derived from the microflow as Studio Pro derives them (path name -> Path, object/list -> Body, HttpRequest/HttpResponse -> none, else Query), each with the microflow parameter's type, merged over the stored parameters so a header / renamed / described one survives. - Mappings and commit go AST -> model -> BSON and back; describe prints them and notes parameters MDL cannot state. An unknown commit option is refused by exec and check (MDL-REST03). - create or modify carries the restated operation's summary, documentation and object handling; the service rewrite carries the stored keys MDL cannot state (authentication, CORS, documentation). List markers as Studio Pro writes them. TestApp's Services.OrdersRestApi leaves the round-trip allowlist. Fixes mendixlabs#1206 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e binding (mendixlabs#1235) Studio Pro stores an input bound to a page variable as SourceVariable {LocalVariable} with no AttributeRef (measured over MCP on TestApp). MDL refused `Attribute: $ShowAll` (MDL-WIDGET34) and describe printed the widget unbound, so describe -> exec cut the binding silently. - builders map a bare `$name` naming a declared page variable to that SourceVariable; check validates it against the document's Variables; ALTER sees the stored variables - describe prints `Attribute: $name` for that shape - text box / text area bound to a variable get MaxLengthCode 0 (unlimited); -1 is mx check CE6553 Also wires ALTER REPLACE's stored-widget description (used by the next commit) through cmd_alter_page.go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he statement does not state (mendixlabs#1247) A pluggable widget is rebuilt from its template, so a REPLACE reset every property MDL has no word for. On TestApp's Studio Pro-authored Rules.BusinessRule_NewEdit, adding a sort to comboBox1 also turned its stored Editable Never into Always and an expression property's PrimitiveValue into 'false'; the reporter lost a translated placeholder and readOnlyStyle. For one pluggable widget replaced by one of the same package, the executor builds the stored widget as describe prints it beside the replacement; the mutator keeps the stored Type and every property/field the two builds agree on, and grafts the differing values with their TypePointers re-aimed at the stored Type by key path. Anything that cannot be lined up falls back to the plain replace. Running the same REPLACE twice writes nothing. Also: findings, mutator-addressing pattern page, alter-page skill. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- mendixlabs#591: list activities and cast carry the flow flavour's error handling (Abort in a nanoflow, where "Rollback" was CE6035); create, commit, call nanoflow and call microflow in a nanoflow accept only a handler without rollback (measured), refused otherwise; check now reports the nanoflow rules exec's build enforces (MDL091) and the annotation rules. - mendixlabs#698: the MCP mapper writes errorHandlingType and refuses a custom handler / error-handler flow PED cannot express. - mendixlabs#991: @anchor and @Curve inside an error handler are applied; describe emits the handler body's layout annotations. - mendixlabs#992: `@anchor(true: (to: top))` parsed as a division; the paren value now wins, unusable @anchor parameters are refused (MDL092), and `@curve(true: …)` is refused on nanoflows too. - mendixlabs#870: lock/unlock name their workflow; `pause all` / `unpause all` is Studio Pro's "(Un)pause instances"; bare `all` is refused (MDL-WF17); describe no longer turns a Studio Pro lock into `all`. - mendixlabs#175: `call workflow … on error continue` refused (MDL076), MDL076 exec-enforced. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s too (mendixlabs#1247) Restating TestApp's dataGrid2_1 with one column caption changed fell back to the template rebuild: the filter widgets nested in the columns value point into their own Type, which the graft could not re-aim, so itemSelectionMethod, onClickTrigger and every column's unmapped properties were reset. A nested pluggable widget is now grafted as built, and an object list that lines up with the baseline is merged object by object. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The hint told authors to declare `Variables: { … }`, the brace form
MDL-DEPR123 deprecates; it now writes `Variables: ( … )`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
Author
|
Independent review: pushed two commits.
Ran: make build, lint, check-conformance, go test ./cmd/mxcli, pagemutator + executor unit tests, make test-integration-roundtrip (pass), and the executor integration tests from the PR. On a TestApp copy edited by every scenario (Editable, footer insert/replace/drop, page-variable inputs of six kinds, DataGrid 2 caption change and column add), 🤖 Generated with Claude Code |
11 tasks done
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.
Four silent page changes. The rule behind all four: when a statement reports success, it must have written what it says, and describe must not drop anything that is stored.
Fixes mendixlabs#1214
Fixes mendixlabs#1235
Fixes mendixlabs#1247
Fixes mendixlabs#293
Closes #528
What changed (one commit per item)
mendixlabs#1214:
set Editable = true on <listview>. This printed "Altered page" and stored nothing. A list view or data view storesEditableas a boolean, but the setter only wrote strings, so the boolean fell through and the setter returned nil. Now the type of the stored value decides what the property accepts:true/falseAlways/Never, written in canonical case ('never'used to be stored as typed)Conditionalwithout an expression, a boolean on an input, andEditableon a widget that has none are all refused. These are new rejections. They replace a silent no-op, or a wrong write in the bare-Conditionalcase.set Editable = [expr]now also writes theConditionalenum next to its settings element, the same way CREATE does.#528 / #293: data view footer. A footer is a region of its data view. Its widgets are stored in the data view's
FooterWidgets, and the footer itself has no stored name. That is why the name the script wrote, and thefooter1that describe invented, both resolved to nothing.dvMain.footeris now an ALTER target, addressed the same way scroll-container regions are:ShowFooteron.footer { … }block is unwrapped.btnSaveused to fail with "duplicate widget name".footer { … }. The 66 gated doc, example and skill occurrences were rewritten, and the grammar's own doc example (replace footer1 with …) was corrected.mendixlabs#1235: input bound to a page variable. I measured the stored shape over the Studio Pro MCP tunnel on TestApp (
Pages.Probe1235_pagevar):sourceVariable {localVariable: "ShowAll"}, noattributeRef, andped_check_errorsclean.checkbox cb (Attribute: $ShowAll)now writes that shape when$ShowAllis a declared page variable.checkvalidates the name against the document'sVariables:(a name not declared there is still MDL-WIDGET34).Attribute: $ShowAll.MaxLengthCode0 (unlimited, Studio Pro's default for variables). -1 means "attribute length", which a variable doesn't have.mendixlabs#1247: REPLACE of a pluggable widget. This applies #830's passthrough principle per property.
Rules.BusinessRule_NewEdit, addingsort by Name asctocomboBox1used to change three things: the sort,Editable"Never" → "Always", and an expression property's PrimitiveValue "" → "false". Now only the sort changes.ADR-0011
ALTER PAGE … REPLACEon a pluggable Combobox silently resets properties the statement doesn't restate (placeholder translations, readOnlyStyle); describe and diff-local don't show the loss mendixlabs/mxcli#1247: fixes a silent wrong write, so the fix applies under both mdl 0 and mdl 1.Test plan (what I ran)
pagemutator: Editable (bool, enum, no property), footer region (resolve, insert, replace, drop, hint),mergeUnstatedPluggablemaxLengthCodeForEditable = false after set Editable = truewidget "dvMain" has no columnsdescribe binding = "", declared variable refused)ALTER PAGE … REPLACEon a pluggable Combobox silently resets properties the statement doesn't restate (placeholder translations, readOnlyStyle); describe and diff-local don't show the loss mendixlabs/mxcli#1247: merge disabled, roundtrip test fails withEditable = "Always"andPrimitiveValue: -> falsego test -tags integration ./mdl/executor -run 'TestAlterPage_SetListViewEditable|TestAlterPage_DataViewFooterRegion|TestPageVariableInputBinding_RoundTrip': describe → exec → describe stable for footer and page variablemdl/roundtripTestReplacePluggableKeepsWhatTheStatementDoesNotStateon TestApp (Studio Pro-authored), including twice-exec writes nothingmake test-integration-roundtripgreenmxcli docker checkreports 0 errors. Before the MaxLengthCode fix it reported CE6553. TheALTER PAGE … REPLACEon a pluggable Combobox silently resets properties the statement doesn't restate (placeholder translations, readOnlyStyle); describe and diff-local don't show the loss mendixlabs/mxcli#1247 REPLACE run twice: the second run writes no file, andmxcli docker checkreports 0 errors.make build,make lint,make check-conformance,make check-migration-reference,make check-findings,go test ./cmd/mxcli/(skill budgets), plus scopedgo testfor pagemutator, modelsdk, executor, visitor, upgrade, deprecation and conformance.Not in this PR (follow-ups)
create or modify pagewith a changed pluggable widget still rebuilds unstated properties from the template. The fix(pages): keep an unchanged pluggable widget's stored Type and Object (#721 L4) #830 passthrough there is all-or-nothing, and the same baseline merge could be applied.emptyOptionTextorreadOnlyStyle. REPLACE now keeps them, but they still aren't visible in describe.footerinside a fragment used in a data view is still discarded without a warning, because the visitor can't see the eventual parent.🤖 Generated with Claude Code