Skip to content

Commit 761ffb7

Browse files
committed
allow for dynamic registering of custom expression functions using enums
1 parent e776dfb commit 761ffb7

File tree

6 files changed

+249
-22
lines changed

6 files changed

+249
-22
lines changed

apps/vps-web/src/main.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ if (url.pathname === '/run-flow') {
5858
resizeObserver.observe(container);
5959
const editor = monaco.editor.create(container, {
6060
fixedOverflowWidgets: true,
61-
value: formField.value.toString(),
61+
value: (formField.value ?? '').toString(),
6262
language: editorLanguage ?? 'html',
6363
scrollBeyondLastLine: false,
6464
scrollbar: {

examples-test-flows/enum-example.json

Lines changed: 190 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
"nodes": [
99
{
1010
"id": "691421ad-a30d-44f2-abd0-072bd8468b89",
11-
"x": 422.3632394523364,
12-
"y": -43.64197821262764,
13-
"width": 119.99997976878514,
14-
"height": 108.00000474727274,
11+
"x": 422.36322859151466,
12+
"y": -43.64198877999732,
13+
"width": 119.99991909724973,
14+
"height": 108.00000511505314,
1515
"nodeType": "Shape",
1616
"nodeInfo": {
1717
"type": "scope-variable",
@@ -38,8 +38,8 @@
3838
},
3939
{
4040
"id": "a21c19c9-7b8d-4a39-9a21-d2ece057e904",
41-
"x": 907.0955307570923,
42-
"y": 66.03645436235243,
41+
"x": 907.0955434054317,
42+
"y": 66.03642587758885,
4343
"width": 199.99993896484375,
4444
"height": 116,
4545
"nodeType": "Shape",
@@ -78,16 +78,16 @@
7878
"nodeInfo": {
7979
"type": "value",
8080
"formValues": {
81-
"value": "test2"
81+
"value": "test1"
8282
}
8383
}
8484
},
8585
{
8686
"id": "e26bac56-73b4-4d5a-9532-fbeafd131a1c",
8787
"x": 1333.6522439657404,
8888
"y": 95.33927303098446,
89-
"width": 119.99999995410255,
90-
"height": 55.9999801828729,
89+
"width": 119.99982168783924,
90+
"height": 55.999988221226005,
9191
"nodeType": "Shape",
9292
"nodeInfo": {
9393
"type": "show-input",
@@ -99,10 +99,114 @@
9999
"isSettingsPopup": true
100100
}
101101
},
102+
{
103+
"id": "10f4b4ce-5b61-4ebd-a80b-e3c0d3796b67",
104+
"x": 989.945805765898,
105+
"y": 285.22262206301843,
106+
"width": 200,
107+
"height": 100,
108+
"nodeType": "Shape",
109+
"nodeInfo": {
110+
"type": "expression",
111+
"formValues": {
112+
"expression": "abc()",
113+
"inputType": "number"
114+
},
115+
"showFormOnlyInPopup": true,
116+
"isSettingsPopup": true
117+
}
118+
},
119+
{
120+
"id": "aa7308c6-cc80-49e3-af24-cacb6a6aed80",
121+
"x": 775.3502968188762,
122+
"y": 629.0476960256525,
123+
"width": 234.0546875,
124+
"height": 136,
125+
"nodeType": "Shape",
126+
"nodeInfo": {
127+
"type": "register-expression-function-node",
128+
"formValues": {
129+
"customFunctionCode": "() => {\n return 42;\n};",
130+
"functionName": "abc"
131+
},
132+
"nodeCannotBeReplaced": true,
133+
"showFormOnlyInPopup": true,
134+
"useInCompositionOnly": false,
135+
"keepPopupOpenAfterUpdate": true,
136+
"isRunOnStart": true
137+
}
138+
},
139+
{
140+
"id": "aac6e617-e3cf-4871-bc4e-d6fb4b648ce9",
141+
"x": 1484.4121306900088,
142+
"y": 306.3676723935463,
143+
"width": 120.00001650666022,
144+
"height": 55.999988221226005,
145+
"nodeType": "Shape",
146+
"nodeInfo": {
147+
"type": "show-value",
148+
"formValues": {
149+
"append": "",
150+
"decimals": "0",
151+
"name": ""
152+
},
153+
"initializeOnStartFlow": true,
154+
"isSettingsPopup": true
155+
}
156+
},
157+
{
158+
"id": "23c18e94-eb0d-4ee2-b95b-8ebd477f868a",
159+
"x": 785.9378613966832,
160+
"y": 808.5298046751491,
161+
"width": 234.0546875,
162+
"height": 136,
163+
"nodeType": "Shape",
164+
"nodeInfo": {
165+
"type": "register-expression-function-node",
166+
"formValues": {
167+
"customFunctionCode": "() => {\n return 84;\n};",
168+
"functionName": "abc"
169+
},
170+
"nodeCannotBeReplaced": true,
171+
"showFormOnlyInPopup": true,
172+
"useInCompositionOnly": false,
173+
"keepPopupOpenAfterUpdate": true,
174+
"isRunOnStart": true
175+
}
176+
},
177+
{
178+
"id": "2e033383-6ad4-4605-914f-6210c2dfc635",
179+
"x": 71.78178204830057,
180+
"y": 737.2590892215512,
181+
"width": 200.00001525878906,
182+
"height": 116,
183+
"nodeType": "Shape",
184+
"nodeInfo": {
185+
"type": "observe-variable",
186+
"formValues": {
187+
"variableName": "enum"
188+
}
189+
}
190+
},
191+
{
192+
"id": "2d168f87-8bc5-4f54-8f2a-2447704d1c88",
193+
"x": 410.7244579937511,
194+
"y": 712.9522688726519,
195+
"width": 200.00003051757812,
196+
"height": 160,
197+
"nodeType": "Shape",
198+
"nodeInfo": {
199+
"type": "split-by-case",
200+
"formValues": {
201+
"case1": "test1",
202+
"case2": "test2"
203+
}
204+
}
205+
},
102206
{
103207
"id": "b49d6ed9-09a3-4daa-b6c4-32f5b05f6d15",
104-
"x": 1107.095469721936,
105-
"y": 124.03645436235243,
208+
"x": 1107.0954823702755,
209+
"y": 124.03642587758885,
106210
"endX": 1333.6522439657404,
107211
"endY": 125.33927303098446,
108212
"startNodeId": "a21c19c9-7b8d-4a39-9a21-d2ece057e904",
@@ -128,6 +232,81 @@
128232
"nodeType": "Connection",
129233
"layer": 1,
130234
"nodeInfo": {}
235+
},
236+
{
237+
"id": "df895ef6-bafb-4da5-9c27-7fd9d94dbd39",
238+
"x": 1189.945805765898,
239+
"y": 335.22262206301843,
240+
"endX": 1484.4121306900088,
241+
"endY": 336.3676723935463,
242+
"startNodeId": "10f4b4ce-5b61-4ebd-a80b-e3c0d3796b67",
243+
"endNodeId": "aac6e617-e3cf-4871-bc4e-d6fb4b648ce9",
244+
"startThumbName": "output",
245+
"endThumbName": "input",
246+
"lineType": "BezierCubic",
247+
"nodeType": "Connection",
248+
"layer": 1,
249+
"nodeInfo": {}
250+
},
251+
{
252+
"id": "e7bbd4cc-c796-4db5-90e6-00368711977b",
253+
"x": 271.7817973070896,
254+
"y": 795.2590892215512,
255+
"endX": 410.7244579937511,
256+
"endY": 792.9522688726519,
257+
"startNodeId": "2e033383-6ad4-4605-914f-6210c2dfc635",
258+
"endNodeId": "2d168f87-8bc5-4f54-8f2a-2447704d1c88",
259+
"startThumbName": "output",
260+
"endThumbName": "input",
261+
"lineType": "BezierCubic",
262+
"nodeType": "Connection",
263+
"layer": 1,
264+
"nodeInfo": {}
265+
},
266+
{
267+
"id": "1bb547e4-5825-42b6-b775-cbd2148ab12d",
268+
"x": 610.7244885113292,
269+
"y": 753.9522688726519,
270+
"endX": 775.3502968188762,
271+
"endY": 697.0476960256525,
272+
"startNodeId": "2d168f87-8bc5-4f54-8f2a-2447704d1c88",
273+
"endNodeId": "aa7308c6-cc80-49e3-af24-cacb6a6aed80",
274+
"startThumbName": "output1",
275+
"endThumbName": "input",
276+
"lineType": "BezierCubic",
277+
"nodeType": "Connection",
278+
"layer": 1,
279+
"nodeInfo": {}
280+
},
281+
{
282+
"id": "b221af89-1569-408b-b287-7cd8f54ec42b",
283+
"x": 610.7244885113292,
284+
"y": 793.9522688726519,
285+
"endX": 785.9378613966832,
286+
"endY": 876.5298046751491,
287+
"startNodeId": "2d168f87-8bc5-4f54-8f2a-2447704d1c88",
288+
"endNodeId": "23c18e94-eb0d-4ee2-b95b-8ebd477f868a",
289+
"startThumbName": "output2",
290+
"endThumbName": "input",
291+
"lineType": "BezierCubic",
292+
"nodeType": "Connection",
293+
"layer": 1,
294+
"nodeInfo": {}
295+
},
296+
{
297+
"id": "aba9aedf-16cc-4336-9015-0e2625630456",
298+
"x": 724.342257706599,
299+
"y": 341.7768752377074,
300+
"endX": 989.945805765898,
301+
"endY": 335.22262206301843,
302+
"startNodeId": "054255b7-f15b-4210-bf4f-2046e4e17515",
303+
"endNodeId": "10f4b4ce-5b61-4ebd-a80b-e3c0d3796b67",
304+
"startThumbName": "output",
305+
"endThumbName": "input",
306+
"lineType": "BezierCubic",
307+
"nodeType": "Connection",
308+
"layer": 1,
309+
"nodeInfo": {}
131310
}
132311
]
133312
}

libs/visual-programming-system/src/canvas-app/flow-core.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export interface IFlowCore {
7171
scopeId?: string,
7272
runCounter?: any,
7373
isInitializing?: boolean
74-
) => void;
74+
) => boolean;
7575

7676
getVariables: (scopeId?: string) => Record<string, any>;
7777

@@ -266,8 +266,11 @@ export class FlowCore implements IFlowCore {
266266
this.tempVariables[scopeId][variableName] = data;
267267
} else if (variableName && this.variables[variableName]) {
268268
const result = this.variables[variableName].setData(data, scopeId);
269-
if (isInitializing || !result) {
270-
return;
269+
if (!result) {
270+
return false;
271+
}
272+
if (isInitializing) {
273+
return true;
271274
}
272275
const dataToObserver = this.variables[variableName].getData(
273276
undefined,
@@ -280,6 +283,7 @@ export class FlowCore implements IFlowCore {
280283
});
281284
}
282285
}
286+
return true;
283287
};
284288

285289
getVariables = (scopeId?: string) => {

libs/web-flow-executor/src/nodes/register-expression-function.tsx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
NodeTask,
88
NodeTaskFactory,
99
Rect,
10+
ThumbConnectionType,
11+
ThumbType,
1012
createJSXElement,
1113
visualNodeFactory,
1214
} from '@devhelpr/visual-programming-system';
@@ -19,7 +21,16 @@ const labelName = 'Register Expression Function';
1921
export const registerExpressionFunctionNodeName =
2022
'register-expression-function-node';
2123
const familyName = 'flow-canvas';
22-
const thumbs: any[] = [];
24+
const thumbs = [
25+
{
26+
thumbType: ThumbType.EndConnectorCenter,
27+
thumbIndex: 0,
28+
connectionType: ThumbConnectionType.end,
29+
color: 'white',
30+
label: ' ',
31+
name: 'input',
32+
},
33+
];
2334

2435
export const getRegisterExpressionFunctionNode: NodeTaskFactory<NodeInfo> = (
2536
updated: (
@@ -118,7 +129,10 @@ export const getRegisterExpressionFunctionNode: NodeTaskFactory<NodeInfo> = (
118129
fieldName: 'customFunctionCode',
119130
label: 'Code',
120131
editorLanguage: 'javascript',
121-
value: values?.['customFunctionCode'] ?? '',
132+
value:
133+
values?.['customFunctionCode'] ??
134+
`() => {
135+
};`,
122136
onChange: (value: string) => {
123137
if (!node.nodeInfo) {
124138
return;
@@ -147,7 +161,14 @@ export const getRegisterExpressionFunctionNode: NodeTaskFactory<NodeInfo> = (
147161
if (rect && rect.resize) {
148162
rect?.resize();
149163
}
150-
164+
if (node.nodeInfo && !node.nodeInfo.formValues?.['customFunctionCode']) {
165+
node.nodeInfo.formValues = {
166+
...node.nodeInfo.formValues,
167+
['customFunctionCode']: `() => {
168+
return 42;
169+
};`,
170+
};
171+
}
151172
if (textElement) {
152173
textElement.textContent =
153174
node.nodeInfo?.formValues?.['functionName'] ?? '';

libs/web-flow-executor/src/nodes/scoped-variable.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { showGridData, StructureInfo } from './data-viewers/grid';
1818
export const scopeVariableNodeName = 'scope-variable';
1919
type FieldTypes = 'value' | 'dictionary' | 'array' | 'grid' | 'enum';
2020

21+
const borderErrorColor = 'border-red-500';
2122
export const getScopedVariable =
2223
(isGlobal = false) =>
2324
(updated: () => void): NodeTask<NodeInfo> => {
@@ -439,9 +440,15 @@ export const getScopedVariable =
439440
clearTimeout(timeout);
440441
timeout = undefined;
441442
}
442-
(
443-
componentWrapper?.domElement as unknown as HTMLElement
444-
)?.classList?.add('border-white');
443+
if (result) {
444+
(
445+
componentWrapper?.domElement as unknown as HTMLElement
446+
)?.classList?.add('border-white');
447+
} else {
448+
(
449+
componentWrapper?.domElement as unknown as HTMLElement
450+
)?.classList?.add(borderErrorColor);
451+
}
445452
(
446453
componentWrapper?.domElement as unknown as HTMLElement
447454
)?.classList?.remove('border-transparent');
@@ -451,6 +458,10 @@ export const getScopedVariable =
451458
componentWrapper?.domElement as unknown as HTMLElement
452459
)?.classList?.remove('border-white');
453460

461+
(
462+
componentWrapper?.domElement as unknown as HTMLElement
463+
)?.classList?.remove(borderErrorColor);
464+
454465
(
455466
componentWrapper?.domElement as unknown as HTMLElement
456467
)?.classList?.add('border-transparent');
@@ -963,6 +974,9 @@ export const getScopedVariable =
963974
(
964975
componentWrapper?.domElement as unknown as HTMLElement
965976
)?.classList?.remove('border-white');
977+
(
978+
componentWrapper?.domElement as unknown as HTMLElement
979+
)?.classList?.remove(borderErrorColor);
966980
(
967981
componentWrapper?.domElement as unknown as HTMLElement
968982
)?.classList?.add('border-transparent');

0 commit comments

Comments
 (0)