Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/grammar", "date": "2026-10-27", "symptom": "ako/mxcli#1516 (mendixlabs/mxcli#1606): `actionbutton b (Caption: 'Ping', Action: call microflow M.Ping())` failed `mxcli check` with `mismatched input ')' expecting the start of a statement`, while `call microflow M.Ping();` parses in a flow body and the widget action parsed without the brackets. Same error for call nanoflow, show page, the deprecated microflow/nanoflow/show_page spellings, a microflow or nanoflow DataSource, OnClick, OnChange, a pluggable widget's action property, `alter page set Action`/`set DataSource`, and a navigation or menu-document item's OnClick. `use fragment Hdr()` was worse: no error at all without a project", "cause": "microflowArgsV3 (MDLPage.g4) required at least one argument, `LPAREN microflowArgV3 (COMMA microflowArgV3)* RPAREN`, and every one of those sites reaches it through actionExprV3 or dataSourceExprV3. The optional rule failed on `( )`, the widget's property list then met `(` and recovery blamed the `)`. fragmentArgs had the same shape, but there the page body's generic widget alternative (`widgetTypeV3` ends in IDENTIFIER, and widgetPropertiesV3 MAY be empty) re-read `use fragment Hdr()` as a widget of type `use` named `fragment` plus a widget of type `Hdr` with `()` as its properties, so check without -p passed and check -p said '`use` is not a widget in this project' (MDL-WIDGET25)", "file": "mdl/grammar/domains/MDLPage.g4 (microflowArgsV3, fragmentArgs)", "fix": "Both rules take an optional list inside the brackets, like workflowCallArguments and the flow-body callArgumentList already did. No visitor change: buildMicroflowArgsV3 and buildFragmentArgs return nil for no children, so `X()` builds the statement `X` builds. Purely additive (a refused script now parses), so no mdl-version gate. describe still writes no brackets", "test": "mdl/visitor/visitor_empty_call_args_test.go: 23 sites, each X() vs X compared as whole statements plus deprecation codes, with a non-empty argument list as the control that must differ. Reverting the grammar (patch out, make grammar) fails all 23: 22 as parse errors and use fragment on statement equality, since it parsed as two widgets. Real 11.13.0 app (mdl-examples/bug-tests/widget-action-1516-empty-call-args.mdl): a page written with () and its bracket-less twin store identical BSON once $ID and the page name are set aside, describe identically, describe -> exec reports Unchanged, mx check 0 errors", "insight": "One shared rule carried eight alternatives (six actions, two data sources) into every site that takes an action or a data source, which is the argument for auditing by rule rather than by the reported spelling: grep for the rule name, not the keyword. Compare WHOLE statements between X() and X, not the Args field: an empty-but-present mapping list, or an alternative that silently matched something else, both show up there, and a control (a real argument list must change the statement) proves the comparison can see a difference. A rule that cannot match does not always produce a parse error: when a generic fall-back alternative exists (here an unknown widget type with an optional empty property list) the input is re-read as something else and `check` without a project passes, so a site that 'parses' at baseline still needs the AST checked. `use building block X()` and `snippetcall (Params: ())` stay errors on purpose: they are an override list and a property map, not an argument list, and the messages already name what is expected", "refs": ["ako/mxcli#1516", "mendixlabs/mxcli#1606"], "rules": ["MDL-WIDGET25"]}
2 changes: 1 addition & 1 deletion cmd/mxcli/syntax/features_page.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ LIST IMPACT OF htmlelement;
"confirmation", "confirm", "are you sure", "progress bar", "progress message",
"disabled during execution", "disabled during action", "asynchronous", "form validations",
},
Syntax: "Action: NOTHING -- deliberately no action (Forms$NoAction)\nAction: SAVE CHANGES\nAction: SAVE CHANGES CLOSE PAGE -- save, then close the pop-up\nAction: CANCEL CHANGES\nAction: CANCEL CHANGES CLOSE PAGE\nAction: CLOSE PAGE\nAction: DELETE\nAction: DELETE CLOSE PAGE\nAction: CALL NANOFLOW Module.NF\nAction: CALL NANOFLOW Module.NF(Param = $val)\nAction: OPEN LINK 'https://example.com'\nAction: OPEN LINK $currentObject/URL -- address read from an attribute\nAction: SIGN OUT\nAction: COMPLETE TASK 'OutcomeName'\nAction: SHOW PAGE Module.Page\nAction: SHOW PAGE Module.Page(Param = $currentObject)\nAction: CALL MICROFLOW Module.MF\nAction: CALL MICROFLOW Module.MF(Param = $val)\nAction: CREATE OBJECT Module.Entity THEN SHOW PAGE Module.Page\n\nThe list above is exhaustive. Anything else in an action slot is an\nERROR: `Action: OPEN LINK` without a URL or `Action: SHOW PAGE` without a\npage is a syntax error, and a value that is not an action at all\n(or a snake-case keyword short its argument) is MDL-WIDGET28.\nSuch a widget used to be written with NO action at all and rendered as a\ndead control, with check, exec and mxbuild all clean, because a\nno-action widget is legal Mendix (mendixlabs/mxcli#1062). Write NOTHING\nwhen a control really is meant to be inert.\n\nThe actions are the words a microflow uses (R8). The snake-case spellings\n(SAVE_CHANGES, SHOW_PAGE, CLOSE_PAGE, DELETE_OBJECT, OPEN_LINK, SIGN_OUT, ...)\nand a flow call without CALL still parse, but are deprecated (MDL-DEPR020);\n`mxcli fmt --upgrade` rewrites them.\n\nThe same forms serve `OnClick:` (an alias of `Action:`) and `OnChange:`.\n\nSETTINGS. Any action but NOTHING takes a `with ( … )` list of the\nsettings Studio Pro shows under the event (ako/mxcli#721):\n\n DisabledDuringExecution: true|false -- every action; default true\n ProgressBar: None|NonBlocking|Blocking -- flow calls; default None\n ProgressMessage: 'text' -- flow calls\n Confirmation: 'question' -- flow calls: ask before running\n ProceedCaption: 'text', CancelCaption: 'text' -- its buttons; default Proceed / Cancel\n Asynchronous: true|false -- call microflow only; default false\n FormValidations: All|Widget|None -- call microflow only; default All\n\nAction: CALL MICROFLOW M.Delete(Order = $currentObject) with (\n ProgressBar: Blocking, ProgressMessage: 'Deleting…',\n Confirmation: 'Delete this order?', ProceedCaption: 'Delete', CancelCaption: 'Keep')\n\nA setting left out keeps its default. DESCRIBE prints only the settings\nthat differ from it. An unknown key, or one the action does not have, is an\nerror. For CREATE OBJECT … THEN SHOW PAGE …, the list goes at the end and\nbelongs to the create.\n\nRETURN VALUE MAPPINGS. A flow call can map what the flow returns back onto\nthe page -- Studio Pro's \"Return value mappings\" (Mendix 11.5). The list\ngoes after the arguments and before `with ( … )`, target = source:\n\nAction: CALL MICROFLOW M.ACT_Vehicle_Get returns (\n Brand = $ActionReturnValue/Brand, -- an attribute of the returned object\n $stringResult = $ActionReturnValue, -- the return value itself\n Brand = 'Demo brand') -- any expression\n\nA bare target is an attribute of the enclosing data container's object;\n`$name` is a page variable. $ActionReturnValue/Attr needs a flow that\nreturns an object. A mapping into an attribute needs Mendix 11.15: mx\n11.13 and 11.14 report CE7006 on it. Leave the list out and the call maps\nnothing; DESCRIBE prints the stored mappings, and re-running a statement\nwithout them removes them (ako/mxcli#977).\n\nA microflow or nanoflow action is a CALL: it needs an argument for every\nparameter the flow declares, or Mendix rejects the page with CE1571. The\nargument list is the same on every widget that takes an action -- a\nCONTAINER (which is clickable) as much as an ACTIONBUTTON. An enclosing\ndata container of the right type supplies it without an argument; a data\ngrid's CONTROL BAR does not, because it is not row-scoped -- pass the\ngrid's selection there (`$dgOrders`).\n\nA SHOW PAGE argument must be the enclosing widget's context object --\neither $currentObject or the name of the variable the enclosing data\nwidget is bound to. Mendix infers it from that widget, so naming any\nother variable is refused (MDL-PAGEARG01); call a microflow instead.\nThe exception is a parameter of the page or snippet itself: it is bound\nby name (Studio Pro stores an explicit mapping), so `(Item = $Item)` works\nanywhere, outside every data widget too (mendixlabs/mxcli#1403).\nOutside any data widget there is no context object to infer, so such a\nbutton takes no OTHER argument -- not $currentObject, not a literal.\nmxcli used to drop it in silence and mxbuild then reported CE1571 per\nparameter of the target page (mendixlabs/mxcli#1029). Route that\nnavigation through a microflow.\n\nOPEN LINK takes a web address, stored as a Forms$StaticOrDynamicString:\neither a literal, or $currentObject/Attr to read it from an attribute of\nthe enclosing data container's object at runtime (Studio Pro's \"Address:\nattribute\"). An address over an association path is not supported yet.\n\nButton styles: Default, Primary, Success, Info, Warning, Danger\n\nMendix has THREE icon elements and the keyword picks which one:\n\nIcon: 'Atlas_Core.Atlas_Filled.pencil' -- an icon collection\nIcon: image MyModule.Images.logo -- an IMAGE collection\nIcon: glyph 57377 -- a font code point\n\nThe bare form is the icon-collection icon and any collection in the\nproject works, third-party ones included. The image form points into a\ndifferent document, and is spelled the same way apart from the keyword\n-- write it without `image` and mxcli stores a custom-icon reference,\nwhich fails the build with CE1613 (mendixlabs/mxcli#1059).\n`mxcli check -p … --references` resolves each kind against its own\ncollection and names the remedy when the kind is wrong.\n\nA glyph carries a code and no name. Codes are sparse, and an undefined\none fails only at `mxbuild --target=deploy`, naming the PAGE rather\nthan the icon -- so MDL078 refuses it (an error) against the font's own\ntable, naming the defined glyphs either side of the code.\nList them with `list glyphs`.\n\nA name may be quoted or bare; a hyphenated segment is double-quoted on\nits own: Atlas_Core.Atlas.\"align-center\".\n\nUse `linkbutton` instead of `actionbutton` for link render mode (same properties).",
Syntax: "Action: NOTHING -- deliberately no action (Forms$NoAction)\nAction: SAVE CHANGES\nAction: SAVE CHANGES CLOSE PAGE -- save, then close the pop-up\nAction: CANCEL CHANGES\nAction: CANCEL CHANGES CLOSE PAGE\nAction: CLOSE PAGE\nAction: DELETE\nAction: DELETE CLOSE PAGE\nAction: CALL NANOFLOW Module.NF\nAction: CALL NANOFLOW Module.NF(Param = $val)\nAction: OPEN LINK 'https://example.com'\nAction: OPEN LINK $currentObject/URL -- address read from an attribute\nAction: SIGN OUT\nAction: COMPLETE TASK 'OutcomeName'\nAction: SHOW PAGE Module.Page\nAction: SHOW PAGE Module.Page(Param = $currentObject)\nAction: CALL MICROFLOW Module.MF\nAction: CALL MICROFLOW Module.MF(Param = $val)\nAction: CREATE OBJECT Module.Entity THEN SHOW PAGE Module.Page\n\nThe list above is exhaustive. Anything else in an action slot is an\nERROR: `Action: OPEN LINK` without a URL or `Action: SHOW PAGE` without a\npage is a syntax error, and a value that is not an action at all\n(or a snake-case keyword short its argument) is MDL-WIDGET28.\nSuch a widget used to be written with NO action at all and rendered as a\ndead control, with check, exec and mxbuild all clean, because a\nno-action widget is legal Mendix (mendixlabs/mxcli#1062). Write NOTHING\nwhen a control really is meant to be inert.\n\nThe actions are the words a microflow uses (R8). The snake-case spellings\n(SAVE_CHANGES, SHOW_PAGE, CLOSE_PAGE, DELETE_OBJECT, OPEN_LINK, SIGN_OUT, ...)\nand a flow call without CALL still parse, but are deprecated (MDL-DEPR020);\n`mxcli fmt --upgrade` rewrites them.\n\nThe same forms serve `OnClick:` (an alias of `Action:`) and `OnChange:`.\n\nA call to a flow or page with no parameters may end in an empty `()`,\nas a flow body writes it. It stores the same action as no list at all,\nand DESCRIBE leaves it out (ako/mxcli#1516).\n\nSETTINGS. Any action but NOTHING takes a `with ( … )` list of the\nsettings Studio Pro shows under the event (ako/mxcli#721):\n\n DisabledDuringExecution: true|false -- every action; default true\n ProgressBar: None|NonBlocking|Blocking -- flow calls; default None\n ProgressMessage: 'text' -- flow calls\n Confirmation: 'question' -- flow calls: ask before running\n ProceedCaption: 'text', CancelCaption: 'text' -- its buttons; default Proceed / Cancel\n Asynchronous: true|false -- call microflow only; default false\n FormValidations: All|Widget|None -- call microflow only; default All\n\nAction: CALL MICROFLOW M.Delete(Order = $currentObject) with (\n ProgressBar: Blocking, ProgressMessage: 'Deleting…',\n Confirmation: 'Delete this order?', ProceedCaption: 'Delete', CancelCaption: 'Keep')\n\nA setting left out keeps its default. DESCRIBE prints only the settings\nthat differ from it. An unknown key, or one the action does not have, is an\nerror. For CREATE OBJECT … THEN SHOW PAGE …, the list goes at the end and\nbelongs to the create.\n\nRETURN VALUE MAPPINGS. A flow call can map what the flow returns back onto\nthe page -- Studio Pro's \"Return value mappings\" (Mendix 11.5). The list\ngoes after the arguments and before `with ( … )`, target = source:\n\nAction: CALL MICROFLOW M.ACT_Vehicle_Get returns (\n Brand = $ActionReturnValue/Brand, -- an attribute of the returned object\n $stringResult = $ActionReturnValue, -- the return value itself\n Brand = 'Demo brand') -- any expression\n\nA bare target is an attribute of the enclosing data container's object;\n`$name` is a page variable. $ActionReturnValue/Attr needs a flow that\nreturns an object. A mapping into an attribute needs Mendix 11.15: mx\n11.13 and 11.14 report CE7006 on it. Leave the list out and the call maps\nnothing; DESCRIBE prints the stored mappings, and re-running a statement\nwithout them removes them (ako/mxcli#977).\n\nA microflow or nanoflow action is a CALL: it needs an argument for every\nparameter the flow declares, or Mendix rejects the page with CE1571. The\nargument list is the same on every widget that takes an action -- a\nCONTAINER (which is clickable) as much as an ACTIONBUTTON. An enclosing\ndata container of the right type supplies it without an argument; a data\ngrid's CONTROL BAR does not, because it is not row-scoped -- pass the\ngrid's selection there (`$dgOrders`).\n\nA SHOW PAGE argument must be the enclosing widget's context object --\neither $currentObject or the name of the variable the enclosing data\nwidget is bound to. Mendix infers it from that widget, so naming any\nother variable is refused (MDL-PAGEARG01); call a microflow instead.\nThe exception is a parameter of the page or snippet itself: it is bound\nby name (Studio Pro stores an explicit mapping), so `(Item = $Item)` works\nanywhere, outside every data widget too (mendixlabs/mxcli#1403).\nOutside any data widget there is no context object to infer, so such a\nbutton takes no OTHER argument -- not $currentObject, not a literal.\nmxcli used to drop it in silence and mxbuild then reported CE1571 per\nparameter of the target page (mendixlabs/mxcli#1029). Route that\nnavigation through a microflow.\n\nOPEN LINK takes a web address, stored as a Forms$StaticOrDynamicString:\neither a literal, or $currentObject/Attr to read it from an attribute of\nthe enclosing data container's object at runtime (Studio Pro's \"Address:\nattribute\"). An address over an association path is not supported yet.\n\nButton styles: Default, Primary, Success, Info, Warning, Danger\n\nMendix has THREE icon elements and the keyword picks which one:\n\nIcon: 'Atlas_Core.Atlas_Filled.pencil' -- an icon collection\nIcon: image MyModule.Images.logo -- an IMAGE collection\nIcon: glyph 57377 -- a font code point\n\nThe bare form is the icon-collection icon and any collection in the\nproject works, third-party ones included. The image form points into a\ndifferent document, and is spelled the same way apart from the keyword\n-- write it without `image` and mxcli stores a custom-icon reference,\nwhich fails the build with CE1613 (mendixlabs/mxcli#1059).\n`mxcli check -p … --references` resolves each kind against its own\ncollection and names the remedy when the kind is wrong.\n\nA glyph carries a code and no name. Codes are sparse, and an undefined\none fails only at `mxbuild --target=deploy`, naming the PAGE rather\nthan the icon -- so MDL078 refuses it (an error) against the font's own\ntable, naming the defined glyphs either side of the code.\nList them with `list glyphs`.\n\nA name may be quoted or bare; a hyphenated segment is double-quoted on\nits own: Atlas_Core.Atlas.\"align-center\".\n\nUse `linkbutton` instead of `actionbutton` for link render mode (same properties).",
Example: "ACTIONBUTTON btnSave (Caption: 'Save', Action: SAVE CHANGES, ButtonStyle: Primary)\nACTIONBUTTON btnEdit (Caption: 'Edit',\n Action: SHOW PAGE Module.EditPage(Item = $currentObject))\nLINKBUTTON btnDelete (Caption: 'Delete', Action: DELETE,\n Icon: 'Atlas_Core.Atlas_Filled.pencil')\n\n-- A clickable CONTAINER in a data grid's control bar, calling a nanoflow\n-- with the grid's selection as its argument.\nDATAGRID dgOrders (DataSource: DATABASE FROM Sales.Order, Selection: Single) {\n COLUMN (Attribute: Number, Caption: 'Order #')\n CONTROLBAR {\n CONTAINER cShip (Class: 'command',\n Action: CALL NANOFLOW Sales.ACT_Ship(Order = $dgOrders)) {\n ACTIONBUTTON btnShip (Caption: 'Ship')\n }\n }\n}",
SeeAlso: []string{"page.widgets"},
})
Expand Down
4 changes: 3 additions & 1 deletion cmd/mxcli/syntax/retired_spellings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ func TestSyntaxDocs_NoRetiredSpellings(t *testing.T) {
"the parser rejects it: \"'Binds:' is no longer supported, use 'Attribute:' instead\"",
},
{
// Not retired since ako/mxcli#1516 — `()` parses and stores nothing —
// but the reference shows the form DESCRIBE writes.
"MICROFLOW Module.MF()",
"a zero-argument microflow DATASOURCE takes no parentheses (unlike RETRIEVE/CALL, where they are normal)",
"the reference shows a zero-argument call or data source the way DESCRIBE writes it, without parentheses; `()` is accepted and means the same (ako/mxcli#1516)",
},
}

Expand Down
6 changes: 6 additions & 0 deletions docs-site/src/reference/page/create-page.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,12 @@ mistake.

The same values serve `OnClick:` (an alias of `Action:`) and `OnChange:`.

A flow or page that takes no parameters may be called with an empty argument
list, as a flow body writes it: `Action: CALL MICROFLOW Module.Name()` stores
exactly what `Action: CALL MICROFLOW Module.Name` stores, and `DESCRIBE` writes
it without the brackets. The same holds for a microflow or nanoflow data source
and for `USE FRAGMENT Name()`.

#### Action settings

Any action but `NOTHING` takes a `with ( … )` list of the settings Studio Pro
Expand Down
Loading
Loading