@nocobase/flow-engine 2.0.22 → 2.1.0-alpha.10

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/src/flowEngine.ts CHANGED
@@ -24,7 +24,11 @@ import type {
24
24
  ActionDefinition,
25
25
  ApplyFlowCacheEntry,
26
26
  CreateModelOptions,
27
+ EnsureBatchResult,
27
28
  EventDefinition,
29
+ FlowModelLoaderEntry,
30
+ FlowModelLoaderMap,
31
+ FlowModelLoaderResult,
28
32
  FlowModelOptions,
29
33
  IFlowModelRepository,
30
34
  ModelConstructor,
@@ -75,6 +79,32 @@ export class FlowEngine {
75
79
  */
76
80
  private _modelClasses: Map<string, ModelConstructor> = observable.shallow(new Map());
77
81
 
82
+ /**
83
+ * Registered model entries.
84
+ * Key is the model class name, value is the model loader entry.
85
+ * @private
86
+ */
87
+ private _modelLoaders: Map<string, FlowModelLoaderEntry> = new Map();
88
+
89
+ /**
90
+ * In-flight model loading promises.
91
+ * Key is the model class name, value is the loading promise.
92
+ * @private
93
+ */
94
+ private _loadingModelPromises: Map<string, Promise<ModelConstructor | null>> = new Map();
95
+
96
+ /**
97
+ * Whether model-loader preload has completed in this session.
98
+ * @private
99
+ */
100
+ private _modelLoadersPreloaded = false;
101
+
102
+ /**
103
+ * In-flight model-loader preload promise.
104
+ * @private
105
+ */
106
+ private _modelLoadersPreloadPromise?: Promise<EnsureBatchResult>;
107
+
78
108
  /**
79
109
  * Created model instances.
80
110
  * Key is the model instance UID, value is the model instance object.
@@ -424,6 +454,13 @@ export class FlowEngine {
424
454
  * @private
425
455
  */
426
456
  #registerModel(name: string, modelClass: ModelConstructor): void {
457
+ return this._registerModel(name, modelClass);
458
+ }
459
+
460
+ /**
461
+ * for proxy instance, the #registerModel can't be called.
462
+ */
463
+ private _registerModel(name: string, modelClass: ModelConstructor): void {
427
464
  if (this._modelClasses.has(name)) {
428
465
  console.warn(`FlowEngine: Model class with name '${name}' is already registered and will be overwritten.`);
429
466
  }
@@ -444,6 +481,296 @@ export class FlowEngine {
444
481
  }
445
482
  }
446
483
 
484
+ /**
485
+ * Register multiple model loader entries.
486
+ * @param {FlowModelLoaderMap} loaders Model loader entry map, key is model name, value is the model loader entry
487
+ * @returns {void}
488
+ * @example
489
+ * flowEngine.registerModelLoaders({
490
+ * DemoModel: {
491
+ * loader: () => import('./models/DemoModel'),
492
+ * },
493
+ * });
494
+ */
495
+ public registerModelLoaders(loaders: FlowModelLoaderMap): void {
496
+ let changed = false;
497
+ for (const [name, entry] of Object.entries(loaders)) {
498
+ if (this._modelLoaders.has(name)) {
499
+ console.warn(`FlowEngine: Model loader with name '${name}' is already registered and will be overwritten.`);
500
+ }
501
+ this._modelLoaders.set(name, entry);
502
+ changed = true;
503
+ }
504
+ if (changed) {
505
+ this._modelLoadersPreloaded = false;
506
+ this._modelLoadersPreloadPromise = undefined;
507
+ }
508
+ }
509
+
510
+ /**
511
+ * Get a registered model class (constructor) asynchronously.
512
+ * This will first ensure the model loader entry is resolved.
513
+ * @param {string} name Model class name
514
+ * @returns {Promise<ModelConstructor | undefined>} Model constructor, or undefined if not found
515
+ */
516
+ public async getModelClassAsync(name: string): Promise<ModelConstructor | undefined> {
517
+ await this.ensureModel(name);
518
+ return this.getModelClass(name);
519
+ }
520
+
521
+ /**
522
+ * Get all registered model classes asynchronously.
523
+ * This will first ensure all registered model loader entries are resolved.
524
+ * @returns {Promise<Map<string, ModelConstructor>>} Model class map
525
+ */
526
+ public async getModelClassesAsync(): Promise<Map<string, ModelConstructor>> {
527
+ await this.ensureModels(Array.from(this._modelLoaders.keys()));
528
+ return this.getModelClasses();
529
+ }
530
+
531
+ /**
532
+ * Create and register a model instance asynchronously.
533
+ * This will first ensure all string-based model references in the model tree are resolved.
534
+ * @template T FlowModel subclass type, defaults to FlowModel.
535
+ * @param {CreateModelOptions} options Model creation options
536
+ * @returns {Promise<T>} Created model instance
537
+ */
538
+ public async createModelAsync<T extends FlowModel = FlowModel>(
539
+ options: CreateModelOptions,
540
+ extra?: { delegateToParent?: boolean; delegate?: FlowContext },
541
+ ): Promise<T> {
542
+ await this.resolveModelTree(options);
543
+ return this.createModel<T>(options, extra);
544
+ }
545
+
546
+ /**
547
+ * Normalize a loader result into a model constructor.
548
+ * @param {string} name Model class name
549
+ * @param {FlowModelLoaderResult} loaded Loader result
550
+ * @returns {ModelConstructor | null} Normalized model constructor
551
+ * @private
552
+ */
553
+ private normalizeModelLoaderResult(name: string, loaded: FlowModelLoaderResult): ModelConstructor | null {
554
+ if (typeof loaded === 'function') {
555
+ return loaded as ModelConstructor;
556
+ }
557
+ if (loaded && typeof loaded === 'object') {
558
+ const defaultExport = loaded.default;
559
+ if (typeof defaultExport === 'function') {
560
+ return defaultExport as ModelConstructor;
561
+ }
562
+ const namedExport = loaded[name];
563
+ if (typeof namedExport === 'function') {
564
+ return namedExport as ModelConstructor;
565
+ }
566
+ }
567
+ console.warn(`FlowEngine: model loader for '${name}' did not resolve to a valid model constructor.`);
568
+ return null;
569
+ }
570
+
571
+ /**
572
+ * Collect string-based model names from a model tree.
573
+ * @param {unknown} data Model tree data
574
+ * @param {Set<string>} names Model name set
575
+ * @private
576
+ */
577
+ private collectModelNamesFromTree(data: unknown, names: Set<string>): void {
578
+ if (!data || typeof data !== 'object') {
579
+ return;
580
+ }
581
+ if (Array.isArray(data)) {
582
+ data.forEach((item) => this.collectModelNamesFromTree(item, names));
583
+ return;
584
+ }
585
+
586
+ const tree = data as Record<string, any>;
587
+ if (typeof tree.use === 'string') {
588
+ names.add(tree.use);
589
+ }
590
+
591
+ const subModels = tree.subModels;
592
+ if (!subModels || typeof subModels !== 'object') {
593
+ return;
594
+ }
595
+
596
+ Object.values(subModels).forEach((value) => {
597
+ this.collectModelNamesFromTree(value, names);
598
+ });
599
+ }
600
+
601
+ /**
602
+ * Collect additional model names from object-form meta.createModelOptions defaults.
603
+ * @param {ModelConstructor} modelClass Model class constructor
604
+ * @param {Set<string>} names Model name set
605
+ * @private
606
+ */
607
+ private collectModelNamesFromMetaDefaults(modelClass: ModelConstructor, names: Set<string>): void {
608
+ const metaCreate = (modelClass as typeof FlowModel).meta?.createModelOptions;
609
+ if (metaCreate && typeof metaCreate === 'object') {
610
+ this.collectModelNamesFromTree(metaCreate, names);
611
+ }
612
+ }
613
+
614
+ /**
615
+ * Ensure a single model class is available.
616
+ * @param {string} name Model class name
617
+ * @returns {Promise<ModelConstructor | null>} Model constructor or null when resolution fails
618
+ * @private
619
+ */
620
+ private async ensureModel(name: string): Promise<ModelConstructor | null> {
621
+ const existing = this._modelClasses.get(name);
622
+ if (existing) {
623
+ return existing;
624
+ }
625
+
626
+ const inflight = this._loadingModelPromises.get(name);
627
+ if (inflight) {
628
+ return inflight;
629
+ }
630
+
631
+ const entry = this._modelLoaders.get(name);
632
+ if (!entry) {
633
+ console.warn(`FlowEngine: Model entry '${name}' not found. Falling back to ErrorFlowModel when needed.`);
634
+ return null;
635
+ }
636
+
637
+ const promise = (async () => {
638
+ try {
639
+ const loaded = await entry.loader();
640
+ const modelClass = this.normalizeModelLoaderResult(name, loaded);
641
+ if (!modelClass) {
642
+ return null;
643
+ }
644
+ // 这里拿到的 this 是 Proxy(FlowEngine) 而不是原始的 FlowEngine,无法直接调用 #registerModel
645
+ this._registerModel(name, modelClass);
646
+ return modelClass;
647
+ } catch (error) {
648
+ console.warn(`FlowEngine: Failed to load model '${name}'. Falling back to ErrorFlowModel when needed.`, error);
649
+ return null;
650
+ } finally {
651
+ this._loadingModelPromises.delete(name);
652
+ }
653
+ })();
654
+
655
+ this._loadingModelPromises.set(name, promise);
656
+ return promise;
657
+ }
658
+
659
+ /**
660
+ * Ensure multiple model classes are available.
661
+ * @param {string[]} names Model class names
662
+ * @returns {Promise<EnsureBatchResult>} Batch ensure result
663
+ * @private
664
+ */
665
+ private async ensureModels(names: string[]): Promise<EnsureBatchResult> {
666
+ const requested = Array.from(new Set(names.filter((name): name is string => !!name)));
667
+ const loaded: string[] = [];
668
+ const failed: EnsureBatchResult['failed'] = [];
669
+
670
+ const results = await Promise.all(
671
+ requested.map(async (name) => {
672
+ const modelClass = await this.ensureModel(name);
673
+ return { name, modelClass };
674
+ }),
675
+ );
676
+
677
+ results.forEach(({ name, modelClass }) => {
678
+ if (modelClass) {
679
+ loaded.push(name);
680
+ } else {
681
+ failed.push({ name });
682
+ }
683
+ });
684
+
685
+ return { requested, loaded, failed };
686
+ }
687
+
688
+ /**
689
+ * Resolve all unresolved string-based model references in a model tree before synchronous creation begins.
690
+ *
691
+ * Use this when you already have a model tree object, such as repository-returned data or resolved
692
+ * `createModelOptions`, and you need to ensure every string `use` in that tree has been loaded and
693
+ * registered into `_modelClasses` before calling `createModel()`.
694
+ *
695
+ * @param {unknown} data Model tree data
696
+ * @returns {Promise<EnsureBatchResult>} Batch ensure result
697
+ */
698
+ public async resolveModelTree(data: unknown): Promise<EnsureBatchResult> {
699
+ const requested = new Set<string>();
700
+ const loaded = new Set<string>();
701
+ const failed = new Map<string, { name: string; error?: unknown }>();
702
+ const processed = new Set<string>();
703
+ const pending = new Set<string>();
704
+
705
+ this.collectModelNamesFromTree(data, pending);
706
+
707
+ while (pending.size > 0) {
708
+ const batch = Array.from(pending).filter((name) => !processed.has(name));
709
+ pending.clear();
710
+ if (batch.length === 0) {
711
+ break;
712
+ }
713
+
714
+ batch.forEach((name) => requested.add(name));
715
+ const result = await this.ensureModels(batch);
716
+
717
+ result.loaded.forEach((name) => {
718
+ processed.add(name);
719
+ loaded.add(name);
720
+ const modelClass = this.getModelClass(name);
721
+ if (modelClass) {
722
+ const discovered = new Set<string>();
723
+ this.collectModelNamesFromMetaDefaults(modelClass, discovered);
724
+ discovered.forEach((discoveredName) => {
725
+ if (!processed.has(discoveredName)) {
726
+ pending.add(discoveredName);
727
+ }
728
+ });
729
+ }
730
+ });
731
+
732
+ result.failed.forEach((item) => {
733
+ processed.add(item.name);
734
+ failed.set(item.name, item);
735
+ });
736
+ }
737
+
738
+ return {
739
+ requested: Array.from(requested),
740
+ loaded: Array.from(loaded),
741
+ failed: Array.from(failed.values()),
742
+ };
743
+ }
744
+
745
+ /**
746
+ * Preload all currently registered unresolved model loaders.
747
+ *
748
+ * This method is intended for flow-settings/discovery style entry points that need registered model
749
+ * classes to exist before UI is rendered, without requiring callers to know which specific models
750
+ * will be touched next.
751
+ *
752
+ * @returns {Promise<EnsureBatchResult>} Batch ensure result
753
+ */
754
+ public async preloadModelLoaders(): Promise<EnsureBatchResult> {
755
+ const unresolved = Array.from(this._modelLoaders.keys()).filter((name) => !this._modelClasses.has(name));
756
+ if (unresolved.length === 0) {
757
+ this._modelLoadersPreloaded = true;
758
+ return { requested: [], loaded: [], failed: [] };
759
+ }
760
+ if (this._modelLoadersPreloadPromise) {
761
+ return this._modelLoadersPreloadPromise;
762
+ }
763
+
764
+ this._modelLoadersPreloadPromise = (async () => {
765
+ const result = await this.ensureModels(unresolved);
766
+ this._modelLoadersPreloaded = result.failed.length === 0;
767
+ this._modelLoadersPreloadPromise = undefined;
768
+ return result;
769
+ })();
770
+
771
+ return this._modelLoadersPreloadPromise;
772
+ }
773
+
447
774
  registerResources(resources: Record<string, any>) {
448
775
  for (const [name, resourceClass] of Object.entries(resources)) {
449
776
  this._resources.set(name, resourceClass);
@@ -865,10 +1192,10 @@ export class FlowEngine {
865
1192
  * Hydrate a model into current engine from an already-existing model instance in previous engines.
866
1193
  * - Avoids repository requests when the model tree is already present in memory.
867
1194
  */
868
- private hydrateModelFromPreviousEngines<T extends FlowModel = FlowModel>(
1195
+ private async hydrateModelFromPreviousEngines<T extends FlowModel = FlowModel>(
869
1196
  options: any,
870
1197
  extra?: { delegateToParent?: boolean; delegate?: FlowContext },
871
- ): T | null {
1198
+ ): Promise<T | null> {
872
1199
  const uid = options?.uid;
873
1200
  const parentId = options?.parentId;
874
1201
  const subKey = options?.subKey;
@@ -882,7 +1209,7 @@ export class FlowEngine {
882
1209
  }
883
1210
  if (existing) {
884
1211
  const data = existing.serialize();
885
- return this.createModel<T>(data as any, extra);
1212
+ return this.createModelAsync<T>(data as any, extra);
886
1213
  }
887
1214
  }
888
1215
 
@@ -897,11 +1224,11 @@ export class FlowEngine {
897
1224
  if (!localParent) {
898
1225
  const parentData = parentFromPrev.serialize();
899
1226
  delete (parentData as any).subModels;
900
- localParent = this.createModel<FlowModel>(parentData as any, extra);
1227
+ localParent = await this.createModelAsync<FlowModel>(parentData as any, extra);
901
1228
  }
902
1229
  // Create (or reuse) the sub-model instance in current engine.
903
1230
  const modelData = modelFromPrev.serialize();
904
- const localModel = this.createModel<T>(modelData as any, extra);
1231
+ const localModel = await this.createModelAsync<T>(modelData as any, extra);
905
1232
 
906
1233
  // Mount under local parent if not mounted yet (so later lookups by parentId/subKey won't hit repo).
907
1234
  const mounted = (localParent.subModels as any)?.[subKey];
@@ -942,20 +1269,21 @@ export class FlowEngine {
942
1269
  if (model) {
943
1270
  return model as T;
944
1271
  }
945
- const hydrated = this.hydrateModelFromPreviousEngines<T>(options);
1272
+ const hydrated = await this.hydrateModelFromPreviousEngines<T>(options);
946
1273
  if (hydrated) {
947
1274
  return hydrated as T;
948
1275
  }
949
1276
  }
950
1277
  const data = await this._modelRepository.findOne(options);
951
1278
  if (!data?.uid) return null;
1279
+ await this.resolveModelTree(data);
952
1280
  if (refresh) {
953
1281
  const existing = this.getModel(data.uid);
954
1282
  if (existing) {
955
1283
  this.removeModelWithSubModels(existing.uid);
956
1284
  }
957
1285
  }
958
- return this.createModel<T>(data as any);
1286
+ return this.createModelAsync<T>(data as any);
959
1287
  }
960
1288
 
961
1289
  /**
@@ -1003,7 +1331,7 @@ export class FlowEngine {
1003
1331
  return m;
1004
1332
  }
1005
1333
 
1006
- const hydrated = this.hydrateModelFromPreviousEngines<T>(options, extra);
1334
+ const hydrated = await this.hydrateModelFromPreviousEngines<T>(options, extra);
1007
1335
  if (hydrated) {
1008
1336
  return hydrated;
1009
1337
  }
@@ -1011,9 +1339,9 @@ export class FlowEngine {
1011
1339
  const data = await this._modelRepository.findOne(options);
1012
1340
  let model: T | null = null;
1013
1341
  if (data?.uid) {
1014
- model = this.createModel<T>(data as any, extra);
1342
+ model = await this.createModelAsync<T>(data as any, extra);
1015
1343
  } else {
1016
- model = this.createModel<T>(options, extra);
1344
+ model = await this.createModelAsync<T>(options, extra);
1017
1345
  if (!extra?.skipSave) {
1018
1346
  await model.save();
1019
1347
  }
@@ -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
  }
@@ -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
+ }
@@ -11,8 +11,6 @@ import { batch, define, observable, observe } from '@formily/reactive';
11
11
  import _ from 'lodash';
12
12
  import React from 'react';
13
13
  import { uid } from 'uid/secure';
14
- import { openRequiredParamsStepFormDialog as openRequiredParamsStepFormDialogFn } from '../components/settings/wrappers/contextual/StepRequiredSettingsDialog';
15
- import { openStepSettingsDialog as openStepSettingsDialogFn } from '../components/settings/wrappers/contextual/StepSettingsDialog';
16
14
  import { Emitter } from '../emitter';
17
15
  import { InstanceFlowRegistry } from '../flow-registry/InstanceFlowRegistry';
18
16
  import { FlowContext, FlowModelContext, FlowRuntimeContext } from '../flowContext';
@@ -36,7 +34,7 @@ import type {
36
34
  import { IModelComponentProps, ReadonlyModelProps } from '../types';
37
35
  import { isInheritedFrom, setupRuntimeContextSteps } from '../utils';
38
36
  // import { FlowExitAllException } from '../utils/exceptions';
39
- import { Typography } from 'antd/lib';
37
+ import { Typography } from 'antd';
40
38
  import { ModelActionRegistry } from '../action-registry/ModelActionRegistry';
41
39
  import { buildSubModelItem } from '../components/subModel/utils';
42
40
  import { ModelEventRegistry } from '../event-registry/ModelEventRegistry';
@@ -88,6 +86,16 @@ type ExtraMenuItemEntry = {
88
86
 
89
87
  const classMenuExtensions = new WeakMap<typeof FlowModel, Set<ExtraMenuItemEntry>>();
90
88
 
89
+ async function loadOpenStepSettingsDialog() {
90
+ const mod = await import('../components/settings/wrappers/contextual/StepSettingsDialog');
91
+ return mod.openStepSettingsDialog;
92
+ }
93
+
94
+ async function loadOpenRequiredParamsStepFormDialog() {
95
+ const mod = await import('../components/settings/wrappers/contextual/StepRequiredSettingsDialog');
96
+ return mod.openRequiredParamsStepFormDialog;
97
+ }
98
+
91
99
  export enum ModelRenderMode {
92
100
  ReactElement = 'reactElement',
93
101
  RenderFunction = 'renderFunction',
@@ -1369,7 +1377,7 @@ export class FlowModel<Structure extends DefaultStructure = DefaultStructure> {
1369
1377
  * @param {string} stepKey 步骤的唯一标识符
1370
1378
  * @returns {void}
1371
1379
  */
1372
- openStepSettingsDialog(flowKey: string, stepKey: string) {
1380
+ async openStepSettingsDialog(flowKey: string, stepKey: string) {
1373
1381
  // 创建流程运行时上下文
1374
1382
  const flow = this.getFlow(flowKey);
1375
1383
  const step = flow?.steps?.[stepKey];
@@ -1383,7 +1391,9 @@ export class FlowModel<Structure extends DefaultStructure = DefaultStructure> {
1383
1391
  setupRuntimeContextSteps(ctx, flow.steps, this, flowKey);
1384
1392
  ctx.defineProperty('currentStep', { value: step });
1385
1393
 
1386
- return openStepSettingsDialogFn({
1394
+ const openStepSettingsDialog = await loadOpenStepSettingsDialog();
1395
+
1396
+ return openStepSettingsDialog({
1387
1397
  model: this,
1388
1398
  flowKey,
1389
1399
  stepKey,
@@ -1399,7 +1409,9 @@ export class FlowModel<Structure extends DefaultStructure = DefaultStructure> {
1399
1409
  * @returns {Promise<any>} 返回表单提交的值
1400
1410
  */
1401
1411
  async configureRequiredSteps(dialogWidth?: number | string, dialogTitle?: string) {
1402
- return openRequiredParamsStepFormDialogFn({
1412
+ const openRequiredParamsStepFormDialog = await loadOpenRequiredParamsStepFormDialog();
1413
+
1414
+ return openRequiredParamsStepFormDialog({
1403
1415
  model: this,
1404
1416
  dialogWidth,
1405
1417
  dialogTitle,