Skip to content

Catalog: widget parent/depth, class/style and primary action (mendixlabs/mxcli#1268) - #965

Merged
ako merged 8 commits into
mainfrom
feat/catalog-widget-tree-class-action
Oct 3, 2026
Merged

ako merged 8 commits into
mainfrom
feat/catalog-widget-tree-class-action

Conversation

@ako

@ako ako commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Implements mendixlabs#1268 per the agreed design in the maintainer comment there.

What changed

Catalog (widgets_data, schema 19): the walker now passes the parent through. New columns:

  • ParentWidgetId is the nearest indexed ancestor. Skipped wrappers (conditionalVisibilityWidget…), layout grid rows and columns, tab pages, and a pluggable widget's properties and object-list items are transparent, so a widget in a LayoutGrid column or a DataGrid2 column is parented to the grid.
  • Depth is 0 at the page or snippet root. A list view template is indexed (Catalog: activities inside loops and their properties; CONV013/CONV014 read the action's error handling #940), so it counts as a level: list view d, template d+1, template content d+2. Depth does not cross a SnippetCallWidget (the snippet's widgets are its own rows, starting at 0).
  • Class, Style and DynamicClasses come from Forms$Appearance.
  • ActionType is the raw $Type of Action, else OnClickAction, else ClickAction.
  • HasConfirmation is set when there is a ConfirmationInfo: MicroflowSettings.ConfirmationInfo for a microflow call, or directly on a nanoflow or workflow call. Forms$DeleteClientAction has no confirmation property, and a test pins this against the generated metamodel.

Starlark widgets() gains parent_widget_id, depth, class_name (class is a keyword), style, dynamic_classes, action_type, has_confirmation and page_ref.

Docs:

  • The widget table moved to write-lint-rules/catalog-tables.md, because SKILL.md would have gone over the 700-line bound. It now includes an example rule: inline style, class allow-list, and delete button → call a microflow with a confirmation.
  • The SKILL.md note that "action_type is the SDK name" now names widget.action_type as the exception: it is the raw storage type.
  • docs-site tools/catalog-tables.md gets a new CATALOG.WIDGETS section.
  • docs-site internals/catalog-schema.md had a stale four-column WIDGETS block; it is replaced with the real schema.
  • CHANGELOG updated.

Vocabulary test: docRowValues returned the first action_type row in the file. The widget row would have shadowed the activity row and silently retargeted TestSkillDocumentsRealActionTypes, so a section-scoped docSectionRowValues was added. Documented widget action types must be Forms$…Action names that the codec registry knows. The issue's own "DeleteAction" would fail this check.

Values measured on TestApp: Forms$NoAction, MicroflowAction (21 with confirmation), CallNanoflowClientAction, FormAction, CancelChangesClientAction, ClosePageClientAction, SaveChangesClientAction, DeleteClientAction, OpenUserTaskClientAction, OpenLinkClientAction, SetTaskOutcomeClientAction and CreateObjectClientAction.

Test plan

  • make build, make lint, make check-conformance, make check-findings
  • go test ./mdl/catalog/... ./mdl/linter/... ./mdl/executor/ ./cmd/mxcli/
  • Walker unit tests (builder_pages_tree_test.go) cover: parent through a skipped wrapper, LayoutGrid + tab container, ListView template (a level of its own), DataGrid2 column and child slot (parented to the grid), snippet roots, appearance, and the primary-action priority and confirmation per action kind.
  • Studio Pro-authored TestApp (builder_pages_tree_testapp_test.go):
    • No dangling parents, child depth = parent + 1, roots at 0, across all 1615 widgets (with a control).
    • A 9-level ancestor chain through layoutGrid → dataView → … → tabContainer → dataGrid2 column → button.
    • Administration.Account_Edit.label4 has the right class and style.
    • Account_Overview.actionButton4 is Forms$DeleteClientAction with no confirmation.
    • A Studio Pro microflow button with a confirmation has HasConfirmation = 1.
  • Starlark projection test (widgets_projection_test.go).
  • End-to-end mxcli lint on a copy of testdata/pedapp. I added a page through MDL with a styled container, a disallowed class, a delete button and a microflow button with Confirmation:. A .claude/lint-rules/widget_hygiene.star rule implementing the issue's three checks plus a depth check reported 7 issues, all expected. The skill's example rule, extracted verbatim, ran clean and reported 4 issues. The confirmed microflow button was not flagged as a delete.
  • Revert checks (each confirmed failing, then restored):
    1. Children not re-parented: tree tests fail (parent "" want dataView1, wrong depths).
    2. Skipped wrapper made non-transparent: textBox1 parent id "wrap", depth 2.
    3. Property bag loses its parent: pb1/emptyText1 parent "", and the TestApp chain collapses to [container5 actionButton5].
    4. MicroflowSettings.ConfirmationInfo not read: got (Forms$MicroflowAction, false).
    5. Appearance not read: unit test and TestApp label4 fail.
    6. has_confirmation dropped from the Starlark struct: projection test fails ("struct has no .has_confirmation").
    7. Skill doc changed to "DeleteAction": vocabulary test fails.
    8. E2E: an mxcli binary built with action and parent extraction reverted reports only the 3 style/class issues. The DELETE and DEPTH findings disappear.

Left open (follow-up)

  • A pluggable widget's actions live in its property bag (WidgetValue.Action, e.g. a DataGrid2 or Gallery on-click), and a widget can have several, so there is no single "primary" one. action_type is empty for those. This needs a design decision.
  • No finding was recorded: this is a feature, not a bug fix.

🤖 Generated with Claude Code

ako and others added 8 commits October 3, 2026 17:42
…structure and the catalog (#963)

list workflows and show structure recursed over outcome flows only and
skipped boundary-event flows and event sub-processes, so TestApp Workflow1
listed 5 activities where the catalog counted 8. The catalog's walk moves to
wfnames.WalkActivities/CountActivities and all three use it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…uct (#963)

The catalog has carried TotalActivityCount (loop bodies included) since #940;
microflows() now hands it to rules for microflows, nanoflows and rules alike.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…g create/change (#963)

commit $Order on a loop variable wrote no refs row because refs had no commit
kind. A commit action, or a create/change with commit Yes/YesWithoutEvents,
now emits FLOW -> ENTITY 'commit', resolved through the same intra-flow
variable map as change/delete. It stays out of the analysis graph and the
caller kinds. The ref_kind skill test now reads every RefKind constant, so a
new kind cannot ship undocumented. Catalog schema version 19.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tion

widgets_data gains ParentWidgetId (nearest indexed ancestor, so skipped
wrappers, layout grid rows/columns, tab pages and pluggable property /
object-list items are transparent), Depth (0 at the page or snippet root;
a list view template is a level), Class, Style, DynamicClasses, ActionType
(raw $Type of Action, else OnClickAction, else ClickAction) and
HasConfirmation (ConfirmationInfo on a microflow/nanoflow/workflow call).
Catalog schema 19. Tested on hand-built shapes and on Studio Pro-authored
TestApp pages. mendixlabs#1268

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gets()

widgets() structs gain parent_widget_id, depth, class_name, style,
dynamic_classes, action_type, has_confirmation and page_ref.
mendixlabs#1268

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The widget table moves to write-lint-rules/catalog-tables.md (SKILL.md was
over the 700-line bound) with an example rule for inline styles, a class
allow-list and direct delete buttons. The vocabulary test scopes action_type
per section (activity vs widget), holds documented widget action types to
codec-registered storage names, and pins that only flow calls carry a
ConfirmationInfo. mendixlabs#1268

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ction' into c24-965

# Conflicts:
#	CHANGELOG.md
#	mdl/catalog/tables.go
#963's commit refs and mendixlabs#1268's widget columns both bumped 18 -> 19 on parallel
branches. A cache built at 19 by either alone would never rebuild for the
other, the 15/16 collision again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ako
ako merged commit 3a7efd0 into main Oct 3, 2026
33 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.

1 participant