Skip to content

feat(mdl): close MDL-NDSL gap — missing page/widget properties #32

@engalar

Description

@engalar

Summary

MDL currently captures widget structure and basic data bindings well, but drops many non-structural properties that affect runtime behavior and styling. Analysis of two pages reveals the scale of information loss:

Page NDSL lines MDL lines Loss ratio
WorkflowBaseline.Page (simple) 229 26 88%
WorkflowCommons.TaskDashboard (complex) 31,799 30 99.9%

The complex page exposes additional categories of gaps beyond simple property omissions: entire widget types are dropped (TabControl, ActionButton, CustomWidget internals).

Gap Analysis

P0 — Entire Widget Types Dropped

These widgets appear in NDSL but MDL emits only a comment or omits entirely:

Widget Type NDSL Representation Current MDL Impact
Forms$TabControl Full tab container with pages, badges, default page -- Forms$TabControl (name) comment Tabs completely lost
Forms$TabPage Caption, badge template, conditional visibility, child widgets Not emitted Tab content lost
Forms$ActionButton Caption, icon, action, style, visibility, tooltip Not emitted (inside dropped parents) Interactive elements lost
CustomWidgets$CustomWidget (DataGrid2 columns, cell widgets) Full property tree with data sources, XPath, templates Opaque blob or omitted Grid column definitions, cell renderers lost

Proposed syntax for TabControl:

TABCONTROL tabContainer1 (Class: 'tab-lined cardtabs-tabs') {
  TAB 'My open tasks' (
    Badge: '{1}' USING $currentObject/MyOpenTaskCount
  ) {
    DATAGRID2 dataGrid24 (
      DataSource: XPATH System.WorkflowUserTask
        WHERE "[WorkflowUserTask_Assignees = '[%CurrentUser%]'][State = 'InProgress']",
      SortBy: EndTime DESC
    ) {
      -- column definitions...
    }
  }
  TAB 'All open tasks' (Badge: '{1}' USING $currentObject/AllOpenTaskCount) { ... }
  TAB 'Unassigned tasks' (Badge: '{1}' USING $currentObject/UnassignedTaskCount) { ... }
  TAB 'Completed tasks' (Badge: '{1}' USING $currentObject/CompletedTaskCount) { ... }
}

Proposed syntax for ActionButton:

ACTIONBUTTON actionButton16 (
  Caption: 'Assign to me',
  RenderType: Button,
  ButtonStyle: Default,
  VISIBLE IF '$currentObject/System.WorkflowUserTask_Assignees = empty',
  ON CLICK CALL MICROFLOW WorkflowCommons.ACT_UserTask_AssignToMe_UpdateTaskCount
)

ACTIONBUTTON actionButton23 (
  Icon: GlyphIcon(57944),
  RenderType: Link,
  ON CLICK OPEN_USER_TASK (AssignOnOpen: true)
)

P0 — Affects Functional Correctness (roundtrip data loss)

NDSL Property Current MDL Proposed Syntax
Appearance.Class (page-level) Not supported Class: 'task-page' in page header
ConditionalVisibilitySettings Not supported VISIBLE IF '$currentObject/Assignees = empty'
ConditionalEditabilitySettings Not supported EDITABLE IF '$Entity/Status = Draft'
DataView Editability Not supported Editable: ReadOnly / Editable: Conditional
Column Weight (numeric) Only AutoFill DesktopWidth: 8 (numeric 1-12)
Column PhoneWeight / TabletWeight Not supported PhoneWidth: 12, TabletWidth: 6
XPathConstraint (multi-line, complex) Partially supported Full multi-line XPath in data sources
GridSortBar / GridSortItem Not supported SortBy: EndTime DESC, StartTime ASC

P1 — Common Usage Scenarios

NDSL Property Current MDL Proposed Syntax
DesignProperties (Atlas UI) Not supported DesignProps: {Spacing: {margin-bottom: 'L'}}
DynamicClasses Not supported DynamicClass: 'if(...)'
Style (inline CSS) Not supported Style: 'color: red; padding: 8px'
Container OnClickAction Not supported ON CLICK CALL Module.Microflow
LayoutGrid Width Not supported Width: FullWidth
DataView ReadOnlyStyle Not supported ReadOnlyStyle: Text
DataView LabelWidth Not supported LabelWidth: 3
DataView ShowFooter Not supported ShowFooter: false
Documentation Not supported Documentation: '...' in header
Row HAlign / VAlign Not supported HAlign: Center, VAlign: Middle
Row SpacingBetweenColumns Not supported Spacing: false
ActionButton Icon Not supported Icon: GlyphIcon(57944)
ActionButton ButtonStyle Not supported ButtonStyle: Success / Primary / Default
ActionButton RenderType Not supported RenderType: Link / Button
ActionButton Tooltip Not supported Tooltip: 'Open task details'
ActionButton AriaRole Not supported AriaRole: Button
ClientTemplate (badge/caption) Not supported Badge: '{1}' USING $obj/Count

P2 — Completeness

NDSL Property Current MDL Proposed Syntax
Page Url Not supported URL: '/my-page'
Page Excluded Not supported EXCLUDED flag
Page ExportLevel Not supported EXPORT Hidden / EXPORT Usable
Page Autofocus Not supported Autofocus: FirstEditableWidget
Page MarkAsUsed Not supported MARK_AS_USED flag
Popup settings Not supported POPUP (Width: 600, Height: 400, ...)
Container RenderMode Not supported RenderAs: Article / RenderAs: Section
Widget TabIndex Not supported TabIndex: 3
TabPage RefreshOnShow Not supported RefreshOnShow: true
DataView NoEntityMessage Not supported NoEntityMessage: 'No data'
MicroflowSettings ProgressBar Not supported ProgressBar: Blocking

Proposed MDL Example — Full Fidelity TaskDashboard

Below is a condensed but representative example showing all proposed syntax extensions applied to WorkflowCommons.TaskDashboard:

CREATE PAGE WorkflowCommons.TaskDashboard (
  Title: 'My task dashboard',
  Layout: Atlas_Core.Atlas_Default,
  Folder: 'UseMe/Pages',
  Autofocus: DesktopOnly,
  EXPORT Hidden
) {
  LAYOUTGRID layoutGrid1 {
    ROW row1 {
      COLUMN col1 (DesktopWidth: AutoFill) {
        DATAVIEW dataView6 (
          DataSource: MICROFLOW WorkflowCommons.DS_TaskDashboard,
          Editable: Always,
          ReadOnlyStyle: Control,
          ShowFooter: false
        ) {
          SNIPPETCALL snippetCall2 (Snippet: WorkflowCommons.Snip_TaskDashboard_Header)

          LAYOUTGRID layoutGrid9 {
            ROW row1 (Spacing: true) {
              COLUMN col1 (DesktopWidth: AutoFill) {
                SNIPPETCALL snippetCall3 (Snippet: WorkflowCommons.Snip_TaskDashboard_Numbers)

                CONTAINER container6 (Class: 'card cardtabs') {
                  DATAVIEW dataView2 (
                    DataSource: MICROFLOW WorkflowCommons.DS_TaskCount,
                    ShowFooter: false
                  ) {
                    TABCONTROL tabContainer1 (Class: 'tab-lined cardtabs-tabs') {
                      TAB 'My open tasks' (
                        Badge: '{1}' USING $currentObject/MyOpenTaskCount
                      ) {
                        DATAGRID2 dataGrid24 (
                          DataSource: XPATH System.WorkflowUserTask
                            WHERE "[WorkflowUserTask_Assignees = '[%CurrentUser%]']
                                   [State = 'InProgress'
                                    and WorkflowUserTask_Workflow/System.Workflow
                                        [State != 'Incompatible' and State != 'Failed']]
                                   [not(WorkflowUserTaskOutcome_WorkflowUserTask
                                        /System.WorkflowUserTaskOutcome
                                        /WorkflowUserTaskOutcome_User
                                        = '[%CurrentUser%]')]",
                          SortBy: EndTime DESC
                        ) {
                          -- DataGrid2 column definitions (CustomWidget properties)
                          CONTAINER container3 (Class: 'controlgroup') {
                            ACTIONBUTTON actionButton16 (
                              Caption: 'Assign to me',
                              RenderType: Button,
                              DesignProps: { Spacing: { margin-right: 'M' } },
                              VISIBLE IF '$currentObject/WorkflowUserTask_Assignees = empty',
                              ON CLICK CALL MICROFLOW
                                WorkflowCommons.ACT_UserTask_AssignToMe_UpdateTaskCount
                            )
                            ACTIONBUTTON actionButton23 (
                              Icon: GlyphIcon(57944),
                              RenderType: Link,
                              ON CLICK OPEN_USER_TASK (AssignOnOpen: true)
                            )
                          }
                        }
                      }

                      TAB 'All open tasks' (
                        Badge: '{1}' USING $currentObject/AllOpenTaskCount
                      ) {
                        DATAGRID2 dataGrid23 (
                          DataSource: XPATH System.WorkflowUserTask
                            WHERE "[WorkflowUserTask_Assignees = '[%CurrentUser%]'
                                    or WorkflowUserTask_TargetUsers = '[%CurrentUser%]'
                                    or WorkflowUserTask_TargetGroups
                                       /System.WorkflowGroup/WorkflowGroup_User
                                       = '[%CurrentUser%]']
                                   [State = 'InProgress' ...]",
                          SortBy: StartTime DESC
                        ) { ... }
                      }

                      TAB 'Unassigned tasks' (
                        Badge: '{1}' USING $currentObject/UnassignedTaskCount
                      ) { ... }

                      TAB 'Completed tasks' (
                        Badge: '{1}' USING $currentObject/CompletedTaskCount
                      ) { ... }
                    }
                  }
                }
              }

              COLUMN col2 (DesktopWidth: AutoFill) {
                SNIPPETCALL snippetCall1 (
                  Snippet: WorkflowCommons.Snip_DashboardContext_Timeline
                )
              }
            }
          }
        }
      }
    }
  }
}

GRANT VIEW ON PAGE WorkflowCommons.TaskDashboard TO WorkflowCommons.User;

Key improvements over current MDL output

  1. TabControl/TabPage — full tab structure with captions and badge templates instead of -- comment
  2. ActionButton — caption, icon, action type, conditional visibility, design properties
  3. ConditionalVisibility — expression-based widget visibility (VISIBLE IF)
  4. ClientTemplate'{1}' USING $obj/Attr for parameterized text templates
  5. DataView propertiesEditable, ReadOnlyStyle, ShowFooter, LabelWidth
  6. Column responsive widthsPhoneWidth, TabletWidth, numeric DesktopWidth
  7. DesignProperties — Atlas UI spacing/styling as structured properties
  8. GridSortBarSortBy: EndTime DESC for default sort order
  9. XPath constraints — multi-line complex XPath with association traversal
  10. Page metadataAutofocus, EXPORT, URL, Documentation

Implementation Priority

  1. Phase 1 — Structure: TabControl, TabPage, ActionButton (restores dropped widgets)
  2. Phase 2 — Behavior: ConditionalVisibility, Editability, OnClickAction (restores runtime logic)
  3. Phase 3 — Styling: DesignProperties, responsive column widths, ButtonStyle (restores visual design)
  4. Phase 4 — Completeness: Page metadata, GridSortBar, ClientTemplate, remaining P2 items

Statistics

Based on WorkflowCommons.TaskDashboard:

  • 36 CustomWidget instances dropped (DataGrid2 columns, cells, actions)
  • 6 ActionButtons dropped (microflow calls, user task actions, conditional visibility)
  • 4 TabPages dropped (with badge templates showing task counts)
  • 1 TabControl dropped (entire tab navigation)
  • Result: MDL shows a skeleton of 2 snippets + 1 container, while the actual page has a full task dashboard with filterable tabs, sortable grids, action buttons, and conditional UI

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions