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
5 changes: 3 additions & 2 deletions .mxcli/widgets/gallery.def.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
{
"propertyKey": "itemSelection",
"source": "Selection",
"operation": "selection"
"operation": "selection",
"default": "Single"
},
{
"propertyKey": "itemSelectionMode",
Expand Down Expand Up @@ -78,7 +79,7 @@
},
{
"propertyKey": "filtersPlaceholder",
"mdlContainer": "FILTERSPLACEHOLDER",
"mdlContainer": "FILTER",
"operation": "widgets"
}
]
Expand Down
5 changes: 4 additions & 1 deletion cmd/mxcli/cmd_widget.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package main
import (
"encoding/json"
"fmt"
"log"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -195,7 +196,9 @@ func runWidgetList(cmd *cobra.Command, args []string) error {
// Load user definitions if project path available
projectPath, _ := cmd.Flags().GetString("project")
if projectPath != "" {
_ = registry.LoadUserDefinitions(projectPath)
if err := registry.LoadUserDefinitions(projectPath); err != nil {
log.Printf("warning: loading user widget definitions: %v", err)
}
}

defs := registry.All()
Expand Down
4 changes: 2 additions & 2 deletions cmd/mxcli/lsp_completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package main

import (
"context"
"log"
"strings"

"github.com/mendixlabs/mxcli/mdl/executor"
Expand Down Expand Up @@ -89,8 +90,7 @@ func (s *mdlServer) widgetRegistryCompletions() []protocol.CompletionItem {
return
}
if err := registry.LoadUserDefinitions(s.mprPath); err != nil {
// Non-fatal: user definitions are optional
_ = err
log.Printf("warning: loading user widget definitions for LSP: %v", err)
}
for _, def := range registry.All() {
s.widgetCompletionItems = append(s.widgetCompletionItems, protocol.CompletionItem{
Expand Down
1 change: 1 addition & 0 deletions docs-site/book.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ git-repository-url = "https://github.com/mendixlabs/mxcli"
edit-url-template = "https://github.com/mendixlabs/mxcli/edit/main/docs-site/src/{path}"
site-url = "/mxcli/"
additional-css = ["theme/custom.css"]
additional-js = ["theme/mermaid-init.js"]

[output.html.search]
enable = true
Expand Down
24 changes: 24 additions & 0 deletions docs-site/theme/mermaid-init.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Render mermaid diagrams in mdbook.
// mdbook renders ```mermaid blocks as <code class="language-mermaid"> inside <pre>.
// This script loads mermaid from CDN and converts them to rendered SVG diagrams.
(function () {
var blocks = document.querySelectorAll('code.language-mermaid');
if (blocks.length === 0) return;

var script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js';
script.onload = function () {
mermaid.initialize({ startOnLoad: false, theme: 'default' });

blocks.forEach(function (code, i) {
var pre = code.parentElement;
var container = document.createElement('div');
container.className = 'mermaid';
container.textContent = code.textContent;
pre.parentElement.replaceChild(container, pre);
});

mermaid.run();
};
document.head.appendChild(script);
})();
24 changes: 12 additions & 12 deletions docs/plans/2026-03-25-pluggable-widget-engine-design.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
# Pluggable Widget Engine: 声明式 Widget 构建系统
# Pluggable Widget Engine: Declarative Widget Build System

**Date**: 2026-03-25
**Status**: Implemented

## Problem

当前每个 pluggable widget 都需要硬编码一个 Go builder 函数(`buildComboBoxV3`, `buildGalleryV3` 等),加上 switch case 注册。新增一个 widget 需要改 4 个地方:
Each pluggable widget currently requires a hardcoded Go builder function (`buildComboBoxV3`, `buildGalleryV3`, etc.) plus a switch-case registration. Adding a new widget requires changes in 4 places:

1. `sdk/pages/pages_widgets_advanced.go` — 添加 WidgetID 常量
2. `sdk/widgets/templates/` — 添加 JSON 模板
3. `mdl/executor/cmd_pages_builder_v3_pluggable.go` — 写专属 build 函数(50-200 行)
4. `mdl/executor/cmd_pages_builder_v3.go` — `buildWidgetV3()` switch 中添加 case
1. `sdk/pages/pages_widgets_advanced.go` — Add WidgetID constant
2. `sdk/widgets/templates/` — Add JSON template
3. `mdl/executor/cmd_pages_builder_v3_pluggable.go` — Write a dedicated build function (50-200 lines)
4. `mdl/executor/cmd_pages_builder_v3.go` — Add case in `buildWidgetV3()` switch

这导致:
- 用户无法自行添加 pluggable widget 支持
- 大量重复代码(30+ builder 函数共享 ~80% 骨架)
- 维护成本随 widget 数量线性增长
This causes:
- Users cannot add pluggable widget support on their own
- Significant code duplication (30+ builder functions sharing ~80% boilerplate)
- Maintenance cost grows linearly with widget count

## Solution: 声明式 Widget 定义 + 通用构建引擎
## Solution: Declarative Widget Definitions + Generic Build Engine

### Architecture

Expand Down Expand Up @@ -126,7 +126,7 @@ Gallery (with child slots):
"childSlots": [
{"propertyKey": "content", "mdlContainer": "TEMPLATE", "operation": "widgets"},
{"propertyKey": "emptyPlaceholder", "mdlContainer": "EMPTYPLACEHOLDER", "operation": "widgets"},
{"propertyKey": "filtersPlaceholder", "mdlContainer": "FILTERSPLACEHOLDER", "operation": "widgets"}
{"propertyKey": "filtersPlaceholder", "mdlContainer": "FILTER", "operation": "widgets"}
]
}
```
Expand Down
Loading