Skip to content

Commit 3cdac49

Browse files
committed
feat(executor): MDL executor for workflows, calculated attributes, demo user entity
- Add SHOW/DESCRIBE WORKFLOW with full MDL-formatted output - Add CREATE/DROP WORKFLOW executing AST against BSON writer - Add GRANT/REVOKE EXECUTE ON WORKFLOW for security access control - Add CALCULATED BY <microflow> support in CREATE/ALTER ENTITY - Add ENTITY clause support in CREATE DEMO USER - Add workflow entries to catalog (builder_modules, builder_strings) - Extend LSP completions for workflow keywords - Update help topics (entity, security, workflow) - Fix DESCRIBE WORKFLOW round-trip: USER TASK due date, boundary events, multi-user task, CALL MICROFLOW WITH parameter mappings
1 parent 29a3fa1 commit 3cdac49

22 files changed

Lines changed: 1985 additions & 46 deletions

cmd/mxcli/docker/build.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,7 @@ func ensureDemoUsers(projectPath string, w io.Writer) error {
700700
}
701701
}
702702

703-
if err := writer.AddDemoUser(ps.ID, "admin", "Admin123!", []string{roleName}); err != nil {
703+
if err := writer.AddDemoUser(ps.ID, "admin", "Admin123!", "", []string{roleName}); err != nil {
704704
return fmt.Errorf("creating demo user: %w", err)
705705
}
706706

cmd/mxcli/help_topics/entity.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ Attribute Constraints:
3434
UNIQUE - Value must be unique
3535
UNIQUE ERROR 'msg' - Unique with custom error message
3636
DEFAULT value - Default value (true, false, 0, 'text')
37+
CALCULATED BY Module.Microflow - Calculated attribute (persistent entities only)
38+
CALCULATED Module.Microflow - Same as above (BY is optional)
39+
CALCULATED - Marks as calculated (bind microflow in Studio Pro)
40+
41+
Note: CALCULATED attributes are only supported on persistent entities.
3742

3843
Complete Example:
3944
CREATE PERSISTENT ENTITY MyModule.Customer (
@@ -48,7 +53,10 @@ Complete Example:
4853
CreatedAt: DateTime,
4954

5055
-- Enumeration reference
51-
CustomerType: Enumeration(MyModule.CustomerType)
56+
CustomerType: Enumeration(MyModule.CustomerType),
57+
58+
-- Calculated attribute (value computed by microflow)
59+
FullName: String(200) CALCULATED BY MyModule.CalcFullName
5260
)
5361
INDEX (Email)
5462
COMMENT 'Stores customer information';

cmd/mxcli/help_topics/security.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ PROJECT SECURITY:
4343
ALTER PROJECT SECURITY DEMO USERS ON|OFF;
4444

4545
DEMO USERS:
46-
CREATE DEMO USER '<name>' PASSWORD '<pass>' (<userrole> [, ...]);
46+
CREATE DEMO USER '<name>' PASSWORD '<pass>' [ENTITY Module.Entity] (<userrole> [, ...]);
4747
DROP DEMO USER '<name>';
4848

4949
Examples:

cmd/mxcli/help_topics/workflow.txt

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,55 @@ CROSS-REFERENCES
4747
- user_targeting: user task targeting microflow
4848
- admin_page: workflow overview page
4949

50+
CREATE WORKFLOW
51+
--------------
52+
53+
CREATE [OR MODIFY] WORKFLOW Module.WorkflowName
54+
PARAMETER $Context: Module.Entity
55+
[OVERVIEW PAGE Module.OverviewPage]
56+
[DUE DATE '<expression>']
57+
BEGIN
58+
<activities>
59+
END WORKFLOW;
60+
61+
Activity types:
62+
USER TASK <name> '<caption>'
63+
[PAGE Module.Page]
64+
[TARGETING MICROFLOW Module.MF | TARGETING XPATH '<xpath>']
65+
[ENTITY Module.Entity]
66+
[OUTCOMES '<outcome1>' { <activities> } '<outcome2>' { <activities> }];
67+
68+
CALL MICROFLOW Module.MF [COMMENT '<text>']
69+
[OUTCOMES '<outcome>' { <activities> } ...];
70+
71+
CALL WORKFLOW Module.WF [COMMENT '<text>'];
72+
73+
DECISION ['<caption>'] [COMMENT '<text>']
74+
OUTCOMES '<outcome>' { <activities> } ...;
75+
76+
PARALLEL SPLIT [COMMENT '<text>']
77+
PATH 1 { <activities> }
78+
PATH 2 { <activities> };
79+
80+
JUMP TO <activity-name> [COMMENT '<text>'];
81+
WAIT FOR TIMER ['<expression>'] [COMMENT '<text>'];
82+
WAIT FOR NOTIFICATION [COMMENT '<text>'];
83+
END;
84+
85+
Example:
86+
CREATE WORKFLOW Module.ApprovalFlow
87+
PARAMETER $Context: Module.Request
88+
BEGIN
89+
USER TASK ReviewTask 'Review the request'
90+
PAGE Module.ReviewPage
91+
OUTCOMES 'Approve' { } 'Reject' { };
92+
END WORKFLOW;
93+
94+
DROP WORKFLOW
95+
-------------
96+
97+
DROP WORKFLOW Module.WorkflowName;
98+
5099
CODE NAVIGATION
51100
---------------
52101

cmd/mxcli/lsp_completions_gen.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mdl/catalog/builder_modules.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ func (b *Builder) buildEntities() error {
198198
isCalculated := 0
199199
if attr.Value != nil {
200200
defaultValue = attr.Value.DefaultValue
201-
if attr.Value.MicroflowID != "" {
201+
if attr.Value.MicroflowName != "" || attr.Value.MicroflowID != "" {
202202
isCalculated = 1
203203
}
204204
}

mdl/catalog/builder_strings.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package catalog
44

55
import (
66
"github.com/mendixlabs/mxcli/sdk/microflows"
7+
"github.com/mendixlabs/mxcli/sdk/workflows"
78
)
89

910
// buildStrings extracts string literals from documents into the FTS5 strings table.
@@ -89,10 +90,85 @@ func (b *Builder) buildStrings() error {
8990
}
9091
}
9192

93+
// Extract from workflows — using cached list
94+
wfList, err := b.cachedWorkflows()
95+
if err == nil {
96+
for _, wf := range wfList {
97+
moduleID := b.hierarchy.findModuleID(wf.ContainerID)
98+
moduleName := b.hierarchy.getModuleName(moduleID)
99+
qn := moduleName + "." + wf.Name
100+
101+
if wf.WorkflowName != "" {
102+
insert(qn, "WORKFLOW", wf.WorkflowName, "workflow_name", moduleName)
103+
}
104+
if wf.WorkflowDescription != "" {
105+
insert(qn, "WORKFLOW", wf.WorkflowDescription, "workflow_description", moduleName)
106+
}
107+
if wf.Documentation != "" {
108+
insert(qn, "WORKFLOW", wf.Documentation, "documentation", moduleName)
109+
}
110+
111+
if wf.Flow != nil {
112+
extractWorkflowFlowStrings(wf.Flow, qn, moduleName, insert)
113+
}
114+
}
115+
}
116+
92117
b.report("strings", count)
93118
return nil
94119
}
95120

121+
// extractWorkflowFlowStrings extracts strings from workflow activities recursively.
122+
func extractWorkflowFlowStrings(flow *workflows.Flow, qn, moduleName string, insert func(string, string, string, string, string)) {
123+
for _, act := range flow.Activities {
124+
if act.GetCaption() != "" {
125+
insert(qn, "WORKFLOW", act.GetCaption(), "activity_caption", moduleName)
126+
}
127+
128+
switch a := act.(type) {
129+
case *workflows.UserTask:
130+
if a.TaskName != "" {
131+
insert(qn, "WORKFLOW", a.TaskName, "task_name", moduleName)
132+
}
133+
if a.TaskDescription != "" {
134+
insert(qn, "WORKFLOW", a.TaskDescription, "task_description", moduleName)
135+
}
136+
for _, outcome := range a.Outcomes {
137+
if outcome.Caption != "" {
138+
insert(qn, "WORKFLOW", outcome.Caption, "outcome_caption", moduleName)
139+
}
140+
if outcome.Flow != nil {
141+
extractWorkflowFlowStrings(outcome.Flow, qn, moduleName, insert)
142+
}
143+
}
144+
case *workflows.SystemTask:
145+
for _, outcome := range a.Outcomes {
146+
if f := outcome.GetFlow(); f != nil {
147+
extractWorkflowFlowStrings(f, qn, moduleName, insert)
148+
}
149+
}
150+
case *workflows.CallMicroflowTask:
151+
for _, outcome := range a.Outcomes {
152+
if f := outcome.GetFlow(); f != nil {
153+
extractWorkflowFlowStrings(f, qn, moduleName, insert)
154+
}
155+
}
156+
case *workflows.ExclusiveSplitActivity:
157+
for _, outcome := range a.Outcomes {
158+
if f := outcome.GetFlow(); f != nil {
159+
extractWorkflowFlowStrings(f, qn, moduleName, insert)
160+
}
161+
}
162+
case *workflows.ParallelSplitActivity:
163+
for _, outcome := range a.Outcomes {
164+
if outcome.Flow != nil {
165+
extractWorkflowFlowStrings(outcome.Flow, qn, moduleName, insert)
166+
}
167+
}
168+
}
169+
}
170+
}
171+
96172
// extractActivityStrings extracts string literals from microflow/nanoflow activities.
97173
func extractActivityStrings(oc *microflows.MicroflowObjectCollection, qn, objType, moduleName string, insert func(string, string, string, string, string)) {
98174
if oc == nil {

0 commit comments

Comments
 (0)