@nocobase/flow-engine 2.1.0-beta.41 → 2.1.0-beta.43
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/components/subModel/LazyDropdown.js +17 -9
- package/lib/flowContext.d.ts +6 -1
- package/lib/flowContext.js +35 -6
- package/lib/flowEngine.d.ts +1 -0
- package/lib/flowEngine.js +53 -30
- package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.js +4 -3
- package/lib/runjs-context/contexts/JSBlockRunJSContext.js +4 -15
- package/lib/runjs-context/contexts/JSColumnRunJSContext.js +5 -2
- package/lib/runjs-context/contexts/JSEditableFieldRunJSContext.js +5 -8
- package/lib/runjs-context/contexts/JSFieldRunJSContext.js +4 -3
- package/lib/runjs-context/contexts/JSItemRunJSContext.js +4 -3
- package/lib/runjs-context/contexts/base.js +464 -29
- package/lib/runjs-context/contexts/elementDoc.d.ts +11 -0
- package/lib/runjs-context/contexts/elementDoc.js +152 -0
- package/lib/utils/loadedPageCache.d.ts +24 -0
- package/lib/utils/loadedPageCache.js +139 -0
- package/package.json +4 -4
- package/src/__tests__/flowContext.test.ts +23 -0
- package/src/__tests__/runjsContext.test.ts +18 -0
- package/src/__tests__/runjsContextImplementations.test.ts +9 -2
- package/src/__tests__/runjsLocales.test.ts +6 -5
- package/src/__tests__/viewScopedFlowEngine.test.ts +133 -0
- package/src/components/subModel/LazyDropdown.tsx +16 -7
- package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +51 -0
- package/src/flowContext.ts +40 -6
- package/src/flowEngine.ts +51 -27
- package/src/runjs-context/contexts/FormJSFieldItemRunJSContext.ts +4 -3
- package/src/runjs-context/contexts/JSBlockRunJSContext.ts +4 -15
- package/src/runjs-context/contexts/JSColumnRunJSContext.ts +4 -2
- package/src/runjs-context/contexts/JSEditableFieldRunJSContext.ts +5 -9
- package/src/runjs-context/contexts/JSFieldRunJSContext.ts +4 -3
- package/src/runjs-context/contexts/JSItemRunJSContext.ts +4 -3
- package/src/runjs-context/contexts/base.ts +467 -31
- package/src/runjs-context/contexts/elementDoc.ts +130 -0
- package/src/utils/loadedPageCache.ts +147 -0
|
@@ -556,6 +556,57 @@ describe('transformItems - searchable flags', () => {
|
|
|
556
556
|
await waitFor(() => expect(screen.getByText('Field 1')).toBeInTheDocument());
|
|
557
557
|
expect(screen.getByRole('textbox')).toHaveValue('');
|
|
558
558
|
});
|
|
559
|
+
|
|
560
|
+
it('keeps root group search value when hovering a sibling submenu', async () => {
|
|
561
|
+
const engine = new FlowEngine();
|
|
562
|
+
await engine.flowSettings.forceEnable();
|
|
563
|
+
class Parent extends FlowModel {}
|
|
564
|
+
engine.registerModels({ Parent });
|
|
565
|
+
const parent = engine.createModel<FlowModel>({ use: 'Parent' });
|
|
566
|
+
|
|
567
|
+
const items = [
|
|
568
|
+
{
|
|
569
|
+
key: 'fields',
|
|
570
|
+
label: '',
|
|
571
|
+
type: 'group' as const,
|
|
572
|
+
searchable: true,
|
|
573
|
+
searchPlaceholder: 'Search fields',
|
|
574
|
+
children: [
|
|
575
|
+
{ key: 'nickname', label: 'Nickname', createModelOptions: { use: 'Parent' } },
|
|
576
|
+
{ key: 'email', label: 'Email', createModelOptions: { use: 'Parent' } },
|
|
577
|
+
],
|
|
578
|
+
},
|
|
579
|
+
{
|
|
580
|
+
key: 'association-fields',
|
|
581
|
+
label: 'Display association fields',
|
|
582
|
+
children: [{ key: 'author', label: 'Author', createModelOptions: { use: 'Parent' } }],
|
|
583
|
+
},
|
|
584
|
+
];
|
|
585
|
+
|
|
586
|
+
const user = userEvent.setup();
|
|
587
|
+
render(
|
|
588
|
+
<FlowEngineProvider engine={engine}>
|
|
589
|
+
<ConfigProvider>
|
|
590
|
+
<App>
|
|
591
|
+
<AddSubModelButton model={parent} subModelKey="items" items={items as any}>
|
|
592
|
+
Open
|
|
593
|
+
</AddSubModelButton>
|
|
594
|
+
</App>
|
|
595
|
+
</ConfigProvider>
|
|
596
|
+
</FlowEngineProvider>,
|
|
597
|
+
);
|
|
598
|
+
|
|
599
|
+
await user.click(screen.getByText('Open'));
|
|
600
|
+
const searchInput = await screen.findByPlaceholderText('Search fields');
|
|
601
|
+
await user.type(searchInput, 'nick');
|
|
602
|
+
await waitFor(() => expect(screen.queryByText('Email')).not.toBeInTheDocument());
|
|
603
|
+
|
|
604
|
+
await user.hover(screen.getByText('Display association fields'));
|
|
605
|
+
|
|
606
|
+
await waitFor(() => expect(screen.getByText('Author')).toBeInTheDocument());
|
|
607
|
+
expect(searchInput).toHaveValue('nick');
|
|
608
|
+
expect(screen.getByText('Nickname')).toBeInTheDocument();
|
|
609
|
+
});
|
|
559
610
|
});
|
|
560
611
|
|
|
561
612
|
describe('transformItems - hide', () => {
|
package/src/flowContext.ts
CHANGED
|
@@ -400,6 +400,10 @@ export type FlowContextGetApiInfosOptions = {
|
|
|
400
400
|
* RunJS 文档版本(默认 v1)。
|
|
401
401
|
*/
|
|
402
402
|
version?: RunJSVersion;
|
|
403
|
+
/**
|
|
404
|
+
* Include editor completion metadata. Defaults to false so API-doc callers keep the compact public shape.
|
|
405
|
+
*/
|
|
406
|
+
includeCompletion?: boolean;
|
|
403
407
|
};
|
|
404
408
|
|
|
405
409
|
export type FlowContextGetVarInfosOptions = {
|
|
@@ -704,10 +708,11 @@ export class FlowContext {
|
|
|
704
708
|
* - 输出仅来自 RunJS doc 与 defineProperty/defineMethod 的 info
|
|
705
709
|
* - 不读取/展开 PropertyMeta(变量结构)
|
|
706
710
|
* - 不自动展开深层 properties
|
|
707
|
-
* -
|
|
711
|
+
* - 默认不返回自动补全字段(例如 completion),传入 includeCompletion=true 时返回
|
|
708
712
|
*/
|
|
709
713
|
async getApiInfos(options: FlowContextGetApiInfosOptions = {}): Promise<Record<string, FlowContextApiInfo>> {
|
|
710
714
|
const version = (options.version as RunJSVersion) || ('v1' as RunJSVersion);
|
|
715
|
+
const includeCompletion = !!options.includeCompletion;
|
|
711
716
|
const evalCtx = this.createProxy();
|
|
712
717
|
|
|
713
718
|
const isPrivateKey = (key: string) => typeof key === 'string' && key.startsWith('_');
|
|
@@ -759,7 +764,14 @@ export class FlowContext {
|
|
|
759
764
|
const src = toDocObject(obj);
|
|
760
765
|
if (!src) return {};
|
|
761
766
|
const out: any = {};
|
|
762
|
-
for (const k of [
|
|
767
|
+
for (const k of [
|
|
768
|
+
'description',
|
|
769
|
+
'examples',
|
|
770
|
+
...(includeCompletion ? ['completion'] : []),
|
|
771
|
+
'ref',
|
|
772
|
+
'params',
|
|
773
|
+
'returns',
|
|
774
|
+
]) {
|
|
763
775
|
const v = (src as any)[k];
|
|
764
776
|
if (typeof v !== 'undefined') out[k] = v;
|
|
765
777
|
}
|
|
@@ -773,7 +785,17 @@ export class FlowContext {
|
|
|
773
785
|
const src = toDocObject(obj);
|
|
774
786
|
if (!src) return {};
|
|
775
787
|
const out: any = {};
|
|
776
|
-
for (const k of [
|
|
788
|
+
for (const k of [
|
|
789
|
+
'title',
|
|
790
|
+
'type',
|
|
791
|
+
'interface',
|
|
792
|
+
'description',
|
|
793
|
+
'examples',
|
|
794
|
+
...(includeCompletion ? ['completion'] : []),
|
|
795
|
+
'ref',
|
|
796
|
+
'params',
|
|
797
|
+
'returns',
|
|
798
|
+
]) {
|
|
777
799
|
const v = (src as any)[k];
|
|
778
800
|
if (typeof v !== 'undefined') out[k] = v;
|
|
779
801
|
}
|
|
@@ -872,7 +894,7 @@ export class FlowContext {
|
|
|
872
894
|
node = { ...node, ...pickPropertyInfo(docObj) };
|
|
873
895
|
node = { ...node, ...pickPropertyInfo(infoObj) };
|
|
874
896
|
delete (node as any).properties;
|
|
875
|
-
delete (node as any).completion;
|
|
897
|
+
if (!includeCompletion) delete (node as any).completion;
|
|
876
898
|
if (!Object.keys(node).length) continue;
|
|
877
899
|
const outKey = mapDocKeyToApiKey(key, docNode);
|
|
878
900
|
// Avoid exposing ctx.React/ctx.ReactDOM/ctx.antd in api docs when mapping to ctx.libs.*.
|
|
@@ -890,7 +912,7 @@ export class FlowContext {
|
|
|
890
912
|
node = { ...node, ...pickMethodInfo(docObj) };
|
|
891
913
|
node = { ...node, ...pickMethodInfo(info) };
|
|
892
914
|
delete (node as any).properties;
|
|
893
|
-
delete (node as any).completion;
|
|
915
|
+
if (!includeCompletion) delete (node as any).completion;
|
|
894
916
|
if (!Object.keys(node).length) continue;
|
|
895
917
|
node.type = 'function';
|
|
896
918
|
|
|
@@ -913,7 +935,7 @@ export class FlowContext {
|
|
|
913
935
|
let node: FlowContextApiInfo = {};
|
|
914
936
|
node = { ...node, ...pickPropertyInfo(childObj) };
|
|
915
937
|
delete (node as any).properties;
|
|
916
|
-
delete (node as any).completion;
|
|
938
|
+
if (!includeCompletion) delete (node as any).completion;
|
|
917
939
|
if (!node.description || !String(node.description).trim()) continue;
|
|
918
940
|
out[outKey] = node;
|
|
919
941
|
}
|
|
@@ -3075,6 +3097,17 @@ class BaseFlowEngineContext extends FlowContext {
|
|
|
3075
3097
|
const jsCode = await prepareRunJsCode(String(code ?? ''), { preprocessTemplates: shouldPreprocessTemplates });
|
|
3076
3098
|
return runner.run(jsCode);
|
|
3077
3099
|
},
|
|
3100
|
+
{
|
|
3101
|
+
description: 'Execute a RunJS code string in the current Flow context.',
|
|
3102
|
+
detail: '(code: string, variables?: Record<string, any>, options?: JSRunnerOptions) => Promise<RunJSResult>',
|
|
3103
|
+
params: [
|
|
3104
|
+
{ name: 'code', type: 'string', description: 'RunJS code to execute.' },
|
|
3105
|
+
{ name: 'variables', type: 'Record<string, any>', optional: true, description: 'Additional globals.' },
|
|
3106
|
+
{ name: 'options', type: 'JSRunnerOptions', optional: true, description: 'Runner options.' },
|
|
3107
|
+
],
|
|
3108
|
+
returns: { type: 'Promise<{ success: boolean; value?: any; error?: any; timeout?: boolean }>' },
|
|
3109
|
+
completion: { insertText: `await ctx.runjs('return 1')` },
|
|
3110
|
+
},
|
|
3078
3111
|
);
|
|
3079
3112
|
}
|
|
3080
3113
|
}
|
|
@@ -3927,6 +3960,7 @@ export type FlowSettingsContext<TModel extends FlowModel = FlowModel> = FlowRunt
|
|
|
3927
3960
|
|
|
3928
3961
|
export type RunJSDocCompletionDoc = {
|
|
3929
3962
|
insertText?: string;
|
|
3963
|
+
requires?: Array<'element'>;
|
|
3930
3964
|
};
|
|
3931
3965
|
|
|
3932
3966
|
export type RunJSDocHiddenDoc = boolean | ((ctx: any) => boolean | Promise<boolean>);
|
package/src/flowEngine.ts
CHANGED
|
@@ -20,6 +20,7 @@ import { APIResource, FlowResource, MultiRecordResource, SingleRecordResource, S
|
|
|
20
20
|
import { Emitter } from './emitter';
|
|
21
21
|
import ModelOperationScheduler from './scheduler/ModelOperationScheduler';
|
|
22
22
|
import type { ScheduleOptions, ScheduledCancel } from './scheduler/ModelOperationScheduler';
|
|
23
|
+
import { createLoadedPageCache } from './utils/loadedPageCache';
|
|
23
24
|
import type {
|
|
24
25
|
ActionDefinition,
|
|
25
26
|
ApplyFlowCacheEntry,
|
|
@@ -135,6 +136,8 @@ export class FlowEngine {
|
|
|
135
136
|
*/
|
|
136
137
|
private _savingModels = new Map<string, Promise<any>>();
|
|
137
138
|
|
|
139
|
+
private _loadedPageCache = createLoadedPageCache();
|
|
140
|
+
|
|
138
141
|
/**
|
|
139
142
|
* Flow engine context object.
|
|
140
143
|
* @private
|
|
@@ -1339,7 +1342,8 @@ export class FlowEngine {
|
|
|
1339
1342
|
async loadModel<T extends FlowModel = FlowModel>(options): Promise<T | null> {
|
|
1340
1343
|
if (!this.ensureModelRepository()) return;
|
|
1341
1344
|
const refresh = !!options?.refresh;
|
|
1342
|
-
|
|
1345
|
+
const bypassLoadedPageCache = this._loadedPageCache.shouldBypass(options, () => this.context.flowSettingsEnabled);
|
|
1346
|
+
if (!refresh && !bypassLoadedPageCache) {
|
|
1343
1347
|
const model = this.findModelByParentId(options.parentId, options.subKey);
|
|
1344
1348
|
if (model) {
|
|
1345
1349
|
return model as T;
|
|
@@ -1350,15 +1354,24 @@ export class FlowEngine {
|
|
|
1350
1354
|
}
|
|
1351
1355
|
}
|
|
1352
1356
|
const data = await this._modelRepository.findOne(options);
|
|
1353
|
-
if (!data?.uid)
|
|
1354
|
-
|
|
1355
|
-
|
|
1357
|
+
if (!data?.uid) {
|
|
1358
|
+
if (bypassLoadedPageCache) {
|
|
1359
|
+
this._loadedPageCache.clear(options);
|
|
1360
|
+
}
|
|
1361
|
+
return null;
|
|
1362
|
+
}
|
|
1363
|
+
if (refresh || bypassLoadedPageCache) {
|
|
1356
1364
|
const existing = this.getModel(data.uid);
|
|
1357
1365
|
if (existing) {
|
|
1358
1366
|
this.removeModelWithSubModels(existing.uid);
|
|
1359
1367
|
}
|
|
1360
1368
|
}
|
|
1361
|
-
|
|
1369
|
+
const model = await this.createModelAsync<T>(data as any);
|
|
1370
|
+
if (bypassLoadedPageCache) {
|
|
1371
|
+
this._loadedPageCache.mountModelToParent(model, true);
|
|
1372
|
+
this._loadedPageCache.clear(options);
|
|
1373
|
+
}
|
|
1374
|
+
return model;
|
|
1362
1375
|
}
|
|
1363
1376
|
|
|
1364
1377
|
/**
|
|
@@ -1398,22 +1411,31 @@ export class FlowEngine {
|
|
|
1398
1411
|
): Promise<T | null> {
|
|
1399
1412
|
if (!this.ensureModelRepository()) return;
|
|
1400
1413
|
const { uid, parentId, subKey } = options;
|
|
1401
|
-
|
|
1414
|
+
const bypassLoadedPageCache = this._loadedPageCache.shouldBypass(options, () => this.context.flowSettingsEnabled);
|
|
1415
|
+
if (uid && !bypassLoadedPageCache && this._modelInstances.has(uid)) {
|
|
1402
1416
|
return this._modelInstances.get(uid) as T;
|
|
1403
1417
|
}
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1418
|
+
if (!bypassLoadedPageCache) {
|
|
1419
|
+
const m = this.findModelByParentId<T>(parentId, subKey);
|
|
1420
|
+
if (m) {
|
|
1421
|
+
return m;
|
|
1422
|
+
}
|
|
1408
1423
|
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1424
|
+
const hydrated = await this.hydrateModelFromPreviousEngines<T>(options, extra);
|
|
1425
|
+
if (hydrated) {
|
|
1426
|
+
return hydrated;
|
|
1427
|
+
}
|
|
1412
1428
|
}
|
|
1413
1429
|
|
|
1414
1430
|
const data = await this._modelRepository.findOne(options);
|
|
1415
1431
|
let model: T | null = null;
|
|
1416
1432
|
if (data?.uid) {
|
|
1433
|
+
if (bypassLoadedPageCache) {
|
|
1434
|
+
const existing = this.getModel(data.uid);
|
|
1435
|
+
if (existing) {
|
|
1436
|
+
this.removeModelWithSubModels(existing.uid);
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1417
1439
|
model = await this.createModelAsync<T>(data as any, extra);
|
|
1418
1440
|
} else {
|
|
1419
1441
|
model = await this.createModelAsync<T>(options, extra);
|
|
@@ -1421,18 +1443,9 @@ export class FlowEngine {
|
|
|
1421
1443
|
await model.save();
|
|
1422
1444
|
}
|
|
1423
1445
|
}
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
});
|
|
1428
|
-
if (subModel) {
|
|
1429
|
-
return model;
|
|
1430
|
-
}
|
|
1431
|
-
if (model.subType === 'array') {
|
|
1432
|
-
model.parent.addSubModel(model.subKey, model);
|
|
1433
|
-
} else {
|
|
1434
|
-
model.parent.setSubModel(model.subKey, model);
|
|
1435
|
-
}
|
|
1446
|
+
this._loadedPageCache.mountModelToParent(model, bypassLoadedPageCache);
|
|
1447
|
+
if (bypassLoadedPageCache) {
|
|
1448
|
+
this._loadedPageCache.clear(options);
|
|
1436
1449
|
}
|
|
1437
1450
|
return model;
|
|
1438
1451
|
}
|
|
@@ -1452,6 +1465,9 @@ export class FlowEngine {
|
|
|
1452
1465
|
if (!this.ensureModelRepository()) return;
|
|
1453
1466
|
|
|
1454
1467
|
const modelUid = model.uid;
|
|
1468
|
+
const dirtyLoadedPageKey = this._loadedPageCache.getDirtyKeyForModel(model, {
|
|
1469
|
+
force: !!options?.onlyStepParams,
|
|
1470
|
+
});
|
|
1455
1471
|
|
|
1456
1472
|
// 如果这个 model 正在保存中,返回现有的保存 Promise
|
|
1457
1473
|
if (this._savingModels.has(modelUid)) {
|
|
@@ -1465,6 +1481,7 @@ export class FlowEngine {
|
|
|
1465
1481
|
|
|
1466
1482
|
try {
|
|
1467
1483
|
const result = await savePromise;
|
|
1484
|
+
this._loadedPageCache.markDirty(dirtyLoadedPageKey);
|
|
1468
1485
|
return result;
|
|
1469
1486
|
} finally {
|
|
1470
1487
|
// 无论成功还是失败,都要清除保存状态
|
|
@@ -1501,11 +1518,16 @@ export class FlowEngine {
|
|
|
1501
1518
|
* @returns {Promise<boolean>} Whether destroyed successfully
|
|
1502
1519
|
*/
|
|
1503
1520
|
async destroyModel(uid: string) {
|
|
1504
|
-
|
|
1521
|
+
const modelInstance = this._modelInstances.get(uid) as FlowModel;
|
|
1522
|
+
const dirtyLoadedPageKey = this._loadedPageCache.getDirtyKeyForModel(modelInstance);
|
|
1523
|
+
const hasModelRepository = this.ensureModelRepository();
|
|
1524
|
+
if (hasModelRepository) {
|
|
1505
1525
|
await this._modelRepository.destroy(uid);
|
|
1506
1526
|
}
|
|
1507
1527
|
|
|
1508
|
-
|
|
1528
|
+
if (hasModelRepository) {
|
|
1529
|
+
this._loadedPageCache.markDirty(dirtyLoadedPageKey);
|
|
1530
|
+
}
|
|
1509
1531
|
const parent = modelInstance?.parent;
|
|
1510
1532
|
const result = this.removeModel(uid);
|
|
1511
1533
|
parent && parent.emitter.emit('onSubModelDestroyed', modelInstance);
|
|
@@ -1620,6 +1642,7 @@ export class FlowEngine {
|
|
|
1620
1642
|
console.warn(`FlowEngine: Cannot move model. Source or target model not found.`);
|
|
1621
1643
|
return;
|
|
1622
1644
|
}
|
|
1645
|
+
const dirtyLoadedPageKey = this._loadedPageCache.getDirtyKeyForModel(sourceModel);
|
|
1623
1646
|
const move = (sourceModel: FlowModel, targetModel: FlowModel) => {
|
|
1624
1647
|
if (!sourceModel.parent || !targetModel.parent || sourceModel.parent !== targetModel.parent) {
|
|
1625
1648
|
console.error('FlowModel.moveTo: Both models must have the same parent to perform move operation.');
|
|
@@ -1667,6 +1690,7 @@ export class FlowEngine {
|
|
|
1667
1690
|
if (options?.persist !== false && this.ensureModelRepository()) {
|
|
1668
1691
|
const position = sourceModel.sortIndex - targetModel.sortIndex > 0 ? 'after' : 'before';
|
|
1669
1692
|
await this._modelRepository.move(sourceId, targetId, position);
|
|
1693
|
+
this._loadedPageCache.markDirty(dirtyLoadedPageKey);
|
|
1670
1694
|
}
|
|
1671
1695
|
// 触发事件以通知其他部分模型已移动
|
|
1672
1696
|
sourceModel.parent.emitter.emit('onSubModelMoved', { source: sourceModel, target: targetModel });
|
|
@@ -8,14 +8,15 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { FlowRunJSContext } from '../../flowContext';
|
|
11
|
+
import { createElementPropertyDoc, createZhCNElementPropertyDoc } from './elementDoc';
|
|
11
12
|
|
|
12
13
|
export class FormJSFieldItemRunJSContext extends FlowRunJSContext {}
|
|
13
14
|
|
|
14
15
|
FormJSFieldItemRunJSContext.define({
|
|
15
16
|
label: 'FormJSFieldItem RunJS context',
|
|
16
17
|
properties: {
|
|
17
|
-
element: `ElementProxy instance providing a safe DOM container for form field rendering.
|
|
18
|
-
Supports innerHTML, append, and other DOM manipulation methods
|
|
18
|
+
element: createElementPropertyDoc(`ElementProxy instance providing a safe DOM container for form field rendering.
|
|
19
|
+
Supports innerHTML, append, and other DOM manipulation methods.`),
|
|
19
20
|
value: `Current field value (read-only in display mode; in controlled scenarios, use setProps to modify).`,
|
|
20
21
|
record: `Current record data object (read-only).
|
|
21
22
|
Contains all field values of the parent record.`,
|
|
@@ -38,7 +39,7 @@ FormJSFieldItemRunJSContext.define(
|
|
|
38
39
|
{
|
|
39
40
|
label: '表单 JS 字段项 RunJS 上下文',
|
|
40
41
|
properties: {
|
|
41
|
-
element: 'ElementProxy,表单字段容器',
|
|
42
|
+
element: createZhCNElementPropertyDoc('ElementProxy,表单字段容器'),
|
|
42
43
|
value: '字段值(展示模式为只读;受控场景用 setProps 修改)',
|
|
43
44
|
record: '当前记录(只读)',
|
|
44
45
|
formValues: {
|
|
@@ -8,21 +8,16 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { FlowRunJSContext } from '../../flowContext';
|
|
11
|
+
import { createElementPropertyDoc, createZhCNElementPropertyDoc } from './elementDoc';
|
|
11
12
|
|
|
12
13
|
export class JSBlockRunJSContext extends FlowRunJSContext {}
|
|
13
14
|
|
|
14
15
|
JSBlockRunJSContext.define({
|
|
15
16
|
label: 'RunJS context',
|
|
16
17
|
properties: {
|
|
17
|
-
element:
|
|
18
|
-
description: `ElementProxy instance providing a safe DOM container.
|
|
18
|
+
element: createElementPropertyDoc(`ElementProxy instance providing a safe DOM container.
|
|
19
19
|
Supports innerHTML, append, and other DOM manipulation methods.
|
|
20
|
-
Use this to render content in the JS block
|
|
21
|
-
detail: 'ElementProxy',
|
|
22
|
-
properties: {
|
|
23
|
-
innerHTML: 'Set or read the HTML content of the container element.',
|
|
24
|
-
},
|
|
25
|
-
},
|
|
20
|
+
Use this to render content in the JS block.`),
|
|
26
21
|
record: `Current record data object (read-only).
|
|
27
22
|
Available when the JS block is within a data block or detail view context.`,
|
|
28
23
|
value: 'Current value of the field or component, if available in the current context.',
|
|
@@ -44,13 +39,7 @@ JSBlockRunJSContext.define(
|
|
|
44
39
|
{
|
|
45
40
|
label: 'RunJS 上下文',
|
|
46
41
|
properties: {
|
|
47
|
-
element:
|
|
48
|
-
description: 'ElementProxy,安全的 DOM 容器,支持 innerHTML/append 等',
|
|
49
|
-
detail: 'ElementProxy',
|
|
50
|
-
properties: {
|
|
51
|
-
innerHTML: '读取或设置容器的 HTML 内容',
|
|
52
|
-
},
|
|
53
|
-
},
|
|
42
|
+
element: createZhCNElementPropertyDoc('ElementProxy,安全的 DOM 容器,支持 innerHTML/append 等'),
|
|
54
43
|
record: '当前记录(只读,用于数据区块/详情等场景)',
|
|
55
44
|
value: '当前值(若存在)',
|
|
56
45
|
React: 'React 库',
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { FlowRunJSContext } from '../../flowContext';
|
|
11
|
+
import { createElementPropertyDoc, createZhCNElementPropertyDoc } from './elementDoc';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* RunJS context for JSColumnModel (table custom column).
|
|
@@ -18,8 +19,9 @@ export class JSColumnRunJSContext extends FlowRunJSContext {}
|
|
|
18
19
|
JSColumnRunJSContext.define({
|
|
19
20
|
label: 'JSColumn RunJS context',
|
|
20
21
|
properties: {
|
|
21
|
-
element:
|
|
22
|
+
element: createElementPropertyDoc(
|
|
22
23
|
'ElementProxy instance providing a safe DOM container for the current table cell. Supports innerHTML/append and basic DOM APIs.',
|
|
24
|
+
),
|
|
23
25
|
record: 'Current row record object (read-only).',
|
|
24
26
|
recordIndex: 'Index of the current row in the page (0-based).',
|
|
25
27
|
collection: 'Collection definition metadata (read-only).',
|
|
@@ -40,7 +42,7 @@ JSColumnRunJSContext.define(
|
|
|
40
42
|
{
|
|
41
43
|
label: 'JS 列 RunJS 上下文',
|
|
42
44
|
properties: {
|
|
43
|
-
element: 'ElementProxy,表格单元格的安全 DOM 容器,支持 innerHTML/append 等',
|
|
45
|
+
element: createZhCNElementPropertyDoc('ElementProxy,表格单元格的安全 DOM 容器,支持 innerHTML/append 等'),
|
|
44
46
|
record: '当前行记录对象(只读)',
|
|
45
47
|
recordIndex: '当前行索引(从 0 开始)',
|
|
46
48
|
collection: '集合定义元数据(只读)',
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { FlowRunJSContext } from '../../flowContext';
|
|
11
|
+
import { createElementPropertyDoc, createZhCNElementPropertyDoc } from './elementDoc';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* RunJS context for JSEditableFieldModel (form editable custom field).
|
|
@@ -19,11 +20,9 @@ export class JSEditableFieldRunJSContext extends FlowRunJSContext {}
|
|
|
19
20
|
JSEditableFieldRunJSContext.define({
|
|
20
21
|
label: 'JSEditableField RunJS context',
|
|
21
22
|
properties: {
|
|
22
|
-
element:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
detail: 'ElementProxy',
|
|
26
|
-
},
|
|
23
|
+
element: createElementPropertyDoc(
|
|
24
|
+
'ElementProxy instance providing a safe DOM container for field rendering. In editable mode this container is typically a <span> element.',
|
|
25
|
+
),
|
|
27
26
|
value: {
|
|
28
27
|
description:
|
|
29
28
|
'Current field value (read-only snapshot). In editable scenarios, prefer ctx.getValue()/ctx.setValue(v) for two-way binding.',
|
|
@@ -69,10 +68,7 @@ JSEditableFieldRunJSContext.define(
|
|
|
69
68
|
{
|
|
70
69
|
label: 'JS 可编辑字段 RunJS 上下文',
|
|
71
70
|
properties: {
|
|
72
|
-
element:
|
|
73
|
-
description: 'ElementProxy,字段渲染的安全容器(通常为 <span> 容器)。',
|
|
74
|
-
detail: 'ElementProxy',
|
|
75
|
-
},
|
|
71
|
+
element: createZhCNElementPropertyDoc('ElementProxy,字段渲染的安全容器(通常为 <span> 容器)。'),
|
|
76
72
|
value: {
|
|
77
73
|
description: '字段当前值(只读快照)。可编辑场景建议使用 ctx.getValue()/ctx.setValue(v) 做双向绑定。',
|
|
78
74
|
detail: 'any',
|
|
@@ -8,14 +8,15 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { FlowRunJSContext } from '../../flowContext';
|
|
11
|
+
import { createElementPropertyDoc, createZhCNElementPropertyDoc } from './elementDoc';
|
|
11
12
|
|
|
12
13
|
export class JSFieldRunJSContext extends FlowRunJSContext {}
|
|
13
14
|
|
|
14
15
|
JSFieldRunJSContext.define({
|
|
15
16
|
label: 'JSField RunJS context',
|
|
16
17
|
properties: {
|
|
17
|
-
element: `ElementProxy instance providing a safe DOM container for field rendering.
|
|
18
|
-
Supports innerHTML, append, and other DOM manipulation methods
|
|
18
|
+
element: createElementPropertyDoc(`ElementProxy instance providing a safe DOM container for field rendering.
|
|
19
|
+
Supports innerHTML, append, and other DOM manipulation methods.`),
|
|
19
20
|
value: `Current value of the field (read-only).
|
|
20
21
|
Contains the data value stored in this field.`,
|
|
21
22
|
record: `Current record data object (read-only).
|
|
@@ -34,7 +35,7 @@ JSFieldRunJSContext.define(
|
|
|
34
35
|
{
|
|
35
36
|
label: 'JS 字段 RunJS 上下文',
|
|
36
37
|
properties: {
|
|
37
|
-
element: 'ElementProxy,字段渲染容器,支持 innerHTML/append 等 DOM 操作',
|
|
38
|
+
element: createZhCNElementPropertyDoc('ElementProxy,字段渲染容器,支持 innerHTML/append 等 DOM 操作'),
|
|
38
39
|
value: '字段当前值(只读)',
|
|
39
40
|
record: '当前记录对象(只读,包含父记录全部字段值)',
|
|
40
41
|
collection: '集合定义元数据(只读,描述字段所属集合的 Schema)',
|
|
@@ -8,14 +8,15 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { FlowRunJSContext } from '../../flowContext';
|
|
11
|
+
import { createElementPropertyDoc, createZhCNElementPropertyDoc } from './elementDoc';
|
|
11
12
|
|
|
12
13
|
export class JSItemRunJSContext extends FlowRunJSContext {}
|
|
13
14
|
|
|
14
15
|
JSItemRunJSContext.define({
|
|
15
16
|
label: 'JSItem RunJS context',
|
|
16
17
|
properties: {
|
|
17
|
-
element: `ElementProxy instance providing a safe DOM container for form item rendering.
|
|
18
|
-
Supports innerHTML, append, and other DOM manipulation methods
|
|
18
|
+
element: createElementPropertyDoc(`ElementProxy instance providing a safe DOM container for form item rendering.
|
|
19
|
+
Supports innerHTML, append, and other DOM manipulation methods.`),
|
|
19
20
|
resource: `Current resource instance (read-only).
|
|
20
21
|
Provides access to the data resource associated with the current form context.`,
|
|
21
22
|
record: `Current record data object (read-only).
|
|
@@ -36,7 +37,7 @@ JSItemRunJSContext.define(
|
|
|
36
37
|
{
|
|
37
38
|
label: 'JS 表单项 RunJS 上下文',
|
|
38
39
|
properties: {
|
|
39
|
-
element: 'ElementProxy,表单项渲染容器,支持 innerHTML/append 等 DOM 操作',
|
|
40
|
+
element: createZhCNElementPropertyDoc('ElementProxy,表单项渲染容器,支持 innerHTML/append 等 DOM 操作'),
|
|
40
41
|
resource: '当前资源(只读)',
|
|
41
42
|
record: '当前记录(只读)',
|
|
42
43
|
formValues: {
|