From 61d51807bd570993ef6de5b14ef5f007597e12fc Mon Sep 17 00:00:00 2001 From: engalar Date: Wed, 1 Apr 2026 10:27:10 +0800 Subject: [PATCH 1/3] feat: WidgetDemo baseline scripts and widget analysis MDL baseline scripts for reproducible WidgetDemo module generation: - 01-domain-model.mdl: 3 enums, 2 entities, 1 association - 01b-snippet.mdl: ButtonShowcase snippet - 02-showcase-page.mdl: 95-widget showcase (62 native, 33 pluggable) - 03-seed-and-navigate.mdl: seed data microflow + navigation WIDGET_ANALYSIS.md: classification of all 95 widgets by type. Co-Authored-By: Claude Opus 4.6 (1M context) --- mdl-examples/widgetdemo/01-domain-model.mdl | 53 ++ mdl-examples/widgetdemo/01b-snippet.mdl | 6 + mdl-examples/widgetdemo/02-showcase-page.mdl | 456 ++++++++++++++++++ .../widgetdemo/03-seed-and-navigate.mdl | 98 ++++ mdl-examples/widgetdemo/WIDGET_ANALYSIS.md | 104 ++++ 5 files changed, 717 insertions(+) create mode 100644 mdl-examples/widgetdemo/01-domain-model.mdl create mode 100644 mdl-examples/widgetdemo/01b-snippet.mdl create mode 100644 mdl-examples/widgetdemo/02-showcase-page.mdl create mode 100644 mdl-examples/widgetdemo/03-seed-and-navigate.mdl create mode 100644 mdl-examples/widgetdemo/WIDGET_ANALYSIS.md diff --git a/mdl-examples/widgetdemo/01-domain-model.mdl b/mdl-examples/widgetdemo/01-domain-model.mdl new file mode 100644 index 0000000..35e9361 --- /dev/null +++ b/mdl-examples/widgetdemo/01-domain-model.mdl @@ -0,0 +1,53 @@ +-- WidgetDemo: self-contained domain model (no external dependencies) +-- Provides entities and enumerations for the widget showcase page. + +CREATE ENUMERATION WidgetDemo.ENUM_Priority ( + LOW 'Low', + MEDIUM 'Medium', + HIGH 'High', + CRITICAL 'Critical' +); + +CREATE ENUMERATION WidgetDemo.ENUM_Status ( + DRAFT 'Draft', + ACTIVE 'Active', + COMPLETED 'Completed', + ARCHIVED 'Archived' +); + +CREATE ENUMERATION WidgetDemo.ENUM_Category ( + GENERAL 'General', + INPUT 'Input', + DISPLAY 'Display', + STRUCTURE 'Structure', + DATA_DISPLAY 'Data Display' +); + +CREATE PERSISTENT ENTITY WidgetDemo.DemoItem ( + Title: String(unlimited) NOT NULL, + Description: String(unlimited), + Code: String(unlimited), + Category: Enumeration(WidgetDemo.ENUM_Category) DEFAULT WidgetDemo.ENUM_Category.GENERAL, + Priority: Enumeration(WidgetDemo.ENUM_Priority) DEFAULT WidgetDemo.ENUM_Priority.MEDIUM, + ItemStatus: Enumeration(WidgetDemo.ENUM_Status) DEFAULT WidgetDemo.ENUM_Status.DRAFT, + IsActive: Boolean DEFAULT true, + Score: Integer DEFAULT 0, + Amount: Decimal DEFAULT 0, + DateCreated: DateTime, + DueDate: DateTime, + Progress: Decimal DEFAULT 0, + Rating: Integer DEFAULT 3, + Notes: String(unlimited), + ImageUrl: String(unlimited) +); + +CREATE NON-PERSISTENT ENTITY WidgetDemo.Helper ( + Attribute: Enumeration(WidgetDemo.ENUM_Category) DEFAULT WidgetDemo.ENUM_Category.GENERAL +); + +CREATE ASSOCIATION WidgetDemo.Helper_DemoItem ( + FROM WidgetDemo.Helper TO WidgetDemo.DemoItem, + Type: ReferenceSet +); + +GRANT WidgetDemo.User ON WidgetDemo.DemoItem (CREATE, DELETE, READ *, WRITE *); diff --git a/mdl-examples/widgetdemo/01b-snippet.mdl b/mdl-examples/widgetdemo/01b-snippet.mdl new file mode 100644 index 0000000..dee5923 --- /dev/null +++ b/mdl-examples/widgetdemo/01b-snippet.mdl @@ -0,0 +1,6 @@ +-- WidgetDemo: Button showcase snippet (referenced by 02-showcase-page) + +CREATE SNIPPET WidgetDemo.SNIPPET_ButtonShowcase { + ACTIONBUTTON btnInfo (Caption: 'Info Button', Action: CLOSE_PAGE, ButtonStyle: Info) + ACTIONBUTTON btnLink (Caption: 'Link Button', Action: CLOSE_PAGE, ButtonStyle: Link) +} diff --git a/mdl-examples/widgetdemo/02-showcase-page.mdl b/mdl-examples/widgetdemo/02-showcase-page.mdl new file mode 100644 index 0000000..f0228be --- /dev/null +++ b/mdl-examples/widgetdemo/02-showcase-page.mdl @@ -0,0 +1,456 @@ +-- WidgetDemo Showcase: comprehensive baseline for all MDL-supported widget types +-- Uses WidgetDemo.DemoItem + WidgetDemo.Helper (no external dependencies) +-- Every widget is fully configured with realistic properties + +CREATE OR REPLACE PAGE WidgetDemo.WidgetDemo_Showcase ( + Title: 'Widget Showcase', + Layout: Atlas_Core.Atlas_Default, + Url: 'widget-demo/{DemoItem}', + Params: { $DemoItem: WidgetDemo.DemoItem } +) { + LAYOUTGRID gridMain { + + -- ======== Section 1: Text ======== + ROW rowS1H { + COLUMN cS1H (DesktopWidth: 12) { + CONTAINER hdrS1 (Class: 'card', Style: 'padding: 16px; background-color: #f0f4ff;') { + DYNAMICTEXT tS1 (Content: '1. Text Widgets', RenderMode: H2) + } + } + } + ROW rowS1 { + COLUMN cS1a (DesktopWidth: 4) { + DYNAMICTEXT txtH1 (Content: 'Heading H1', RenderMode: H1) + DYNAMICTEXT txtH2 (Content: 'Heading H2', RenderMode: H2) + DYNAMICTEXT txtH3 (Content: 'Heading H3', RenderMode: H3) + } + COLUMN cS1b (DesktopWidth: 4) { + DYNAMICTEXT txtH4 (Content: 'Heading H4', RenderMode: H4) + DYNAMICTEXT txtH5 (Content: 'Heading H5', RenderMode: H5) + DYNAMICTEXT txtH6 (Content: 'Heading H6', RenderMode: H6) + } + COLUMN cS1c (DesktopWidth: 4) { + DYNAMICTEXT txtPar (Content: 'Paragraph text using RenderMode: Paragraph.', RenderMode: Paragraph) + } + } + + -- ======== Section 2: Layout (Container, GroupBox, TabContainer, LayoutGrid) ======== + ROW rowS2H { + COLUMN cS2H (DesktopWidth: 12) { + CONTAINER hdrS2 (Class: 'card', Style: 'padding: 16px; background-color: #e8f5e9;') { + DYNAMICTEXT tS2 (Content: '2. Layout Widgets', RenderMode: H2) + } + } + } + ROW rowS2 { + COLUMN cS2a (DesktopWidth: 4) { + CONTAINER ctnDemo (Class: 'card', Style: 'padding: 12px;') { + DYNAMICTEXT ctnL (Content: 'CONTAINER', RenderMode: H4) + DYNAMICTEXT ctnD (Content: 'Generic div container with class/style', RenderMode: Paragraph) + } + } + COLUMN cS2b (DesktopWidth: 4) { + GROUPBOX gbDemo (Caption: 'GROUPBOX') { + DYNAMICTEXT gbL (Content: 'Collapsible labeled container', RenderMode: Paragraph) + } + } + COLUMN cS2c (DesktopWidth: 4) { + TABCONTAINER tabDemo { + TABPAGE tabPage1 (Caption: 'Tab 1') { + DYNAMICTEXT tab1L (Content: 'First tab content', RenderMode: Paragraph) + } + TABPAGE tabPage2 (Caption: 'Tab 2') { + DYNAMICTEXT tab2L (Content: 'Second tab content', RenderMode: Paragraph) + } + TABPAGE tabPage3 (Caption: 'Tab 3') { + DYNAMICTEXT tab3L (Content: 'Third tab content', RenderMode: Paragraph) + } + } + } + } + + -- ======== Section 3: Buttons ======== + ROW rowS3H { + COLUMN cS3H (DesktopWidth: 12) { + CONTAINER hdrS3 (Class: 'card', Style: 'padding: 16px; background-color: #fff3e0;') { + DYNAMICTEXT tS3 (Content: '3. Buttons', RenderMode: H2) + } + } + } + ROW rowS3 { + COLUMN cS3a (DesktopWidth: 12) { + ACTIONBUTTON btnDef (Caption: 'Default', Action: CLOSE_PAGE) + ACTIONBUTTON btnPri (Caption: 'Primary', Action: CLOSE_PAGE, ButtonStyle: Primary) + ACTIONBUTTON btnSuc (Caption: 'Success', Action: CLOSE_PAGE, ButtonStyle: Success) + ACTIONBUTTON btnWar (Caption: 'Warning', Action: CLOSE_PAGE, ButtonStyle: Warning) + ACTIONBUTTON btnDng (Caption: 'Danger', Action: CLOSE_PAGE, ButtonStyle: Danger) + } + } + + -- ======== Section 4: Gallery + Filters + DataView + Inputs ======== + ROW rowS4H { + COLUMN cS4H (DesktopWidth: 12) { + CONTAINER hdrS4 (Class: 'card', Style: 'padding: 16px; background-color: #e3f2fd;') { + DYNAMICTEXT tS4 (Content: '4. Gallery + Filters + DataView + Inputs', RenderMode: H2) + } + } + } + ROW rowS4 { + COLUMN cS4a (DesktopWidth: 12) { + GALLERY galItems ( + DataSource: DATABASE FROM WidgetDemo.DemoItem SORT BY DateCreated DESC, + Selection: Single, + DesktopColumns: 2 + ) { + FILTER flt1 { + TEXTFILTER tfTitle (Attributes: [Title, Code]) + DROPDOWNFILTER dfCat + NUMBERFILTER nfAmt (Attributes: [Amount]) + DATEFILTER dtfDate (Attributes: [DateCreated]) + PLUGGABLEWIDGET 'com.mendix.widget.web.dropdownsort.DropdownSort' ddSort1 + } + TEMPLATE tmpl1 { + DYNAMICTEXT tTitle (Content: '{1}', RenderMode: H4, ContentParams: [{1} = Title]) + DYNAMICTEXT tCode (Content: 'Code: {1} | Priority: {2}', ContentParams: [{1} = Code, {2} = Priority]) + DYNAMICTEXT tAmount (Content: 'Amount: {1} | Score: {2}', ContentParams: [{1} = Amount, {2} = Score]) + } + } + DATAVIEW dvDetail (DataSource: $DemoItem) { + LAYOUTGRID gForm { + ROW rF1 { + COLUMN cF1 (DesktopWidth: 6) { + TEXTBOX txtTitle (Label: 'Title', Attribute: Title) + } + COLUMN cF2 (DesktopWidth: 6) { + TEXTBOX txtCode (Label: 'Code', Attribute: Code) + } + } + ROW rF2 { + COLUMN cF3 (DesktopWidth: 6) { + DATEPICKER dpCreated (Label: 'Date Created', Attribute: DateCreated) + } + COLUMN cF4 (DesktopWidth: 6) { + DATEPICKER dpDue (Label: 'Due Date', Attribute: DueDate) + } + } + ROW rF3 { + COLUMN cF5 (DesktopWidth: 6) { + PLUGGABLEWIDGET 'com.mendix.widget.web.combobox.Combobox' cbPri (Label: 'Priority', attributeEnumeration: Priority) + } + COLUMN cF6 (DesktopWidth: 6) { + RADIOBUTTONS rbStatus (Label: 'Status', Attribute: ItemStatus) + } + } + ROW rF3b { + COLUMN cF5b (DesktopWidth: 12) { + PLUGGABLEWIDGET 'com.mendix.widget.web.combobox.Combobox' cbCat (Label: 'Category', attributeEnumeration: Category) + } + } + ROW rF4 { + COLUMN cF7 (DesktopWidth: 6) { + CHECKBOX cbActive (Label: 'Active', Attribute: IsActive) + } + COLUMN cF8 (DesktopWidth: 6) { + TEXTAREA taNotes (Label: 'Notes', Attribute: Notes) + } + } + } + FOOTER ftr1 { + ACTIONBUTTON btnSv (Caption: 'Save', Action: SAVE_CHANGES, ButtonStyle: Primary) + ACTIONBUTTON btnCn (Caption: 'Cancel', Action: CANCEL_CHANGES) + } + } + } + } + + -- ======== Section 5: DataGrid ======== + ROW rowS5H { + COLUMN cS5H (DesktopWidth: 12) { + CONTAINER hdrS5 (Class: 'card', Style: 'padding: 16px; background-color: #fce4ec;') { + DYNAMICTEXT tS5 (Content: '5. DataGrid + ControlBar', RenderMode: H2) + } + } + } + ROW rowS5 { + COLUMN cS5a (DesktopWidth: 12) { + DATAGRID dgItems ( + DataSource: DATABASE FROM WidgetDemo.DemoItem SORT BY DateCreated DESC, + PageSize: 5 + ) { + CONTROLBAR cbDG { + ACTIONBUTTON btnNewDG (Caption: 'New Item', Action: CLOSE_PAGE, ButtonStyle: Primary) + } + COLUMN cTitle (Attribute: Title, Caption: 'Title') + COLUMN cCode (Attribute: Code, Caption: 'Code') + COLUMN cPri (Attribute: Priority, Caption: 'Priority', Alignment: center) + COLUMN cAmt (Attribute: Amount, Caption: 'Amount', Alignment: right) + COLUMN cScore (Attribute: Score, Caption: 'Score', Alignment: right) + } + } + } + + -- ======== Section 6: ListView ======== + ROW rowS6H { + COLUMN cS6H (DesktopWidth: 12) { + CONTAINER hdrS6 (Class: 'card', Style: 'padding: 16px; background-color: #f3e5f5;') { + DYNAMICTEXT tS6 (Content: '6. ListView', RenderMode: H2) + } + } + } + ROW rowS6 { + COLUMN cS6a (DesktopWidth: 12) { + LISTVIEW lvItems (DataSource: DATABASE FROM WidgetDemo.DemoItem SORT BY Title ASC) { + DYNAMICTEXT lvT (Content: '{1}', RenderMode: H4, ContentParams: [{1} = Title]) + DYNAMICTEXT lvD (Content: '{1}', ContentParams: [{1} = Description]) + } + } + } + + -- ======== Section 7: Navigation + SnippetCall ======== + ROW rowS7H { + COLUMN cS7H (DesktopWidth: 12) { + CONTAINER hdrS7 (Class: 'card', Style: 'padding: 16px; background-color: #e0f2f1;') { + DYNAMICTEXT tS7 (Content: '7. Navigation + SnippetCall', RenderMode: H2) + } + } + } + ROW rowS7 { + COLUMN cS7a (DesktopWidth: 4) { + NAVIGATIONLIST navQ { + ITEM nHome (Action: CLOSE_PAGE) { + DYNAMICTEXT nHt (Content: 'Home') + } + ITEM nList (Action: CLOSE_PAGE) { + DYNAMICTEXT nLt (Content: 'Item List') + } + ITEM nSettings (Action: CLOSE_PAGE) { + DYNAMICTEXT nSt (Content: 'Settings') + } + } + } + COLUMN cS7b (DesktopWidth: 8) { + SNIPPETCALL snCall (Snippet: WidgetDemo.SNIPPET_ButtonShowcase) + } + } + + -- ======== Section 8: Pluggable Widgets ======== + ROW rowS8H { + COLUMN cS8H (DesktopWidth: 12) { + CONTAINER hdrS8 (Class: 'card', Style: 'padding: 16px; background-color: #ede7f6;') { + DYNAMICTEXT tS8 (Content: '8. Pluggable Widgets', RenderMode: H2) + DYNAMICTEXT tS8d (Content: 'React-based widgets with explicit property bindings', RenderMode: Paragraph) + } + } + } + + -- 8a: Input pluggable widgets (entity context from DataView) + ROW rowS8a { + COLUMN cS8a1 (DesktopWidth: 12) { + DATAVIEW dvPluggable (DataSource: $DemoItem) { + LAYOUTGRID gPlug { + ROW rPlug1 { + COLUMN cPlug1 (DesktopWidth: 3) { + PLUGGABLEWIDGET 'com.mendix.widget.custom.switch.Switch' switch1 (booleanAttribute: IsActive) + } + COLUMN cPlug2 (DesktopWidth: 3) { + PLUGGABLEWIDGET 'com.mendix.widget.custom.starrating.StarRating' rating1 (rateAttribute: Rating) + } + COLUMN cPlug3 (DesktopWidth: 3) { + PLUGGABLEWIDGET 'com.mendix.widget.custom.slider.Slider' slider1 (valueAttribute: Score) + } + COLUMN cPlug4 (DesktopWidth: 3) { + PLUGGABLEWIDGET 'com.mendix.widget.custom.RangeSlider.RangeSlider' rangeSlider1 (lowerBoundAttribute: Score, upperBoundAttribute: Rating) + } + } + ROW rPlug2 { + COLUMN cPlug5 (DesktopWidth: 6) { + PLUGGABLEWIDGET 'com.mendix.widget.web.barcodescanner.BarcodeScanner' scanner1 (Attribute: Code) + } + COLUMN cPlug6 (DesktopWidth: 6) { + -- HTMLElement: tagContentMode='container' with child widgets + PLUGGABLEWIDGET 'com.mendix.widget.web.htmlelement.HTMLElement' htmlElem1 (tagContentMode: 'container') { + CONTAINER tagContentContainer { + DYNAMICTEXT htmlContent (Content: 'Content inside HTML element', RenderMode: Paragraph) + } + } + } + } + } + } + } + } + + -- 8b: Display pluggable widgets + ROW rowS8b { + COLUMN cS8b1 (DesktopWidth: 3) { + PLUGGABLEWIDGET 'com.mendix.widget.custom.badge.Badge' badge1 + } + COLUMN cS8b2 (DesktopWidth: 3) { + PLUGGABLEWIDGET 'com.mendix.widget.custom.badgebutton.BadgeButton' badgeBtn1 + } + COLUMN cS8b3 (DesktopWidth: 3) { + PLUGGABLEWIDGET 'com.mendix.widget.custom.progressbar.ProgressBar' progBar1 + } + COLUMN cS8b4 (DesktopWidth: 3) { + PLUGGABLEWIDGET 'com.mendix.widget.custom.progresscircle.ProgressCircle' progCirc1 + } + } + + -- 8c: Layout pluggable widgets with child content + ROW rowS8c { + COLUMN cS8c1 (DesktopWidth: 4) { + PLUGGABLEWIDGET 'com.mendix.widget.web.accordion.Accordion' accordion1 ( + expandBehavior: 'singleExpanded', + showIcon: 'right' + ) + } + COLUMN cS8c2 (DesktopWidth: 4) { + PLUGGABLEWIDGET 'com.mendix.widget.web.fieldset.Fieldset' fieldset1 { + DYNAMICTEXT fsBody (Content: 'Fieldset wraps content with an optional legend', RenderMode: Paragraph) + } + } + COLUMN cS8c3 (DesktopWidth: 4) { + PLUGGABLEWIDGET 'com.mendix.widget.web.tooltip.Tooltip' myTooltip1 ( + renderMethod: 'text', + textMessage: 'Additional info shown on hover', + tooltipPosition: 'top', + arrowPosition: 'none', + openOn: 'hover' + ) { + CONTAINER trigger { + ACTIONBUTTON btnTooltip (Caption: 'Hover me for tooltip', Action: CLOSE_PAGE, ButtonStyle: Info) + } + } + } + } + + -- 8d: Data-driven pluggable widgets + ROW rowS8d { + COLUMN cS8d1 (DesktopWidth: 6) { + -- Timeline mode 1: default visualization (TextTemplate properties) + PLUGGABLEWIDGET 'com.mendix.widget.web.timeline.Timeline' timelineText ( + DataSource: DATABASE FROM WidgetDemo.DemoItem SORT BY DateCreated DESC, + title: '{Title}', + description: '{Description}', + timeIndication: '{DateCreated}', + groupEvents: false, + customVisualization: false + ) + } + COLUMN cS8d2 (DesktopWidth: 6) { + -- Timeline mode 2: custom visualization (Widgets child containers) + PLUGGABLEWIDGET 'com.mendix.widget.web.timeline.Timeline' timelineCustom ( + DataSource: DATABASE FROM WidgetDemo.DemoItem SORT BY DateCreated DESC, + groupEvents: false, + customVisualization: true + ) { + CONTAINER customTitle { + DYNAMICTEXT tlTitle (Content: '{1}', RenderMode: H4, ContentParams: [{1} = Title]) + } + CONTAINER customDescription { + DYNAMICTEXT tlDesc (Content: '{1}', ContentParams: [{1} = Description]) + } + } + } + } + ROW rowS8d2 { + COLUMN cS8d2a (DesktopWidth: 4) { + PLUGGABLEWIDGET 'com.mendix.widget.web.videoplayer.VideoPlayer' videoPlayer1 ( + type: 'expression', + urlExpression: '''https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4''' + ) + } + COLUMN cS8d3 (DesktopWidth: 4) { + PLUGGABLEWIDGET 'com.mendix.widget.web.image.Image' myImage1 ( + datasource: 'imageUrl', + imageUrl: 'https://placehold.co/300x200?text=MDL+Image+Widget' + ) + } + } + + -- 8e: Menu + Tree + Selection + ROW rowS8e { + COLUMN cS8e1 (DesktopWidth: 4) { + PLUGGABLEWIDGET 'com.mendix.widget.web.popupmenu.PopupMenu' myPopupMenu1 { + CONTAINER menuTrigger { + ACTIONBUTTON btnPopup (Caption: 'Open Menu', Action: CLOSE_PAGE, ButtonStyle: Primary) + } + } + } + COLUMN cS8e2 (DesktopWidth: 4) { + -- TreeNode mode 1: text header, flat list (no children) + PLUGGABLEWIDGET 'com.mendix.widget.web.treenode.TreeNode' treeText ( + DataSource: DATABASE FROM WidgetDemo.DemoItem, + headerType: 'text', + headerCaption: '{Title}', + hasChildren: false, + showIcon: 'no' + ) + } + COLUMN cS8e3 (DesktopWidth: 4) { + PLUGGABLEWIDGET 'com.mendix.widget.web.selectionhelper.SelectionHelper' selHelper1 (renderStyle: 'checkbox') + } + } + ROW rowS8e2 { + COLUMN cS8e2a (DesktopWidth: 6) { + -- TreeNode mode 2: text header, expandable with children content + PLUGGABLEWIDGET 'com.mendix.widget.web.treenode.TreeNode' treeNested ( + DataSource: DATABASE FROM WidgetDemo.DemoItem, + headerType: 'text', + headerCaption: '{Title} ({Code})', + hasChildren: true, + startExpanded: true, + showIcon: 'left' + ) { + CONTAINER children { + DYNAMICTEXT treeChildText (Content: 'Score: {1} | Amount: {2}', ContentParams: [{1} = Score, {2} = Amount]) + } + } + } + COLUMN cS8e2b (DesktopWidth: 6) { + -- TreeNode mode 3: custom header with widgets + PLUGGABLEWIDGET 'com.mendix.widget.web.treenode.TreeNode' treeCustom ( + DataSource: DATABASE FROM WidgetDemo.DemoItem, + headerType: 'custom', + hasChildren: false + ) { + CONTAINER headerContent { + DYNAMICTEXT treeHdrTitle (Content: '{1}', RenderMode: H5, ContentParams: [{1} = Title]) + DYNAMICTEXT treeHdrMeta (Content: 'Priority: {1}', ContentParams: [{1} = Priority]) + } + } + } + } + + -- 8f: Language + Accessibility + ROW rowS8f { + COLUMN cS8f1 (DesktopWidth: 6) { + PLUGGABLEWIDGET 'com.mendix.widget.web.languageselector.LanguageSelector' langSel1 ( + DataSource: DATABASE FROM WidgetDemo.DemoItem, + languageCaption: '''en_US''' + ) + } + COLUMN cS8f2 (DesktopWidth: 6) { + PLUGGABLEWIDGET 'com.mendix.widget.web.accessibilityhelper.AccessibilityHelper' accHelper1 (targetSelector: '.mx-name-accHelper1') { + DYNAMICTEXT accBody (Content: 'Accessible content area with ARIA attributes') + } + } + } + + -- 8g: Maps + Charts + ROW rowS8g { + COLUMN cS8g1 (DesktopWidth: 6) { + PLUGGABLEWIDGET 'com.mendix.widget.custom.Maps.Maps' maps1 ( + apiKey: 'demo-key', + geodecodeApiKey: 'demo-key', + googleMapId: 'default' + ) + } + COLUMN cS8g2 (DesktopWidth: 6) { + PLUGGABLEWIDGET 'com.mendix.widget.web.areachart.AreaChart' areaChart1 + } + } + } +} + +GRANT VIEW ON PAGE WidgetDemo.WidgetDemo_Showcase TO WidgetDemo.User; diff --git a/mdl-examples/widgetdemo/03-seed-and-navigate.mdl b/mdl-examples/widgetdemo/03-seed-and-navigate.mdl new file mode 100644 index 0000000..93234ec --- /dev/null +++ b/mdl-examples/widgetdemo/03-seed-and-navigate.mdl @@ -0,0 +1,98 @@ +-- WidgetDemo: seed data microflow + navigation +-- This script is part of the WidgetDemo module bootstrap (run after 01 and 02) + +/** + * Seeds DemoItem data and opens the showcase page. + * Skips creation if data already exists. + */ +CREATE OR REPLACE MICROFLOW WidgetDemo.SeedAndShowShowcase () +BEGIN + @position(200, 200) + RETRIEVE $Existing FROM WidgetDemo.DemoItem LIMIT 1; + + @position(400, 200) + IF $Existing != empty THEN + @position(600, 100) + SHOW PAGE WidgetDemo.WidgetDemo_Showcase(DemoItem: $Existing); + @position(800, 100) + RETURN; + END IF; + + @position(400, 400) + $Item1 = CREATE WidgetDemo.DemoItem ( + Title = 'Wireless Headphones', + Description = 'Noise-cancelling over-ear headphones with 30h battery', + Code = 'WH-001', + IsActive = true, + Score = 85, + Amount = 299.99, + DateCreated = [%CurrentDateTime%], + Progress = 0.75, + Rating = 4, + Notes = 'Best seller in electronics category', + ImageUrl = 'https://placehold.co/200x200?text=Headphones'); + + @position(400, 500) + $Item2 = CREATE WidgetDemo.DemoItem ( + Title = 'Smart Watch Pro', + Description = 'Health tracking with ECG and blood oxygen monitoring', + Code = 'SW-002', + IsActive = true, + Score = 92, + Amount = 499.00, + DateCreated = [%CurrentDateTime%], + Progress = 0.30, + Rating = 5, + Notes = 'Pending supplier confirmation', + ImageUrl = 'https://placehold.co/200x200?text=Watch'); + + @position(400, 600) + $Item3 = CREATE WidgetDemo.DemoItem ( + Title = 'USB-C Hub', + Description = '7-in-1 hub with HDMI and SD card reader', + Code = 'UH-003', + IsActive = false, + Score = 45, + Amount = 49.95, + DateCreated = [%CurrentDateTime%], + Progress = 1.0, + Rating = 3, + Notes = 'Shipped to warehouse', + ImageUrl = 'https://placehold.co/200x200?text=Hub'); + + @position(400, 700) + $Item4 = CREATE WidgetDemo.DemoItem ( + Title = 'Mechanical Keyboard', + Description = 'Cherry MX Blue switches, RGB backlight', + Code = 'MK-004', + IsActive = true, + Score = 78, + Amount = 159.00, + DateCreated = [%CurrentDateTime%], + Progress = 0.50, + Rating = 4, + Notes = 'Restocking in progress', + ImageUrl = 'https://placehold.co/200x200?text=Keyboard'); + + @position(400, 800) + $Item5 = CREATE WidgetDemo.DemoItem ( + Title = 'Portable Charger', + Description = '20000mAh power bank with fast charging', + Code = 'PC-005', + IsActive = false, + Score = 30, + Amount = 35.50, + DateCreated = [%CurrentDateTime%], + Progress = 1.0, + Rating = 2, + Notes = 'Discontinued model', + ImageUrl = 'https://placehold.co/200x200?text=Charger'); + + @position(600, 400) + SHOW PAGE WidgetDemo.WidgetDemo_Showcase(DemoItem: $Item1); + @position(800, 400) + RETURN; +END; +/ + +GRANT EXECUTE ON MICROFLOW WidgetDemo.SeedAndShowShowcase TO WidgetDemo.User; diff --git a/mdl-examples/widgetdemo/WIDGET_ANALYSIS.md b/mdl-examples/widgetdemo/WIDGET_ANALYSIS.md new file mode 100644 index 0000000..0e3c9e3 --- /dev/null +++ b/mdl-examples/widgetdemo/WIDGET_ANALYSIS.md @@ -0,0 +1,104 @@ +# WidgetDemo_Showcase Widget Analysis + +Analysis of all widget instances in `WidgetDemo.WidgetDemo_Showcase`, classified by Mendix widget type. + +## Summary + +| Category | Count | Description | +|----------|-------|-------------| +| Native | 62 | Built-in Mendix platform widgets (`Forms$*`, `Pages$*`) | +| Pluggable (dedicated) | 9 | Pluggable widgets with specialized DESCRIBE output | +| Pluggable (generic) | 22 | Pluggable widgets using generic `PLUGGABLEWIDGET` output | +| Pluggable (misclassified) | 2 | Pluggable widgets rendered with native-style names | +| **Total** | **95** | | + +## Native Widgets (62) + +Standard Mendix platform widgets serialized as `Forms$*` / `Pages$*` BSON types. + +| Widget Type | Count | Instances | +|-------------|-------|-----------| +| DYNAMICTEXT | 26 | tS1, txtH1–H6, txtPar, tS2, ctnL, ctnD, gbL, tS3, tS4, tTitle, tCode, tAmount, tS5, tS6, lvT, lvD, tS7, nHt, nLt, nSt, tS8, tS8d | +| CONTAINER | 9 | hdrS1–S8, ctnDemo | +| ACTIONBUTTON | 9 | btnDef, btnPri, btnSuc, btnWar, btnDng, btnNewDG, btnSv, btnCn | +| LAYOUTGRID | 3 | gridMain, gForm, gPlug | +| DATAVIEW | 2 | dvDetail, dvPluggable | +| TEXTBOX | 2 | txtTitle, txtCode | +| DATEPICKER | 2 | dpCreated, dpDue | +| GROUPBOX | 1 | gbDemo | +| TABCONTAINER | 1 | tabDemo (rendered as `Forms$TabControl` comment) | +| CHECKBOX | 1 | cbActive | +| TEXTAREA | 1 | taNotes | +| RADIOBUTTONS | 1 | rbStatus | +| DATAGRID | 1 | dgItems | +| LISTVIEW | 1 | lvItems | +| NAVIGATIONLIST | 1 | navQ | +| SNIPPETCALL | 1 | snCall | + +Not counted as widgets (structural elements): ROW (24), COLUMN (varied), FOOTER (1), CONTROLBAR (1), FILTER (1), TEMPLATE (1), ITEM (3), DATAGRID COLUMN (5). + +## Pluggable Widgets — Dedicated DESCRIBE (9) + +Pluggable widgets recognized by `isKnownCustomWidgetType()` with specialized output format. + +| DESCRIBE Name | Widget ID | Count | Instances | +|---------------|-----------|-------|-----------| +| GALLERY | `com.mendix.widget.web.gallery.Gallery` | 1 | galItems | +| COMBOBOX | `com.mendix.widget.web.combobox.Combobox` | 2 | cbPri, cbCat | +| TEXTFILTER | `com.mendix.widget.web.datagridtextfilter.DatagridTextFilter` | 1 | tfTitle | +| DROPDOWNFILTER | `com.mendix.widget.web.datagriddropdownfilter.DatagridDropdownFilter` | 1 | dfCat | +| NUMBERFILTER | `com.mendix.widget.web.datagridnumberfilter.DatagridNumberFilter` | 1 | nfAmt | +| DATEFILTER | `com.mendix.widget.web.datagriddatefilter.DatagridDateFilter` | 1 | dtfDate | +| DROPDOWNSORT | `com.mendix.widget.web.dropdownsort.DropdownSort` | 1 | ddSort1 | +| IMAGE | `com.mendix.widget.web.image.Image` | 1 | myImage1 | + +## Pluggable Widgets — Generic PLUGGABLEWIDGET (22) + +Pluggable widgets rendered with full widget ID via `extractExplicitProperties()`. + +| Widget ID | Short Name | Count | Instances | +|-----------|------------|-------|-----------| +| `com.mendix.widget.custom.switch.Switch` | Switch | 1 | switch1 | +| `com.mendix.widget.custom.starrating.StarRating` | StarRating | 1 | rating1 | +| `com.mendix.widget.custom.slider.Slider` | Slider | 1 | slider1 | +| `com.mendix.widget.custom.RangeSlider.RangeSlider` | RangeSlider | 1 | rangeSlider1 | +| `com.mendix.widget.web.barcodescanner.BarcodeScanner` | BarcodeScanner | 1 | scanner1 | +| `com.mendix.widget.web.htmlelement.HTMLElement` | HTMLElement | 1 | htmlElem1 | +| `com.mendix.widget.custom.badge.Badge` | Badge | 1 | badge1 | +| `com.mendix.widget.custom.progressbar.ProgressBar` | ProgressBar | 1 | progBar1 | +| `com.mendix.widget.custom.progresscircle.ProgressCircle` | ProgressCircle | 1 | progCirc1 | +| `com.mendix.widget.web.accordion.Accordion` | Accordion | 1 | accordion1 | +| `com.mendix.widget.web.tooltip.Tooltip` | Tooltip | 1 | myTooltip1 | +| `com.mendix.widget.web.timeline.Timeline` | Timeline | 2 | timelineText, timelineCustom | +| `com.mendix.widget.web.videoplayer.VideoPlayer` | VideoPlayer | 1 | videoPlayer1 | +| `com.mendix.widget.web.popupmenu.PopupMenu` | PopupMenu | 1 | myPopupMenu1 | +| `com.mendix.widget.web.treenode.TreeNode` | TreeNode | 3 | treeText, treeNested, treeCustom | +| `com.mendix.widget.web.selectionhelper.SelectionHelper` | SelectionHelper | 1 | selHelper1 | +| `com.mendix.widget.web.languageselector.LanguageSelector` | LanguageSelector | 1 | langSel1 | +| `com.mendix.widget.web.accessibilityhelper.AccessibilityHelper` | AccessibilityHelper | 1 | accHelper1 | +| `com.mendix.widget.custom.Maps.Maps` | Maps | 1 | maps1 | +| `com.mendix.widget.web.areachart.AreaChart` | AreaChart | 1 | areaChart1 | + +## Pluggable Widgets — Misclassified as Native (2) + +These are pluggable widgets (`CustomWidgets$CustomWidget` in BSON) but DESCRIBE renders them with native-style short names instead of `PLUGGABLEWIDGET 'widget.id'` syntax. This is a DESCRIBE bug — the widget type mapping in `customWidgetTypeShortNames` produces a native-looking name. + +| DESCRIBE Name | Widget ID | Count | Instances | +|---------------|-----------|-------|-----------| +| BADGEBUTTON | `com.mendix.widget.custom.badgebutton.BadgeButton` | 1 | badgeBtn1 | +| FIELDSET | `com.mendix.widget.web.fieldset.Fieldset` | 1 | fieldset1 | + +## Widget Feature Coverage + +| Feature | Widgets Demonstrating It | +|---------|--------------------------| +| DataSource (database) | galItems, dgItems, lvItems, timelineText, timelineCustom, treeText, treeNested, treeCustom, langSel1 | +| DataSource (parameter) | dvDetail, dvPluggable | +| Attribute binding | txtTitle, txtCode, dpCreated, dpDue, cbPri, cbCat, cbActive, taNotes, rbStatus, switch1, rating1, slider1, rangeSlider1, scanner1 | +| TextTemplate `{Param}` | tTitle, tCode, tAmount, lvT, lvD | +| Child widget slots | htmlElem1, fieldset1, myTooltip1, timelineCustom, myPopupMenu1, treeNested, treeCustom, accHelper1 | +| Explicit properties | All 22 generic PLUGGABLEWIDGET instances | +| Action binding | btnDef–btnDng, btnNewDG, btnSv, btnCn | +| Filter widgets | tfTitle, dfCat, nfAmt, dtfDate, ddSort1 | +| Selection | galItems (Single) | +| DesignProperties/Class/Style | hdrS1–S8, ctnDemo | From 0b0c1c01f7783d7c6996a21e2324723fb3e2c8d8 Mon Sep 17 00:00:00 2001 From: engalar Date: Mon, 6 Apr 2026 17:26:32 +0800 Subject: [PATCH 2/3] fix: address PR #69 review feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove WIDGET_ANALYSIS.md (working document, not permanent docs) - Renumber files sequentially: 01b→02, 02→03, 03→04 - Remove nonsensical LanguageSelector datasource (DemoItem entity) --- .../{01b-snippet.mdl => 02-snippet.mdl} | 2 +- ...showcase-page.mdl => 03-showcase-page.mdl} | 5 +- ...-navigate.mdl => 04-seed-and-navigate.mdl} | 2 +- mdl-examples/widgetdemo/WIDGET_ANALYSIS.md | 104 ------------------ 4 files changed, 3 insertions(+), 110 deletions(-) rename mdl-examples/widgetdemo/{01b-snippet.mdl => 02-snippet.mdl} (78%) rename mdl-examples/widgetdemo/{02-showcase-page.mdl => 03-showcase-page.mdl} (99%) rename mdl-examples/widgetdemo/{03-seed-and-navigate.mdl => 04-seed-and-navigate.mdl} (99%) delete mode 100644 mdl-examples/widgetdemo/WIDGET_ANALYSIS.md diff --git a/mdl-examples/widgetdemo/01b-snippet.mdl b/mdl-examples/widgetdemo/02-snippet.mdl similarity index 78% rename from mdl-examples/widgetdemo/01b-snippet.mdl rename to mdl-examples/widgetdemo/02-snippet.mdl index dee5923..f2babfd 100644 --- a/mdl-examples/widgetdemo/01b-snippet.mdl +++ b/mdl-examples/widgetdemo/02-snippet.mdl @@ -1,4 +1,4 @@ --- WidgetDemo: Button showcase snippet (referenced by 02-showcase-page) +-- WidgetDemo: Button showcase snippet (referenced by 03-showcase-page) CREATE SNIPPET WidgetDemo.SNIPPET_ButtonShowcase { ACTIONBUTTON btnInfo (Caption: 'Info Button', Action: CLOSE_PAGE, ButtonStyle: Info) diff --git a/mdl-examples/widgetdemo/02-showcase-page.mdl b/mdl-examples/widgetdemo/03-showcase-page.mdl similarity index 99% rename from mdl-examples/widgetdemo/02-showcase-page.mdl rename to mdl-examples/widgetdemo/03-showcase-page.mdl index f0228be..c0b3ba6 100644 --- a/mdl-examples/widgetdemo/02-showcase-page.mdl +++ b/mdl-examples/widgetdemo/03-showcase-page.mdl @@ -425,10 +425,7 @@ CREATE OR REPLACE PAGE WidgetDemo.WidgetDemo_Showcase ( -- 8f: Language + Accessibility ROW rowS8f { COLUMN cS8f1 (DesktopWidth: 6) { - PLUGGABLEWIDGET 'com.mendix.widget.web.languageselector.LanguageSelector' langSel1 ( - DataSource: DATABASE FROM WidgetDemo.DemoItem, - languageCaption: '''en_US''' - ) + PLUGGABLEWIDGET 'com.mendix.widget.web.languageselector.LanguageSelector' langSel1 } COLUMN cS8f2 (DesktopWidth: 6) { PLUGGABLEWIDGET 'com.mendix.widget.web.accessibilityhelper.AccessibilityHelper' accHelper1 (targetSelector: '.mx-name-accHelper1') { diff --git a/mdl-examples/widgetdemo/03-seed-and-navigate.mdl b/mdl-examples/widgetdemo/04-seed-and-navigate.mdl similarity index 99% rename from mdl-examples/widgetdemo/03-seed-and-navigate.mdl rename to mdl-examples/widgetdemo/04-seed-and-navigate.mdl index 93234ec..6a614da 100644 --- a/mdl-examples/widgetdemo/03-seed-and-navigate.mdl +++ b/mdl-examples/widgetdemo/04-seed-and-navigate.mdl @@ -1,5 +1,5 @@ -- WidgetDemo: seed data microflow + navigation --- This script is part of the WidgetDemo module bootstrap (run after 01 and 02) +-- This script is part of the WidgetDemo module bootstrap (run after 01, 02 and 03) /** * Seeds DemoItem data and opens the showcase page. diff --git a/mdl-examples/widgetdemo/WIDGET_ANALYSIS.md b/mdl-examples/widgetdemo/WIDGET_ANALYSIS.md deleted file mode 100644 index 0e3c9e3..0000000 --- a/mdl-examples/widgetdemo/WIDGET_ANALYSIS.md +++ /dev/null @@ -1,104 +0,0 @@ -# WidgetDemo_Showcase Widget Analysis - -Analysis of all widget instances in `WidgetDemo.WidgetDemo_Showcase`, classified by Mendix widget type. - -## Summary - -| Category | Count | Description | -|----------|-------|-------------| -| Native | 62 | Built-in Mendix platform widgets (`Forms$*`, `Pages$*`) | -| Pluggable (dedicated) | 9 | Pluggable widgets with specialized DESCRIBE output | -| Pluggable (generic) | 22 | Pluggable widgets using generic `PLUGGABLEWIDGET` output | -| Pluggable (misclassified) | 2 | Pluggable widgets rendered with native-style names | -| **Total** | **95** | | - -## Native Widgets (62) - -Standard Mendix platform widgets serialized as `Forms$*` / `Pages$*` BSON types. - -| Widget Type | Count | Instances | -|-------------|-------|-----------| -| DYNAMICTEXT | 26 | tS1, txtH1–H6, txtPar, tS2, ctnL, ctnD, gbL, tS3, tS4, tTitle, tCode, tAmount, tS5, tS6, lvT, lvD, tS7, nHt, nLt, nSt, tS8, tS8d | -| CONTAINER | 9 | hdrS1–S8, ctnDemo | -| ACTIONBUTTON | 9 | btnDef, btnPri, btnSuc, btnWar, btnDng, btnNewDG, btnSv, btnCn | -| LAYOUTGRID | 3 | gridMain, gForm, gPlug | -| DATAVIEW | 2 | dvDetail, dvPluggable | -| TEXTBOX | 2 | txtTitle, txtCode | -| DATEPICKER | 2 | dpCreated, dpDue | -| GROUPBOX | 1 | gbDemo | -| TABCONTAINER | 1 | tabDemo (rendered as `Forms$TabControl` comment) | -| CHECKBOX | 1 | cbActive | -| TEXTAREA | 1 | taNotes | -| RADIOBUTTONS | 1 | rbStatus | -| DATAGRID | 1 | dgItems | -| LISTVIEW | 1 | lvItems | -| NAVIGATIONLIST | 1 | navQ | -| SNIPPETCALL | 1 | snCall | - -Not counted as widgets (structural elements): ROW (24), COLUMN (varied), FOOTER (1), CONTROLBAR (1), FILTER (1), TEMPLATE (1), ITEM (3), DATAGRID COLUMN (5). - -## Pluggable Widgets — Dedicated DESCRIBE (9) - -Pluggable widgets recognized by `isKnownCustomWidgetType()` with specialized output format. - -| DESCRIBE Name | Widget ID | Count | Instances | -|---------------|-----------|-------|-----------| -| GALLERY | `com.mendix.widget.web.gallery.Gallery` | 1 | galItems | -| COMBOBOX | `com.mendix.widget.web.combobox.Combobox` | 2 | cbPri, cbCat | -| TEXTFILTER | `com.mendix.widget.web.datagridtextfilter.DatagridTextFilter` | 1 | tfTitle | -| DROPDOWNFILTER | `com.mendix.widget.web.datagriddropdownfilter.DatagridDropdownFilter` | 1 | dfCat | -| NUMBERFILTER | `com.mendix.widget.web.datagridnumberfilter.DatagridNumberFilter` | 1 | nfAmt | -| DATEFILTER | `com.mendix.widget.web.datagriddatefilter.DatagridDateFilter` | 1 | dtfDate | -| DROPDOWNSORT | `com.mendix.widget.web.dropdownsort.DropdownSort` | 1 | ddSort1 | -| IMAGE | `com.mendix.widget.web.image.Image` | 1 | myImage1 | - -## Pluggable Widgets — Generic PLUGGABLEWIDGET (22) - -Pluggable widgets rendered with full widget ID via `extractExplicitProperties()`. - -| Widget ID | Short Name | Count | Instances | -|-----------|------------|-------|-----------| -| `com.mendix.widget.custom.switch.Switch` | Switch | 1 | switch1 | -| `com.mendix.widget.custom.starrating.StarRating` | StarRating | 1 | rating1 | -| `com.mendix.widget.custom.slider.Slider` | Slider | 1 | slider1 | -| `com.mendix.widget.custom.RangeSlider.RangeSlider` | RangeSlider | 1 | rangeSlider1 | -| `com.mendix.widget.web.barcodescanner.BarcodeScanner` | BarcodeScanner | 1 | scanner1 | -| `com.mendix.widget.web.htmlelement.HTMLElement` | HTMLElement | 1 | htmlElem1 | -| `com.mendix.widget.custom.badge.Badge` | Badge | 1 | badge1 | -| `com.mendix.widget.custom.progressbar.ProgressBar` | ProgressBar | 1 | progBar1 | -| `com.mendix.widget.custom.progresscircle.ProgressCircle` | ProgressCircle | 1 | progCirc1 | -| `com.mendix.widget.web.accordion.Accordion` | Accordion | 1 | accordion1 | -| `com.mendix.widget.web.tooltip.Tooltip` | Tooltip | 1 | myTooltip1 | -| `com.mendix.widget.web.timeline.Timeline` | Timeline | 2 | timelineText, timelineCustom | -| `com.mendix.widget.web.videoplayer.VideoPlayer` | VideoPlayer | 1 | videoPlayer1 | -| `com.mendix.widget.web.popupmenu.PopupMenu` | PopupMenu | 1 | myPopupMenu1 | -| `com.mendix.widget.web.treenode.TreeNode` | TreeNode | 3 | treeText, treeNested, treeCustom | -| `com.mendix.widget.web.selectionhelper.SelectionHelper` | SelectionHelper | 1 | selHelper1 | -| `com.mendix.widget.web.languageselector.LanguageSelector` | LanguageSelector | 1 | langSel1 | -| `com.mendix.widget.web.accessibilityhelper.AccessibilityHelper` | AccessibilityHelper | 1 | accHelper1 | -| `com.mendix.widget.custom.Maps.Maps` | Maps | 1 | maps1 | -| `com.mendix.widget.web.areachart.AreaChart` | AreaChart | 1 | areaChart1 | - -## Pluggable Widgets — Misclassified as Native (2) - -These are pluggable widgets (`CustomWidgets$CustomWidget` in BSON) but DESCRIBE renders them with native-style short names instead of `PLUGGABLEWIDGET 'widget.id'` syntax. This is a DESCRIBE bug — the widget type mapping in `customWidgetTypeShortNames` produces a native-looking name. - -| DESCRIBE Name | Widget ID | Count | Instances | -|---------------|-----------|-------|-----------| -| BADGEBUTTON | `com.mendix.widget.custom.badgebutton.BadgeButton` | 1 | badgeBtn1 | -| FIELDSET | `com.mendix.widget.web.fieldset.Fieldset` | 1 | fieldset1 | - -## Widget Feature Coverage - -| Feature | Widgets Demonstrating It | -|---------|--------------------------| -| DataSource (database) | galItems, dgItems, lvItems, timelineText, timelineCustom, treeText, treeNested, treeCustom, langSel1 | -| DataSource (parameter) | dvDetail, dvPluggable | -| Attribute binding | txtTitle, txtCode, dpCreated, dpDue, cbPri, cbCat, cbActive, taNotes, rbStatus, switch1, rating1, slider1, rangeSlider1, scanner1 | -| TextTemplate `{Param}` | tTitle, tCode, tAmount, lvT, lvD | -| Child widget slots | htmlElem1, fieldset1, myTooltip1, timelineCustom, myPopupMenu1, treeNested, treeCustom, accHelper1 | -| Explicit properties | All 22 generic PLUGGABLEWIDGET instances | -| Action binding | btnDef–btnDng, btnNewDG, btnSv, btnCn | -| Filter widgets | tfTitle, dfCat, nfAmt, dtfDate, ddSort1 | -| Selection | galItems (Single) | -| DesignProperties/Class/Style | hdrS1–S8, ctnDemo | From 8a33ee15f14828ce6ec6f7955b1adbd5871df976 Mon Sep 17 00:00:00 2001 From: engalar Date: Mon, 6 Apr 2026 19:33:44 +0800 Subject: [PATCH 3/3] fix: widget-demo scripts self-contained and mx-check clean MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add CREATE MODULE and CREATE MODULE ROLE to 01-domain-model.mdl - Add Attributes to DROPDOWNFILTER dfCat (was missing required binding) - Replace LanguageSelector with placeholder (requires runtime config) - Add ALTER USER ROLE to assign WidgetDemo.User to Administrator/User - Fix dropdownfilter.def.json: attrChoice "linked" → "custom" for MDL Co-Authored-By: Claude Opus 4.6 (1M context) --- mdl-examples/widgetdemo/01-domain-model.mdl | 3 +++ mdl-examples/widgetdemo/03-showcase-page.mdl | 6 ++++-- mdl-examples/widgetdemo/04-seed-and-navigate.mdl | 3 +++ sdk/widgets/definitions/dropdownfilter.def.json | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/mdl-examples/widgetdemo/01-domain-model.mdl b/mdl-examples/widgetdemo/01-domain-model.mdl index 35e9361..c19f70a 100644 --- a/mdl-examples/widgetdemo/01-domain-model.mdl +++ b/mdl-examples/widgetdemo/01-domain-model.mdl @@ -1,6 +1,9 @@ -- WidgetDemo: self-contained domain model (no external dependencies) -- Provides entities and enumerations for the widget showcase page. +CREATE MODULE WidgetDemo; +CREATE MODULE ROLE WidgetDemo.User; + CREATE ENUMERATION WidgetDemo.ENUM_Priority ( LOW 'Low', MEDIUM 'Medium', diff --git a/mdl-examples/widgetdemo/03-showcase-page.mdl b/mdl-examples/widgetdemo/03-showcase-page.mdl index c0b3ba6..8d00347 100644 --- a/mdl-examples/widgetdemo/03-showcase-page.mdl +++ b/mdl-examples/widgetdemo/03-showcase-page.mdl @@ -104,7 +104,7 @@ CREATE OR REPLACE PAGE WidgetDemo.WidgetDemo_Showcase ( ) { FILTER flt1 { TEXTFILTER tfTitle (Attributes: [Title, Code]) - DROPDOWNFILTER dfCat + DROPDOWNFILTER dfCat (Attributes: [Category]) NUMBERFILTER nfAmt (Attributes: [Amount]) DATEFILTER dtfDate (Attributes: [DateCreated]) PLUGGABLEWIDGET 'com.mendix.widget.web.dropdownsort.DropdownSort' ddSort1 @@ -425,7 +425,9 @@ CREATE OR REPLACE PAGE WidgetDemo.WidgetDemo_Showcase ( -- 8f: Language + Accessibility ROW rowS8f { COLUMN cS8f1 (DesktopWidth: 6) { - PLUGGABLEWIDGET 'com.mendix.widget.web.languageselector.LanguageSelector' langSel1 + -- LanguageSelector requires runtime data source and caption — omitted (needs running app) + -- PLUGGABLEWIDGET 'com.mendix.widget.web.languageselector.LanguageSelector' langSel1 + DYNAMICTEXT langPlaceholder (Content: '[LanguageSelector — requires runtime config]', RenderMode: Paragraph) } COLUMN cS8f2 (DesktopWidth: 6) { PLUGGABLEWIDGET 'com.mendix.widget.web.accessibilityhelper.AccessibilityHelper' accHelper1 (targetSelector: '.mx-name-accHelper1') { diff --git a/mdl-examples/widgetdemo/04-seed-and-navigate.mdl b/mdl-examples/widgetdemo/04-seed-and-navigate.mdl index 6a614da..822b9da 100644 --- a/mdl-examples/widgetdemo/04-seed-and-navigate.mdl +++ b/mdl-examples/widgetdemo/04-seed-and-navigate.mdl @@ -96,3 +96,6 @@ END; / GRANT EXECUTE ON MICROFLOW WidgetDemo.SeedAndShowShowcase TO WidgetDemo.User; + +ALTER USER ROLE Administrator ADD MODULE ROLES (WidgetDemo.User); +ALTER USER ROLE User ADD MODULE ROLES (WidgetDemo.User); diff --git a/sdk/widgets/definitions/dropdownfilter.def.json b/sdk/widgets/definitions/dropdownfilter.def.json index c0b99ff..3640df4 100644 --- a/sdk/widgets/definitions/dropdownfilter.def.json +++ b/sdk/widgets/definitions/dropdownfilter.def.json @@ -4,7 +4,7 @@ "templateFile": "datagrid-dropdown-filter.json", "defaultEditable": "Always", "propertyMappings": [ - {"propertyKey": "attrChoice", "value": "linked", "operation": "primitive"}, + {"propertyKey": "attrChoice", "value": "custom", "operation": "primitive"}, {"propertyKey": "attributes", "source": "Attributes", "operation": "attributeObjects"}, {"propertyKey": "defaultFilter", "source": "FilterType", "operation": "primitive"} ]