@nocobase/flow-engine 2.1.0-alpha.3 → 2.1.0-alpha.30

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.
Files changed (160) hide show
  1. package/LICENSE +201 -661
  2. package/README.md +79 -10
  3. package/lib/JSRunner.d.ts +10 -1
  4. package/lib/JSRunner.js +50 -5
  5. package/lib/ViewScopedFlowEngine.js +5 -1
  6. package/lib/components/FieldModelRenderer.js +2 -2
  7. package/lib/components/FlowModelRenderer.d.ts +3 -1
  8. package/lib/components/FlowModelRenderer.js +12 -6
  9. package/lib/components/MobilePopup.js +6 -5
  10. package/lib/components/dnd/gridDragPlanner.d.ts +59 -2
  11. package/lib/components/dnd/gridDragPlanner.js +601 -21
  12. package/lib/components/dnd/index.d.ts +19 -1
  13. package/lib/components/dnd/index.js +243 -23
  14. package/lib/components/settings/wrappers/component/SelectWithTitle.d.ts +2 -1
  15. package/lib/components/settings/wrappers/component/SelectWithTitle.js +14 -12
  16. package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.d.ts +3 -0
  17. package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +68 -10
  18. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.d.ts +23 -43
  19. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +352 -295
  20. package/lib/components/settings/wrappers/contextual/StepSettingsDialog.js +16 -2
  21. package/lib/components/settings/wrappers/contextual/useFloatToolbarPortal.d.ts +36 -0
  22. package/lib/components/settings/wrappers/contextual/useFloatToolbarPortal.js +274 -0
  23. package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.d.ts +30 -0
  24. package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.js +315 -0
  25. package/lib/components/subModel/AddSubModelButton.js +27 -1
  26. package/lib/components/subModel/index.d.ts +1 -0
  27. package/lib/components/subModel/index.js +19 -0
  28. package/lib/components/subModel/utils.d.ts +1 -1
  29. package/lib/components/subModel/utils.js +2 -2
  30. package/lib/data-source/index.d.ts +73 -0
  31. package/lib/data-source/index.js +211 -1
  32. package/lib/executor/FlowExecutor.js +31 -8
  33. package/lib/flowContext.d.ts +2 -0
  34. package/lib/flowContext.js +31 -1
  35. package/lib/flowEngine.d.ts +151 -1
  36. package/lib/flowEngine.js +389 -15
  37. package/lib/flowI18n.js +2 -1
  38. package/lib/flowSettings.d.ts +14 -6
  39. package/lib/flowSettings.js +34 -6
  40. package/lib/lazy-helper.d.ts +14 -0
  41. package/lib/lazy-helper.js +71 -0
  42. package/lib/locale/en-US.json +1 -0
  43. package/lib/locale/index.d.ts +2 -0
  44. package/lib/locale/zh-CN.json +1 -0
  45. package/lib/models/DisplayItemModel.d.ts +1 -1
  46. package/lib/models/EditableItemModel.d.ts +1 -1
  47. package/lib/models/FilterableItemModel.d.ts +1 -1
  48. package/lib/models/flowModel.d.ts +13 -10
  49. package/lib/models/flowModel.js +78 -18
  50. package/lib/provider.js +38 -23
  51. package/lib/reactive/observer.js +46 -16
  52. package/lib/runjs-context/registry.d.ts +1 -1
  53. package/lib/runjs-context/setup.js +20 -12
  54. package/lib/runjs-context/snippets/index.js +13 -2
  55. package/lib/runjs-context/snippets/scene/detail/set-field-style.snippet.d.ts +11 -0
  56. package/lib/runjs-context/snippets/scene/detail/set-field-style.snippet.js +50 -0
  57. package/lib/runjs-context/snippets/scene/table/set-cell-style.snippet.d.ts +11 -0
  58. package/lib/runjs-context/snippets/scene/table/set-cell-style.snippet.js +54 -0
  59. package/lib/scheduler/ModelOperationScheduler.d.ts +5 -1
  60. package/lib/scheduler/ModelOperationScheduler.js +3 -2
  61. package/lib/types.d.ts +47 -1
  62. package/lib/utils/createCollectionContextMeta.js +6 -2
  63. package/lib/utils/index.d.ts +2 -2
  64. package/lib/utils/index.js +4 -0
  65. package/lib/utils/parsePathnameToViewParams.js +1 -1
  66. package/lib/utils/runjsTemplateCompat.js +1 -1
  67. package/lib/utils/runjsValue.js +41 -11
  68. package/lib/utils/schema-utils.d.ts +7 -1
  69. package/lib/utils/schema-utils.js +19 -0
  70. package/lib/views/FlowView.d.ts +7 -1
  71. package/lib/views/runViewBeforeClose.d.ts +10 -0
  72. package/lib/views/runViewBeforeClose.js +45 -0
  73. package/lib/views/useDialog.d.ts +2 -1
  74. package/lib/views/useDialog.js +20 -3
  75. package/lib/views/useDrawer.d.ts +2 -1
  76. package/lib/views/useDrawer.js +20 -3
  77. package/lib/views/usePage.d.ts +2 -1
  78. package/lib/views/usePage.js +10 -3
  79. package/package.json +6 -5
  80. package/src/JSRunner.ts +68 -4
  81. package/src/ViewScopedFlowEngine.ts +4 -0
  82. package/src/__tests__/JSRunner.test.ts +27 -1
  83. package/src/__tests__/flow-engine.test.ts +166 -0
  84. package/src/__tests__/flowContext.test.ts +65 -1
  85. package/src/__tests__/flowEngine.modelLoaders.test.ts +245 -0
  86. package/src/__tests__/flowSettings.test.ts +94 -15
  87. package/src/__tests__/objectVariable.test.ts +24 -0
  88. package/src/__tests__/provider.test.tsx +24 -2
  89. package/src/__tests__/renderHiddenInConfig.test.tsx +6 -6
  90. package/src/__tests__/runjsContext.test.ts +16 -0
  91. package/src/__tests__/runjsContextRuntime.test.ts +2 -0
  92. package/src/__tests__/runjsPreprocessDefault.test.ts +23 -0
  93. package/src/__tests__/runjsSnippets.test.ts +21 -0
  94. package/src/__tests__/viewScopedFlowEngine.test.ts +3 -3
  95. package/src/components/FieldModelRenderer.tsx +2 -1
  96. package/src/components/FlowModelRenderer.tsx +18 -6
  97. package/src/components/MobilePopup.tsx +4 -2
  98. package/src/components/__tests__/FlowModelRenderer.test.tsx +65 -2
  99. package/src/components/__tests__/dnd.test.ts +44 -0
  100. package/src/components/__tests__/flow-model-render-error-fallback.test.tsx +20 -10
  101. package/src/components/__tests__/gridDragPlanner.test.ts +512 -3
  102. package/src/components/dnd/__tests__/DndProvider.test.tsx +98 -0
  103. package/src/components/dnd/gridDragPlanner.ts +743 -19
  104. package/src/components/dnd/index.tsx +291 -27
  105. package/src/components/settings/wrappers/component/SelectWithTitle.tsx +21 -9
  106. package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +88 -10
  107. package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +487 -440
  108. package/src/components/settings/wrappers/contextual/StepSettingsDialog.tsx +18 -2
  109. package/src/components/settings/wrappers/contextual/__tests__/DefaultSettingsIcon.test.tsx +189 -3
  110. package/src/components/settings/wrappers/contextual/__tests__/FlowsFloatContextMenu.test.tsx +778 -0
  111. package/src/components/settings/wrappers/contextual/useFloatToolbarPortal.ts +360 -0
  112. package/src/components/settings/wrappers/contextual/useFloatToolbarVisibility.ts +361 -0
  113. package/src/components/subModel/AddSubModelButton.tsx +32 -2
  114. package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +142 -32
  115. package/src/components/subModel/index.ts +1 -0
  116. package/src/components/subModel/utils.ts +1 -1
  117. package/src/data-source/__tests__/index.test.ts +34 -1
  118. package/src/data-source/index.ts +258 -2
  119. package/src/executor/FlowExecutor.ts +34 -9
  120. package/src/executor/__tests__/flowExecutor.test.ts +57 -0
  121. package/src/flowContext.ts +37 -3
  122. package/src/flowEngine.ts +445 -11
  123. package/src/flowI18n.ts +2 -1
  124. package/src/flowSettings.ts +40 -6
  125. package/src/lazy-helper.tsx +57 -0
  126. package/src/locale/en-US.json +1 -0
  127. package/src/locale/zh-CN.json +1 -0
  128. package/src/models/DisplayItemModel.tsx +1 -1
  129. package/src/models/EditableItemModel.tsx +1 -1
  130. package/src/models/FilterableItemModel.tsx +1 -1
  131. package/src/models/__tests__/dispatchEvent.when.test.ts +214 -0
  132. package/src/models/__tests__/flowModel.test.ts +19 -3
  133. package/src/models/flowModel.tsx +119 -33
  134. package/src/provider.tsx +41 -25
  135. package/src/reactive/__tests__/observer.test.tsx +82 -0
  136. package/src/reactive/observer.tsx +87 -25
  137. package/src/runjs-context/registry.ts +1 -1
  138. package/src/runjs-context/setup.ts +22 -12
  139. package/src/runjs-context/snippets/index.ts +12 -1
  140. package/src/runjs-context/snippets/scene/detail/set-field-style.snippet.ts +30 -0
  141. package/src/runjs-context/snippets/scene/table/set-cell-style.snippet.ts +34 -0
  142. package/src/scheduler/ModelOperationScheduler.ts +14 -3
  143. package/src/types.ts +60 -0
  144. package/src/utils/__tests__/createCollectionContextMeta.test.ts +48 -0
  145. package/src/utils/__tests__/parsePathnameToViewParams.test.ts +7 -0
  146. package/src/utils/__tests__/runjsValue.test.ts +11 -0
  147. package/src/utils/__tests__/utils.test.ts +62 -0
  148. package/src/utils/createCollectionContextMeta.ts +6 -2
  149. package/src/utils/index.ts +2 -1
  150. package/src/utils/parsePathnameToViewParams.ts +2 -2
  151. package/src/utils/runjsTemplateCompat.ts +1 -1
  152. package/src/utils/runjsValue.ts +50 -11
  153. package/src/utils/schema-utils.ts +30 -1
  154. package/src/views/FlowView.tsx +11 -1
  155. package/src/views/__tests__/runViewBeforeClose.test.ts +30 -0
  156. package/src/views/__tests__/useDialog.closeDestroy.test.tsx +13 -12
  157. package/src/views/runViewBeforeClose.ts +19 -0
  158. package/src/views/useDialog.tsx +25 -3
  159. package/src/views/useDrawer.tsx +25 -3
  160. package/src/views/usePage.tsx +12 -3
@@ -0,0 +1,11 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ import type { SnippetModule } from '../../types';
10
+ declare const snippet: SnippetModule;
11
+ export default snippet;
@@ -0,0 +1,50 @@
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
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var set_field_style_snippet_exports = {};
28
+ __export(set_field_style_snippet_exports, {
29
+ default: () => set_field_style_snippet_default
30
+ });
31
+ module.exports = __toCommonJS(set_field_style_snippet_exports);
32
+ const snippet = {
33
+ contexts: ["*"],
34
+ scenes: ["detailFieldEvent", "formFieldEvent"],
35
+ prefix: "sn-item-style",
36
+ label: "Set form item/details item style",
37
+ description: "Customize form item and details item container styles",
38
+ locales: {
39
+ "zh-CN": {
40
+ label: "\u8BBE\u7F6E\u8868\u5355\u9879/\u8BE6\u60C5\u9879\u6837\u5F0F",
41
+ description: "\u81EA\u5B9A\u4E49\u8868\u5355\u9879\u548C\u8BE6\u60C5\u9879\u5BB9\u5668\u6837\u5F0F"
42
+ }
43
+ },
44
+ content: `
45
+ ctx.model.props.style = {
46
+ background: 'red',
47
+ };
48
+ `
49
+ };
50
+ var set_field_style_snippet_default = snippet;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ import type { SnippetModule } from '../../types';
10
+ declare const snippet: SnippetModule;
11
+ export default snippet;
@@ -0,0 +1,54 @@
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
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var set_cell_style_snippet_exports = {};
28
+ __export(set_cell_style_snippet_exports, {
29
+ default: () => set_cell_style_snippet_default
30
+ });
31
+ module.exports = __toCommonJS(set_cell_style_snippet_exports);
32
+ const snippet = {
33
+ contexts: ["*"],
34
+ scenes: ["tableFieldEvent"],
35
+ prefix: "sn-table-cell-style",
36
+ label: "Set table cell style",
37
+ description: "Customize table field cell styles with onCell",
38
+ locales: {
39
+ "zh-CN": {
40
+ label: "\u8868\u683C\u5B57\u6BB5\u6837\u5F0F\u8BBE\u7F6E",
41
+ description: "\u901A\u8FC7 onCell \u81EA\u5B9A\u4E49\u8868\u683C\u5B57\u6BB5\u5355\u5143\u683C\u6837\u5F0F"
42
+ }
43
+ },
44
+ content: `
45
+ ctx.model.props.onCell = (record, rowIndex) => {
46
+ return {
47
+ style: {
48
+ background: 'red',
49
+ },
50
+ };
51
+ };
52
+ `
53
+ };
54
+ var set_cell_style_snippet_default = snippet;
@@ -9,7 +9,10 @@
9
9
  import type { FlowEngine } from '../flowEngine';
10
10
  import type { FlowModel } from '../models/flowModel';
11
11
  type LifecycleType = 'created' | 'mounted' | 'unmounted' | 'destroyed' | `event:${string}:start` | `event:${string}:end` | `event:${string}:error`;
12
- export type ScheduleWhen = LifecycleType | ((e: LifecycleEvent) => boolean);
12
+ type EventPredicateWhen = ((e: LifecycleEvent) => boolean) & {
13
+ __eventType?: string;
14
+ };
15
+ export type ScheduleWhen = LifecycleType | EventPredicateWhen;
13
16
  export interface ScheduleOptions {
14
17
  when?: ScheduleWhen;
15
18
  }
@@ -22,6 +25,7 @@ export interface LifecycleEvent {
22
25
  error?: any;
23
26
  inputArgs?: Record<string, any>;
24
27
  result?: any;
28
+ aborted?: boolean;
25
29
  flowKey?: string;
26
30
  stepKey?: string;
27
31
  }
@@ -171,8 +171,9 @@ const _ModelOperationScheduler = class _ModelOperationScheduler {
171
171
  this.unbindHandlers.push(() => emitter.off("model:destroyed", onDestroyed));
172
172
  }
173
173
  ensureEventSubscriptionIfNeeded(when) {
174
- if (!when || typeof when !== "string") return;
175
- const parsed = this.parseEventWhen(when);
174
+ const eventType = typeof when === "string" ? when : typeof when === "function" ? when.__eventType : void 0;
175
+ if (!eventType) return;
176
+ const parsed = this.parseEventWhen(eventType);
176
177
  if (!parsed) return;
177
178
  const { name } = parsed;
178
179
  if (this.subscribedEventNames.has(name)) return;
package/lib/types.d.ts CHANGED
@@ -177,7 +177,7 @@ export interface ActionDefinition<TModel extends FlowModel = FlowModel, TCtx ext
177
177
  * - 收录内置常用事件,便于智能提示;
178
178
  * - 允许扩展字符串以保持向后兼容。
179
179
  */
180
- export type FlowEventName = 'click' | 'submit' | 'reset' | 'remove' | 'openView' | 'dropdownOpen' | 'popupScroll' | 'search' | 'customRequest' | 'collapseToggle' | (string & {});
180
+ export type FlowEventName = 'click' | 'close' | 'submit' | 'reset' | 'remove' | 'openView' | 'dropdownOpen' | 'popupScroll' | 'search' | 'customRequest' | 'collapseToggle' | (string & {});
181
181
  /**
182
182
  * 事件流的执行时机(phase)。
183
183
  *
@@ -303,6 +303,52 @@ export interface CreateModelOptions {
303
303
  delegateToParent?: boolean;
304
304
  [key: string]: any;
305
305
  }
306
+ /**
307
+ * FlowModel loader result.
308
+ * Supports returning the model constructor directly, a default export, or a module object containing the named export.
309
+ */
310
+ export type FlowModelLoaderResult = ModelConstructor | {
311
+ default?: ModelConstructor;
312
+ [key: string]: unknown;
313
+ } | Record<string, unknown>;
314
+ /**
315
+ * FlowModel loader function.
316
+ */
317
+ export type FlowModelLoader = () => Promise<FlowModelLoaderResult>;
318
+ /**
319
+ * FlowModel loader entry (normalized internal form).
320
+ */
321
+ export interface FlowModelLoaderEntry {
322
+ loader: FlowModelLoader;
323
+ extends?: string[];
324
+ }
325
+ /**
326
+ * FlowModel loader input (user-facing form for registerModelLoaders).
327
+ * The `extends` field accepts flexible formats that will be normalized to `string[]` at registration time.
328
+ */
329
+ export interface FlowModelLoaderInput {
330
+ loader: FlowModelLoader;
331
+ extends?: string | ModelConstructor | (string | ModelConstructor)[];
332
+ }
333
+ /**
334
+ * FlowModel loader entry map (normalized internal form).
335
+ */
336
+ export type FlowModelLoaderMap = Record<string, FlowModelLoaderEntry>;
337
+ /**
338
+ * FlowModel loader input map (user-facing form for registerModelLoaders).
339
+ */
340
+ export type FlowModelLoaderInputMap = Record<string, FlowModelLoaderInput>;
341
+ /**
342
+ * Batch ensure result.
343
+ */
344
+ export interface EnsureBatchResult {
345
+ requested: string[];
346
+ loaded: string[];
347
+ failed: Array<{
348
+ name: string;
349
+ error?: unknown;
350
+ }>;
351
+ }
306
352
  export interface IFlowModelRepository<T extends FlowModel = FlowModel> {
307
353
  findOne(query: Record<string, any>): Promise<Record<string, any> | null>;
308
354
  save(model: T, options?: {
@@ -32,6 +32,10 @@ __export(createCollectionContextMeta_exports, {
32
32
  module.exports = __toCommonJS(createCollectionContextMeta_exports);
33
33
  const RELATION_FIELD_TYPES = ["belongsTo", "hasOne", "hasMany", "belongsToMany", "belongsToArray"];
34
34
  const NUMERIC_FIELD_TYPES = ["integer", "float", "double", "decimal"];
35
+ function shouldShowFieldInMeta(field, includeNonFilterable) {
36
+ return Boolean(field.interface && (includeNonFilterable || field.filterable));
37
+ }
38
+ __name(shouldShowFieldInMeta, "shouldShowFieldInMeta");
35
39
  function createFieldMetadata(field, includeNonFilterable) {
36
40
  const baseProperties = createMetaBaseProperties(field);
37
41
  if (field.isAssociationField()) {
@@ -49,7 +53,7 @@ function createFieldMetadata(field, includeNonFilterable) {
49
53
  properties: /* @__PURE__ */ __name(async () => {
50
54
  const subProperties = {};
51
55
  targetCollection.fields.forEach((subField) => {
52
- if (includeNonFilterable || subField.filterable) {
56
+ if (shouldShowFieldInMeta(subField, includeNonFilterable)) {
53
57
  subProperties[subField.name] = createFieldMetadata(subField, includeNonFilterable);
54
58
  }
55
59
  });
@@ -104,7 +108,7 @@ function createCollectionContextMeta(collectionOrFactory, title, includeNonFilte
104
108
  properties: /* @__PURE__ */ __name(async () => {
105
109
  const properties = {};
106
110
  collection.fields.forEach((field) => {
107
- if (includeNonFilterable || field.filterable) {
111
+ if (shouldShowFieldInMeta(field, includeNonFilterable)) {
108
112
  properties[field.name] = createFieldMetadata(field, includeNonFilterable);
109
113
  }
110
114
  });
@@ -8,11 +8,11 @@
8
8
  */
9
9
  export { BLOCK_GROUP_CONFIGS, BLOCK_TYPES, FLOW_ENGINE_NAMESPACE, MENU_KEYS, type BlockBuilderConfig, } from './constants';
10
10
  export { escapeT, getT, tExpr } from './translation';
11
- export { FlowCancelSaveException, FlowExitException } from './exceptions';
11
+ export { FlowCancelSaveException, FlowExitAllException, FlowExitException } from './exceptions';
12
12
  export { defineAction } from './flow-definitions';
13
13
  export { isInheritedFrom } from './inheritance';
14
14
  export { resolveCreateModelOptions, resolveDefaultParams, resolveExpressions } from './params-resolvers';
15
- export { compileUiSchema, resolveStepUiSchema, resolveStepDisabledInSettings, resolveUiMode, shouldHideStepInSettings, } from './schema-utils';
15
+ export { compileUiSchema, resolveStepUiSchema, resolveStepDisabledInSettings, resolveUiMode, shouldHideEventInSettings, shouldHideStepInSettings, } from './schema-utils';
16
16
  export { setupRuntimeContextSteps } from './setupRuntimeContextSteps';
17
17
  export { createCollectionContextMeta } from './createCollectionContextMeta';
18
18
  export { createAssociationAwareObjectMetaFactory, createAssociationSubpathResolver } from './associationObjectVariable';
@@ -30,6 +30,7 @@ __export(utils_exports, {
30
30
  BLOCK_TYPES: () => import_constants.BLOCK_TYPES,
31
31
  FLOW_ENGINE_NAMESPACE: () => import_constants.FLOW_ENGINE_NAMESPACE,
32
32
  FlowCancelSaveException: () => import_exceptions.FlowCancelSaveException,
33
+ FlowExitAllException: () => import_exceptions.FlowExitAllException,
33
34
  FlowExitException: () => import_exceptions.FlowExitException,
34
35
  MENU_KEYS: () => import_constants.MENU_KEYS,
35
36
  buildRecordMeta: () => import_variablesParams.buildRecordMeta,
@@ -86,6 +87,7 @@ __export(utils_exports, {
86
87
  serializeCtxDateValue: () => import_dateVariable.serializeCtxDateValue,
87
88
  setAutoFlowError: () => import_autoFlowError.setAutoFlowError,
88
89
  setupRuntimeContextSteps: () => import_setupRuntimeContextSteps.setupRuntimeContextSteps,
90
+ shouldHideEventInSettings: () => import_schema_utils.shouldHideEventInSettings,
89
91
  shouldHideStepInSettings: () => import_schema_utils.shouldHideStepInSettings,
90
92
  tExpr: () => import_translation.tExpr
91
93
  });
@@ -119,6 +121,7 @@ var import_resolveModuleUrl = require("./resolveModuleUrl");
119
121
  BLOCK_TYPES,
120
122
  FLOW_ENGINE_NAMESPACE,
121
123
  FlowCancelSaveException,
124
+ FlowExitAllException,
122
125
  FlowExitException,
123
126
  MENU_KEYS,
124
127
  buildRecordMeta,
@@ -175,6 +178,7 @@ var import_resolveModuleUrl = require("./resolveModuleUrl");
175
178
  serializeCtxDateValue,
176
179
  setAutoFlowError,
177
180
  setupRuntimeContextSteps,
181
+ shouldHideEventInSettings,
178
182
  shouldHideStepInSettings,
179
183
  tExpr
180
184
  });
@@ -92,7 +92,7 @@ const parsePathnameToViewParams = /* @__PURE__ */ __name((pathname) => {
92
92
  } catch (_) {
93
93
  parsed = decoded;
94
94
  }
95
- } else if (decoded && decoded.includes("=") && decoded.includes("&")) {
95
+ } else if (decoded && /^[^=&]+=[^=&]*(?:&[^=&]+=[^=&]*)*$/.test(decoded)) {
96
96
  parsed = parseKeyValuePairs(decoded);
97
97
  }
98
98
  currentView.filterByTk = parsed;
@@ -527,8 +527,8 @@ function extractUsedCtxLibKeys(code) {
527
527
  }
528
528
  __name(extractUsedCtxLibKeys, "extractUsedCtxLibKeys");
529
529
  function injectEnsureLibsPreamble(code) {
530
- if (!CTX_LIBS_MARKER_RE.test(code)) return code;
531
530
  if (ENSURE_LIBS_MARKER_RE.test(code)) return code;
531
+ if (!CTX_LIBS_MARKER_RE.test(code)) return code;
532
532
  const keys = extractUsedCtxLibKeys(code);
533
533
  if (!keys.length) return code;
534
534
  return `/* __runjs_ensure_libs */
@@ -231,6 +231,34 @@ function normalizeSubPath(raw) {
231
231
  return { subPath: s, wildcard: false };
232
232
  }
233
233
  __name(normalizeSubPath, "normalizeSubPath");
234
+ function extractCtxRootUsage(expr) {
235
+ const raw = String(expr || "").trim();
236
+ if (!raw || raw === "ctx") return null;
237
+ const dotMatch = raw.match(/^ctx\.([a-zA-Z_$][a-zA-Z0-9_$]*)([\s\S]*)$/);
238
+ if (dotMatch) {
239
+ const varName = dotMatch[1] || "";
240
+ const rest = dotMatch[2] || "";
241
+ const normalized = normalizeSubPath(rest);
242
+ return {
243
+ varName,
244
+ subPath: normalized.subPath,
245
+ wildcard: normalized.wildcard
246
+ };
247
+ }
248
+ const bracketMatch = raw.match(/^ctx\s*\[\s*(['"])([a-zA-Z_$][a-zA-Z0-9_$]*)\1\s*\]([\s\S]*)$/);
249
+ if (bracketMatch) {
250
+ const varName = bracketMatch[2] || "";
251
+ const rest = bracketMatch[3] || "";
252
+ const normalized = normalizeSubPath(rest);
253
+ return {
254
+ varName,
255
+ subPath: normalized.subPath,
256
+ wildcard: normalized.wildcard
257
+ };
258
+ }
259
+ return null;
260
+ }
261
+ __name(extractCtxRootUsage, "extractCtxRootUsage");
234
262
  function extractUsedVariablePathsFromRunJS(code) {
235
263
  if (typeof code !== "string" || !code.trim()) return {};
236
264
  const src = stripStringsAndComments(code);
@@ -242,23 +270,25 @@ function extractUsedVariablePathsFromRunJS(code) {
242
270
  set.add(subPath || "");
243
271
  usage.set(varName, set);
244
272
  }, "add");
273
+ const addCtxUsage = /* @__PURE__ */ __name((expr) => {
274
+ const hit = extractCtxRootUsage(expr);
275
+ if (!(hit == null ? void 0 : hit.varName)) return;
276
+ add(hit.varName, hit.wildcard ? "" : hit.subPath);
277
+ }, "addCtxUsage");
245
278
  const dotRe = /ctx\.([a-zA-Z_$][a-zA-Z0-9_$]*(?:(?:\.[a-zA-Z_$][a-zA-Z0-9_$]*)|(?:\[[^\]]+\]))*)(?!\s*\()/g;
246
279
  let match;
247
280
  while (match = dotRe.exec(src)) {
248
- const pathAfterCtx = match[1] || "";
249
- const firstKeyMatch = pathAfterCtx.match(/^([a-zA-Z_$][a-zA-Z0-9_$]*)/);
250
- if (!firstKeyMatch) continue;
251
- const firstKey = firstKeyMatch[1];
252
- const rest = pathAfterCtx.slice(firstKey.length);
253
- const { subPath, wildcard } = normalizeSubPath(rest);
254
- add(firstKey, wildcard ? "" : subPath);
281
+ addCtxUsage(`ctx.${match[1] || ""}`);
255
282
  }
256
283
  const bracketRootRe = /ctx\s*\[\s*(['"])([a-zA-Z_$][a-zA-Z0-9_$]*)\1\s*\]((?:(?:\.[a-zA-Z_$][a-zA-Z0-9_$]*)|(?:\[[^\]]+\]))*)(?!\s*\()/g;
257
284
  while (match = bracketRootRe.exec(srcWithStrings)) {
258
- const varName = match[2] || "";
259
- const rest = match[3] || "";
260
- const { subPath, wildcard } = normalizeSubPath(rest);
261
- add(varName, wildcard ? "" : subPath);
285
+ addCtxUsage(`ctx['${match[2] || ""}']${match[3] || ""}`);
286
+ }
287
+ const getVarRe = /ctx\.getVar\s*\(\s*(['"])((?:\\.|(?!\1)[\s\S])*)\1\s*\)/g;
288
+ while (match = getVarRe.exec(srcWithStrings)) {
289
+ const expr = String(match[2] || "").replace(/\\'/g, "'").replace(/\\"/g, '"').trim();
290
+ if (!expr.startsWith("ctx")) continue;
291
+ addCtxUsage(expr);
262
292
  }
263
293
  const out = {};
264
294
  for (const [k, set] of usage.entries()) {
@@ -9,7 +9,7 @@
9
9
  import type { ISchema } from '@formily/json-schema';
10
10
  import type { FlowModel } from '../models';
11
11
  import { FlowRuntimeContext } from '../flowContext';
12
- import type { StepDefinition, StepUIMode } from '../types';
12
+ import type { EventDefinition, StepDefinition, StepUIMode } from '../types';
13
13
  /**
14
14
  * 解析 uiMode,支持静态值和函数形式
15
15
  * 函数可以接收 FlowRuntimeContext
@@ -38,6 +38,12 @@ export declare function compileUiSchema(scope: Record<string, any>, uiSchema: an
38
38
  * @returns 合并后的uiSchema对象,如果为空则返回null
39
39
  */
40
40
  export declare function resolveStepUiSchema<TModel extends FlowModel = FlowModel>(model: TModel, flow: any, step: StepDefinition): Promise<Record<string, ISchema> | null>;
41
+ /**
42
+ * 判断事件在设置菜单中是否应被隐藏。
43
+ * - 支持 EventDefinition.hideInSettings。
44
+ * - hideInSettings 可为布尔值或函数(接收 FlowRuntimeContext)。
45
+ */
46
+ export declare function shouldHideEventInSettings<TModel extends FlowModel = FlowModel>(model: TModel, flow: any, event: EventDefinition<TModel> | undefined): Promise<boolean>;
41
47
  /**
42
48
  * 判断步骤在设置菜单中是否应被隐藏。
43
49
  * - 支持 StepDefinition.hideInSettings 与 ActionDefinition.hideInSettings(step 优先)。
@@ -31,6 +31,7 @@ __export(schema_utils_exports, {
31
31
  resolveStepDisabledInSettings: () => resolveStepDisabledInSettings,
32
32
  resolveStepUiSchema: () => resolveStepUiSchema,
33
33
  resolveUiMode: () => resolveUiMode,
34
+ shouldHideEventInSettings: () => shouldHideEventInSettings,
34
35
  shouldHideStepInSettings: () => shouldHideStepInSettings
35
36
  });
36
37
  module.exports = __toCommonJS(schema_utils_exports);
@@ -195,6 +196,23 @@ async function resolveStepUiSchema(model, flow, step) {
195
196
  return resolvedStepUiSchema;
196
197
  }
197
198
  __name(resolveStepUiSchema, "resolveStepUiSchema");
199
+ async function shouldHideEventInSettings(model, flow, event) {
200
+ if (!event) return true;
201
+ const { hideInSettings } = event;
202
+ if (typeof hideInSettings === "function") {
203
+ try {
204
+ const ctx = new import_flowContext.FlowRuntimeContext(model, flow.key, "settings");
205
+ (0, import_setupRuntimeContextSteps.setupRuntimeContextSteps)(ctx, flow.steps || {}, model, flow.key);
206
+ const result = await hideInSettings(ctx);
207
+ return !!result;
208
+ } catch (error) {
209
+ console.warn(`Error evaluating hideInSettings for event '${event.name || ""}' in flow '${flow.key}':`, error);
210
+ return false;
211
+ }
212
+ }
213
+ return !!hideInSettings;
214
+ }
215
+ __name(shouldHideEventInSettings, "shouldHideEventInSettings");
198
216
  async function shouldHideStepInSettings(model, flow, step) {
199
217
  var _a;
200
218
  if (!step) return true;
@@ -283,5 +301,6 @@ __name(resolveStepDisabledInSettings, "resolveStepDisabledInSettings");
283
301
  resolveStepDisabledInSettings,
284
302
  resolveStepUiSchema,
285
303
  resolveUiMode,
304
+ shouldHideEventInSettings,
286
305
  shouldHideStepInSettings
287
306
  });
@@ -10,6 +10,11 @@
10
10
  import { PopoverProps as AntdPopoverProps } from 'antd';
11
11
  import { FlowContext } from '../flowContext';
12
12
  import { ViewNavigation } from './ViewNavigation';
13
+ export type FlowViewBeforeClosePayload = {
14
+ result?: any;
15
+ force?: boolean;
16
+ };
17
+ export type FlowViewBeforeCloseHandler = (payload: FlowViewBeforeClosePayload) => Promise<boolean | void> | boolean | void;
13
18
  export type FlowView = {
14
19
  type: 'drawer' | 'popover' | 'dialog' | 'embed';
15
20
  inputArgs: any;
@@ -20,8 +25,9 @@ export type FlowView = {
20
25
  Footer: React.FC<{
21
26
  children?: React.ReactNode;
22
27
  }> | null;
23
- close: (result?: any, force?: boolean) => void;
28
+ close: (result?: any, force?: boolean) => Promise<boolean | void> | boolean | void;
24
29
  update: (newConfig: any) => void;
30
+ beforeClose?: FlowViewBeforeCloseHandler;
25
31
  navigation?: ViewNavigation;
26
32
  /** 页面的销毁方法 */
27
33
  destroy?: () => void;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ import type { FlowView, FlowViewBeforeClosePayload } from './FlowView';
10
+ export declare function runViewBeforeClose(view: FlowView, payload: FlowViewBeforeClosePayload): Promise<boolean>;
@@ -0,0 +1,45 @@
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
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
15
+ var __export = (target, all) => {
16
+ for (var name in all)
17
+ __defProp(target, name, { get: all[name], enumerable: true });
18
+ };
19
+ var __copyProps = (to, from, except, desc) => {
20
+ if (from && typeof from === "object" || typeof from === "function") {
21
+ for (let key of __getOwnPropNames(from))
22
+ if (!__hasOwnProp.call(to, key) && key !== except)
23
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
24
+ }
25
+ return to;
26
+ };
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var runViewBeforeClose_exports = {};
29
+ __export(runViewBeforeClose_exports, {
30
+ runViewBeforeClose: () => runViewBeforeClose
31
+ });
32
+ module.exports = __toCommonJS(runViewBeforeClose_exports);
33
+ async function runViewBeforeClose(view, payload) {
34
+ var _a;
35
+ if (payload.force) {
36
+ return true;
37
+ }
38
+ const result = await ((_a = view.beforeClose) == null ? void 0 : _a.call(view, payload));
39
+ return result !== false;
40
+ }
41
+ __name(runViewBeforeClose, "runViewBeforeClose");
42
+ // Annotate the CommonJS export names for ESM import in node:
43
+ 0 && (module.exports = {
44
+ runViewBeforeClose
45
+ });
@@ -12,9 +12,10 @@ export declare function useDialog(): (React.JSX.Element | {
12
12
  type: "dialog";
13
13
  inputArgs: any;
14
14
  preventClose: boolean;
15
+ beforeClose: any;
15
16
  destroy: (result?: any) => void;
16
17
  update: (newConfig: any) => void;
17
- close: (result?: any, force?: boolean) => void;
18
+ close: (result?: any, force?: boolean) => Promise<boolean>;
18
19
  Footer: React.FC<{
19
20
  children?: React.ReactNode;
20
21
  }>;
@@ -52,6 +52,7 @@ var import_viewEvents = require("./viewEvents");
52
52
  var import_provider = require("../provider");
53
53
  var import_ViewScopedFlowEngine = require("../ViewScopedFlowEngine");
54
54
  var import_variablesParams = require("../utils/variablesParams");
55
+ var import_runViewBeforeClose = require("./runViewBeforeClose");
55
56
  let uuid = 0;
56
57
  function useDialog() {
57
58
  const holderRef = React.useRef(null);
@@ -103,12 +104,16 @@ function useDialog() {
103
104
  } else {
104
105
  ctx.addDelegate(flowContext.engine.context);
105
106
  }
107
+ let destroyed = false;
106
108
  const currentDialog = {
107
109
  type: "dialog",
108
110
  inputArgs: config.inputArgs || {},
109
111
  preventClose: !!config.preventClose,
112
+ beforeClose: void 0,
110
113
  destroy: /* @__PURE__ */ __name((result) => {
111
114
  var _a2, _b2, _c2, _d;
115
+ if (destroyed) return;
116
+ destroyed = true;
112
117
  (_a2 = config.onClose) == null ? void 0 : _a2.call(config);
113
118
  (_b2 = dialogRef.current) == null ? void 0 : _b2.destroy();
114
119
  closeFunc == null ? void 0 : closeFunc();
@@ -122,16 +127,21 @@ function useDialog() {
122
127
  var _a2;
123
128
  return (_a2 = dialogRef.current) == null ? void 0 : _a2.update(newConfig);
124
129
  }, "update"),
125
- close: /* @__PURE__ */ __name((result, force) => {
130
+ close: /* @__PURE__ */ __name(async (result, force) => {
126
131
  var _a2, _b2;
127
132
  if (config.preventClose && !force) {
128
- return;
133
+ return false;
134
+ }
135
+ const shouldClose = await (0, import_runViewBeforeClose.runViewBeforeClose)(currentDialog, { result, force });
136
+ if (!shouldClose) {
137
+ return false;
129
138
  }
130
139
  if (config.triggerByRouter && ((_b2 = (_a2 = config.inputArgs) == null ? void 0 : _a2.navigation) == null ? void 0 : _b2.back)) {
131
140
  config.inputArgs.navigation.back();
132
- return;
141
+ return true;
133
142
  }
134
143
  currentDialog.destroy(result);
144
+ return true;
135
145
  }, "close"),
136
146
  Footer: FooterComponent,
137
147
  Header: HeaderComponent,
@@ -154,6 +164,13 @@ function useDialog() {
154
164
  get: /* @__PURE__ */ __name(() => currentDialog, "get"),
155
165
  resolveOnServer: (0, import_variablesParams.createViewRecordResolveOnServer)(ctx, () => (0, import_variablesParams.getViewRecordFromParent)(flowContext, ctx))
156
166
  });
167
+ scopedEngine.setDestroyView(() => {
168
+ var _a2, _b2;
169
+ if (config.triggerByRouter && ((_b2 = (_a2 = config.inputArgs) == null ? void 0 : _a2.navigation) == null ? void 0 : _b2.back)) {
170
+ config.inputArgs.navigation.back();
171
+ }
172
+ currentDialog.destroy();
173
+ });
157
174
  (0, import_createViewMeta.registerPopupVariable)(ctx, currentDialog);
158
175
  const DialogWithContext = (0, import__.observer)(
159
176
  () => {
@@ -13,9 +13,10 @@ export declare function useDrawer(): (React.JSX.Element | {
13
13
  type: "drawer";
14
14
  inputArgs: any;
15
15
  preventClose: boolean;
16
+ beforeClose: any;
16
17
  destroy: (result?: any) => void;
17
18
  update: (newConfig: any) => void;
18
- close: (result?: any, force?: boolean) => void;
19
+ close: (result?: any, force?: boolean) => Promise<boolean>;
19
20
  Footer: React.FC<{
20
21
  children?: React.ReactNode;
21
22
  }>;