@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
|
@@ -361,6 +361,13 @@ export declare class FlowModel<Structure extends DefaultStructure = DefaultStruc
|
|
|
361
361
|
}): Promise<void>;
|
|
362
362
|
get translate(): any;
|
|
363
363
|
serialize(): Record<string, any>;
|
|
364
|
+
/**
|
|
365
|
+
* 复制当前模型实例为一个新的实例。
|
|
366
|
+
* 新实例及其所有子模型都会有新的 uid,且不保留 root model 的 parent 关系。
|
|
367
|
+
* 内部所有引用旧 uid 的地方(如 parentId, parentUid 等)都会被替换为对应的新 uid。
|
|
368
|
+
* @returns {FlowModel} 复制后的新模型实例
|
|
369
|
+
*/
|
|
370
|
+
clone<T extends FlowModel = this>(): T;
|
|
364
371
|
/**
|
|
365
372
|
* Opens the flow settings dialog for this flow model.
|
|
366
373
|
* @param options - Configuration options for opening flow settings, excluding the model property
|
package/lib/models/flowModel.js
CHANGED
|
@@ -353,7 +353,18 @@ const _FlowModel = class _FlowModel {
|
|
|
353
353
|
const meta = Cls.meta;
|
|
354
354
|
const metaCreate = meta == null ? void 0 : meta.createModelOptions;
|
|
355
355
|
if (metaCreate && typeof metaCreate === "object" && metaCreate.subModels) {
|
|
356
|
-
|
|
356
|
+
const replaceArrays = /* @__PURE__ */ __name((objValue, srcValue) => {
|
|
357
|
+
if (Array.isArray(objValue) && Array.isArray(srcValue)) {
|
|
358
|
+
return srcValue;
|
|
359
|
+
}
|
|
360
|
+
return void 0;
|
|
361
|
+
}, "replaceArrays");
|
|
362
|
+
mergedSubModels = import_lodash.default.mergeWith(
|
|
363
|
+
{},
|
|
364
|
+
import_lodash.default.cloneDeep(metaCreate.subModels || {}),
|
|
365
|
+
import_lodash.default.cloneDeep(subModels || {}),
|
|
366
|
+
replaceArrays
|
|
367
|
+
);
|
|
357
368
|
}
|
|
358
369
|
} catch (e) {
|
|
359
370
|
}
|
|
@@ -1119,6 +1130,60 @@ const _FlowModel = class _FlowModel {
|
|
|
1119
1130
|
}
|
|
1120
1131
|
return data;
|
|
1121
1132
|
}
|
|
1133
|
+
/**
|
|
1134
|
+
* 复制当前模型实例为一个新的实例。
|
|
1135
|
+
* 新实例及其所有子模型都会有新的 uid,且不保留 root model 的 parent 关系。
|
|
1136
|
+
* 内部所有引用旧 uid 的地方(如 parentId, parentUid 等)都会被替换为对应的新 uid。
|
|
1137
|
+
* @returns {FlowModel} 复制后的新模型实例
|
|
1138
|
+
*/
|
|
1139
|
+
clone() {
|
|
1140
|
+
if (!this.flowEngine) {
|
|
1141
|
+
throw new Error("FlowEngine is not set on this model. Please set flowEngine before cloning.");
|
|
1142
|
+
}
|
|
1143
|
+
const serialized = this.serialize();
|
|
1144
|
+
const uidMap = /* @__PURE__ */ new Map();
|
|
1145
|
+
const collectUids = /* @__PURE__ */ __name((data) => {
|
|
1146
|
+
if (data.uid && typeof data.uid === "string") {
|
|
1147
|
+
uidMap.set(data.uid, (0, import_secure.uid)());
|
|
1148
|
+
}
|
|
1149
|
+
if (data.subModels) {
|
|
1150
|
+
for (const key in data.subModels) {
|
|
1151
|
+
const subModel = data.subModels[key];
|
|
1152
|
+
if (Array.isArray(subModel)) {
|
|
1153
|
+
subModel.forEach((item) => collectUids(item));
|
|
1154
|
+
} else if (subModel && typeof subModel === "object") {
|
|
1155
|
+
collectUids(subModel);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
}, "collectUids");
|
|
1160
|
+
collectUids(serialized);
|
|
1161
|
+
const replaceUidReferences = /* @__PURE__ */ __name((data, isRoot = false) => {
|
|
1162
|
+
if (data === null || data === void 0) {
|
|
1163
|
+
return data;
|
|
1164
|
+
}
|
|
1165
|
+
if (typeof data === "string") {
|
|
1166
|
+
return uidMap.get(data) ?? data;
|
|
1167
|
+
}
|
|
1168
|
+
if (Array.isArray(data)) {
|
|
1169
|
+
return data.map((item) => replaceUidReferences(item, false));
|
|
1170
|
+
}
|
|
1171
|
+
if (typeof data === "object") {
|
|
1172
|
+
const result = {};
|
|
1173
|
+
for (const key in data) {
|
|
1174
|
+
if (!Object.prototype.hasOwnProperty.call(data, key)) continue;
|
|
1175
|
+
if (isRoot && key === "parentId") {
|
|
1176
|
+
continue;
|
|
1177
|
+
}
|
|
1178
|
+
result[key] = replaceUidReferences(data[key], false);
|
|
1179
|
+
}
|
|
1180
|
+
return result;
|
|
1181
|
+
}
|
|
1182
|
+
return data;
|
|
1183
|
+
}, "replaceUidReferences");
|
|
1184
|
+
const clonedData = replaceUidReferences(serialized, true);
|
|
1185
|
+
return this.flowEngine.createModel(clonedData);
|
|
1186
|
+
}
|
|
1122
1187
|
/**
|
|
1123
1188
|
* Opens the flow settings dialog for this flow model.
|
|
1124
1189
|
* @param options - Configuration options for opening flow settings, excluding the model property
|
package/lib/provider.js
CHANGED
|
@@ -79,17 +79,17 @@ const FlowEngineGlobalsContextProvider = /* @__PURE__ */ __name(({ children }) =
|
|
|
79
79
|
cache: false,
|
|
80
80
|
get: /* @__PURE__ */ __name((ctx) => new import_FlowView.FlowViewer(ctx, { drawer, embed, popover, dialog }), "get")
|
|
81
81
|
});
|
|
82
|
-
engine.context.defineProperty("themeToken", {
|
|
83
|
-
get: /* @__PURE__ */ __name(() => token, "get"),
|
|
84
|
-
observable: true,
|
|
85
|
-
cache: true
|
|
86
|
-
});
|
|
87
82
|
for (const item of Object.entries(context)) {
|
|
88
83
|
const [key, value] = item;
|
|
89
84
|
if (value) {
|
|
90
85
|
engine.context.defineProperty(key, { value });
|
|
91
86
|
}
|
|
92
87
|
}
|
|
88
|
+
engine.context.defineProperty("themeToken", {
|
|
89
|
+
get: /* @__PURE__ */ __name(() => token, "get"),
|
|
90
|
+
observable: true,
|
|
91
|
+
cache: true
|
|
92
|
+
});
|
|
93
93
|
engine.reactView.refresh();
|
|
94
94
|
}, [engine, drawer, modal, message, notification, config, popover, token, dialog, embed]);
|
|
95
95
|
return /* @__PURE__ */ import_react.default.createElement(import_antd.ConfigProvider, { ...config, locale: (_a = engine.context.locales) == null ? void 0 : _a.antd, popupMatchSelectWidth: false }, children, contextHolder, popoverContextHolder, pageContextHolder, dialogContextHolder);
|
|
@@ -97,9 +97,10 @@ const FlowEngineGlobalsContextProvider = /* @__PURE__ */ __name(({ children }) =
|
|
|
97
97
|
const useFlowEngine = /* @__PURE__ */ __name(({ throwError = true } = {}) => {
|
|
98
98
|
const context = (0, import_react.useContext)(FlowEngineReactContext);
|
|
99
99
|
if (!context && throwError) {
|
|
100
|
-
|
|
100
|
+
console.warn(
|
|
101
101
|
"useFlowEngine must be used within a FlowEngineProvider, and FlowEngineProvider must be supplied with an engine."
|
|
102
102
|
);
|
|
103
|
+
return;
|
|
103
104
|
}
|
|
104
105
|
return context;
|
|
105
106
|
}, "useFlowEngine");
|
|
@@ -30,6 +30,11 @@ export declare abstract class BaseRecordResource<TData = any> extends APIResourc
|
|
|
30
30
|
runAction<TData = any, TMeta = any>(action: string, options: any): Promise<any>;
|
|
31
31
|
setResourceName(resourceName: string): this;
|
|
32
32
|
getResourceName(): string;
|
|
33
|
+
/**
|
|
34
|
+
* Mark current resource as dirty on the root FlowEngine.
|
|
35
|
+
* Used to coordinate "refresh on active" across view stacks.
|
|
36
|
+
*/
|
|
37
|
+
protected markDataSourceDirty(resourceName?: string): void;
|
|
33
38
|
setSourceId(sourceId: string | number): this;
|
|
34
39
|
getSourceId(): string | number;
|
|
35
40
|
setDataSourceKey(dataSourceKey: string): this;
|
|
@@ -44,6 +44,7 @@ var import_lodash = __toESM(require("lodash"));
|
|
|
44
44
|
var import_apiResource = require("./apiResource");
|
|
45
45
|
var import_filterItem = require("./filterItem");
|
|
46
46
|
var import_flowResource = require("./flowResource");
|
|
47
|
+
var import_viewEvents = require("../views/viewEvents");
|
|
47
48
|
const _BaseRecordResource = class _BaseRecordResource extends import_apiResource.APIResource {
|
|
48
49
|
resourceName;
|
|
49
50
|
sourceId = null;
|
|
@@ -145,6 +146,29 @@ const _BaseRecordResource = class _BaseRecordResource extends import_apiResource
|
|
|
145
146
|
getResourceName() {
|
|
146
147
|
return this.resourceName;
|
|
147
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* Mark current resource as dirty on the root FlowEngine.
|
|
151
|
+
* Used to coordinate "refresh on active" across view stacks.
|
|
152
|
+
*/
|
|
153
|
+
markDataSourceDirty(resourceName) {
|
|
154
|
+
var _a, _b;
|
|
155
|
+
const engine = this.context.engine;
|
|
156
|
+
if (!engine) return;
|
|
157
|
+
const dataSourceKey = this.getDataSourceKey() || "main";
|
|
158
|
+
const resName = resourceName || this.getResourceName();
|
|
159
|
+
if (!resName) return;
|
|
160
|
+
const affectedResourceNames = /* @__PURE__ */ new Set([String(resName)]);
|
|
161
|
+
if (typeof resName === "string" && resName.includes(".")) {
|
|
162
|
+
affectedResourceNames.add(resName.split(".")[0]);
|
|
163
|
+
}
|
|
164
|
+
for (const name of affectedResourceNames) {
|
|
165
|
+
engine.markDataSourceDirty(dataSourceKey, name);
|
|
166
|
+
}
|
|
167
|
+
(_b = (_a = engine.emitter) == null ? void 0 : _a.emit) == null ? void 0 : _b.call(_a, import_viewEvents.DATA_SOURCE_DIRTY_EVENT, {
|
|
168
|
+
dataSourceKey,
|
|
169
|
+
resourceNames: Array.from(affectedResourceNames)
|
|
170
|
+
});
|
|
171
|
+
}
|
|
148
172
|
setSourceId(sourceId) {
|
|
149
173
|
this.sourceId = sourceId;
|
|
150
174
|
return this;
|
|
@@ -16,6 +16,7 @@ export declare class MultiRecordResource<TDataItem = any> extends BaseRecordReso
|
|
|
16
16
|
value: Record<string, any>;
|
|
17
17
|
};
|
|
18
18
|
private refreshTimer;
|
|
19
|
+
private refreshWaiters;
|
|
19
20
|
protected createActionOptions: {};
|
|
20
21
|
protected updateActionOptions: {};
|
|
21
22
|
protected _refreshActionName: string;
|
|
@@ -47,6 +47,7 @@ const _MultiRecordResource = class _MultiRecordResource extends import_baseRecor
|
|
|
47
47
|
_data = import_reactive.observable.ref([]);
|
|
48
48
|
_meta = import_reactive.observable.ref({});
|
|
49
49
|
refreshTimer = null;
|
|
50
|
+
refreshWaiters = [];
|
|
50
51
|
createActionOptions = {};
|
|
51
52
|
updateActionOptions = {};
|
|
52
53
|
_refreshActionName = "list";
|
|
@@ -130,6 +131,7 @@ const _MultiRecordResource = class _MultiRecordResource extends import_baseRecor
|
|
|
130
131
|
async create(data, options) {
|
|
131
132
|
const config = this.mergeRequestConfig({ data }, this.createActionOptions, options);
|
|
132
133
|
const res = await this.runAction("create", config);
|
|
134
|
+
this.markDataSourceDirty();
|
|
133
135
|
this.emit("saved", data);
|
|
134
136
|
if ((options == null ? void 0 : options.refresh) !== false) {
|
|
135
137
|
await this.refresh();
|
|
@@ -160,6 +162,7 @@ const _MultiRecordResource = class _MultiRecordResource extends import_baseRecor
|
|
|
160
162
|
options
|
|
161
163
|
);
|
|
162
164
|
await this.runAction("update", config);
|
|
165
|
+
this.markDataSourceDirty();
|
|
163
166
|
this.emit("saved", data);
|
|
164
167
|
await this.refresh();
|
|
165
168
|
}
|
|
@@ -180,6 +183,7 @@ const _MultiRecordResource = class _MultiRecordResource extends import_baseRecor
|
|
|
180
183
|
options
|
|
181
184
|
);
|
|
182
185
|
await this.runAction("destroy", config);
|
|
186
|
+
this.markDataSourceDirty();
|
|
183
187
|
const currentPage = this.getPage();
|
|
184
188
|
const lastPage = Math.ceil((this.getCount() - import_lodash.default.castArray(filterByTk).length) / this.getPageSize());
|
|
185
189
|
if (currentPage > lastPage) {
|
|
@@ -202,7 +206,11 @@ const _MultiRecordResource = class _MultiRecordResource extends import_baseRecor
|
|
|
202
206
|
clearTimeout(this.refreshTimer);
|
|
203
207
|
}
|
|
204
208
|
return new Promise((resolve, reject) => {
|
|
209
|
+
this.refreshWaiters.push({ resolve, reject });
|
|
205
210
|
this.refreshTimer = setTimeout(async () => {
|
|
211
|
+
const waiters = this.refreshWaiters;
|
|
212
|
+
this.refreshWaiters = [];
|
|
213
|
+
this.refreshTimer = null;
|
|
206
214
|
try {
|
|
207
215
|
this.clearError();
|
|
208
216
|
this.loading = true;
|
|
@@ -218,13 +226,12 @@ const _MultiRecordResource = class _MultiRecordResource extends import_baseRecor
|
|
|
218
226
|
this.setPageSize(meta.pageSize);
|
|
219
227
|
}
|
|
220
228
|
this.emit("refresh");
|
|
221
|
-
|
|
222
|
-
resolve();
|
|
229
|
+
waiters.forEach((w) => w.resolve());
|
|
223
230
|
} catch (error) {
|
|
224
231
|
this.setError(error);
|
|
225
|
-
|
|
232
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
233
|
+
waiters.forEach((w) => w.reject(err));
|
|
226
234
|
} finally {
|
|
227
|
-
this.refreshTimer = null;
|
|
228
235
|
this.loading = false;
|
|
229
236
|
}
|
|
230
237
|
});
|
|
@@ -70,6 +70,7 @@ const _SingleRecordResource = class _SingleRecordResource extends import_baseRec
|
|
|
70
70
|
...config,
|
|
71
71
|
data: result
|
|
72
72
|
});
|
|
73
|
+
this.markDataSourceDirty();
|
|
73
74
|
this.emit("saved", data);
|
|
74
75
|
if ((options == null ? void 0 : options.refresh) !== false) {
|
|
75
76
|
await this.refresh();
|
|
@@ -86,6 +87,7 @@ const _SingleRecordResource = class _SingleRecordResource extends import_baseRec
|
|
|
86
87
|
options
|
|
87
88
|
);
|
|
88
89
|
await this.runAction("destroy", config);
|
|
90
|
+
this.markDataSourceDirty();
|
|
89
91
|
this.setData(null);
|
|
90
92
|
}
|
|
91
93
|
async refresh() {
|
|
@@ -126,6 +126,7 @@ const _SQLResource = class _SQLResource extends import_baseRecordResource.BaseRe
|
|
|
126
126
|
_data = import_reactive.observable.ref(null);
|
|
127
127
|
_meta = import_reactive.observable.ref({});
|
|
128
128
|
refreshTimer = null;
|
|
129
|
+
refreshWaiters = [];
|
|
129
130
|
_debugEnabled = false;
|
|
130
131
|
_sql;
|
|
131
132
|
// 请求配置 - 与 APIClient 接口保持一致
|
|
@@ -261,7 +262,11 @@ const _SQLResource = class _SQLResource extends import_baseRecordResource.BaseRe
|
|
|
261
262
|
clearTimeout(this.refreshTimer);
|
|
262
263
|
}
|
|
263
264
|
return new Promise((resolve, reject) => {
|
|
265
|
+
this.refreshWaiters.push({ resolve, reject });
|
|
264
266
|
this.refreshTimer = setTimeout(async () => {
|
|
267
|
+
const waiters = this.refreshWaiters;
|
|
268
|
+
this.refreshWaiters = [];
|
|
269
|
+
this.refreshTimer = null;
|
|
265
270
|
try {
|
|
266
271
|
this.clearError();
|
|
267
272
|
this.loading = true;
|
|
@@ -270,12 +275,12 @@ const _SQLResource = class _SQLResource extends import_baseRecordResource.BaseRe
|
|
|
270
275
|
this.setData(data).setMeta(meta);
|
|
271
276
|
this.loading = false;
|
|
272
277
|
this.emit("refresh");
|
|
273
|
-
resolve();
|
|
278
|
+
waiters.forEach((w) => w.resolve());
|
|
274
279
|
} catch (error) {
|
|
275
280
|
this.setError(error);
|
|
276
|
-
|
|
281
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
282
|
+
waiters.forEach((w) => w.reject(err));
|
|
277
283
|
} finally {
|
|
278
|
-
this.refreshTimer = null;
|
|
279
284
|
this.loading = false;
|
|
280
285
|
}
|
|
281
286
|
});
|
|
@@ -67,14 +67,17 @@ function defineBaseContextMeta() {
|
|
|
67
67
|
ReactDOM: "ReactDOM client API including createRoot for rendering React components. Also available via `ctx.libs.ReactDOM`.",
|
|
68
68
|
antd: "Ant Design component library. Recommended access path: `ctx.libs.antd`.",
|
|
69
69
|
libs: {
|
|
70
|
-
description: "Namespace for third-party and shared libraries. Includes React, ReactDOM, Ant Design, and
|
|
70
|
+
description: "Namespace for third-party and shared libraries. Includes React, ReactDOM, Ant Design, dayjs, lodash, math.js, and formula.js.",
|
|
71
71
|
detail: "Libraries namespace",
|
|
72
72
|
properties: {
|
|
73
73
|
React: "React namespace (same as ctx.React).",
|
|
74
74
|
ReactDOM: "ReactDOM client API (same as ctx.ReactDOM).",
|
|
75
75
|
antd: "Ant Design component library (same as ctx.antd).",
|
|
76
76
|
dayjs: "dayjs date-time utility library.",
|
|
77
|
-
antdIcons: "Ant Design icons library. Example: `ctx.libs.antdIcons.PlusOutlined`."
|
|
77
|
+
antdIcons: "Ant Design icons library. Example: `ctx.libs.antdIcons.PlusOutlined`.",
|
|
78
|
+
lodash: 'Lodash utility library. Example: `ctx.libs.lodash.get(obj, "a.b.c")`.',
|
|
79
|
+
math: 'Math.js library for mathematical operations. Example: `ctx.libs.math.evaluate("2 + 3 * 4")`.',
|
|
80
|
+
formula: "Formula.js library for spreadsheet-like formulas. Example: `ctx.libs.formula.SUM([1, 2, 3])`."
|
|
78
81
|
}
|
|
79
82
|
}
|
|
80
83
|
},
|
|
@@ -156,14 +159,17 @@ function defineBaseContextMeta() {
|
|
|
156
159
|
ReactDOM: "ReactDOM \u5BA2\u6237\u7AEF API\uFF0C\u542B createRoot \u7B49\u6E32\u67D3\u65B9\u6CD5\u3002\u63A8\u8350\u901A\u8FC7 `ctx.libs.ReactDOM` \u8BBF\u95EE\u3002",
|
|
157
160
|
antd: "Ant Design \u7EC4\u4EF6\u5E93\uFF08RunJS \u73AF\u5883\u4E2D\u53EF\u7528\uFF09\u3002\u63A8\u8350\u4F7F\u7528 `ctx.libs.antd` \u8BBF\u95EE\u3002",
|
|
158
161
|
libs: {
|
|
159
|
-
description: "\u7B2C\u4E09\u65B9/\u901A\u7528\u5E93\u7684\u7EDF\u4E00\u547D\u540D\u7A7A\u95F4\uFF0C\u5305\u542B React\u3001ReactDOM\u3001Ant Design\u3001dayjs \u7B49\u3002\u540E\u7EED\u65B0\u589E\u5E93\u4F1A\u4F18\u5148\u6302\u5728\u6B64\u5904\u3002",
|
|
162
|
+
description: "\u7B2C\u4E09\u65B9/\u901A\u7528\u5E93\u7684\u7EDF\u4E00\u547D\u540D\u7A7A\u95F4\uFF0C\u5305\u542B React\u3001ReactDOM\u3001Ant Design\u3001dayjs\u3001lodash\u3001math.js\u3001formula.js \u7B49\u3002\u540E\u7EED\u65B0\u589E\u5E93\u4F1A\u4F18\u5148\u6302\u5728\u6B64\u5904\u3002",
|
|
160
163
|
detail: "\u901A\u7528\u5E93\u547D\u540D\u7A7A\u95F4",
|
|
161
164
|
properties: {
|
|
162
165
|
React: "React \u547D\u540D\u7A7A\u95F4\uFF08\u7B49\u4EF7\u4E8E ctx.React\uFF09\u3002",
|
|
163
166
|
ReactDOM: "ReactDOM \u5BA2\u6237\u7AEF API\uFF08\u7B49\u4EF7\u4E8E ctx.ReactDOM\uFF09\u3002",
|
|
164
167
|
antd: "Ant Design \u7EC4\u4EF6\u5E93\uFF08\u7B49\u4EF7\u4E8E ctx.antd\uFF09\u3002",
|
|
165
168
|
dayjs: "dayjs \u65E5\u671F\u65F6\u95F4\u5DE5\u5177\u5E93\u3002",
|
|
166
|
-
antdIcons: "Ant Design \u56FE\u6807\u5E93\u3002 \u4F8B\u5982\uFF1A`ctx.libs.antdIcons.PlusOutlined`\u3002"
|
|
169
|
+
antdIcons: "Ant Design \u56FE\u6807\u5E93\u3002 \u4F8B\u5982\uFF1A`ctx.libs.antdIcons.PlusOutlined`\u3002",
|
|
170
|
+
lodash: 'Lodash \u5DE5\u5177\u5E93\u3002\u4F8B\u5982\uFF1A`ctx.libs.lodash.get(obj, "a.b.c")`\u3002',
|
|
171
|
+
math: 'Math.js \u6570\u5B66\u8FD0\u7B97\u5E93\u3002\u4F8B\u5982\uFF1A`ctx.libs.math.evaluate("2 + 3 * 4")`\u3002',
|
|
172
|
+
formula: "Formula.js \u7535\u5B50\u8868\u683C\u516C\u5F0F\u5E93\u3002\u4F8B\u5982\uFF1A`ctx.libs.formula.SUM([1, 2, 3])`\u3002"
|
|
167
173
|
}
|
|
168
174
|
}
|
|
169
175
|
},
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import type { FlowContext } from './flowContext';
|
|
10
|
+
export type RunJSLibCache = 'global' | 'context';
|
|
11
|
+
export type RunJSLibLoader<T = any> = (ctx: FlowContext) => T | Promise<T>;
|
|
12
|
+
export declare function registerRunJSLib(name: string, loader: RunJSLibLoader, options?: {
|
|
13
|
+
cache?: RunJSLibCache;
|
|
14
|
+
}): void;
|
|
15
|
+
export declare function setupRunJSLibs(ctx: FlowContext): void;
|
|
16
|
+
export declare function setRunJSLibOverride(ctx: FlowContext, name: string, value: unknown, options?: {
|
|
17
|
+
topLevelKey?: string | false;
|
|
18
|
+
}): void;
|
|
19
|
+
export declare function externalReactRender(options: {
|
|
20
|
+
ctx: any;
|
|
21
|
+
entry: any;
|
|
22
|
+
vnode: any;
|
|
23
|
+
containerEl: any;
|
|
24
|
+
rootMap: WeakMap<any, any>;
|
|
25
|
+
unmountContainerRoot: () => void;
|
|
26
|
+
internalReact: any;
|
|
27
|
+
internalAntd: any;
|
|
28
|
+
}): any;
|