@nocobase/flow-engine 2.0.0-beta.20 → 2.0.0-beta.22
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/JSRunner.js +23 -1
- package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +3 -3
- package/lib/data-source/index.d.ts +7 -27
- package/lib/data-source/index.js +67 -46
- package/lib/flowContext.d.ts +62 -0
- package/lib/flowContext.js +92 -3
- package/lib/flowEngine.js +18 -8
- package/lib/index.d.ts +4 -1
- package/lib/index.js +5 -0
- package/lib/resources/sqlResource.d.ts +3 -3
- package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.js +12 -2
- package/lib/runjs-context/contexts/JSBlockRunJSContext.js +2 -2
- package/lib/runjs-context/contexts/JSEditableFieldRunJSContext.d.ts +16 -0
- package/lib/runjs-context/contexts/JSEditableFieldRunJSContext.js +125 -0
- package/lib/runjs-context/contexts/JSItemRunJSContext.js +12 -2
- package/lib/runjs-context/contexts/base.js +691 -23
- package/lib/runjs-context/contributions.d.ts +33 -0
- package/lib/runjs-context/contributions.js +88 -0
- package/lib/runjs-context/setup.js +6 -0
- package/lib/runjs-context/snippets/index.d.ts +11 -1
- package/lib/runjs-context/snippets/index.js +61 -40
- package/lib/utils/safeGlobals.js +2 -0
- package/package.json +4 -4
- package/src/JSRunner.ts +29 -1
- package/src/__tests__/JSRunner.test.ts +64 -0
- package/src/__tests__/flowContext.test.ts +90 -0
- package/src/__tests__/flowModel.openView.navigation.test.ts +28 -0
- package/src/__tests__/runjsContext.test.ts +4 -1
- package/src/__tests__/runjsLocales.test.ts +4 -1
- package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +3 -3
- package/src/data-source/index.ts +71 -105
- package/src/flowContext.ts +160 -2
- package/src/flowEngine.ts +18 -8
- package/src/index.ts +4 -1
- package/src/resources/sqlResource.ts +3 -3
- package/src/runjs-context/contexts/FormJSFieldItemRunJSContext.ts +10 -0
- package/src/runjs-context/contexts/JSBlockRunJSContext.ts +6 -2
- package/src/runjs-context/contexts/JSEditableFieldRunJSContext.ts +106 -0
- package/src/runjs-context/contexts/JSItemRunJSContext.ts +10 -0
- package/src/runjs-context/contexts/base.ts +698 -30
- package/src/runjs-context/contributions.ts +88 -0
- package/src/runjs-context/setup.ts +6 -0
- package/src/runjs-context/snippets/index.ts +75 -41
- package/src/utils/__tests__/safeGlobals.test.ts +8 -0
- package/src/utils/safeGlobals.ts +3 -1
package/lib/JSRunner.js
CHANGED
|
@@ -35,6 +35,7 @@ const _JSRunner = class _JSRunner {
|
|
|
35
35
|
globals;
|
|
36
36
|
timeoutMs;
|
|
37
37
|
constructor(options = {}) {
|
|
38
|
+
var _a, _b;
|
|
38
39
|
const bindWindowFn = /* @__PURE__ */ __name((key) => {
|
|
39
40
|
if (typeof window !== "undefined" && typeof window[key] === "function") {
|
|
40
41
|
return window[key].bind(window);
|
|
@@ -42,13 +43,34 @@ const _JSRunner = class _JSRunner {
|
|
|
42
43
|
const fn = globalThis[key];
|
|
43
44
|
return typeof fn === "function" ? fn.bind(globalThis) : fn;
|
|
44
45
|
}, "bindWindowFn");
|
|
46
|
+
const providedGlobals = options.globals || {};
|
|
47
|
+
const liftedGlobals = {};
|
|
48
|
+
if (!Object.prototype.hasOwnProperty.call(providedGlobals, "Blob")) {
|
|
49
|
+
try {
|
|
50
|
+
const blobCtor = (_a = providedGlobals.window) == null ? void 0 : _a.Blob;
|
|
51
|
+
if (typeof blobCtor !== "undefined") {
|
|
52
|
+
liftedGlobals.Blob = blobCtor;
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (!Object.prototype.hasOwnProperty.call(providedGlobals, "URL")) {
|
|
58
|
+
try {
|
|
59
|
+
const urlCtor = (_b = providedGlobals.window) == null ? void 0 : _b.URL;
|
|
60
|
+
if (typeof urlCtor !== "undefined") {
|
|
61
|
+
liftedGlobals.URL = urlCtor;
|
|
62
|
+
}
|
|
63
|
+
} catch {
|
|
64
|
+
}
|
|
65
|
+
}
|
|
45
66
|
this.globals = {
|
|
46
67
|
console,
|
|
47
68
|
setTimeout: bindWindowFn("setTimeout"),
|
|
48
69
|
clearTimeout: bindWindowFn("clearTimeout"),
|
|
49
70
|
setInterval: bindWindowFn("setInterval"),
|
|
50
71
|
clearInterval: bindWindowFn("clearInterval"),
|
|
51
|
-
...
|
|
72
|
+
...liftedGlobals,
|
|
73
|
+
...providedGlobals
|
|
52
74
|
};
|
|
53
75
|
this.timeoutMs = options.timeoutMs ?? 5e3;
|
|
54
76
|
}
|
|
@@ -521,7 +521,7 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
|
|
|
521
521
|
};
|
|
522
522
|
items.push({
|
|
523
523
|
key: uniqueKey,
|
|
524
|
-
label: /* @__PURE__ */ import_react.default.createElement(MenuLabelItem, { title:
|
|
524
|
+
label: /* @__PURE__ */ import_react.default.createElement(MenuLabelItem, { title: stepInfo.title, uiMode, itemProps })
|
|
525
525
|
});
|
|
526
526
|
});
|
|
527
527
|
if (flow.options.divider === "bottom") {
|
|
@@ -555,7 +555,7 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
|
|
|
555
555
|
const uniqueKey = generateUniqueKey(`${flow.key}:${stepInfo.stepKey}`);
|
|
556
556
|
items.push({
|
|
557
557
|
key: uniqueKey,
|
|
558
|
-
label:
|
|
558
|
+
label: stepInfo.title
|
|
559
559
|
});
|
|
560
560
|
});
|
|
561
561
|
});
|
|
@@ -567,7 +567,7 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
|
|
|
567
567
|
const uniqueKey = generateUniqueKey(`${modelKey}:${flow.key}:${stepInfo.stepKey}`);
|
|
568
568
|
subMenuChildren.push({
|
|
569
569
|
key: uniqueKey,
|
|
570
|
-
label:
|
|
570
|
+
label: stepInfo.title
|
|
571
571
|
});
|
|
572
572
|
});
|
|
573
573
|
});
|
|
@@ -66,6 +66,11 @@ export interface CollectionOptions {
|
|
|
66
66
|
export declare class CollectionManager {
|
|
67
67
|
dataSource: DataSource;
|
|
68
68
|
collections: Map<string, Collection>;
|
|
69
|
+
allCollectionsInheritChain: string[];
|
|
70
|
+
protected childrenCollectionsName: {
|
|
71
|
+
supportView?: string[];
|
|
72
|
+
notSupportView?: string[];
|
|
73
|
+
};
|
|
69
74
|
constructor(dataSource: DataSource);
|
|
70
75
|
get flowEngine(): FlowEngine;
|
|
71
76
|
addCollection(collection: Collection | CollectionOptions): void;
|
|
@@ -83,33 +88,8 @@ export declare class CollectionManager {
|
|
|
83
88
|
clearCollections(): void;
|
|
84
89
|
getAssociation(associationName: string): CollectionField | undefined;
|
|
85
90
|
getChildrenCollections(name: any): any[];
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
cached?: Record<string, any>;
|
|
89
|
-
collectionNames?: string[];
|
|
90
|
-
/**
|
|
91
|
-
* 为 true 时允许查询所有关联字段
|
|
92
|
-
* 为 Array<string> 时仅允许查询指定的关联字段
|
|
93
|
-
*/
|
|
94
|
-
association?: boolean | string[];
|
|
95
|
-
/**
|
|
96
|
-
* Max depth of recursion
|
|
97
|
-
*/
|
|
98
|
-
maxDepth?: number;
|
|
99
|
-
allowAllTypes?: boolean;
|
|
100
|
-
/**
|
|
101
|
-
* 排除这些接口的字段
|
|
102
|
-
*/
|
|
103
|
-
exceptInterfaces?: string[];
|
|
104
|
-
/**
|
|
105
|
-
* field value 的前缀,用 . 连接,比如 a.b.c
|
|
106
|
-
*/
|
|
107
|
-
prefixFieldValue?: string;
|
|
108
|
-
/**
|
|
109
|
-
* 是否使用 prefixFieldValue 作为 field value
|
|
110
|
-
*/
|
|
111
|
-
usePrefix?: boolean;
|
|
112
|
-
}): any;
|
|
91
|
+
getChildrenCollectionsName(name: any, isSupportView?: boolean): string[];
|
|
92
|
+
getAllCollectionsInheritChain(name: any): string[];
|
|
113
93
|
}
|
|
114
94
|
export declare class Collection {
|
|
115
95
|
fields: Map<string, CollectionField>;
|
package/lib/data-source/index.js
CHANGED
|
@@ -188,6 +188,8 @@ const _CollectionManager = class _CollectionManager {
|
|
|
188
188
|
this.collections = import_reactive.observable.shallow(/* @__PURE__ */ new Map());
|
|
189
189
|
}
|
|
190
190
|
collections;
|
|
191
|
+
allCollectionsInheritChain;
|
|
192
|
+
childrenCollectionsName = {};
|
|
191
193
|
get flowEngine() {
|
|
192
194
|
return this.dataSource.flowEngine;
|
|
193
195
|
}
|
|
@@ -317,56 +319,75 @@ const _CollectionManager = class _CollectionManager {
|
|
|
317
319
|
}, "getChildrens");
|
|
318
320
|
return getChildrens(name);
|
|
319
321
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
cached = {},
|
|
325
|
-
collectionNames = [collectionName],
|
|
326
|
-
maxDepth = 1,
|
|
327
|
-
allowAllTypes = false,
|
|
328
|
-
exceptInterfaces = [],
|
|
329
|
-
prefixFieldValue = "",
|
|
330
|
-
usePrefix = false,
|
|
331
|
-
dataSource: customDataSourceNameValue
|
|
332
|
-
} = opts || {};
|
|
333
|
-
if (collectionNames.length - 1 > maxDepth) {
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
if (cached[collectionName]) {
|
|
337
|
-
return import_lodash.default.cloneDeep(cached[collectionName]);
|
|
322
|
+
getChildrenCollectionsName(name, isSupportView = false) {
|
|
323
|
+
const cacheKey = isSupportView ? "supportView" : "notSupportView";
|
|
324
|
+
if (this.childrenCollectionsName[cacheKey]) {
|
|
325
|
+
return this.childrenCollectionsName[cacheKey].slice();
|
|
338
326
|
}
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
...opts,
|
|
356
|
-
cached,
|
|
357
|
-
dataSource: customDataSourceNameValue,
|
|
358
|
-
collectionNames: [...collectionNames, field.target],
|
|
359
|
-
prefixFieldValue: usePrefix ? prefixFieldValue ? `${prefixFieldValue}.${field.name}` : field.name : "",
|
|
360
|
-
usePrefix
|
|
327
|
+
const children = [];
|
|
328
|
+
const collections = [...this.getCollections()];
|
|
329
|
+
const getChildrenCollectionsInner = /* @__PURE__ */ __name((collectionName) => {
|
|
330
|
+
const inheritCollections = collections.filter((v) => {
|
|
331
|
+
var _a;
|
|
332
|
+
return (_a = [...v.inherits]) == null ? void 0 : _a.includes(collectionName);
|
|
333
|
+
});
|
|
334
|
+
inheritCollections.forEach((v) => {
|
|
335
|
+
const collectionKey = v.name;
|
|
336
|
+
children.push(collectionKey);
|
|
337
|
+
return getChildrenCollectionsInner(collectionKey);
|
|
338
|
+
});
|
|
339
|
+
if (isSupportView) {
|
|
340
|
+
const sourceCollections = collections.filter((v) => {
|
|
341
|
+
var _a;
|
|
342
|
+
return ((_a = [...v.sources]) == null ? void 0 : _a.length) === 1 && (v == null ? void 0 : v.sources[0]) === collectionName;
|
|
361
343
|
});
|
|
362
|
-
|
|
363
|
-
|
|
344
|
+
sourceCollections.forEach((v) => {
|
|
345
|
+
const collectionKey = v.name;
|
|
346
|
+
children.push(v.name);
|
|
347
|
+
return getChildrenCollectionsInner(collectionKey);
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
return import_lodash.default.uniq(children);
|
|
351
|
+
}, "getChildrenCollectionsInner");
|
|
352
|
+
this.childrenCollectionsName[cacheKey] = getChildrenCollectionsInner(name);
|
|
353
|
+
return this.childrenCollectionsName[cacheKey];
|
|
354
|
+
}
|
|
355
|
+
getAllCollectionsInheritChain(name) {
|
|
356
|
+
if (this.allCollectionsInheritChain) {
|
|
357
|
+
return this.allCollectionsInheritChain.slice();
|
|
358
|
+
}
|
|
359
|
+
const collectionsInheritChain = [name];
|
|
360
|
+
const getInheritChain = /* @__PURE__ */ __name((name2) => {
|
|
361
|
+
const collection = this.getCollection(name2);
|
|
362
|
+
if (collection) {
|
|
363
|
+
const { inherits } = collection;
|
|
364
|
+
const children = this.getChildrenCollectionsName(name2);
|
|
365
|
+
if (inherits) {
|
|
366
|
+
for (let index = 0; index < inherits.length; index++) {
|
|
367
|
+
const collectionKey = inherits[index];
|
|
368
|
+
if (collectionsInheritChain.includes(collectionKey)) {
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
collectionsInheritChain.push(collectionKey);
|
|
372
|
+
getInheritChain(collectionKey);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
if (children) {
|
|
376
|
+
for (let index = 0; index < children.length; index++) {
|
|
377
|
+
const collection2 = this.getCollection(children[index]);
|
|
378
|
+
const collectionKey = collection2.name;
|
|
379
|
+
if (collectionsInheritChain.includes(collectionKey)) {
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
collectionsInheritChain.push(collectionKey);
|
|
383
|
+
getInheritChain(collectionKey);
|
|
384
|
+
}
|
|
364
385
|
}
|
|
365
386
|
}
|
|
366
|
-
return
|
|
367
|
-
})
|
|
368
|
-
|
|
369
|
-
return
|
|
387
|
+
return collectionsInheritChain;
|
|
388
|
+
}, "getInheritChain");
|
|
389
|
+
this.allCollectionsInheritChain = getInheritChain(name);
|
|
390
|
+
return this.allCollectionsInheritChain || [];
|
|
370
391
|
}
|
|
371
392
|
};
|
|
372
393
|
__name(_CollectionManager, "CollectionManager");
|
package/lib/flowContext.d.ts
CHANGED
|
@@ -143,6 +143,29 @@ export declare class FlowContext {
|
|
|
143
143
|
* @returns 属性定义选项,或 undefined(未定义)
|
|
144
144
|
*/
|
|
145
145
|
getPropertyOptions(key: string): PropertyOptions | undefined;
|
|
146
|
+
/**
|
|
147
|
+
* 获取当前上下文可用的顶层 API 信息(主要用于编辑器补全/工具)。
|
|
148
|
+
*
|
|
149
|
+
* 注意:
|
|
150
|
+
* - 目前返回值以“尽量可用”为目标,允许不完整。
|
|
151
|
+
* - 该方法不会展开变量 meta(变量结构应由 `getPropertyMetaTree()`/VariableInput 等机制负责)。
|
|
152
|
+
*/
|
|
153
|
+
getApiInfos(options?: {
|
|
154
|
+
version?: string;
|
|
155
|
+
}): Promise<Record<string, any>>;
|
|
156
|
+
/**
|
|
157
|
+
* 变量结构信息(保留给编辑器/工具使用)。
|
|
158
|
+
* 当前实现为保底空对象,避免 RunJS doc 中补全到该方法时调用报错。
|
|
159
|
+
*/
|
|
160
|
+
getVarInfos(_options?: {
|
|
161
|
+
path?: string | string[];
|
|
162
|
+
maxDepth?: number;
|
|
163
|
+
}): Promise<Record<string, any>>;
|
|
164
|
+
/**
|
|
165
|
+
* 运行时环境信息(保留给编辑器/工具使用)。
|
|
166
|
+
* 当前实现为保底空对象,避免 RunJS doc 中补全到该方法时调用报错。
|
|
167
|
+
*/
|
|
168
|
+
getEnvInfos(): Promise<Record<string, any>>;
|
|
146
169
|
}
|
|
147
170
|
declare class BaseFlowEngineContext extends FlowContext {
|
|
148
171
|
router: Router;
|
|
@@ -158,6 +181,7 @@ declare class BaseFlowEngineContext extends FlowContext {
|
|
|
158
181
|
*/
|
|
159
182
|
renderJson: (template: JSONValue) => Promise<any>;
|
|
160
183
|
resolveJsonTemplate: (template: JSONValue) => Promise<any>;
|
|
184
|
+
getVar: (path: string) => Promise<any>;
|
|
161
185
|
runjs: (code: string, variables?: Record<string, any>, options?: JSRunnerOptions) => Promise<any>;
|
|
162
186
|
getAction: <TModel extends FlowModel = FlowModel, TCtx extends FlowContext = FlowContext>(name: string) => ActionDefinition<TModel, TCtx> | undefined;
|
|
163
187
|
getActions: <TModel extends FlowModel = FlowModel, TCtx extends FlowContext = FlowContext>() => Map<string, ActionDefinition<TModel, TCtx>>;
|
|
@@ -219,22 +243,60 @@ export declare class FlowRuntimeContext<TModel extends FlowModel = FlowModel, TM
|
|
|
219
243
|
get mode(): TMode;
|
|
220
244
|
}
|
|
221
245
|
export type FlowSettingsContext<TModel extends FlowModel = FlowModel> = FlowRuntimeContext<TModel, 'settings'>;
|
|
246
|
+
export type FlowContextDocRef = string | {
|
|
247
|
+
url: string;
|
|
248
|
+
title?: string;
|
|
249
|
+
};
|
|
250
|
+
export type FlowDeprecationDoc = boolean | {
|
|
251
|
+
message?: string;
|
|
252
|
+
replacedBy?: string | string[];
|
|
253
|
+
since?: string;
|
|
254
|
+
removedIn?: string;
|
|
255
|
+
ref?: FlowContextDocRef;
|
|
256
|
+
};
|
|
257
|
+
export type FlowContextDocParam = {
|
|
258
|
+
name: string;
|
|
259
|
+
description?: string;
|
|
260
|
+
type?: string;
|
|
261
|
+
optional?: boolean;
|
|
262
|
+
default?: JSONValue;
|
|
263
|
+
};
|
|
264
|
+
export type FlowContextDocReturn = {
|
|
265
|
+
description?: string;
|
|
266
|
+
type?: string;
|
|
267
|
+
};
|
|
222
268
|
export type RunJSDocCompletionDoc = {
|
|
223
269
|
insertText?: string;
|
|
224
270
|
};
|
|
271
|
+
export type RunJSDocHiddenDoc = boolean | ((ctx: any) => boolean | Promise<boolean>);
|
|
272
|
+
export type RunJSDocHiddenOrPathsDoc = boolean | string[] | ((ctx: any) => boolean | string[] | Promise<boolean | string[]>);
|
|
225
273
|
export type RunJSDocPropertyDoc = string | {
|
|
226
274
|
description?: string;
|
|
227
275
|
detail?: string;
|
|
228
276
|
type?: string;
|
|
229
277
|
examples?: string[];
|
|
230
278
|
completion?: RunJSDocCompletionDoc;
|
|
279
|
+
ref?: FlowContextDocRef;
|
|
280
|
+
deprecated?: FlowDeprecationDoc;
|
|
281
|
+
params?: FlowContextDocParam[];
|
|
282
|
+
returns?: FlowContextDocReturn;
|
|
231
283
|
properties?: Record<string, RunJSDocPropertyDoc>;
|
|
284
|
+
hidden?: RunJSDocHiddenOrPathsDoc;
|
|
285
|
+
disabled?: boolean | ((ctx: any) => boolean | Promise<boolean>);
|
|
286
|
+
disabledReason?: string | ((ctx: any) => string | undefined | Promise<string | undefined>);
|
|
232
287
|
};
|
|
233
288
|
export type RunJSDocMethodDoc = string | {
|
|
234
289
|
description?: string;
|
|
235
290
|
detail?: string;
|
|
236
291
|
examples?: string[];
|
|
237
292
|
completion?: RunJSDocCompletionDoc;
|
|
293
|
+
ref?: FlowContextDocRef;
|
|
294
|
+
deprecated?: FlowDeprecationDoc;
|
|
295
|
+
params?: FlowContextDocParam[];
|
|
296
|
+
returns?: FlowContextDocReturn;
|
|
297
|
+
hidden?: RunJSDocHiddenDoc;
|
|
298
|
+
disabled?: boolean | ((ctx: any) => boolean | Promise<boolean>);
|
|
299
|
+
disabledReason?: string | ((ctx: any) => string | undefined | Promise<string | undefined>);
|
|
238
300
|
};
|
|
239
301
|
export type RunJSDocMeta = {
|
|
240
302
|
label?: string;
|
package/lib/flowContext.js
CHANGED
|
@@ -469,6 +469,73 @@ const _FlowContext = class _FlowContext {
|
|
|
469
469
|
}
|
|
470
470
|
return this._findPropertyInDelegates(this._delegates, key);
|
|
471
471
|
}
|
|
472
|
+
/**
|
|
473
|
+
* 获取当前上下文可用的顶层 API 信息(主要用于编辑器补全/工具)。
|
|
474
|
+
*
|
|
475
|
+
* 注意:
|
|
476
|
+
* - 目前返回值以“尽量可用”为目标,允许不完整。
|
|
477
|
+
* - 该方法不会展开变量 meta(变量结构应由 `getPropertyMetaTree()`/VariableInput 等机制负责)。
|
|
478
|
+
*/
|
|
479
|
+
async getApiInfos(options = {}) {
|
|
480
|
+
var _a, _b, _c, _d, _e;
|
|
481
|
+
const version = (options == null ? void 0 : options.version) || "v1";
|
|
482
|
+
const modelClass = (0, import_registry.getModelClassName)(this);
|
|
483
|
+
const Ctor = import_registry.RunJSContextRegistry.resolve(version, modelClass) || import_registry.RunJSContextRegistry.resolve(version, "*");
|
|
484
|
+
const locale = ((_b = (_a = this == null ? void 0 : this.api) == null ? void 0 : _a.auth) == null ? void 0 : _b.locale) || ((_c = this == null ? void 0 : this.i18n) == null ? void 0 : _c.language) || (this == null ? void 0 : this.locale);
|
|
485
|
+
let doc = {};
|
|
486
|
+
try {
|
|
487
|
+
if ((_d = Ctor == null ? void 0 : Ctor.getDoc) == null ? void 0 : _d.length) doc = Ctor.getDoc(locale) || {};
|
|
488
|
+
else doc = ((_e = Ctor == null ? void 0 : Ctor.getDoc) == null ? void 0 : _e.call(Ctor)) || {};
|
|
489
|
+
} catch (_2) {
|
|
490
|
+
doc = {};
|
|
491
|
+
}
|
|
492
|
+
const isPrivateKey = /* @__PURE__ */ __name((key) => typeof key === "string" && key.startsWith("_"), "isPrivateKey");
|
|
493
|
+
const out = {};
|
|
494
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
495
|
+
const walk = /* @__PURE__ */ __name((ctx) => {
|
|
496
|
+
if (!ctx || visited.has(ctx)) return;
|
|
497
|
+
visited.add(ctx);
|
|
498
|
+
try {
|
|
499
|
+
for (const key of Object.keys(ctx._props || {})) {
|
|
500
|
+
if (isPrivateKey(key)) continue;
|
|
501
|
+
if (typeof out[key] === "undefined") out[key] = { type: "property" };
|
|
502
|
+
}
|
|
503
|
+
} catch (_2) {
|
|
504
|
+
}
|
|
505
|
+
try {
|
|
506
|
+
for (const key of Object.keys(ctx._methods || {})) {
|
|
507
|
+
if (isPrivateKey(key)) continue;
|
|
508
|
+
if (typeof out[key] === "undefined") out[key] = { type: "function" };
|
|
509
|
+
}
|
|
510
|
+
} catch (_2) {
|
|
511
|
+
}
|
|
512
|
+
try {
|
|
513
|
+
const delegates = Array.isArray(ctx._delegates) ? ctx._delegates : [];
|
|
514
|
+
for (const d of delegates) walk(d);
|
|
515
|
+
} catch (_2) {
|
|
516
|
+
}
|
|
517
|
+
}, "walk");
|
|
518
|
+
walk(this);
|
|
519
|
+
return {
|
|
520
|
+
...out,
|
|
521
|
+
...(doc == null ? void 0 : doc.properties) || {},
|
|
522
|
+
...(doc == null ? void 0 : doc.methods) || {}
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* 变量结构信息(保留给编辑器/工具使用)。
|
|
527
|
+
* 当前实现为保底空对象,避免 RunJS doc 中补全到该方法时调用报错。
|
|
528
|
+
*/
|
|
529
|
+
async getVarInfos(_options = {}) {
|
|
530
|
+
return {};
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* 运行时环境信息(保留给编辑器/工具使用)。
|
|
534
|
+
* 当前实现为保底空对象,避免 RunJS doc 中补全到该方法时调用报错。
|
|
535
|
+
*/
|
|
536
|
+
async getEnvInfos() {
|
|
537
|
+
return {};
|
|
538
|
+
}
|
|
472
539
|
};
|
|
473
540
|
_proxy = new WeakMap();
|
|
474
541
|
_FlowContext_instances = new WeakSet();
|
|
@@ -763,7 +830,8 @@ const _FlowEngineContext = class _FlowEngineContext extends BaseFlowEngineContex
|
|
|
763
830
|
value: this.engine
|
|
764
831
|
});
|
|
765
832
|
this.defineProperty("sql", {
|
|
766
|
-
get: /* @__PURE__ */ __name(() => new import_resources.FlowSQLRepository(
|
|
833
|
+
get: /* @__PURE__ */ __name((ctx) => new import_resources.FlowSQLRepository(ctx), "get"),
|
|
834
|
+
cache: false
|
|
767
835
|
});
|
|
768
836
|
this.defineProperty("dataSourceManager", {
|
|
769
837
|
value: dataSourceManager
|
|
@@ -915,6 +983,19 @@ const _FlowEngineContext = class _FlowEngineContext extends BaseFlowEngineContex
|
|
|
915
983
|
}
|
|
916
984
|
return (0, import_utils.resolveExpressions)(serverResolved, this);
|
|
917
985
|
});
|
|
986
|
+
this.defineMethod(
|
|
987
|
+
"getVar",
|
|
988
|
+
async function(varPath) {
|
|
989
|
+
const raw = typeof varPath === "string" ? varPath : String(varPath ?? "");
|
|
990
|
+
const s = raw.trim();
|
|
991
|
+
if (!s) return void 0;
|
|
992
|
+
if (s !== "ctx" && !s.startsWith("ctx.")) {
|
|
993
|
+
throw new Error(`ctx.getVar(path) expects an expression starting with "ctx.", got: "${s}"`);
|
|
994
|
+
}
|
|
995
|
+
return this.resolveJsonTemplate(`{{ ${s} }}`);
|
|
996
|
+
},
|
|
997
|
+
'Resolve a ctx expression value by path (expression starts with "ctx.").'
|
|
998
|
+
);
|
|
918
999
|
this.defineProperty("requirejs", {
|
|
919
1000
|
get: /* @__PURE__ */ __name(() => {
|
|
920
1001
|
var _a, _b;
|
|
@@ -1127,7 +1208,7 @@ const _FlowModelContext = class _FlowModelContext extends BaseFlowModelContext {
|
|
|
1127
1208
|
}, "get")
|
|
1128
1209
|
});
|
|
1129
1210
|
this.defineMethod("openView", async function(uid, options) {
|
|
1130
|
-
var _a, _b, _c, _d;
|
|
1211
|
+
var _a, _b, _c, _d, _e;
|
|
1131
1212
|
const opts = { ...options };
|
|
1132
1213
|
if (opts.defineProperties || opts.defineMethods) {
|
|
1133
1214
|
opts.navigation = false;
|
|
@@ -1177,8 +1258,16 @@ const _FlowModelContext = class _FlowModelContext extends BaseFlowModelContext {
|
|
|
1177
1258
|
engineCtx: this.engine.context
|
|
1178
1259
|
};
|
|
1179
1260
|
model2.context.defineProperty("view", { value: pendingView });
|
|
1261
|
+
const popupFlow = (_e = model2.getFlow) == null ? void 0 : _e.call(model2, "popupSettings");
|
|
1262
|
+
const on = popupFlow == null ? void 0 : popupFlow.on;
|
|
1263
|
+
let openEventName = "click";
|
|
1264
|
+
if (typeof on === "string" && on) {
|
|
1265
|
+
openEventName = on;
|
|
1266
|
+
} else if (on && typeof on === "object" && typeof on.eventName === "string" && on.eventName) {
|
|
1267
|
+
openEventName = on.eventName;
|
|
1268
|
+
}
|
|
1180
1269
|
await model2.dispatchEvent(
|
|
1181
|
-
|
|
1270
|
+
openEventName,
|
|
1182
1271
|
{
|
|
1183
1272
|
// navigation: false, // TODO: 路由模式有bug,不支持多层同样viewId的弹窗,因此这里默认先用false
|
|
1184
1273
|
// ...this.model?.['getInputArgs']?.(), // 避免部分关系字段信息丢失, 仿照 ClickableCollectionField 做法
|
package/lib/flowEngine.js
CHANGED
|
@@ -762,16 +762,26 @@ const _FlowEngine = class _FlowEngine {
|
|
|
762
762
|
*/
|
|
763
763
|
async loadModel(options) {
|
|
764
764
|
if (!this.ensureModelRepository()) return;
|
|
765
|
-
const
|
|
766
|
-
if (
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
765
|
+
const refresh = !!(options == null ? void 0 : options.refresh);
|
|
766
|
+
if (!refresh) {
|
|
767
|
+
const model = this.findModelByParentId(options.parentId, options.subKey);
|
|
768
|
+
if (model) {
|
|
769
|
+
return model;
|
|
770
|
+
}
|
|
771
|
+
const hydrated = this.hydrateModelFromPreviousEngines(options);
|
|
772
|
+
if (hydrated) {
|
|
773
|
+
return hydrated;
|
|
774
|
+
}
|
|
772
775
|
}
|
|
773
776
|
const data = await this._modelRepository.findOne(options);
|
|
774
|
-
|
|
777
|
+
if (!(data == null ? void 0 : data.uid)) return null;
|
|
778
|
+
if (refresh) {
|
|
779
|
+
const existing = this.getModel(data.uid);
|
|
780
|
+
if (existing) {
|
|
781
|
+
this.removeModelWithSubModels(existing.uid);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
return this.createModel(data);
|
|
775
785
|
}
|
|
776
786
|
/**
|
|
777
787
|
* Find a sub-model by parent model ID and subKey.
|
package/lib/index.d.ts
CHANGED
|
@@ -27,7 +27,10 @@ export * from './JSRunner';
|
|
|
27
27
|
export { getRunJSDocFor, createJSRunnerWithVersion, getRunJSScenesForModel, getRunJSScenesForContext, } from './runjs-context/helpers';
|
|
28
28
|
export { RunJSContextRegistry, getModelClassName } from './runjs-context/registry';
|
|
29
29
|
export { setupRunJSContexts } from './runjs-context/setup';
|
|
30
|
-
export {
|
|
30
|
+
export type { RunJSContextContribution, RunJSContextContributionApi } from './runjs-context/contributions';
|
|
31
|
+
export { registerRunJSContextContribution } from './runjs-context/contributions';
|
|
32
|
+
export type { RunJSSnippetLoader } from './runjs-context/snippets';
|
|
33
|
+
export { getSnippetBody, listSnippetsForContext, registerRunJSSnippet } from './runjs-context/snippets';
|
|
31
34
|
export * from './views';
|
|
32
35
|
export { DATA_SOURCE_DIRTY_EVENT, ENGINE_SCOPE_KEY, getEmitterViewActivatedVersion, VIEW_ACTIVATED_EVENT, VIEW_ACTIVATED_VERSION, VIEW_ENGINE_SCOPE, } from './views/viewEvents';
|
|
33
36
|
export * from './FlowDefinition';
|
package/lib/index.js
CHANGED
|
@@ -44,7 +44,9 @@ __export(src_exports, {
|
|
|
44
44
|
getRunJSScenesForModel: () => import_helpers.getRunJSScenesForModel,
|
|
45
45
|
getSnippetBody: () => import_snippets.getSnippetBody,
|
|
46
46
|
listSnippetsForContext: () => import_snippets.listSnippetsForContext,
|
|
47
|
+
registerRunJSContextContribution: () => import_contributions.registerRunJSContextContribution,
|
|
47
48
|
registerRunJSLib: () => import_runjsLibs.registerRunJSLib,
|
|
49
|
+
registerRunJSSnippet: () => import_snippets.registerRunJSSnippet,
|
|
48
50
|
setupRunJSContexts: () => import_setup.setupRunJSContexts
|
|
49
51
|
});
|
|
50
52
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -68,6 +70,7 @@ __reExport(src_exports, require("./JSRunner"), module.exports);
|
|
|
68
70
|
var import_helpers = require("./runjs-context/helpers");
|
|
69
71
|
var import_registry = require("./runjs-context/registry");
|
|
70
72
|
var import_setup = require("./runjs-context/setup");
|
|
73
|
+
var import_contributions = require("./runjs-context/contributions");
|
|
71
74
|
var import_snippets = require("./runjs-context/snippets");
|
|
72
75
|
__reExport(src_exports, require("./views"), module.exports);
|
|
73
76
|
var import_viewEvents = require("./views/viewEvents");
|
|
@@ -93,7 +96,9 @@ var import_BlockScopedFlowEngine = require("./BlockScopedFlowEngine");
|
|
|
93
96
|
getRunJSScenesForModel,
|
|
94
97
|
getSnippetBody,
|
|
95
98
|
listSnippetsForContext,
|
|
99
|
+
registerRunJSContextContribution,
|
|
96
100
|
registerRunJSLib,
|
|
101
|
+
registerRunJSSnippet,
|
|
97
102
|
setupRunJSContexts,
|
|
98
103
|
...require("./types"),
|
|
99
104
|
...require("./utils"),
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
|
-
import { FlowEngineContext } from '../flowContext';
|
|
9
|
+
import { FlowContext, FlowEngineContext } from '../flowContext';
|
|
10
10
|
import { BaseRecordResource } from './baseRecordResource';
|
|
11
11
|
type SQLRunOptions = {
|
|
12
12
|
bind?: Record<string, any>;
|
|
@@ -20,8 +20,8 @@ type SQLSaveOptions = {
|
|
|
20
20
|
dataSourceKey?: string;
|
|
21
21
|
};
|
|
22
22
|
export declare class FlowSQLRepository {
|
|
23
|
-
protected ctx:
|
|
24
|
-
constructor(ctx:
|
|
23
|
+
protected ctx: FlowContext;
|
|
24
|
+
constructor(ctx: FlowContext);
|
|
25
25
|
run(sql: string, options?: SQLRunOptions): Promise<any>;
|
|
26
26
|
save(data: SQLSaveOptions): Promise<void>;
|
|
27
27
|
runById(uid: string, options?: SQLRunOptions): Promise<any>;
|
|
@@ -42,7 +42,12 @@ FormJSFieldItemRunJSContext.define({
|
|
|
42
42
|
Supports innerHTML, append, and other DOM manipulation methods.`,
|
|
43
43
|
value: `Current field value (read-only in display mode; in controlled scenarios, use setProps to modify).`,
|
|
44
44
|
record: `Current record data object (read-only).
|
|
45
|
-
Contains all field values of the parent record
|
|
45
|
+
Contains all field values of the parent record.`,
|
|
46
|
+
formValues: {
|
|
47
|
+
description: "Snapshot of current form values (object). Available in form contexts (CreateForm/EditForm).",
|
|
48
|
+
detail: "Record<string, any>",
|
|
49
|
+
examples: ["const { name, status } = ctx.formValues || {};"]
|
|
50
|
+
}
|
|
46
51
|
},
|
|
47
52
|
methods: {
|
|
48
53
|
onRefReady: `Wait for form field container DOM element to be ready before executing callback.
|
|
@@ -58,7 +63,12 @@ FormJSFieldItemRunJSContext.define(
|
|
|
58
63
|
properties: {
|
|
59
64
|
element: "ElementProxy\uFF0C\u8868\u5355\u5B57\u6BB5\u5BB9\u5668",
|
|
60
65
|
value: "\u5B57\u6BB5\u503C\uFF08\u5C55\u793A\u6A21\u5F0F\u4E3A\u53EA\u8BFB\uFF1B\u53D7\u63A7\u573A\u666F\u7528 setProps \u4FEE\u6539\uFF09",
|
|
61
|
-
record: "\u5F53\u524D\u8BB0\u5F55\uFF08\u53EA\u8BFB\uFF09"
|
|
66
|
+
record: "\u5F53\u524D\u8BB0\u5F55\uFF08\u53EA\u8BFB\uFF09",
|
|
67
|
+
formValues: {
|
|
68
|
+
description: "\u5F53\u524D\u8868\u5355\u503C\u5FEB\u7167\uFF08\u5BF9\u8C61\uFF09\u3002\u4EC5\u8868\u5355\u76F8\u5173\u4E0A\u4E0B\u6587\u53EF\u7528\uFF08Create/Edit Form\uFF09\u3002",
|
|
69
|
+
detail: "Record<string, any>",
|
|
70
|
+
examples: ["const { name, status } = ctx.formValues || {};"]
|
|
71
|
+
}
|
|
62
72
|
},
|
|
63
73
|
methods: {
|
|
64
74
|
onRefReady: "\u5BB9\u5668\u5C31\u7EEA\u56DE\u8C03",
|
|
@@ -58,7 +58,7 @@ JSBlockRunJSContext.define({
|
|
|
58
58
|
Parameters: (ref: React.RefObject, callback: (element: HTMLElement) => void, timeout?: number) => void
|
|
59
59
|
Example: ctx.onRefReady(ctx.ref, (el) => { el.innerHTML = "Ready!" })`,
|
|
60
60
|
requireAsync: "Load external library: `const lib = await ctx.requireAsync(url)`",
|
|
61
|
-
importAsync: "Dynamically import ESM module: `const mod = await ctx.importAsync(url)`"
|
|
61
|
+
importAsync: "Dynamically import an ESM module by URL: `const mod = await ctx.importAsync(url)`.\nNote: if the module has only a default export, ctx.importAsync returns that default value directly (no `.default`)."
|
|
62
62
|
}
|
|
63
63
|
});
|
|
64
64
|
JSBlockRunJSContext.define(
|
|
@@ -80,7 +80,7 @@ JSBlockRunJSContext.define(
|
|
|
80
80
|
methods: {
|
|
81
81
|
onRefReady: "\u5BB9\u5668 ref \u5C31\u7EEA\u56DE\u8C03\uFF1A\n```js\nctx.onRefReady(ctx.ref, el => { /* ... */ })\n```",
|
|
82
82
|
requireAsync: "\u52A0\u8F7D\u5916\u90E8\u5E93\uFF1A`const lib = await ctx.requireAsync(url)`",
|
|
83
|
-
importAsync: "\u6309 URL \u52A8\u6001\u5BFC\u5165 ESM \u6A21\u5757\uFF1A`const mod = await ctx.importAsync(url)
|
|
83
|
+
importAsync: "\u6309 URL \u52A8\u6001\u5BFC\u5165 ESM \u6A21\u5757\uFF1A`const mod = await ctx.importAsync(url)`\u3002\n\u6CE8\u610F\uFF1A\u5F53\u6A21\u5757\u53EA\u6709 default \u4E00\u4E2A\u5BFC\u51FA\u65F6\uFF0Cctx.importAsync \u4F1A\u76F4\u63A5\u8FD4\u56DE default \u503C\uFF08\u65E0\u9700\u518D\u5199 `.default`\uFF09\u3002"
|
|
84
84
|
}
|
|
85
85
|
},
|
|
86
86
|
{ locale: "zh-CN" }
|
|
@@ -0,0 +1,16 @@
|
|
|
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 { FlowRunJSContext } from '../../flowContext';
|
|
10
|
+
/**
|
|
11
|
+
* RunJS context for JSEditableFieldModel (form editable custom field).
|
|
12
|
+
* NOTE: Some APIs (e.g., getValue/setValue/element) are provided by the model's runtime handler.
|
|
13
|
+
* This doc is used for editor autocomplete and AI coding assistance.
|
|
14
|
+
*/
|
|
15
|
+
export declare class JSEditableFieldRunJSContext extends FlowRunJSContext {
|
|
16
|
+
}
|