Skip to content

fix: ALTER STYLING writes design properties on pages and snippets (#631)#632

Merged
ako merged 5 commits into
mendixlabs:mainfrom
peterjumpnl:fix/631-alter-styling-design-properties
Jun 3, 2026
Merged

fix: ALTER STYLING writes design properties on pages and snippets (#631)#632
ako merged 5 commits into
mendixlabs:mainfrom
peterjumpnl:fix/631-alter-styling-design-properties

Conversation

@peterjumpnl

Copy link
Copy Markdown
Contributor

ALTER STYLING failed with "unsupported container type: PAGE" because the visitor stores ContainerType uppercase while the executor compared lowercase; the same casing bug silently broke DESCRIBE STYLING. Beyond casing, ALTER STYLING used the legacy reflection walker (walkPageWidgets + UpdatePage), which could not locate widgets in MDL-builder-created pages and bypassed the required mutator pattern.

  • Normalise container type case in execAlterStyling/execDescribeStyling.
  • Route ALTER STYLING through OpenPageForMutation (mutator pattern), matching ALTER PAGE; report a clean not-found error via FindWidget.
  • Add SetDesignProperty/RemoveDesignProperty/ClearDesignProperties to the PageMutator interface; the MPR implementation writes the widget's Appearance.DesignProperties BSON array (Toggle/Option/Custom value), preserving an existing custom kind on option updates.
  • Remove the dead reflection walker (widget_property.go).
  • Tests: mutator-level BSON tests + executor dispatch/casing tests.
  • Re-enable the ALTER STYLING examples and add a bug-test repro.

…ndixlabs#631)

ALTER STYLING failed with "unsupported container type: PAGE" because the
visitor stores ContainerType uppercase while the executor compared lowercase;
the same casing bug silently broke DESCRIBE STYLING. Beyond casing, ALTER
STYLING used the legacy reflection walker (walkPageWidgets + UpdatePage),
which could not locate widgets in MDL-builder-created pages and bypassed the
required mutator pattern.

- Normalise container type case in execAlterStyling/execDescribeStyling.
- Route ALTER STYLING through OpenPageForMutation (mutator pattern), matching
  ALTER PAGE; report a clean not-found error via FindWidget.
- Add SetDesignProperty/RemoveDesignProperty/ClearDesignProperties to the
  PageMutator interface; the MPR implementation writes the widget's
  Appearance.DesignProperties BSON array (Toggle/Option/Custom value),
  preserving an existing custom kind on option updates.
- Remove the dead reflection walker (widget_property.go).
- Tests: mutator-level BSON tests + executor dispatch/casing tests.
- Re-enable the ALTER STYLING examples and add a bug-test repro.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

AI Code Review

Critical Issues

None found.

Moderate Issues

None found.

Minor Issues

None found.

What Looks Good

  • Root cause fix: Correctly identifies and resolves the two layered bugs (casing mismatch and legacy reflection walker) that caused ALTER STYLING to fail
  • Architectural compliance: Properly routes ALTER STYLING through OpenPageForMutation (mutator pattern) matching ALTER PAGE, as required by backend abstraction guidelines
  • Complete implementation: Adds all three design property mutator methods (SetDesignProperty, RemoveDesignProperty, ClearDesignProperties) to the PageMutator interface with proper MPR implementation
  • Test coverage: Includes mutator-level BSON tests, executor dispatch/casing tests, bug reproduction test, and re-enabled examples
  • Code quality: Removes dead reflection walker code, normalizes container type casing consistently, and preserves existing custom design property kinds during updates
  • Error handling: Provides clean not-found errors via FindWidget matching ALTER PAGE behavior
  • BACKEND ABSTRACTION: Executor no longer imports sdk/mpr for write paths; all mutations go through ctx.Backend.*
  • DESCRIBE roundtrip: Fixes the silent failure in DESCRIBE STYLING mentioned in the PR body

Recommendation

Approve - The PR is well-scoped, thoroughly tested, and correctly implements the fix while following all architectural guidelines. No changes are needed before merging.


Automated review via OpenRouter (Nemotron Super 120B) — workflow source

…dixlabs#631)

Flip the Styling row to reflect the fix: DESCRIBE and ALTER now Y (the
casing bug that broke DESCRIBE STYLING is fixed, and ALTER STYLING sets/
removes/clears design properties via the mutator), and Examples/Tests now Y.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

AI Code Review

Critical Issues

None found.

Moderate Issues

None found.

Minor Issues

  • Test organization: The bug test file mdl-examples/bug-tests/631-alter-styling-design-properties.mdl creates a module BugTest631 but doesn't clean it up. While this is acceptable for test files that are meant to be executed in isolation, it's worth noting that running this test multiple times would fail on the create module statement. However, since these are bug reproduction tests designed to be run manually or in a clean environment, this is minor.

  • Documentation consistency: The PR updates MDL_FEATURE_MATRIX.md to mark Styling as supported (Y) for more versions, but doesn't mention if there are any version restrictions for the design property functionality. Given that design properties (Atlas styling) were introduced in Mendix 10.6+, this might need version gating. However, the PR doesn't add any version checks, which could be problematic for older Mendix versions.

What Looks Good

  • Root cause identification: The PR correctly identifies two layered bugs (casing mismatch and legacy reflection walker) and fixes both cleanly.
  • Mutator pattern compliance: ALTER STYLING now properly uses OpenPageForMutation like ALTER PAGE, ensuring it works on both Studio Pro-created and MDL-builder-created pages/snippets.
  • Complete implementation: Adds all three design property operations (Set/Remove/Clear) with proper BSON handling that preserves custom kinds during option updates.
  • Test coverage: Includes mutator-level BSON tests, executor dispatch/casing tests, and a comprehensive bug reproduction test.
  • Code cleanup: Removes the dead reflection walker (widget_property.go) that was causing the inconsistency.
  • Backward compatibility: Fixes executor-side casing issue without changing visitor behavior, maintaining compatibility with existing AST structure.
  • Mock updates: Properly extends the mock implementation with the new design property methods.
  • Documentation: Updates both doctype tests and bug tests to demonstrate the fixed behavior, and updates the feature matrix to reflect restored functionality.

Recommendation

Approve the PR. The fix is well-targeted, follows established patterns (mutator pattern, backend abstraction), includes comprehensive tests at multiple layers, removes dead code, and resolves both the explicit failure case and the silent DESCRIBE STYLING bug. The minor concerns about test cleanup and version gating are outweighed by the correctness of the fix and the fact that this resolves a blocking issue (#631).

The PR demonstrates good understanding of the codebase architecture and makes minimal, focused changes to resolve the issue while improving overall consistency (removing legacy reflection walker in favor of the mutator pattern used elsewhere).


Automated review via OpenRouter (Nemotron Super 120B) — workflow source

…dixlabs#631)

Two correctness fixes for the design-property write path, found by dogfooding
an Atlas 3 -> 4 migration:

1. Value-type encoding: ALTER STYLING hardcoded "option" for every `= 'value'`
   assignment, so ToggleButtonGroup/ColorPicker properties (Flex container,
   Align items X/Y, Item/Column gap, Button Style, ...) were written as
   Forms$OptionDesignPropertyValue instead of Forms$CustomDesignPropertyValue —
   Studio Pro would not recognise the value. The executor now resolves the BSON
   value-type from the theme registry (reusing the same Toggle/Option/Custom
   classification the CREATE PAGE builder uses) and the mutator honours an
   explicit "custom" type.

2. 'Style'/'Class' key collision: a quoted design-property key 'Style' (e.g.
   Button Style = 'Icon button') was routed to the CSS Style widget property
   because it shared StylingAssignment.Property with the STYLE keyword. Added
   an IsCSS flag set only for the CLASS/STYLE keywords; quoted keys are now
   always treated as design properties.

Tests: resolveStylingValueType classification, quoted-'Style' dispatch, and
mutator Custom-value encoding.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

AI Code Review

Critical Issues

None found.

Moderate Issues

None found.

Minor Issues

None found.

What Looks Good

Bug Fix Implementation

  • Correctly identifies and fixes root causes: Addresses both the casing bug (visitor storing uppercase "PAGE"/"SNIPPET" vs executor comparing lowercase) and the architectural violation (using legacy reflection walker instead of mutator pattern)
  • Follows established patterns: Routes ALTER STYLING through OpenPageForMutation() just like ALTER PAGE, using the proper mutator pattern
  • Complete backend implementation:
    • Adds SetDesignProperty/RemoveDesignProperty/ClearDesignProperties to PageMutator interface
    • Proper MPR implementation in page_mutator.go that handles BSON serialization correctly
    • Preserves existing custom kind on option updates as required
    • Comprehensive mock implementation for testing
  • Thorough test coverage:
    • Bug test reproducing the exact issue (mdl-examples/bug-tests/631-alter-styling-design-properties.mdl)
    • Updated doctype tests showing working examples (mdl-examples/doctype-tests/12-styling-examples.mdl)
    • BSON-level unit tests for mutator methods (design_property_mut_test.go)
    • Executor mock tests covering all code paths (cmd_styling_mock_test.go)

Code Quality

  • Clean removal of dead code: Deletes the problematic widget_property.go reflection walker entirely
  • Consistent styling:
    • Properly distinguishes CSS properties (Class, Style) from design properties using IsCSS flag
    • Correctly handles quoted property names (e.g., 'Style' = 'Icon button' as design property)
    • Uses strings.ToLower() early for case-insensitive container type comparison
  • Error handling: Provides clean not-found errors via mutator.FindWidget() instead of silent failures
  • Maintains invariants: Preserves BSON marker-only array for DesignProperties when clearing

Documentation & Process

  • Updates symptom table: Adds clear documentation of the fix to .claude/skills/fix-issue.md
  • Re-enables examples: Uncomments previously broken ALTER STYLING examples in doctype tests
  • Follows contribution process: Addresses the exact issue described in the PR with targeted fixes

Architecture Compliance

  • Backend abstraction: Zero direct sdk/mpr write imports in executor; all mutations go through ctx.Backend.*
  • Interface compliance:
    • New methods added to PageMutator interface with proper var _ backend.PageMutator = (*impl)(nil) checks (implied by implementation)
    • MPR implementation in correct location (mdl/backend/mpr/)
    • Mock stubs updated with descriptive error defaults
  • Full-stack wiring: While not adding new MDL syntax, the fix properly works through all layers:
    • AST: Minor struct enhancement (IsCSS flag)
    • Visitor: Correctly sets flags for CSS vs design properties
    • Executor: Uses mutator pattern correctly
    • Backend: Interface and implementations updated
    • LSP/DESCRIBE: No changes needed as feature already existed; fix makes DESCRIBE STYLING work correctly

Recommendation

Approve. This PR correctly fixes a significant bug in ALTER STYLING by addressing both the surface-level casing issue and the deeper architectural problem of bypassing the mutator pattern. The implementation follows established patterns in the codebase (like ALTER PAGE), includes comprehensive test coverage at multiple levels, removes dead code, and maintains all architectural invariants. The fix is minimal, focused, and thoroughly verified.


Automated review via OpenRouter (Nemotron Super 120B) — workflow source

…ustom (mendixlabs#631)

Correction to the prior value-type change. ToggleButtonGroup (and Dropdown)
single-selection design properties are stored as Forms$OptionDesignPropertyValue,
NOT Forms$CustomDesignPropertyValue. Verified against Studio Pro-authored
widgets: e.g. `Flex container` appears 123x as Option vs 0x as Custom in a real
Atlas 4 project; encoding them as Custom triggers consistency error CE6084
("Expected design property X to be of type Toggle button group, but found
Custom").

- ALTER STYLING now writes single-value design properties as "option" (the
  original, correct behaviour); the theme-registry "custom" resolution is removed.
- Mutator: drop the "preserve existing custom kind" heuristic so re-applying an
  option value repairs a stale Custom entry; buildDesignPropertyValueDoc honours
  the requested value-type strictly.
- The quoted-'Style' design-property fix (IsCSS) is retained — Button
  Style='Icon button' now writes as Option, which matches Studio Pro.

NOTE: the SDK's serializeDesignProperties / page-builder resolveDesignProperty-
ValueType still classify ToggleButtonGroup as "custom"; that is a separate
pre-existing bug (affects CREATE PAGE) tracked independently.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

AI Code Review

Critical Issues

None found.

Moderate Issues

None found.

Minor Issues

  • Test coverage for DESCRIBE STYLING: While the PR adds bug tests and doctype tests for ALTER STYLING, it doesn't explicitly add a test verifying DESCRIBE STYLING output after ALTER STYLING changes (though the bug test includes DESCRIBE STYLING commands). The existing doctype test updates implicitly cover this, but a dedicated DESCRIBE STYLING assertion in the bug test would strengthen verification.
  • Error message consistency: In execDescribeStyling, the error message for missing widgets uses containerType (normalized) but the "No widgets found" message also uses containerType - this is correct. However, the original bug report noted DESCRIBE STYLING was "silently broken"; the fix resolves this via casing normalization, but no test confirms DESCRIBE STYLING now properly reports widget counts post-ALTER STYLING.

What Looks Good

  • Root cause fix: Addresses both layered bugs (casing mismatch + legacy walker) comprehensively.
  • Mutator pattern compliance: Routes ALTER STYLING through OpenPageForMutation matching ALTER PAGE, ensuring uniform handling of Studio Pro and MDL-builder pages.
  • Backend abstraction: Properly extends PageMutator interface with design property methods, implements them in MPR backend, and provides mock stubs.
  • Test thoroughness: Includes mutator-level BSON tests, executor dispatch/casing tests, bug test repro, and re-enabled doctype examples.
  • Code cleanup: Removes dead reflection walker (widget_property.go) and normalizes container type handling consistently.
  • LSP/DESCRIBE safety: No LSP changes needed (existing feature fix), and DESCRIBE STYLING now works via casing fix without breaking roundtrip expectations.

Recommendation

Approve. The PR fully resolves issue #631 with minimal, focused changes that adhere to the project's architectural patterns (mutator pattern, backend abstraction). Test coverage is adequate, and no checklist violations are present. Minor test enhancements are optional but not blocking.


Automated review via OpenRouter (Nemotron Super 120B) — workflow source

The interface and mutator doc comments claimed an option-type set
"preserves" an existing custom value's kind. The implementation does the
opposite — it fully rewrites the entry's Value, overwriting a stale
Custom value with an OptionDesignPropertyValue, which is what repairs the
CE6084 a Custom encoding triggers (and what TestSetDesignProperty_
OptionOverwritesCustom asserts). Comment-only change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown

AI Code Review

Critical Issues

None found.

Moderate Issues

None found.

Minor Issues

  • In mdl/executor/cmd_styling.go, the function execDescribeStyling now uses containerType (lowercase) in the output messages, which is good for consistency. However, the original s.ContainerType (uppercase) is still used in the error message for NewNotFound when a page/snippet isn't found. This creates inconsistent casing in error messages (e.g., "page not found in PAGE MyModule.Home" vs "page not found in page MyModule.Home"). Consider using containerType consistently in all user-facing strings for casing normalization.

  • The PR updates docs/01-project/MDL_FEATURE_MATRIX.md to mark ALTER STYLING as supported (Y). While accurate after the fix, this change is unrelated to the core bug fix and could be separated into a documentation-only PR for better atomicity. However, it's harmless and appropriate.

What Looks Good

  • The fix correctly addresses both layered bugs: casing normalization and migration to the mutator pattern.
  • The executor changes are clean: removal of the legacy reflection walker (walkPageWidgets/walkSnippetWidgets) and replacement with the mutator pattern (OpenPageForMutation + FindWidget), matching ALTER PAGE.
  • The backend changes properly extend PageMutator with design property methods (SetDesignProperty/RemoveDesignProperty/ClearDesignProperties) with thorough BSON-level tests preserving custom kinds on option updates.
  • Test coverage is excellent: mutator-level BSON tests, executor dispatch/casing tests, bug test reproduction, and updated doctype examples.
  • The AST/visitor changes correctly distinguish CSS properties (Class/Style) from design properties using the new IsCSS flag, preventing misrouting of quoted keys like 'Style'.
  • Mock tests comprehensively verify the new executor paths including edge cases (toggle OFF, clear properties, quoted design properties).
  • The PR re-enables ALTER STYLING examples and adds a meaningful bug test that validates the fix against Studio Pro.

Recommendation

Approve. The PR fixes the reported issue comprehensively, follows established patterns (mutator pattern, backend abstraction), includes adequate tests, and maintains code quality. Minor issues are trivial and do not block merging.


Automated review via OpenRouter (Nemotron Super 120B) — workflow source

@ako ako merged commit 2f08a1a into mendixlabs:main Jun 3, 2026
1 of 2 checks passed
This was referenced Jun 3, 2026
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