@nocobase/flow-engine 2.0.0-beta.2 → 2.0.0-beta.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/BlockScopedFlowEngine.js +0 -1
- package/lib/JSRunner.d.ts +6 -0
- package/lib/JSRunner.js +2 -1
- package/lib/ViewScopedFlowEngine.js +3 -0
- package/lib/acl/Acl.js +13 -3
- package/lib/components/dnd/gridDragPlanner.d.ts +1 -0
- package/lib/components/dnd/gridDragPlanner.js +53 -1
- package/lib/components/settings/wrappers/component/SwitchWithTitle.js +2 -1
- package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +11 -3
- package/lib/components/variables/VariableInput.js +8 -2
- package/lib/data-source/index.js +6 -0
- package/lib/executor/FlowExecutor.d.ts +2 -1
- package/lib/executor/FlowExecutor.js +156 -22
- package/lib/flowContext.d.ts +4 -1
- package/lib/flowContext.js +176 -107
- package/lib/flowEngine.d.ts +21 -0
- package/lib/flowEngine.js +38 -0
- package/lib/flowSettings.js +12 -10
- package/lib/index.d.ts +3 -0
- package/lib/index.js +16 -0
- package/lib/models/CollectionFieldModel.d.ts +1 -0
- package/lib/models/CollectionFieldModel.js +3 -2
- package/lib/models/flowModel.d.ts +7 -0
- package/lib/models/flowModel.js +66 -1
- package/lib/provider.js +7 -6
- package/lib/resources/baseRecordResource.d.ts +5 -0
- package/lib/resources/baseRecordResource.js +24 -0
- package/lib/resources/multiRecordResource.d.ts +1 -0
- package/lib/resources/multiRecordResource.js +11 -4
- package/lib/resources/singleRecordResource.js +2 -0
- package/lib/resources/sqlResource.d.ts +1 -0
- package/lib/resources/sqlResource.js +8 -3
- package/lib/runjs-context/contexts/base.js +10 -4
- package/lib/runjsLibs.d.ts +28 -0
- package/lib/runjsLibs.js +532 -0
- package/lib/scheduler/ModelOperationScheduler.d.ts +2 -0
- package/lib/scheduler/ModelOperationScheduler.js +21 -21
- package/lib/types.d.ts +15 -0
- package/lib/utils/createCollectionContextMeta.js +1 -0
- package/lib/utils/index.d.ts +2 -0
- package/lib/utils/index.js +10 -0
- package/lib/utils/params-resolvers.js +16 -9
- package/lib/utils/resolveModuleUrl.d.ts +58 -0
- package/lib/utils/resolveModuleUrl.js +65 -0
- package/lib/utils/runjsModuleLoader.d.ts +58 -0
- package/lib/utils/runjsModuleLoader.js +422 -0
- package/lib/utils/runjsTemplateCompat.d.ts +35 -0
- package/lib/utils/runjsTemplateCompat.js +743 -0
- package/lib/utils/safeGlobals.d.ts +5 -9
- package/lib/utils/safeGlobals.js +129 -17
- package/lib/views/createViewMeta.d.ts +0 -7
- package/lib/views/createViewMeta.js +19 -70
- package/lib/views/index.d.ts +1 -2
- package/lib/views/index.js +4 -3
- package/lib/views/useDialog.js +8 -3
- package/lib/views/useDrawer.js +7 -2
- package/lib/views/usePage.d.ts +4 -0
- package/lib/views/usePage.js +43 -6
- package/lib/views/usePopover.js +4 -1
- package/lib/views/viewEvents.d.ts +17 -0
- package/lib/views/viewEvents.js +90 -0
- package/package.json +4 -4
- package/src/BlockScopedFlowEngine.ts +2 -5
- package/src/JSRunner.ts +8 -1
- package/src/ViewScopedFlowEngine.ts +4 -0
- package/src/__tests__/createViewMeta.popup.test.ts +62 -1
- package/src/__tests__/flowEngine.dataSourceDirty.test.ts +63 -0
- package/src/__tests__/flowSettings.open.test.tsx +69 -15
- package/src/__tests__/provider.test.tsx +0 -5
- package/src/__tests__/runjsExternalLibs.test.ts +242 -0
- package/src/__tests__/runjsLibsLazyLoading.test.ts +44 -0
- package/src/__tests__/runjsPreprocessDefault.test.ts +49 -0
- package/src/acl/Acl.tsx +3 -3
- package/src/components/__tests__/gridDragPlanner.test.ts +141 -1
- package/src/components/dnd/gridDragPlanner.ts +60 -0
- package/src/components/settings/wrappers/component/SwitchWithTitle.tsx +2 -1
- package/src/components/settings/wrappers/component/__tests__/InlineControls.test.tsx +74 -0
- package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +11 -3
- package/src/components/settings/wrappers/contextual/__tests__/DefaultSettingsIcon.test.tsx +63 -4
- package/src/components/variables/VariableInput.tsx +8 -2
- package/src/data-source/index.ts +6 -0
- package/src/executor/FlowExecutor.ts +193 -23
- package/src/executor/__tests__/flowExecutor.test.ts +66 -0
- package/src/flowContext.ts +234 -118
- package/src/flowEngine.ts +41 -0
- package/src/flowSettings.ts +12 -11
- package/src/index.ts +10 -0
- package/src/models/CollectionFieldModel.tsx +3 -1
- package/src/models/__tests__/dispatchEvent.when.test.ts +356 -0
- package/src/models/__tests__/flowModel.clone.test.ts +416 -0
- package/src/models/__tests__/flowModel.test.ts +16 -0
- package/src/models/flowModel.tsx +94 -1
- package/src/provider.tsx +9 -7
- package/src/resources/__tests__/multiRecordResource.test.ts +44 -0
- package/src/resources/__tests__/sqlResource.test.ts +60 -0
- package/src/resources/baseRecordResource.ts +31 -0
- package/src/resources/multiRecordResource.ts +11 -4
- package/src/resources/singleRecordResource.ts +3 -0
- package/src/resources/sqlResource.ts +8 -3
- package/src/runjs-context/contexts/base.ts +9 -2
- package/src/runjsLibs.ts +622 -0
- package/src/scheduler/ModelOperationScheduler.ts +23 -21
- package/src/types.ts +26 -1
- package/src/utils/__tests__/params-resolvers.test.ts +40 -0
- package/src/utils/__tests__/runjsRequireAsyncAutoWhitelist.test.ts +38 -0
- package/src/utils/__tests__/runjsTemplateCompat.test.ts +159 -0
- package/src/utils/__tests__/safeGlobals.test.ts +49 -2
- package/src/utils/createCollectionContextMeta.ts +1 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/params-resolvers.ts +23 -9
- package/src/utils/resolveModuleUrl.ts +91 -0
- package/src/utils/runjsModuleLoader.ts +553 -0
- package/src/utils/runjsTemplateCompat.ts +828 -0
- package/src/utils/safeGlobals.ts +133 -16
- package/src/views/__tests__/FlowView.usePage.test.tsx +54 -1
- package/src/views/__tests__/useDialog.closeDestroy.test.tsx +35 -8
- package/src/views/__tests__/viewEvents.resolveOpenerEngine.test.ts +28 -0
- package/src/views/createViewMeta.ts +22 -75
- package/src/views/index.tsx +1 -2
- package/src/views/useDialog.tsx +9 -2
- package/src/views/useDrawer.tsx +8 -1
- package/src/views/usePage.tsx +51 -5
- package/src/views/usePopover.tsx +4 -1
- package/src/views/viewEvents.ts +55 -0
|
@@ -37,7 +37,6 @@ function createBlockScopedEngine(parent) {
|
|
|
37
37
|
local.setModelRepository(parent.modelRepository);
|
|
38
38
|
}
|
|
39
39
|
local.context.addDelegate(parent.context);
|
|
40
|
-
const originalUnlink = local.unlinkFromStack.bind(local);
|
|
41
40
|
local.unlinkFromStack = function() {
|
|
42
41
|
const prev = local._previousEngine;
|
|
43
42
|
const next = local._nextEngine;
|
package/lib/JSRunner.d.ts
CHANGED
|
@@ -11,6 +11,12 @@ export interface JSRunnerOptions {
|
|
|
11
11
|
timeoutMs?: number;
|
|
12
12
|
globals?: Record<string, any>;
|
|
13
13
|
version?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Enable RunJS template compatibility preprocessing for `{{ ... }}`.
|
|
16
|
+
* When enabled via `ctx.runjs(code, vars, { preprocessTemplates: true })` (default),
|
|
17
|
+
* the code will be rewritten to call `ctx.resolveJsonTemplate(...)` at runtime.
|
|
18
|
+
*/
|
|
19
|
+
preprocessTemplates?: boolean;
|
|
14
20
|
}
|
|
15
21
|
export declare class JSRunner {
|
|
16
22
|
private globals;
|
package/lib/JSRunner.js
CHANGED
|
@@ -62,7 +62,8 @@ const _JSRunner = class _JSRunner {
|
|
|
62
62
|
* 异步运行代码,带错误处理和超时机制
|
|
63
63
|
*/
|
|
64
64
|
async run(code) {
|
|
65
|
-
|
|
65
|
+
const search = typeof location !== "undefined" ? location.search : void 0;
|
|
66
|
+
if (typeof search === "string" && search.includes("skipRunJs=true")) {
|
|
66
67
|
return { success: true, value: null };
|
|
67
68
|
}
|
|
68
69
|
const wrapped = `(async () => {
|
|
@@ -31,8 +31,10 @@ __export(ViewScopedFlowEngine_exports, {
|
|
|
31
31
|
});
|
|
32
32
|
module.exports = __toCommonJS(ViewScopedFlowEngine_exports);
|
|
33
33
|
var import_flowEngine = require("./flowEngine");
|
|
34
|
+
var import_viewEvents = require("./views/viewEvents");
|
|
34
35
|
function createViewScopedEngine(parent) {
|
|
35
36
|
const local = new import_flowEngine.FlowEngine();
|
|
37
|
+
Object.defineProperty(local, import_viewEvents.ENGINE_SCOPE_KEY, { value: import_viewEvents.VIEW_ENGINE_SCOPE, configurable: true });
|
|
36
38
|
if (parent.modelRepository) {
|
|
37
39
|
local.setModelRepository(parent.modelRepository);
|
|
38
40
|
}
|
|
@@ -48,6 +50,7 @@ function createViewScopedEngine(parent) {
|
|
|
48
50
|
"_applyFlowCache",
|
|
49
51
|
"executor",
|
|
50
52
|
"context",
|
|
53
|
+
import_viewEvents.ENGINE_SCOPE_KEY,
|
|
51
54
|
"previousEngine",
|
|
52
55
|
"nextEngine",
|
|
53
56
|
// 调度器与事件总线局部化
|
package/lib/acl/Acl.js
CHANGED
|
@@ -7,9 +7,11 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
var __create = Object.create;
|
|
10
11
|
var __defProp = Object.defineProperty;
|
|
11
12
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
13
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
13
15
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
16
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
15
17
|
var __export = (target, all) => {
|
|
@@ -24,13 +26,21 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
24
26
|
}
|
|
25
27
|
return to;
|
|
26
28
|
};
|
|
29
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
30
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
31
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
32
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
33
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
34
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
35
|
+
mod
|
|
36
|
+
));
|
|
27
37
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
38
|
var Acl_exports = {};
|
|
29
39
|
__export(Acl_exports, {
|
|
30
40
|
ACL: () => ACL
|
|
31
41
|
});
|
|
32
42
|
module.exports = __toCommonJS(Acl_exports);
|
|
33
|
-
var import_lodash = require("lodash");
|
|
43
|
+
var import_lodash = __toESM(require("lodash"));
|
|
34
44
|
const _ACL = class _ACL {
|
|
35
45
|
constructor(flowEngine) {
|
|
36
46
|
this.flowEngine = flowEngine;
|
|
@@ -43,10 +53,10 @@ const _ACL = class _ACL {
|
|
|
43
53
|
// 记录上一次用于鉴权的 token,用于识别登录态变更
|
|
44
54
|
lastToken = null;
|
|
45
55
|
setData(data) {
|
|
46
|
-
this.data = data;
|
|
56
|
+
this.data = import_lodash.default.cloneDeep(data);
|
|
47
57
|
}
|
|
48
58
|
setMeta(data) {
|
|
49
|
-
this.meta = data;
|
|
59
|
+
this.meta = import_lodash.default.cloneDeep(data);
|
|
50
60
|
}
|
|
51
61
|
async load() {
|
|
52
62
|
var _a, _b, _c, _d;
|
|
@@ -59,6 +59,43 @@ const COLUMN_EDGE_MAX_WIDTH = 28;
|
|
|
59
59
|
const COLUMN_EDGE_WIDTH_RATIO = 0.2;
|
|
60
60
|
const COLUMN_INSERT_THICKNESS_RATIO = 0.5;
|
|
61
61
|
const ROW_GAP_HEIGHT_RATIO = 0.33;
|
|
62
|
+
const deriveRowOrder = /* @__PURE__ */ __name((rows, provided) => {
|
|
63
|
+
const order = [];
|
|
64
|
+
const used = /* @__PURE__ */ new Set();
|
|
65
|
+
(provided || Object.keys(rows)).forEach((rowId) => {
|
|
66
|
+
if (rows[rowId] && !used.has(rowId)) {
|
|
67
|
+
order.push(rowId);
|
|
68
|
+
used.add(rowId);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
Object.keys(rows).forEach((rowId) => {
|
|
72
|
+
if (!used.has(rowId)) {
|
|
73
|
+
order.push(rowId);
|
|
74
|
+
used.add(rowId);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
return order;
|
|
78
|
+
}, "deriveRowOrder");
|
|
79
|
+
const normalizeRowsWithOrder = /* @__PURE__ */ __name((rows, order) => {
|
|
80
|
+
const next = {};
|
|
81
|
+
order.forEach((rowId) => {
|
|
82
|
+
if (rows[rowId]) {
|
|
83
|
+
next[rowId] = rows[rowId];
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
Object.keys(rows).forEach((rowId) => {
|
|
87
|
+
if (!next[rowId]) {
|
|
88
|
+
next[rowId] = rows[rowId];
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
return next;
|
|
92
|
+
}, "normalizeRowsWithOrder");
|
|
93
|
+
const ensureRowOrder = /* @__PURE__ */ __name((layout) => {
|
|
94
|
+
const order = deriveRowOrder(layout.rows, layout.rowOrder);
|
|
95
|
+
layout.rowOrder = order;
|
|
96
|
+
layout.rows = normalizeRowsWithOrder(layout.rows, order);
|
|
97
|
+
return order;
|
|
98
|
+
}, "ensureRowOrder");
|
|
62
99
|
const toRect = /* @__PURE__ */ __name((domRect) => ({
|
|
63
100
|
top: domRect.top,
|
|
64
101
|
left: domRect.left,
|
|
@@ -330,9 +367,11 @@ const removeItemFromLayout = /* @__PURE__ */ __name((layout, uidValue) => {
|
|
|
330
367
|
if (columns.length === 0) {
|
|
331
368
|
delete layout.rows[rowId];
|
|
332
369
|
delete layout.sizes[rowId];
|
|
370
|
+
ensureRowOrder(layout);
|
|
333
371
|
return;
|
|
334
372
|
}
|
|
335
373
|
normalizeRowSizes(rowId, layout);
|
|
374
|
+
ensureRowOrder(layout);
|
|
336
375
|
}, "removeItemFromLayout");
|
|
337
376
|
const toIntSizes = /* @__PURE__ */ __name((weights, count) => {
|
|
338
377
|
if (count === 0) {
|
|
@@ -420,8 +459,10 @@ const simulateLayoutForSlot = /* @__PURE__ */ __name(({
|
|
|
420
459
|
}) => {
|
|
421
460
|
const cloned = {
|
|
422
461
|
rows: import_lodash.default.cloneDeep(layout.rows),
|
|
423
|
-
sizes: import_lodash.default.cloneDeep(layout.sizes)
|
|
462
|
+
sizes: import_lodash.default.cloneDeep(layout.sizes),
|
|
463
|
+
rowOrder: layout.rowOrder ? [...layout.rowOrder] : void 0
|
|
424
464
|
};
|
|
465
|
+
ensureRowOrder(cloned);
|
|
425
466
|
removeItemFromLayout(cloned, sourceUid);
|
|
426
467
|
const createRowId = generateRowId ?? import_shared.uid;
|
|
427
468
|
switch (slot.type) {
|
|
@@ -464,8 +505,15 @@ const simulateLayoutForSlot = /* @__PURE__ */ __name(({
|
|
|
464
505
|
case "row-gap": {
|
|
465
506
|
const newRowId = createRowId();
|
|
466
507
|
const rowPosition = slot.position === "above" ? "before" : "after";
|
|
508
|
+
const currentOrder = deriveRowOrder(cloned.rows, cloned.rowOrder);
|
|
467
509
|
cloned.rows = insertRow(cloned.rows, slot.targetRowId, newRowId, rowPosition, [[sourceUid]]);
|
|
468
510
|
cloned.sizes[newRowId] = [DEFAULT_GRID_COLUMNS];
|
|
511
|
+
const targetIndex = currentOrder.indexOf(slot.targetRowId);
|
|
512
|
+
const insertIndex = targetIndex === -1 ? currentOrder.length : rowPosition === "before" ? targetIndex : targetIndex + 1;
|
|
513
|
+
const nextOrder = [...currentOrder];
|
|
514
|
+
nextOrder.splice(insertIndex, 0, newRowId);
|
|
515
|
+
cloned.rowOrder = nextOrder;
|
|
516
|
+
cloned.rows = normalizeRowsWithOrder(cloned.rows, nextOrder);
|
|
469
517
|
break;
|
|
470
518
|
}
|
|
471
519
|
case "empty-row": {
|
|
@@ -475,11 +523,15 @@ const simulateLayoutForSlot = /* @__PURE__ */ __name(({
|
|
|
475
523
|
[newRowId]: [[sourceUid]]
|
|
476
524
|
};
|
|
477
525
|
cloned.sizes[newRowId] = [DEFAULT_GRID_COLUMNS];
|
|
526
|
+
const currentOrder = deriveRowOrder(cloned.rows, cloned.rowOrder);
|
|
527
|
+
cloned.rowOrder = [...currentOrder.filter((id) => id !== newRowId), newRowId];
|
|
528
|
+
cloned.rows = normalizeRowsWithOrder(cloned.rows, cloned.rowOrder);
|
|
478
529
|
break;
|
|
479
530
|
}
|
|
480
531
|
default:
|
|
481
532
|
break;
|
|
482
533
|
}
|
|
534
|
+
ensureRowOrder(cloned);
|
|
483
535
|
return cloned;
|
|
484
536
|
}, "simulateLayoutForSlot");
|
|
485
537
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -73,7 +73,8 @@ const SwitchWithTitle = (0, import_reactive.observer)(
|
|
|
73
73
|
setChecked(val);
|
|
74
74
|
onChange == null ? void 0 : onChange({ [itemKey]: val });
|
|
75
75
|
}, "handleChange");
|
|
76
|
-
const handleWrapperClick = /* @__PURE__ */ __name(() => {
|
|
76
|
+
const handleWrapperClick = /* @__PURE__ */ __name((e) => {
|
|
77
|
+
e.stopPropagation();
|
|
77
78
|
if (disabled) return;
|
|
78
79
|
handleChange(!checked);
|
|
79
80
|
}, "handleWrapperClick");
|
|
@@ -153,6 +153,9 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
|
|
|
153
153
|
const [visible, setVisible] = (0, import_react.useState)(false);
|
|
154
154
|
const [refreshTick, setRefreshTick] = (0, import_react.useState)(0);
|
|
155
155
|
const [extraMenuItems, setExtraMenuItems] = (0, import_react.useState)([]);
|
|
156
|
+
const closeDropdown = (0, import_react.useCallback)(() => {
|
|
157
|
+
setVisible(false);
|
|
158
|
+
}, []);
|
|
156
159
|
const handleOpenChange = (0, import_react.useCallback)((nextOpen, info) => {
|
|
157
160
|
if (info.source === "trigger" || nextOpen) {
|
|
158
161
|
(0, import_react.startTransition)(() => {
|
|
@@ -249,6 +252,7 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
|
|
|
249
252
|
[model, copyUidToClipboard]
|
|
250
253
|
);
|
|
251
254
|
const handleDelete = (0, import_react.useCallback)(() => {
|
|
255
|
+
closeDropdown();
|
|
252
256
|
import_antd.Modal.confirm({
|
|
253
257
|
title: t("Confirm delete"),
|
|
254
258
|
icon: /* @__PURE__ */ import_react.default.createElement(import_icons.ExclamationCircleOutlined, null),
|
|
@@ -269,7 +273,7 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
|
|
|
269
273
|
}
|
|
270
274
|
}
|
|
271
275
|
});
|
|
272
|
-
}, [model]);
|
|
276
|
+
}, [closeDropdown, model, t]);
|
|
273
277
|
const handleStepConfiguration = (0, import_react.useCallback)(
|
|
274
278
|
(key) => {
|
|
275
279
|
const keyParts = key.split(":");
|
|
@@ -294,6 +298,7 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
|
|
|
294
298
|
[flowKey, stepKey] = keyParts;
|
|
295
299
|
}
|
|
296
300
|
try {
|
|
301
|
+
closeDropdown();
|
|
297
302
|
targetModel.openFlowSettings({
|
|
298
303
|
flowKey,
|
|
299
304
|
stepKey
|
|
@@ -302,23 +307,26 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
|
|
|
302
307
|
console.log(t("Configuration popup cancelled or error"), ":", error);
|
|
303
308
|
}
|
|
304
309
|
},
|
|
305
|
-
[model]
|
|
310
|
+
[closeDropdown, model, t]
|
|
306
311
|
);
|
|
307
312
|
const handleMenuClick = (0, import_react.useCallback)(
|
|
308
313
|
({ key }) => {
|
|
309
314
|
const originalKey = key;
|
|
310
315
|
const cleanKey = key.includes("-") && /^(.+)-\d+$/.test(key) ? key.replace(/-\d+$/, "") : key;
|
|
311
316
|
if (cleanKey.startsWith("copy-pop-uid:")) {
|
|
317
|
+
closeDropdown();
|
|
312
318
|
handleCopyPopupUid(cleanKey);
|
|
313
319
|
return;
|
|
314
320
|
}
|
|
315
321
|
const extra = extraMenuItems.find((it) => (it == null ? void 0 : it.key) === originalKey || (it == null ? void 0 : it.key) === cleanKey);
|
|
316
322
|
if (extra == null ? void 0 : extra.onClick) {
|
|
323
|
+
closeDropdown();
|
|
317
324
|
extra.onClick();
|
|
318
325
|
return;
|
|
319
326
|
}
|
|
320
327
|
switch (cleanKey) {
|
|
321
328
|
case "copy-uid":
|
|
329
|
+
closeDropdown();
|
|
322
330
|
handleCopyUid();
|
|
323
331
|
break;
|
|
324
332
|
case "delete":
|
|
@@ -329,7 +337,7 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
|
|
|
329
337
|
break;
|
|
330
338
|
}
|
|
331
339
|
},
|
|
332
|
-
[handleCopyUid, handleDelete, handleStepConfiguration, handleCopyPopupUid, extraMenuItems]
|
|
340
|
+
[closeDropdown, handleCopyUid, handleDelete, handleStepConfiguration, handleCopyPopupUid, extraMenuItems]
|
|
333
341
|
);
|
|
334
342
|
const getModelConfigurableFlowsAndSteps = (0, import_react.useCallback)(
|
|
335
343
|
async (targetModel, modelKey) => {
|
|
@@ -230,12 +230,18 @@ const VariableInputComponent = /* @__PURE__ */ __name(({
|
|
|
230
230
|
);
|
|
231
231
|
const handleVariableSelect = (0, import_react.useCallback)(
|
|
232
232
|
(variableValue, metaTreeNode) => {
|
|
233
|
+
if (!metaTreeNode && variableValue === "") {
|
|
234
|
+
const cleared = clearValue !== void 0 ? clearValue : null;
|
|
235
|
+
setInnerValue(cleared);
|
|
236
|
+
emitChange(cleared);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
233
239
|
setCurrentMetaTreeNode(metaTreeNode);
|
|
234
240
|
const finalValue = (resolveValueFromPath == null ? void 0 : resolveValueFromPath(metaTreeNode)) || variableValue;
|
|
235
241
|
setInnerValue(finalValue);
|
|
236
242
|
emitChange(finalValue, metaTreeNode);
|
|
237
243
|
},
|
|
238
|
-
[emitChange, resolveValueFromPath]
|
|
244
|
+
[emitChange, resolveValueFromPath, clearValue]
|
|
239
245
|
);
|
|
240
246
|
const { disabled } = restProps;
|
|
241
247
|
const handleClear = (0, import_react.useCallback)(() => {
|
|
@@ -265,7 +271,7 @@ const VariableInputComponent = /* @__PURE__ */ __name(({
|
|
|
265
271
|
}, [restProps]);
|
|
266
272
|
const inputProps = (0, import_react.useMemo)(() => {
|
|
267
273
|
const baseProps = {
|
|
268
|
-
value: innerValue ?? "",
|
|
274
|
+
value: ValueComponent === import_antd.Input ? innerValue ?? "" : innerValue,
|
|
269
275
|
onChange: handleInputChange,
|
|
270
276
|
disabled
|
|
271
277
|
};
|
package/lib/data-source/index.js
CHANGED
|
@@ -400,6 +400,9 @@ const _Collection = class _Collection {
|
|
|
400
400
|
if (typeof this.filterTargetKey === "string") {
|
|
401
401
|
return record[this.filterTargetKey];
|
|
402
402
|
}
|
|
403
|
+
if (Array.isArray(this.filterTargetKey) && this.filterTargetKey.length === 1) {
|
|
404
|
+
return record[this.filterTargetKey[0]];
|
|
405
|
+
}
|
|
403
406
|
return import_lodash.default.pick(record, this.filterTargetKey);
|
|
404
407
|
}
|
|
405
408
|
get titleableFields() {
|
|
@@ -682,6 +685,9 @@ const _CollectionField = class _CollectionField {
|
|
|
682
685
|
if (typeof v !== "object") {
|
|
683
686
|
return v;
|
|
684
687
|
}
|
|
688
|
+
if (v.value === null || v.value === void 0) {
|
|
689
|
+
return v;
|
|
690
|
+
}
|
|
685
691
|
return {
|
|
686
692
|
...v,
|
|
687
693
|
value: Number(v.value)
|
|
@@ -12,12 +12,13 @@ import type { DispatchEventOptions } from '../types';
|
|
|
12
12
|
export declare class FlowExecutor {
|
|
13
13
|
private readonly engine;
|
|
14
14
|
constructor(engine: FlowEngine);
|
|
15
|
+
private emitModelEventIf;
|
|
15
16
|
/** Cache wrapper for applyFlow cache lifecycle */
|
|
16
17
|
private withApplyFlowCache;
|
|
17
18
|
/**
|
|
18
19
|
* Execute a single flow on model.
|
|
19
20
|
*/
|
|
20
|
-
runFlow(model: FlowModel, flowKey: string, inputArgs?: Record<string, any>, runId?: string): Promise<any>;
|
|
21
|
+
runFlow(model: FlowModel, flowKey: string, inputArgs?: Record<string, any>, runId?: string, eventName?: string): Promise<any>;
|
|
21
22
|
/**
|
|
22
23
|
* Dispatch an event to flows bound via flow.on and execute them.
|
|
23
24
|
*/
|
|
@@ -51,6 +51,10 @@ const _FlowExecutor = class _FlowExecutor {
|
|
|
51
51
|
constructor(engine) {
|
|
52
52
|
this.engine = engine;
|
|
53
53
|
}
|
|
54
|
+
async emitModelEventIf(eventName, topic, payload) {
|
|
55
|
+
if (!eventName) return;
|
|
56
|
+
await this.engine.emitter.emitAsync(`model:event:${eventName}:${topic}`, payload);
|
|
57
|
+
}
|
|
54
58
|
/** Cache wrapper for applyFlow cache lifecycle */
|
|
55
59
|
async withApplyFlowCache(cacheKey, executor) {
|
|
56
60
|
if (!cacheKey || !this.engine) return await executor();
|
|
@@ -81,7 +85,7 @@ const _FlowExecutor = class _FlowExecutor {
|
|
|
81
85
|
/**
|
|
82
86
|
* Execute a single flow on model.
|
|
83
87
|
*/
|
|
84
|
-
async runFlow(model, flowKey, inputArgs, runId) {
|
|
88
|
+
async runFlow(model, flowKey, inputArgs, runId, eventName) {
|
|
85
89
|
var _a;
|
|
86
90
|
const flow = model.getFlow(flowKey);
|
|
87
91
|
if (!flow) {
|
|
@@ -113,6 +117,14 @@ const _FlowExecutor = class _FlowExecutor {
|
|
|
113
117
|
const stepDefs = eventStep ? { eventStep, ...flow.steps } : flow.steps;
|
|
114
118
|
(0, import_setupRuntimeContextSteps.setupRuntimeContextSteps)(flowContext, stepDefs, model, flowKey);
|
|
115
119
|
const stepsRuntime = flowContext.steps;
|
|
120
|
+
const flowEventBasePayload = {
|
|
121
|
+
uid: model.uid,
|
|
122
|
+
model,
|
|
123
|
+
runId: flowContext.runId,
|
|
124
|
+
inputArgs,
|
|
125
|
+
flowKey
|
|
126
|
+
};
|
|
127
|
+
await this.emitModelEventIf(eventName, `flow:${flowKey}:start`, flowEventBasePayload);
|
|
116
128
|
for (const [stepKey, step] of Object.entries(stepDefs)) {
|
|
117
129
|
let handler;
|
|
118
130
|
let combinedParams = {};
|
|
@@ -163,20 +175,56 @@ const _FlowExecutor = class _FlowExecutor {
|
|
|
163
175
|
);
|
|
164
176
|
continue;
|
|
165
177
|
}
|
|
178
|
+
await this.emitModelEventIf(eventName, `flow:${flowKey}:step:${stepKey}:start`, {
|
|
179
|
+
...flowEventBasePayload,
|
|
180
|
+
stepKey
|
|
181
|
+
});
|
|
166
182
|
const currentStepResult = handler(runtimeCtx, combinedParams);
|
|
167
183
|
const isAwait = step.isAwait !== false;
|
|
168
184
|
lastResult = isAwait ? await currentStepResult : currentStepResult;
|
|
169
185
|
stepResults[stepKey] = lastResult;
|
|
170
186
|
stepsRuntime[stepKey].result = stepResults[stepKey];
|
|
187
|
+
await this.emitModelEventIf(eventName, `flow:${flowKey}:step:${stepKey}:end`, {
|
|
188
|
+
...flowEventBasePayload,
|
|
189
|
+
result: lastResult,
|
|
190
|
+
stepKey
|
|
191
|
+
});
|
|
171
192
|
} catch (error) {
|
|
193
|
+
if (!(error instanceof import_utils.FlowExitException) && !(error instanceof import_exceptions.FlowExitAllException)) {
|
|
194
|
+
await this.emitModelEventIf(eventName, `flow:${flowKey}:step:${stepKey}:error`, {
|
|
195
|
+
...flowEventBasePayload,
|
|
196
|
+
error,
|
|
197
|
+
stepKey
|
|
198
|
+
});
|
|
199
|
+
}
|
|
172
200
|
if (error instanceof import_utils.FlowExitException) {
|
|
173
201
|
flowContext.logger.info(`[FlowEngine] ${error.message}`);
|
|
202
|
+
await this.emitModelEventIf(eventName, `flow:${flowKey}:step:${stepKey}:end`, {
|
|
203
|
+
...flowEventBasePayload,
|
|
204
|
+
stepKey
|
|
205
|
+
});
|
|
206
|
+
await this.emitModelEventIf(eventName, `flow:${flowKey}:end`, {
|
|
207
|
+
...flowEventBasePayload,
|
|
208
|
+
result: stepResults
|
|
209
|
+
});
|
|
174
210
|
return Promise.resolve(stepResults);
|
|
175
211
|
}
|
|
176
212
|
if (error instanceof import_exceptions.FlowExitAllException) {
|
|
177
213
|
flowContext.logger.info(`[FlowEngine] ${error.message}`);
|
|
214
|
+
await this.emitModelEventIf(eventName, `flow:${flowKey}:step:${stepKey}:end`, {
|
|
215
|
+
...flowEventBasePayload,
|
|
216
|
+
stepKey
|
|
217
|
+
});
|
|
218
|
+
await this.emitModelEventIf(eventName, `flow:${flowKey}:end`, {
|
|
219
|
+
...flowEventBasePayload,
|
|
220
|
+
result: error
|
|
221
|
+
});
|
|
178
222
|
return Promise.resolve(error);
|
|
179
223
|
}
|
|
224
|
+
await this.emitModelEventIf(eventName, `flow:${flowKey}:error`, {
|
|
225
|
+
...flowEventBasePayload,
|
|
226
|
+
error
|
|
227
|
+
});
|
|
180
228
|
flowContext.logger.error(
|
|
181
229
|
{ err: error },
|
|
182
230
|
`BaseModel.applyFlow: Error executing step '${stepKey}' in flow '${flowKey}':`
|
|
@@ -184,9 +232,12 @@ const _FlowExecutor = class _FlowExecutor {
|
|
|
184
232
|
return Promise.reject(error);
|
|
185
233
|
}
|
|
186
234
|
}
|
|
235
|
+
await this.emitModelEventIf(eventName, `flow:${flowKey}:end`, {
|
|
236
|
+
...flowEventBasePayload,
|
|
237
|
+
result: stepResults
|
|
238
|
+
});
|
|
187
239
|
return Promise.resolve(stepResults);
|
|
188
240
|
}
|
|
189
|
-
// runAutoFlows 已移除:统一通过 dispatchEvent('beforeRender') + useCache 控制
|
|
190
241
|
/**
|
|
191
242
|
* Dispatch an event to flows bound via flow.on and execute them.
|
|
192
243
|
*/
|
|
@@ -198,13 +249,14 @@ const _FlowExecutor = class _FlowExecutor {
|
|
|
198
249
|
const throwOnError = isBeforeRender;
|
|
199
250
|
const runId = `${model.uid}-${eventName}-${Date.now()}`;
|
|
200
251
|
const logger = model.context.logger;
|
|
252
|
+
const eventBasePayload = {
|
|
253
|
+
uid: model.uid,
|
|
254
|
+
model,
|
|
255
|
+
runId,
|
|
256
|
+
inputArgs
|
|
257
|
+
};
|
|
201
258
|
try {
|
|
202
|
-
await this.
|
|
203
|
-
uid: model.uid,
|
|
204
|
-
model,
|
|
205
|
-
runId,
|
|
206
|
-
inputArgs
|
|
207
|
-
});
|
|
259
|
+
await this.emitModelEventIf(eventName, "start", eventBasePayload);
|
|
208
260
|
await ((_a = model.onDispatchEventStart) == null ? void 0 : _a.call(model, eventName, options, inputArgs));
|
|
209
261
|
} catch (err) {
|
|
210
262
|
if (isBeforeRender && err instanceof import_utils.FlowExitException) {
|
|
@@ -226,9 +278,17 @@ const _FlowExecutor = class _FlowExecutor {
|
|
|
226
278
|
if (typeof on === "object") return on.eventName === eventName;
|
|
227
279
|
return false;
|
|
228
280
|
});
|
|
281
|
+
const isRouterReplayClick = eventName === "click" && (inputArgs == null ? void 0 : inputArgs.triggerByRouter) === true;
|
|
282
|
+
const flowsToRun = isRouterReplayClick ? flows.filter((flow) => {
|
|
283
|
+
var _a2;
|
|
284
|
+
const reg = flow["flowRegistry"];
|
|
285
|
+
const type = (_a2 = reg == null ? void 0 : reg.constructor) == null ? void 0 : _a2._type;
|
|
286
|
+
return type !== "instance";
|
|
287
|
+
}) : flows;
|
|
288
|
+
const scheduledCancels = [];
|
|
229
289
|
const execute = /* @__PURE__ */ __name(async () => {
|
|
230
290
|
if (sequential) {
|
|
231
|
-
const flowsWithIndex =
|
|
291
|
+
const flowsWithIndex = flowsToRun.map((f, i) => ({ f, i }));
|
|
232
292
|
const ordered = flowsWithIndex.slice().sort((a, b) => {
|
|
233
293
|
var _a2, _b2;
|
|
234
294
|
const regA = a.f["flowRegistry"];
|
|
@@ -244,12 +304,88 @@ const _FlowExecutor = class _FlowExecutor {
|
|
|
244
304
|
return a.i - b.i;
|
|
245
305
|
}).map((x) => x.f);
|
|
246
306
|
const results2 = [];
|
|
307
|
+
const staticFlowsByKey = new Map(
|
|
308
|
+
ordered.filter((f) => {
|
|
309
|
+
var _a2;
|
|
310
|
+
const reg = f["flowRegistry"];
|
|
311
|
+
const type = (_a2 = reg == null ? void 0 : reg.constructor) == null ? void 0 : _a2._type;
|
|
312
|
+
return type !== "instance";
|
|
313
|
+
}).map((f) => [f.key, f])
|
|
314
|
+
);
|
|
315
|
+
const scheduled = /* @__PURE__ */ new Set();
|
|
316
|
+
const scheduleGroups = /* @__PURE__ */ new Map();
|
|
317
|
+
ordered.forEach((flow, indexInOrdered) => {
|
|
318
|
+
var _a2;
|
|
319
|
+
const on = flow.on;
|
|
320
|
+
const onObj = typeof on === "object" ? on : void 0;
|
|
321
|
+
if (!onObj) return;
|
|
322
|
+
const phase = onObj.phase;
|
|
323
|
+
const flowKey = onObj.flowKey;
|
|
324
|
+
const stepKey = onObj.stepKey;
|
|
325
|
+
if (!phase || phase === "beforeAllFlows") return;
|
|
326
|
+
let whenKey = null;
|
|
327
|
+
if (phase === "afterAllFlows") {
|
|
328
|
+
whenKey = `event:${eventName}:end`;
|
|
329
|
+
} else if (phase === "beforeFlow" || phase === "afterFlow") {
|
|
330
|
+
if (!flowKey) {
|
|
331
|
+
whenKey = `event:${eventName}:end`;
|
|
332
|
+
} else {
|
|
333
|
+
const anchorFlow = staticFlowsByKey.get(String(flowKey));
|
|
334
|
+
if (anchorFlow) {
|
|
335
|
+
const anchorPhase = phase === "beforeFlow" ? "start" : "end";
|
|
336
|
+
whenKey = `event:${eventName}:flow:${String(flowKey)}:${anchorPhase}`;
|
|
337
|
+
} else {
|
|
338
|
+
whenKey = `event:${eventName}:end`;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
} else if (phase === "beforeStep" || phase === "afterStep") {
|
|
342
|
+
if (!flowKey || !stepKey) {
|
|
343
|
+
whenKey = `event:${eventName}:end`;
|
|
344
|
+
} else {
|
|
345
|
+
const anchorFlow = staticFlowsByKey.get(String(flowKey));
|
|
346
|
+
const anchorStepExists = !!((_a2 = anchorFlow == null ? void 0 : anchorFlow.hasStep) == null ? void 0 : _a2.call(anchorFlow, String(stepKey)));
|
|
347
|
+
if (anchorFlow && anchorStepExists) {
|
|
348
|
+
const anchorPhase = phase === "beforeStep" ? "start" : "end";
|
|
349
|
+
whenKey = `event:${eventName}:flow:${String(flowKey)}:step:${String(stepKey)}:${anchorPhase}`;
|
|
350
|
+
} else {
|
|
351
|
+
whenKey = `event:${eventName}:end`;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
} else {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if (!whenKey) return;
|
|
358
|
+
scheduled.add(flow.key);
|
|
359
|
+
const list = scheduleGroups.get(whenKey) || [];
|
|
360
|
+
list.push({ flow, order: indexInOrdered });
|
|
361
|
+
scheduleGroups.set(whenKey, list);
|
|
362
|
+
});
|
|
363
|
+
for (const [whenKey, list] of scheduleGroups.entries()) {
|
|
364
|
+
const sorted = list.slice().sort((a, b) => {
|
|
365
|
+
const sa = a.flow.sort ?? 0;
|
|
366
|
+
const sb = b.flow.sort ?? 0;
|
|
367
|
+
if (sa !== sb) return sa - sb;
|
|
368
|
+
return a.order - b.order;
|
|
369
|
+
});
|
|
370
|
+
for (const it of sorted) {
|
|
371
|
+
const cancel = model.scheduleModelOperation(
|
|
372
|
+
model.uid,
|
|
373
|
+
async (m) => {
|
|
374
|
+
const res = await this.runFlow(m, it.flow.key, inputArgs, runId, eventName);
|
|
375
|
+
results2.push(res);
|
|
376
|
+
},
|
|
377
|
+
{ when: whenKey }
|
|
378
|
+
);
|
|
379
|
+
scheduledCancels.push(cancel);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
247
382
|
for (const flow of ordered) {
|
|
383
|
+
if (scheduled.has(flow.key)) continue;
|
|
248
384
|
try {
|
|
249
385
|
logger.debug(
|
|
250
386
|
`BaseModel '${model.uid}' dispatching event '${eventName}' to flow '${flow.key}' (sequential).`
|
|
251
387
|
);
|
|
252
|
-
const result = await this.runFlow(model, flow.key, inputArgs, runId);
|
|
388
|
+
const result = await this.runFlow(model, flow.key, inputArgs, runId, eventName);
|
|
253
389
|
if (result instanceof import_exceptions.FlowExitAllException) {
|
|
254
390
|
logger.debug(`[FlowEngine.dispatchEvent] ${result.message}`);
|
|
255
391
|
break;
|
|
@@ -266,10 +402,10 @@ const _FlowExecutor = class _FlowExecutor {
|
|
|
266
402
|
return results2;
|
|
267
403
|
}
|
|
268
404
|
const results = await Promise.all(
|
|
269
|
-
|
|
405
|
+
flowsToRun.map(async (flow) => {
|
|
270
406
|
logger.debug(`BaseModel '${model.uid}' dispatching event '${eventName}' to flow '${flow.key}'.`);
|
|
271
407
|
try {
|
|
272
|
-
return await this.runFlow(model, flow.key, inputArgs, runId);
|
|
408
|
+
return await this.runFlow(model, flow.key, inputArgs, runId, eventName);
|
|
273
409
|
} catch (error) {
|
|
274
410
|
logger.error(
|
|
275
411
|
{ err: error },
|
|
@@ -295,11 +431,8 @@ const _FlowExecutor = class _FlowExecutor {
|
|
|
295
431
|
} catch (hookErr) {
|
|
296
432
|
logger.error({ err: hookErr }, `BaseModel.dispatchEvent: End hook error for event '${eventName}'`);
|
|
297
433
|
}
|
|
298
|
-
await this.
|
|
299
|
-
|
|
300
|
-
model,
|
|
301
|
-
runId,
|
|
302
|
-
inputArgs,
|
|
434
|
+
await this.emitModelEventIf(eventName, "end", {
|
|
435
|
+
...eventBasePayload,
|
|
303
436
|
result
|
|
304
437
|
});
|
|
305
438
|
return result;
|
|
@@ -312,14 +445,15 @@ const _FlowExecutor = class _FlowExecutor {
|
|
|
312
445
|
{ err: error },
|
|
313
446
|
`BaseModel.dispatchEvent: Error executing event '${eventName}' for model '${model.uid}':`
|
|
314
447
|
);
|
|
315
|
-
await this.
|
|
316
|
-
|
|
317
|
-
model,
|
|
318
|
-
runId,
|
|
319
|
-
inputArgs,
|
|
448
|
+
await this.emitModelEventIf(eventName, "error", {
|
|
449
|
+
...eventBasePayload,
|
|
320
450
|
error
|
|
321
451
|
});
|
|
322
452
|
if (throwOnError) throw error;
|
|
453
|
+
} finally {
|
|
454
|
+
for (const cancel of scheduledCancels) {
|
|
455
|
+
cancel();
|
|
456
|
+
}
|
|
323
457
|
}
|
|
324
458
|
}
|
|
325
459
|
};
|
package/lib/flowContext.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export interface MetaTreeNode {
|
|
|
31
31
|
title: string;
|
|
32
32
|
type: string;
|
|
33
33
|
interface?: string;
|
|
34
|
+
options?: any;
|
|
34
35
|
uiSchema?: ISchema;
|
|
35
36
|
render?: (props: any) => JSX.Element;
|
|
36
37
|
paths: string[];
|
|
@@ -44,6 +45,7 @@ export interface PropertyMeta {
|
|
|
44
45
|
type: string;
|
|
45
46
|
title: string;
|
|
46
47
|
interface?: string;
|
|
48
|
+
options?: any;
|
|
47
49
|
uiSchema?: ISchema;
|
|
48
50
|
render?: (props: any) => JSX.Element;
|
|
49
51
|
sort?: number;
|
|
@@ -147,7 +149,7 @@ declare class BaseFlowEngineContext extends FlowContext {
|
|
|
147
149
|
dataSourceManager: DataSourceManager;
|
|
148
150
|
requireAsync: (url: string) => Promise<any>;
|
|
149
151
|
importAsync: (url: string) => Promise<any>;
|
|
150
|
-
createJSRunner: (options?: JSRunnerOptions) => JSRunner
|
|
152
|
+
createJSRunner: (options?: JSRunnerOptions) => Promise<JSRunner>;
|
|
151
153
|
pageInfo: {
|
|
152
154
|
version?: 'v1' | 'v2';
|
|
153
155
|
};
|
|
@@ -172,6 +174,7 @@ declare class BaseFlowEngineContext extends FlowContext {
|
|
|
172
174
|
location: Location;
|
|
173
175
|
sql: FlowSQLRepository;
|
|
174
176
|
logger: pino.Logger;
|
|
177
|
+
constructor();
|
|
175
178
|
}
|
|
176
179
|
declare class BaseFlowModelContext extends BaseFlowEngineContext {
|
|
177
180
|
model: FlowModel;
|