@nocobase/flow-engine 2.1.0-beta.9 → 2.2.0-alpha.1
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/FlowContextProvider.d.ts +5 -1
- package/lib/FlowContextProvider.js +9 -2
- package/lib/components/FieldModelRenderer.js +2 -2
- package/lib/components/FlowModelRenderer.d.ts +3 -1
- package/lib/components/FlowModelRenderer.js +12 -6
- package/lib/components/FormItem.d.ts +6 -0
- package/lib/components/FormItem.js +11 -3
- package/lib/components/MobilePopup.js +6 -5
- package/lib/components/dnd/gridDragPlanner.d.ts +59 -2
- package/lib/components/dnd/gridDragPlanner.js +607 -19
- package/lib/components/dnd/index.d.ts +31 -2
- package/lib/components/dnd/index.js +244 -23
- package/lib/components/settings/wrappers/component/SelectWithTitle.d.ts +2 -1
- package/lib/components/settings/wrappers/component/SelectWithTitle.js +14 -12
- package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.d.ts +3 -0
- package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +152 -42
- package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.d.ts +23 -43
- package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +352 -295
- package/lib/components/settings/wrappers/contextual/useFloatToolbarPortal.d.ts +36 -0
- package/lib/components/settings/wrappers/contextual/useFloatToolbarPortal.js +274 -0
- package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.d.ts +30 -0
- package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.js +315 -0
- package/lib/components/subModel/AddSubModelButton.js +12 -1
- package/lib/components/subModel/LazyDropdown.js +301 -52
- package/lib/components/subModel/index.d.ts +1 -0
- package/lib/components/subModel/index.js +19 -0
- package/lib/components/subModel/utils.d.ts +2 -1
- package/lib/components/subModel/utils.js +15 -5
- package/lib/components/variables/VariableHybridInput.d.ts +27 -0
- package/lib/components/variables/VariableHybridInput.js +499 -0
- package/lib/components/variables/index.d.ts +2 -0
- package/lib/components/variables/index.js +3 -0
- package/lib/data-source/index.d.ts +84 -0
- package/lib/data-source/index.js +269 -7
- package/lib/executor/FlowExecutor.js +6 -3
- package/lib/flow-registry/DetachedFlowRegistry.d.ts +21 -0
- package/lib/flow-registry/DetachedFlowRegistry.js +80 -0
- package/lib/flow-registry/index.d.ts +1 -0
- package/lib/flow-registry/index.js +3 -1
- package/lib/flowContext.d.ts +9 -1
- package/lib/flowContext.js +77 -6
- package/lib/flowEngine.d.ts +136 -4
- package/lib/flowEngine.js +429 -51
- package/lib/flowI18n.js +2 -1
- package/lib/flowSettings.d.ts +14 -6
- package/lib/flowSettings.js +34 -6
- package/lib/index.d.ts +2 -0
- package/lib/index.js +7 -0
- package/lib/lazy-helper.d.ts +14 -0
- package/lib/lazy-helper.js +71 -0
- package/lib/locale/en-US.json +1 -0
- package/lib/locale/index.d.ts +2 -0
- package/lib/locale/zh-CN.json +1 -0
- package/lib/models/DisplayItemModel.d.ts +1 -1
- package/lib/models/EditableItemModel.d.ts +1 -1
- package/lib/models/FilterableItemModel.d.ts +1 -1
- package/lib/models/flowModel.d.ts +13 -10
- package/lib/models/flowModel.js +126 -34
- package/lib/provider.js +38 -23
- package/lib/reactive/observer.js +46 -16
- 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/runjs-context/setup.js +1 -0
- package/lib/runjs-context/snippets/index.js +13 -2
- package/lib/runjs-context/snippets/scene/detail/set-field-style.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/detail/set-field-style.snippet.js +50 -0
- package/lib/runjs-context/snippets/scene/table/set-cell-style.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/table/set-cell-style.snippet.js +54 -0
- package/lib/types.d.ts +50 -2
- package/lib/types.js +1 -0
- package/lib/utils/createCollectionContextMeta.js +6 -2
- package/lib/utils/index.d.ts +3 -2
- package/lib/utils/index.js +7 -0
- package/lib/utils/loadedPageCache.d.ts +24 -0
- package/lib/utils/loadedPageCache.js +139 -0
- package/lib/utils/parsePathnameToViewParams.d.ts +5 -1
- package/lib/utils/parsePathnameToViewParams.js +28 -4
- package/lib/utils/randomId.d.ts +39 -0
- package/lib/utils/randomId.js +45 -0
- package/lib/utils/runjsTemplateCompat.js +1 -1
- package/lib/utils/runjsValue.js +41 -11
- package/lib/utils/schema-utils.d.ts +7 -1
- package/lib/utils/schema-utils.js +19 -0
- package/lib/views/FlowView.d.ts +7 -1
- package/lib/views/FlowView.js +11 -1
- package/lib/views/PageComponent.js +8 -6
- package/lib/views/ViewNavigation.d.ts +12 -2
- package/lib/views/ViewNavigation.js +28 -9
- package/lib/views/createViewMeta.js +114 -50
- package/lib/views/inheritLayoutContext.d.ts +10 -0
- package/lib/views/inheritLayoutContext.js +50 -0
- package/lib/views/runViewBeforeClose.d.ts +10 -0
- package/lib/views/runViewBeforeClose.js +45 -0
- package/lib/views/useDialog.d.ts +2 -1
- package/lib/views/useDialog.js +12 -3
- package/lib/views/useDrawer.d.ts +2 -1
- package/lib/views/useDrawer.js +12 -3
- package/lib/views/usePage.d.ts +5 -11
- package/lib/views/usePage.js +304 -144
- package/package.json +5 -4
- package/src/FlowContextProvider.tsx +9 -1
- package/src/__tests__/createViewMeta.popup.test.ts +115 -1
- package/src/__tests__/flow-engine.test.ts +166 -0
- package/src/__tests__/flowContext.test.ts +105 -1
- package/src/__tests__/flowEngine.modelLoaders.test.ts +245 -0
- package/src/__tests__/flowEngine.moveModel.test.ts +81 -1
- package/src/__tests__/flowEngine.removeModel.test.ts +47 -3
- package/src/__tests__/flowSettings.test.ts +94 -15
- package/src/__tests__/objectVariable.test.ts +24 -0
- package/src/__tests__/provider.test.tsx +24 -2
- package/src/__tests__/renderHiddenInConfig.test.tsx +6 -6
- package/src/__tests__/runjsContext.test.ts +21 -0
- package/src/__tests__/runjsContextImplementations.test.ts +9 -2
- package/src/__tests__/runjsContextRuntime.test.ts +2 -0
- package/src/__tests__/runjsLocales.test.ts +6 -5
- package/src/__tests__/runjsSnippets.test.ts +21 -0
- package/src/__tests__/viewScopedFlowEngine.test.ts +136 -3
- package/src/components/FieldModelRenderer.tsx +2 -1
- package/src/components/FlowModelRenderer.tsx +18 -6
- package/src/components/FormItem.tsx +7 -1
- package/src/components/MobilePopup.tsx +4 -2
- package/src/components/__tests__/FlowModelRenderer.test.tsx +65 -2
- package/src/components/__tests__/FormItem.test.tsx +25 -0
- package/src/components/__tests__/dnd.test.ts +44 -0
- package/src/components/__tests__/flow-model-render-error-fallback.test.tsx +20 -10
- package/src/components/__tests__/gridDragPlanner.test.ts +472 -5
- package/src/components/dnd/__tests__/DndProvider.test.tsx +98 -0
- package/src/components/dnd/gridDragPlanner.ts +750 -17
- package/src/components/dnd/index.tsx +305 -28
- package/src/components/settings/wrappers/component/SelectWithTitle.tsx +21 -9
- package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +178 -48
- package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +487 -440
- package/src/components/settings/wrappers/contextual/__tests__/DefaultSettingsIcon.test.tsx +344 -8
- package/src/components/settings/wrappers/contextual/__tests__/FlowsFloatContextMenu.test.tsx +778 -0
- package/src/components/settings/wrappers/contextual/useFloatToolbarPortal.ts +360 -0
- package/src/components/settings/wrappers/contextual/useFloatToolbarVisibility.ts +361 -0
- package/src/components/subModel/AddSubModelButton.tsx +16 -2
- package/src/components/subModel/LazyDropdown.tsx +341 -56
- package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +524 -38
- package/src/components/subModel/__tests__/utils.test.ts +24 -0
- package/src/components/subModel/index.ts +1 -0
- package/src/components/subModel/utils.ts +13 -2
- package/src/components/variables/VariableHybridInput.tsx +531 -0
- package/src/components/variables/index.ts +2 -0
- package/src/data-source/__tests__/collection.test.ts +41 -2
- package/src/data-source/__tests__/index.test.ts +69 -2
- package/src/data-source/index.ts +332 -8
- package/src/executor/FlowExecutor.ts +6 -3
- package/src/executor/__tests__/flowExecutor.test.ts +57 -0
- package/src/flow-registry/DetachedFlowRegistry.ts +46 -0
- package/src/flow-registry/__tests__/detachedFlowRegistry.test.ts +47 -0
- package/src/flow-registry/index.ts +1 -0
- package/src/flowContext.ts +85 -6
- package/src/flowEngine.ts +484 -45
- package/src/flowI18n.ts +2 -1
- package/src/flowSettings.ts +40 -6
- package/src/index.ts +2 -0
- package/src/lazy-helper.tsx +57 -0
- package/src/locale/en-US.json +1 -0
- package/src/locale/zh-CN.json +1 -0
- package/src/models/DisplayItemModel.tsx +1 -1
- package/src/models/EditableItemModel.tsx +1 -1
- package/src/models/FilterableItemModel.tsx +1 -1
- package/src/models/__tests__/flowEngine.resolveUse.test.ts +0 -15
- package/src/models/__tests__/flowModel.test.ts +65 -37
- package/src/models/flowModel.tsx +184 -65
- package/src/provider.tsx +41 -25
- package/src/reactive/__tests__/observer.test.tsx +82 -0
- package/src/reactive/observer.tsx +87 -25
- 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/runjs-context/setup.ts +1 -0
- package/src/runjs-context/snippets/index.ts +12 -1
- package/src/runjs-context/snippets/scene/detail/set-field-style.snippet.ts +30 -0
- package/src/runjs-context/snippets/scene/table/set-cell-style.snippet.ts +34 -0
- package/src/types.ts +62 -0
- package/src/utils/__tests__/createCollectionContextMeta.test.ts +48 -0
- package/src/utils/__tests__/parsePathnameToViewParams.test.ts +21 -0
- package/src/utils/__tests__/runjsValue.test.ts +11 -0
- package/src/utils/__tests__/utils.test.ts +62 -0
- package/src/utils/createCollectionContextMeta.ts +6 -2
- package/src/utils/index.ts +5 -1
- package/src/utils/loadedPageCache.ts +147 -0
- package/src/utils/parsePathnameToViewParams.ts +45 -5
- package/src/utils/randomId.ts +48 -0
- package/src/utils/runjsTemplateCompat.ts +1 -1
- package/src/utils/runjsValue.ts +50 -11
- package/src/utils/schema-utils.ts +30 -1
- package/src/views/FlowView.tsx +22 -2
- package/src/views/PageComponent.tsx +7 -4
- package/src/views/ViewNavigation.ts +46 -9
- package/src/views/__tests__/FlowView.usePage.test.tsx +243 -3
- package/src/views/__tests__/ViewNavigation.test.ts +52 -0
- package/src/views/__tests__/inheritLayoutContext.test.ts +53 -0
- package/src/views/__tests__/runViewBeforeClose.test.ts +30 -0
- package/src/views/__tests__/useDialog.closeDestroy.test.tsx +12 -12
- package/src/views/createViewMeta.ts +106 -34
- package/src/views/inheritLayoutContext.ts +26 -0
- package/src/views/runViewBeforeClose.ts +19 -0
- package/src/views/useDialog.tsx +13 -3
- package/src/views/useDrawer.tsx +13 -3
- package/src/views/usePage.tsx +367 -180
package/src/flowI18n.ts
CHANGED
|
@@ -52,7 +52,8 @@ export class FlowI18n {
|
|
|
52
52
|
*/
|
|
53
53
|
private translateKey(key: string, options?: any): string {
|
|
54
54
|
if (this.context?.i18n?.t) {
|
|
55
|
-
|
|
55
|
+
const translated = this.context.i18n.t(key, options);
|
|
56
|
+
return translated == null || translated === '' ? key : translated;
|
|
56
57
|
}
|
|
57
58
|
// 如果没有翻译函数,返回原始键值
|
|
58
59
|
return key;
|
package/src/flowSettings.ts
CHANGED
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
import { FlowExitAllException } from './utils/exceptions';
|
|
36
36
|
import { FlowStepContext } from './hooks/useFlowStep';
|
|
37
37
|
import { GLOBAL_EMBED_CONTAINER_ID, EMBED_REPLACING_DATA_KEY } from './views';
|
|
38
|
+
import { lazy } from './lazy-helper';
|
|
38
39
|
|
|
39
40
|
const Panel = Collapse.Panel;
|
|
40
41
|
|
|
@@ -114,16 +115,23 @@ export interface FlowSettingsOpenOptions {
|
|
|
114
115
|
onSaved?: () => void | Promise<void>;
|
|
115
116
|
}
|
|
116
117
|
|
|
118
|
+
export type FlowSettingsComponent = React.ComponentType<any>;
|
|
119
|
+
export type FlowSettingsComponentModule = { default?: FlowSettingsComponent } | Record<string, FlowSettingsComponent>;
|
|
120
|
+
export type FlowSettingsComponentLoader = () => Promise<FlowSettingsComponentModule | FlowSettingsComponent>;
|
|
121
|
+
export type FlowSettingsComponentLoaderMap = Record<string, FlowSettingsComponentLoader>;
|
|
122
|
+
|
|
117
123
|
export class FlowSettings {
|
|
118
124
|
public components: Record<string, any> = {};
|
|
119
125
|
public scopes: Record<string, any> = {};
|
|
120
126
|
private antdComponentsLoaded = false;
|
|
121
127
|
public enabled: boolean;
|
|
128
|
+
private engine: FlowEngine;
|
|
122
129
|
#forceEnabled = false; // 强制启用状态,主要用于设计模式下的强制启用
|
|
123
130
|
public toolbarItems: ToolbarItemConfig[] = [];
|
|
124
131
|
#emitter: Emitter = new Emitter();
|
|
125
132
|
|
|
126
133
|
constructor(engine: FlowEngine) {
|
|
134
|
+
this.engine = engine;
|
|
127
135
|
// 初始默认为 false,由 SchemaComponentProvider 根据实际设计模式状态同步设置
|
|
128
136
|
this.enabled = false;
|
|
129
137
|
engine.context.defineProperty('flowSettingsEnabled', {
|
|
@@ -291,6 +299,30 @@ export class FlowSettings {
|
|
|
291
299
|
});
|
|
292
300
|
}
|
|
293
301
|
|
|
302
|
+
public registerComponentLoaders(loaders: FlowSettingsComponentLoaderMap): void {
|
|
303
|
+
Object.entries(loaders).forEach(([name, loader]) => {
|
|
304
|
+
if (this.components[name]) {
|
|
305
|
+
console.warn(`FlowSettings: Component with name '${name}' is already registered and will be overwritten.`);
|
|
306
|
+
}
|
|
307
|
+
this.components[name] = lazy(async () => {
|
|
308
|
+
const loaded = await loader();
|
|
309
|
+
if (typeof loaded === 'function') {
|
|
310
|
+
return { default: loaded };
|
|
311
|
+
}
|
|
312
|
+
if (loaded?.default && typeof loaded.default === 'function') {
|
|
313
|
+
return { default: loaded.default };
|
|
314
|
+
}
|
|
315
|
+
const namedComponent = loaded?.[name];
|
|
316
|
+
if (typeof namedComponent === 'function') {
|
|
317
|
+
return { default: namedComponent };
|
|
318
|
+
}
|
|
319
|
+
throw new Error(
|
|
320
|
+
`FlowSettings: component loader for '${name}' must resolve to a React component or a module exporting it.`,
|
|
321
|
+
);
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
|
|
294
326
|
/**
|
|
295
327
|
* 添加作用域到 FlowSettings 的作用域注册表中。
|
|
296
328
|
* 这些作用域可以在 flow step 的 uiSchema 中使用。
|
|
@@ -311,13 +343,15 @@ export class FlowSettings {
|
|
|
311
343
|
/**
|
|
312
344
|
* 启用流程设置组件的显示
|
|
313
345
|
* @example
|
|
314
|
-
* flowSettings.enable();
|
|
346
|
+
* await flowSettings.enable();
|
|
315
347
|
*/
|
|
316
|
-
public enable(): void {
|
|
348
|
+
public async enable(): Promise<void> {
|
|
349
|
+
await this.engine.preloadModelLoaders();
|
|
317
350
|
this.enabled = true;
|
|
318
351
|
}
|
|
319
352
|
|
|
320
|
-
public forceEnable() {
|
|
353
|
+
public async forceEnable(): Promise<void> {
|
|
354
|
+
await this.engine.preloadModelLoaders();
|
|
321
355
|
this.#forceEnabled = true;
|
|
322
356
|
this.enabled = true;
|
|
323
357
|
}
|
|
@@ -325,16 +359,16 @@ export class FlowSettings {
|
|
|
325
359
|
/**
|
|
326
360
|
* 禁用流程设置组件的显示
|
|
327
361
|
* @example
|
|
328
|
-
* flowSettings.disable();
|
|
362
|
+
* await flowSettings.disable();
|
|
329
363
|
*/
|
|
330
|
-
public disable(): void {
|
|
364
|
+
public async disable(): Promise<void> {
|
|
331
365
|
if (this.#forceEnabled) {
|
|
332
366
|
return;
|
|
333
367
|
}
|
|
334
368
|
this.enabled = false;
|
|
335
369
|
}
|
|
336
370
|
|
|
337
|
-
public forceDisable() {
|
|
371
|
+
public async forceDisable(): Promise<void> {
|
|
338
372
|
this.#forceEnabled = false;
|
|
339
373
|
this.enabled = false;
|
|
340
374
|
}
|
package/src/index.ts
CHANGED
|
@@ -57,5 +57,7 @@ export {
|
|
|
57
57
|
} from './views/viewEvents';
|
|
58
58
|
|
|
59
59
|
export * from './FlowDefinition';
|
|
60
|
+
export { DetachedFlowRegistry, replaceFlowRegistry, serializeFlowRegistry } from './flow-registry';
|
|
61
|
+
export type { FlowRegistryData } from './flow-registry';
|
|
60
62
|
export { createViewScopedEngine } from './ViewScopedFlowEngine';
|
|
61
63
|
export { createBlockScopedEngine } from './BlockScopedFlowEngine';
|
|
@@ -0,0 +1,57 @@
|
|
|
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
|
+
|
|
10
|
+
import React, { lazy as reactLazy } from 'react';
|
|
11
|
+
|
|
12
|
+
type LazyComponentType<M extends Record<string, any>, K extends keyof M> = {
|
|
13
|
+
[P in K]: M[P];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function lazy<M extends Record<'default', any>>(factory: () => Promise<M>): M['default'];
|
|
17
|
+
|
|
18
|
+
export function lazy<M extends Record<string, any>, K extends keyof M = keyof M>(
|
|
19
|
+
factory: () => Promise<M>,
|
|
20
|
+
...componentNames: K[]
|
|
21
|
+
): LazyComponentType<M, K>;
|
|
22
|
+
|
|
23
|
+
export function lazy<M extends Record<string, any>, K extends keyof M>(
|
|
24
|
+
factory: () => Promise<M>,
|
|
25
|
+
...componentNames: K[]
|
|
26
|
+
) {
|
|
27
|
+
if (componentNames.length === 0) {
|
|
28
|
+
const LazyComponent = reactLazy(() =>
|
|
29
|
+
factory().then((module) => ({
|
|
30
|
+
default: module.default,
|
|
31
|
+
})),
|
|
32
|
+
);
|
|
33
|
+
const Component = (props) => (
|
|
34
|
+
<React.Suspense fallback={null}>
|
|
35
|
+
<LazyComponent {...props} />
|
|
36
|
+
</React.Suspense>
|
|
37
|
+
);
|
|
38
|
+
return Component;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return componentNames.reduce(
|
|
42
|
+
(acc, name) => {
|
|
43
|
+
const LazyComponent = reactLazy(() =>
|
|
44
|
+
factory().then((module) => ({
|
|
45
|
+
default: module[name],
|
|
46
|
+
})),
|
|
47
|
+
);
|
|
48
|
+
acc[name] = ((props) => (
|
|
49
|
+
<React.Suspense fallback={null}>
|
|
50
|
+
<LazyComponent {...props} />
|
|
51
|
+
</React.Suspense>
|
|
52
|
+
)) as M[K];
|
|
53
|
+
return acc;
|
|
54
|
+
},
|
|
55
|
+
{} as LazyComponentType<M, K>,
|
|
56
|
+
);
|
|
57
|
+
}
|
package/src/locale/en-US.json
CHANGED
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"Failed to destroy model after creation error": "Failed to destroy model after creation error",
|
|
35
35
|
"Failed to get action {{action}}": "Failed to get action {{action}}",
|
|
36
36
|
"Failed to get configurable flows for model {{model}}": "Failed to get configurable flows for model {{model}}",
|
|
37
|
+
"Attributes are unavailable before selecting a record": "Attributes are unavailable before selecting a record",
|
|
37
38
|
"Failed to import FormDialog": "Failed to import FormDialog",
|
|
38
39
|
"Failed to import FormDialog or FormStep": "Failed to import FormDialog or FormStep",
|
|
39
40
|
"Failed to import Formily components": "Failed to import Formily components",
|
package/src/locale/zh-CN.json
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"Failed to destroy model after creation error": "创建错误后销毁模型失败",
|
|
32
32
|
"Failed to get action {{action}}": "获取 action '{{action}}' 失败",
|
|
33
33
|
"Failed to get configurable flows for model {{model}}": "获取模型 '{{model}}' 的可配置 flows 失败",
|
|
34
|
+
"Attributes are unavailable before selecting a record": "选择记录之前,当前项属性不可用",
|
|
34
35
|
"Failed to import FormDialog": "导入 FormDialog 失败",
|
|
35
36
|
"Failed to import FormDialog or FormStep": "导入 FormDialog 或 FormStep 失败",
|
|
36
37
|
"Failed to import Formily components": "导入 Formily 组件失败",
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { DefaultStructure } from '
|
|
10
|
+
import type { DefaultStructure } from '../types';
|
|
11
11
|
import { CollectionFieldModel } from './CollectionFieldModel';
|
|
12
12
|
|
|
13
13
|
export class DisplayItemModel<T extends DefaultStructure = DefaultStructure> extends CollectionFieldModel<T> {}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { DefaultStructure } from '
|
|
10
|
+
import type { DefaultStructure } from '../types';
|
|
11
11
|
import { CollectionFieldModel } from './CollectionFieldModel';
|
|
12
12
|
|
|
13
13
|
export class EditableItemModel<T extends DefaultStructure = DefaultStructure> extends CollectionFieldModel<T> {}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { DefaultStructure } from '
|
|
10
|
+
import type { DefaultStructure } from '../types';
|
|
11
11
|
import { CollectionFieldModel } from './CollectionFieldModel';
|
|
12
12
|
|
|
13
13
|
export class FilterableItemModel<T extends DefaultStructure = DefaultStructure> extends CollectionFieldModel<T> {}
|
|
@@ -61,21 +61,6 @@ describe('FlowEngine.createModel resolveUse hook', () => {
|
|
|
61
61
|
expect(warnSpy).not.toHaveBeenCalled();
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
-
test('should break resolveUse on circular reference and warn', () => {
|
|
65
|
-
class LoopModel extends FlowModel {
|
|
66
|
-
static resolveUse() {
|
|
67
|
-
return 'LoopModel';
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
engine.registerModels({ LoopModel });
|
|
72
|
-
|
|
73
|
-
const model = engine.createModel({ use: 'LoopModel', uid: 'loop-model', flowEngine: engine });
|
|
74
|
-
|
|
75
|
-
expect(model).toBeInstanceOf(LoopModel);
|
|
76
|
-
expect(warnSpy).toHaveBeenCalled();
|
|
77
|
-
});
|
|
78
|
-
|
|
79
64
|
test('should fall back to ErrorFlowModel when resolveUse returns unregistered name', () => {
|
|
80
65
|
class MissingTargetEntry extends FlowModel {
|
|
81
66
|
static resolveUse() {
|
|
@@ -313,6 +313,19 @@ describe('FlowModel', () => {
|
|
|
313
313
|
|
|
314
314
|
model.emitter.off('onStepParamsChanged', listener);
|
|
315
315
|
});
|
|
316
|
+
|
|
317
|
+
test('should not emit onStepParamsChanged when params are unchanged', () => {
|
|
318
|
+
const listener = vi.fn();
|
|
319
|
+
model.emitter.on('onStepParamsChanged', listener);
|
|
320
|
+
|
|
321
|
+
model.setStepParams('testFlow', 'step1', { param1: 'value1' });
|
|
322
|
+
model.setStepParams('testFlow', { step1: { param1: 'value1' } });
|
|
323
|
+
model.setStepParams({ testFlow: { step1: { param1: 'value1' } } });
|
|
324
|
+
|
|
325
|
+
expect(listener).not.toHaveBeenCalled();
|
|
326
|
+
|
|
327
|
+
model.emitter.off('onStepParamsChanged', listener);
|
|
328
|
+
});
|
|
316
329
|
});
|
|
317
330
|
});
|
|
318
331
|
|
|
@@ -370,15 +383,17 @@ describe('FlowModel', () => {
|
|
|
370
383
|
};
|
|
371
384
|
|
|
372
385
|
TestFlowModel.registerFlow(exitFlow);
|
|
373
|
-
const
|
|
386
|
+
const loggerSpy = vi.spyOn(model.flowEngine.logger, 'debug').mockImplementation(() => {});
|
|
374
387
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
expect(result).toBeInstanceOf(FlowExitAllException);
|
|
378
|
-
expect(exitFlow.steps.step2.handler).not.toHaveBeenCalled();
|
|
379
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('[FlowModel]'));
|
|
388
|
+
try {
|
|
389
|
+
const result = await model.applyFlow('exitFlow');
|
|
380
390
|
|
|
381
|
-
|
|
391
|
+
expect(result).toBeInstanceOf(FlowExitAllException);
|
|
392
|
+
expect(exitFlow.steps.step2.handler).not.toHaveBeenCalled();
|
|
393
|
+
expect(loggerSpy).toHaveBeenCalledWith(expect.stringContaining('[FlowModel]'));
|
|
394
|
+
} finally {
|
|
395
|
+
loggerSpy.mockRestore();
|
|
396
|
+
}
|
|
382
397
|
});
|
|
383
398
|
|
|
384
399
|
test('should handle ctx.exit() as FlowExitAllException in beforeRender dispatch', async () => {
|
|
@@ -474,15 +489,17 @@ describe('FlowModel', () => {
|
|
|
474
489
|
};
|
|
475
490
|
|
|
476
491
|
TestFlowModel.registerFlow(exitFlow);
|
|
477
|
-
const
|
|
478
|
-
|
|
479
|
-
const result = await model.applyFlow('exitFlow');
|
|
492
|
+
const loggerSpy = vi.spyOn(model.flowEngine.logger, 'debug').mockImplementation(() => {});
|
|
480
493
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('[FlowModel]'));
|
|
494
|
+
try {
|
|
495
|
+
const result = await model.applyFlow('exitFlow');
|
|
484
496
|
|
|
485
|
-
|
|
497
|
+
expect(result).toBeInstanceOf(FlowExitAllException);
|
|
498
|
+
expect(exitFlow.steps.step2.handler).not.toHaveBeenCalled();
|
|
499
|
+
expect(loggerSpy).toHaveBeenCalledWith(expect.stringContaining('[FlowModel]'));
|
|
500
|
+
} finally {
|
|
501
|
+
loggerSpy.mockRestore();
|
|
502
|
+
}
|
|
486
503
|
});
|
|
487
504
|
|
|
488
505
|
test('should propagate step execution errors', async () => {
|
|
@@ -768,7 +785,7 @@ describe('FlowModel', () => {
|
|
|
768
785
|
const eventFlow = createEventFlowDefinition('testEvent');
|
|
769
786
|
TestFlowModel.registerFlow(eventFlow);
|
|
770
787
|
|
|
771
|
-
const
|
|
788
|
+
const loggerSpy = vi.spyOn(model.flowEngine.logger, 'debug').mockImplementation(() => {});
|
|
772
789
|
|
|
773
790
|
try {
|
|
774
791
|
model.dispatchEvent('testEvent', { data: 'payload' });
|
|
@@ -776,7 +793,7 @@ describe('FlowModel', () => {
|
|
|
776
793
|
// Use a more reliable approach than arbitrary timeout
|
|
777
794
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
778
795
|
|
|
779
|
-
expect(
|
|
796
|
+
expect(loggerSpy).toHaveBeenCalledWith(
|
|
780
797
|
expect.stringContaining('[FlowModel] dispatchEvent: uid=test-model-uid, event=testEvent'),
|
|
781
798
|
);
|
|
782
799
|
expect(eventFlow.steps.eventStep.handler).toHaveBeenCalledWith(
|
|
@@ -786,7 +803,7 @@ describe('FlowModel', () => {
|
|
|
786
803
|
expect.any(Object),
|
|
787
804
|
);
|
|
788
805
|
} finally {
|
|
789
|
-
|
|
806
|
+
loggerSpy.mockRestore();
|
|
790
807
|
}
|
|
791
808
|
});
|
|
792
809
|
|
|
@@ -1597,7 +1614,7 @@ describe('FlowModel', () => {
|
|
|
1597
1614
|
fork1.dispose = vi.fn();
|
|
1598
1615
|
fork2.dispose = vi.fn();
|
|
1599
1616
|
|
|
1600
|
-
const
|
|
1617
|
+
const loggerSpy = vi.spyOn(model.flowEngine.logger, 'debug').mockImplementation(() => {});
|
|
1601
1618
|
|
|
1602
1619
|
try {
|
|
1603
1620
|
model.clearForks();
|
|
@@ -1606,19 +1623,19 @@ describe('FlowModel', () => {
|
|
|
1606
1623
|
expect(fork2.dispose).toHaveBeenCalled();
|
|
1607
1624
|
expect(model.forks.size).toBe(0);
|
|
1608
1625
|
} finally {
|
|
1609
|
-
|
|
1626
|
+
loggerSpy.mockRestore();
|
|
1610
1627
|
}
|
|
1611
1628
|
});
|
|
1612
1629
|
|
|
1613
1630
|
test('should handle empty forks collection when clearing', () => {
|
|
1614
|
-
const
|
|
1631
|
+
const loggerSpy = vi.spyOn(model.flowEngine.logger, 'debug').mockImplementation(() => {});
|
|
1615
1632
|
|
|
1616
1633
|
try {
|
|
1617
1634
|
model.clearForks();
|
|
1618
1635
|
|
|
1619
1636
|
expect(model.forks.size).toBe(0);
|
|
1620
1637
|
} finally {
|
|
1621
|
-
|
|
1638
|
+
loggerSpy.mockRestore();
|
|
1622
1639
|
}
|
|
1623
1640
|
});
|
|
1624
1641
|
});
|
|
@@ -1746,7 +1763,7 @@ describe('FlowModel', () => {
|
|
|
1746
1763
|
test('should clean up resources on remove', () => {
|
|
1747
1764
|
model.createFork();
|
|
1748
1765
|
model.createFork();
|
|
1749
|
-
const
|
|
1766
|
+
const loggerSpy = vi.spyOn(model.flowEngine.logger, 'debug').mockImplementation(() => {});
|
|
1750
1767
|
|
|
1751
1768
|
// Mock removeModel to simulate proper fork cleanup
|
|
1752
1769
|
flowEngine.removeModel = vi.fn().mockImplementation(() => {
|
|
@@ -1763,7 +1780,7 @@ describe('FlowModel', () => {
|
|
|
1763
1780
|
expect(model.forks.size).toBe(0);
|
|
1764
1781
|
expect(flowEngine.removeModel).toHaveBeenCalledWith(model.uid);
|
|
1765
1782
|
} finally {
|
|
1766
|
-
|
|
1783
|
+
loggerSpy.mockRestore();
|
|
1767
1784
|
}
|
|
1768
1785
|
});
|
|
1769
1786
|
});
|
|
@@ -1840,22 +1857,17 @@ describe('FlowModel', () => {
|
|
|
1840
1857
|
});
|
|
1841
1858
|
|
|
1842
1859
|
test('should rerender triggers beforeRender without cache', async () => {
|
|
1843
|
-
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
1844
1860
|
model.dispatchEvent = vi.fn().mockResolvedValue(undefined) as any;
|
|
1845
1861
|
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
});
|
|
1851
|
-
} finally {
|
|
1852
|
-
consoleSpy.mockRestore();
|
|
1853
|
-
}
|
|
1862
|
+
await expect(model.rerender()).resolves.not.toThrow();
|
|
1863
|
+
expect(model.dispatchEvent).toHaveBeenCalledWith('beforeRender', undefined, {
|
|
1864
|
+
useCache: false,
|
|
1865
|
+
});
|
|
1854
1866
|
});
|
|
1855
1867
|
});
|
|
1856
1868
|
|
|
1857
1869
|
describe('serialization', () => {
|
|
1858
|
-
test('should serialize basic model data
|
|
1870
|
+
test('should serialize basic model data with the latest props, excluding flowEngine', () => {
|
|
1859
1871
|
model.sortIndex = 5;
|
|
1860
1872
|
model.setProps({ name: 'Test Model', value: 42 });
|
|
1861
1873
|
model.setStepParams({
|
|
@@ -1867,13 +1879,12 @@ describe('FlowModel', () => {
|
|
|
1867
1879
|
expect(serialized).toEqual(
|
|
1868
1880
|
expect.objectContaining({
|
|
1869
1881
|
uid: model.uid,
|
|
1882
|
+
props: expect.objectContaining({ name: 'Test Model', value: 42 }),
|
|
1870
1883
|
stepParams: expect.objectContaining({ flow1: { step1: { param1: 'value1' } } }),
|
|
1871
1884
|
sortIndex: 5,
|
|
1872
1885
|
subModels: expect.any(Object),
|
|
1873
1886
|
}),
|
|
1874
1887
|
);
|
|
1875
|
-
// props should be excluded from serialization
|
|
1876
|
-
expect(serialized.props).toBeUndefined();
|
|
1877
1888
|
expect(serialized.flowEngine).toBeUndefined();
|
|
1878
1889
|
});
|
|
1879
1890
|
|
|
@@ -1892,6 +1903,7 @@ describe('FlowModel', () => {
|
|
|
1892
1903
|
expect(serialized).toEqual(
|
|
1893
1904
|
expect.objectContaining({
|
|
1894
1905
|
uid: 'empty-model',
|
|
1906
|
+
props: expect.objectContaining({ foo: 'bar' }),
|
|
1895
1907
|
stepParams: expect.any(Object),
|
|
1896
1908
|
sortIndex: expect.any(Number),
|
|
1897
1909
|
subModels: expect.any(Object),
|
|
@@ -1899,6 +1911,22 @@ describe('FlowModel', () => {
|
|
|
1899
1911
|
);
|
|
1900
1912
|
expect(serialized.flowEngine).toBeUndefined();
|
|
1901
1913
|
});
|
|
1914
|
+
|
|
1915
|
+
test('should serialize the latest props after multiple updates', () => {
|
|
1916
|
+
model.setProps({ fieldNames: { title: 'name' }, searchable: true });
|
|
1917
|
+
model.setProps({ fieldNames: { title: 'age' } });
|
|
1918
|
+
model.setProps('defaultExpandAll', false);
|
|
1919
|
+
|
|
1920
|
+
const serialized = model.serialize();
|
|
1921
|
+
|
|
1922
|
+
expect(serialized.props).toEqual(
|
|
1923
|
+
expect.objectContaining({
|
|
1924
|
+
fieldNames: { title: 'age' },
|
|
1925
|
+
searchable: true,
|
|
1926
|
+
defaultExpandAll: false,
|
|
1927
|
+
}),
|
|
1928
|
+
);
|
|
1929
|
+
});
|
|
1902
1930
|
});
|
|
1903
1931
|
});
|
|
1904
1932
|
|
|
@@ -2874,7 +2902,7 @@ describe('FlowModel', () => {
|
|
|
2874
2902
|
describe('Edge Cases & Error Handling', () => {
|
|
2875
2903
|
test('should handle model destruction gracefully', () => {
|
|
2876
2904
|
const model = new FlowModel(modelOptions);
|
|
2877
|
-
const
|
|
2905
|
+
const loggerSpy = vi.spyOn(model.flowEngine.logger, 'debug').mockImplementation(() => {});
|
|
2878
2906
|
|
|
2879
2907
|
model.createFork();
|
|
2880
2908
|
model.setProps({ testProp: 'value' });
|
|
@@ -2882,7 +2910,7 @@ describe('FlowModel', () => {
|
|
|
2882
2910
|
try {
|
|
2883
2911
|
expect(() => model.remove()).not.toThrow();
|
|
2884
2912
|
} finally {
|
|
2885
|
-
|
|
2913
|
+
loggerSpy.mockRestore();
|
|
2886
2914
|
}
|
|
2887
2915
|
});
|
|
2888
2916
|
|