@nocobase/flow-engine 2.1.0-beta.9 → 2.2.0-beta.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.
Files changed (215) hide show
  1. package/lib/FlowContextProvider.d.ts +5 -1
  2. package/lib/FlowContextProvider.js +9 -2
  3. package/lib/components/FieldModelRenderer.js +2 -2
  4. package/lib/components/FlowModelRenderer.d.ts +3 -1
  5. package/lib/components/FlowModelRenderer.js +12 -6
  6. package/lib/components/FormItem.d.ts +6 -0
  7. package/lib/components/FormItem.js +11 -3
  8. package/lib/components/MobilePopup.js +6 -5
  9. package/lib/components/dnd/gridDragPlanner.d.ts +59 -2
  10. package/lib/components/dnd/gridDragPlanner.js +607 -19
  11. package/lib/components/dnd/index.d.ts +31 -2
  12. package/lib/components/dnd/index.js +244 -23
  13. package/lib/components/settings/wrappers/component/SelectWithTitle.d.ts +2 -1
  14. package/lib/components/settings/wrappers/component/SelectWithTitle.js +14 -12
  15. package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.d.ts +3 -0
  16. package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +152 -42
  17. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.d.ts +23 -43
  18. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +352 -295
  19. package/lib/components/settings/wrappers/contextual/useFloatToolbarPortal.d.ts +36 -0
  20. package/lib/components/settings/wrappers/contextual/useFloatToolbarPortal.js +274 -0
  21. package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.d.ts +30 -0
  22. package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.js +315 -0
  23. package/lib/components/subModel/AddSubModelButton.js +12 -1
  24. package/lib/components/subModel/LazyDropdown.js +301 -52
  25. package/lib/components/subModel/index.d.ts +1 -0
  26. package/lib/components/subModel/index.js +19 -0
  27. package/lib/components/subModel/utils.d.ts +2 -1
  28. package/lib/components/subModel/utils.js +15 -5
  29. package/lib/components/variables/VariableHybridInput.d.ts +27 -0
  30. package/lib/components/variables/VariableHybridInput.js +499 -0
  31. package/lib/components/variables/index.d.ts +2 -0
  32. package/lib/components/variables/index.js +3 -0
  33. package/lib/data-source/index.d.ts +84 -0
  34. package/lib/data-source/index.js +269 -7
  35. package/lib/executor/FlowExecutor.js +6 -3
  36. package/lib/flow-registry/DetachedFlowRegistry.d.ts +21 -0
  37. package/lib/flow-registry/DetachedFlowRegistry.js +80 -0
  38. package/lib/flow-registry/index.d.ts +1 -0
  39. package/lib/flow-registry/index.js +3 -1
  40. package/lib/flowContext.d.ts +9 -1
  41. package/lib/flowContext.js +77 -6
  42. package/lib/flowEngine.d.ts +136 -4
  43. package/lib/flowEngine.js +429 -51
  44. package/lib/flowI18n.js +2 -1
  45. package/lib/flowSettings.d.ts +14 -6
  46. package/lib/flowSettings.js +34 -6
  47. package/lib/index.d.ts +2 -0
  48. package/lib/index.js +7 -0
  49. package/lib/lazy-helper.d.ts +14 -0
  50. package/lib/lazy-helper.js +71 -0
  51. package/lib/locale/en-US.json +1 -0
  52. package/lib/locale/index.d.ts +2 -0
  53. package/lib/locale/zh-CN.json +1 -0
  54. package/lib/models/DisplayItemModel.d.ts +1 -1
  55. package/lib/models/EditableItemModel.d.ts +1 -1
  56. package/lib/models/FilterableItemModel.d.ts +1 -1
  57. package/lib/models/flowModel.d.ts +13 -10
  58. package/lib/models/flowModel.js +126 -34
  59. package/lib/provider.js +38 -23
  60. package/lib/reactive/observer.js +46 -16
  61. package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.js +4 -3
  62. package/lib/runjs-context/contexts/JSBlockRunJSContext.js +4 -15
  63. package/lib/runjs-context/contexts/JSColumnRunJSContext.js +5 -2
  64. package/lib/runjs-context/contexts/JSEditableFieldRunJSContext.js +5 -8
  65. package/lib/runjs-context/contexts/JSFieldRunJSContext.js +4 -3
  66. package/lib/runjs-context/contexts/JSItemRunJSContext.js +4 -3
  67. package/lib/runjs-context/contexts/base.js +464 -29
  68. package/lib/runjs-context/contexts/elementDoc.d.ts +11 -0
  69. package/lib/runjs-context/contexts/elementDoc.js +152 -0
  70. package/lib/runjs-context/setup.js +1 -0
  71. package/lib/runjs-context/snippets/index.js +13 -2
  72. package/lib/runjs-context/snippets/scene/detail/set-field-style.snippet.d.ts +11 -0
  73. package/lib/runjs-context/snippets/scene/detail/set-field-style.snippet.js +50 -0
  74. package/lib/runjs-context/snippets/scene/table/set-cell-style.snippet.d.ts +11 -0
  75. package/lib/runjs-context/snippets/scene/table/set-cell-style.snippet.js +54 -0
  76. package/lib/types.d.ts +50 -2
  77. package/lib/types.js +1 -0
  78. package/lib/utils/createCollectionContextMeta.js +6 -2
  79. package/lib/utils/index.d.ts +3 -2
  80. package/lib/utils/index.js +7 -0
  81. package/lib/utils/loadedPageCache.d.ts +24 -0
  82. package/lib/utils/loadedPageCache.js +139 -0
  83. package/lib/utils/parsePathnameToViewParams.d.ts +5 -1
  84. package/lib/utils/parsePathnameToViewParams.js +28 -4
  85. package/lib/utils/randomId.d.ts +39 -0
  86. package/lib/utils/randomId.js +45 -0
  87. package/lib/utils/runjsTemplateCompat.js +1 -1
  88. package/lib/utils/runjsValue.js +41 -11
  89. package/lib/utils/schema-utils.d.ts +7 -1
  90. package/lib/utils/schema-utils.js +19 -0
  91. package/lib/views/FlowView.d.ts +7 -1
  92. package/lib/views/FlowView.js +11 -1
  93. package/lib/views/PageComponent.js +8 -6
  94. package/lib/views/ViewNavigation.d.ts +12 -2
  95. package/lib/views/ViewNavigation.js +28 -9
  96. package/lib/views/createViewMeta.js +114 -50
  97. package/lib/views/inheritLayoutContext.d.ts +10 -0
  98. package/lib/views/inheritLayoutContext.js +50 -0
  99. package/lib/views/runViewBeforeClose.d.ts +10 -0
  100. package/lib/views/runViewBeforeClose.js +45 -0
  101. package/lib/views/useDialog.d.ts +2 -1
  102. package/lib/views/useDialog.js +12 -3
  103. package/lib/views/useDrawer.d.ts +2 -1
  104. package/lib/views/useDrawer.js +12 -3
  105. package/lib/views/usePage.d.ts +5 -11
  106. package/lib/views/usePage.js +304 -144
  107. package/package.json +5 -4
  108. package/src/FlowContextProvider.tsx +9 -1
  109. package/src/__tests__/createViewMeta.popup.test.ts +115 -1
  110. package/src/__tests__/flow-engine.test.ts +166 -0
  111. package/src/__tests__/flowContext.test.ts +105 -1
  112. package/src/__tests__/flowEngine.modelLoaders.test.ts +245 -0
  113. package/src/__tests__/flowEngine.moveModel.test.ts +81 -1
  114. package/src/__tests__/flowEngine.removeModel.test.ts +47 -3
  115. package/src/__tests__/flowSettings.test.ts +94 -15
  116. package/src/__tests__/objectVariable.test.ts +24 -0
  117. package/src/__tests__/provider.test.tsx +24 -2
  118. package/src/__tests__/renderHiddenInConfig.test.tsx +6 -6
  119. package/src/__tests__/runjsContext.test.ts +21 -0
  120. package/src/__tests__/runjsContextImplementations.test.ts +9 -2
  121. package/src/__tests__/runjsContextRuntime.test.ts +2 -0
  122. package/src/__tests__/runjsLocales.test.ts +6 -5
  123. package/src/__tests__/runjsSnippets.test.ts +21 -0
  124. package/src/__tests__/viewScopedFlowEngine.test.ts +136 -3
  125. package/src/components/FieldModelRenderer.tsx +2 -1
  126. package/src/components/FlowModelRenderer.tsx +18 -6
  127. package/src/components/FormItem.tsx +7 -1
  128. package/src/components/MobilePopup.tsx +4 -2
  129. package/src/components/__tests__/FlowModelRenderer.test.tsx +65 -2
  130. package/src/components/__tests__/FormItem.test.tsx +25 -0
  131. package/src/components/__tests__/dnd.test.ts +44 -0
  132. package/src/components/__tests__/flow-model-render-error-fallback.test.tsx +20 -10
  133. package/src/components/__tests__/gridDragPlanner.test.ts +472 -5
  134. package/src/components/dnd/__tests__/DndProvider.test.tsx +98 -0
  135. package/src/components/dnd/gridDragPlanner.ts +750 -17
  136. package/src/components/dnd/index.tsx +305 -28
  137. package/src/components/settings/wrappers/component/SelectWithTitle.tsx +21 -9
  138. package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +178 -48
  139. package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +487 -440
  140. package/src/components/settings/wrappers/contextual/__tests__/DefaultSettingsIcon.test.tsx +344 -8
  141. package/src/components/settings/wrappers/contextual/__tests__/FlowsFloatContextMenu.test.tsx +778 -0
  142. package/src/components/settings/wrappers/contextual/useFloatToolbarPortal.ts +360 -0
  143. package/src/components/settings/wrappers/contextual/useFloatToolbarVisibility.ts +361 -0
  144. package/src/components/subModel/AddSubModelButton.tsx +16 -2
  145. package/src/components/subModel/LazyDropdown.tsx +341 -56
  146. package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +524 -38
  147. package/src/components/subModel/__tests__/utils.test.ts +24 -0
  148. package/src/components/subModel/index.ts +1 -0
  149. package/src/components/subModel/utils.ts +13 -2
  150. package/src/components/variables/VariableHybridInput.tsx +531 -0
  151. package/src/components/variables/index.ts +2 -0
  152. package/src/data-source/__tests__/collection.test.ts +41 -2
  153. package/src/data-source/__tests__/index.test.ts +69 -2
  154. package/src/data-source/index.ts +332 -8
  155. package/src/executor/FlowExecutor.ts +6 -3
  156. package/src/executor/__tests__/flowExecutor.test.ts +57 -0
  157. package/src/flow-registry/DetachedFlowRegistry.ts +46 -0
  158. package/src/flow-registry/__tests__/detachedFlowRegistry.test.ts +47 -0
  159. package/src/flow-registry/index.ts +1 -0
  160. package/src/flowContext.ts +85 -6
  161. package/src/flowEngine.ts +484 -45
  162. package/src/flowI18n.ts +2 -1
  163. package/src/flowSettings.ts +40 -6
  164. package/src/index.ts +2 -0
  165. package/src/lazy-helper.tsx +57 -0
  166. package/src/locale/en-US.json +1 -0
  167. package/src/locale/zh-CN.json +1 -0
  168. package/src/models/DisplayItemModel.tsx +1 -1
  169. package/src/models/EditableItemModel.tsx +1 -1
  170. package/src/models/FilterableItemModel.tsx +1 -1
  171. package/src/models/__tests__/flowEngine.resolveUse.test.ts +0 -15
  172. package/src/models/__tests__/flowModel.test.ts +65 -37
  173. package/src/models/flowModel.tsx +184 -65
  174. package/src/provider.tsx +41 -25
  175. package/src/reactive/__tests__/observer.test.tsx +82 -0
  176. package/src/reactive/observer.tsx +87 -25
  177. package/src/runjs-context/contexts/FormJSFieldItemRunJSContext.ts +4 -3
  178. package/src/runjs-context/contexts/JSBlockRunJSContext.ts +4 -15
  179. package/src/runjs-context/contexts/JSColumnRunJSContext.ts +4 -2
  180. package/src/runjs-context/contexts/JSEditableFieldRunJSContext.ts +5 -9
  181. package/src/runjs-context/contexts/JSFieldRunJSContext.ts +4 -3
  182. package/src/runjs-context/contexts/JSItemRunJSContext.ts +4 -3
  183. package/src/runjs-context/contexts/base.ts +467 -31
  184. package/src/runjs-context/contexts/elementDoc.ts +130 -0
  185. package/src/runjs-context/setup.ts +1 -0
  186. package/src/runjs-context/snippets/index.ts +12 -1
  187. package/src/runjs-context/snippets/scene/detail/set-field-style.snippet.ts +30 -0
  188. package/src/runjs-context/snippets/scene/table/set-cell-style.snippet.ts +34 -0
  189. package/src/types.ts +62 -0
  190. package/src/utils/__tests__/createCollectionContextMeta.test.ts +48 -0
  191. package/src/utils/__tests__/parsePathnameToViewParams.test.ts +21 -0
  192. package/src/utils/__tests__/runjsValue.test.ts +11 -0
  193. package/src/utils/__tests__/utils.test.ts +62 -0
  194. package/src/utils/createCollectionContextMeta.ts +6 -2
  195. package/src/utils/index.ts +5 -1
  196. package/src/utils/loadedPageCache.ts +147 -0
  197. package/src/utils/parsePathnameToViewParams.ts +45 -5
  198. package/src/utils/randomId.ts +48 -0
  199. package/src/utils/runjsTemplateCompat.ts +1 -1
  200. package/src/utils/runjsValue.ts +50 -11
  201. package/src/utils/schema-utils.ts +30 -1
  202. package/src/views/FlowView.tsx +22 -2
  203. package/src/views/PageComponent.tsx +7 -4
  204. package/src/views/ViewNavigation.ts +46 -9
  205. package/src/views/__tests__/FlowView.usePage.test.tsx +243 -3
  206. package/src/views/__tests__/ViewNavigation.test.ts +52 -0
  207. package/src/views/__tests__/inheritLayoutContext.test.ts +53 -0
  208. package/src/views/__tests__/runViewBeforeClose.test.ts +30 -0
  209. package/src/views/__tests__/useDialog.closeDestroy.test.tsx +12 -12
  210. package/src/views/createViewMeta.ts +106 -34
  211. package/src/views/inheritLayoutContext.ts +26 -0
  212. package/src/views/runViewBeforeClose.ts +19 -0
  213. package/src/views/useDialog.tsx +13 -3
  214. package/src/views/useDrawer.tsx +13 -3
  215. package/src/views/usePage.tsx +367 -180
@@ -0,0 +1,139 @@
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 loadedPageCache_exports = {};
29
+ __export(loadedPageCache_exports, {
30
+ createLoadedPageCache: () => createLoadedPageCache
31
+ });
32
+ module.exports = __toCommonJS(loadedPageCache_exports);
33
+ const getLoadedPageKey = /* @__PURE__ */ __name((options) => {
34
+ const parentId = options == null ? void 0 : options.parentId;
35
+ const subKey = options == null ? void 0 : options.subKey;
36
+ if (!parentId || subKey !== "page") {
37
+ return void 0;
38
+ }
39
+ return `${parentId}::${subKey}`;
40
+ }, "getLoadedPageKey");
41
+ const getLoadedPageKeyFromModel = /* @__PURE__ */ __name((model) => {
42
+ var _a;
43
+ let current = model;
44
+ while (current) {
45
+ if (current.subKey === "page" && ((_a = current.parent) == null ? void 0 : _a.uid)) {
46
+ return getLoadedPageKey({ parentId: current.parent.uid, subKey: current.subKey });
47
+ }
48
+ current = current.parent;
49
+ }
50
+ return void 0;
51
+ }, "getLoadedPageKeyFromModel");
52
+ const isFlowSettingsEnabledForContext = /* @__PURE__ */ __name((context) => {
53
+ try {
54
+ return !!(context == null ? void 0 : context.flowSettingsEnabled);
55
+ } catch (error) {
56
+ return false;
57
+ }
58
+ }, "isFlowSettingsEnabledForContext");
59
+ const isFlowSettingsEnabledForModel = /* @__PURE__ */ __name((model) => {
60
+ if (isFlowSettingsEnabledForContext(model == null ? void 0 : model.context)) {
61
+ return true;
62
+ }
63
+ const visited = /* @__PURE__ */ new Set();
64
+ let engine = model == null ? void 0 : model.flowEngine;
65
+ while (engine && !visited.has(engine)) {
66
+ visited.add(engine);
67
+ if (isFlowSettingsEnabledForContext(engine.context)) {
68
+ return true;
69
+ }
70
+ engine = engine.previousEngine;
71
+ }
72
+ return false;
73
+ }, "isFlowSettingsEnabledForModel");
74
+ const removeLoadedModelTree = /* @__PURE__ */ __name((model) => {
75
+ if (!(model == null ? void 0 : model.uid) || !model.flowEngine) {
76
+ return;
77
+ }
78
+ if (model.flowEngine.getModel(model.uid) === model) {
79
+ model.flowEngine.removeModelWithSubModels(model.uid);
80
+ }
81
+ }, "removeLoadedModelTree");
82
+ const mountLoadedModelToParent = /* @__PURE__ */ __name((model, forceReplace = false) => {
83
+ var _a;
84
+ if (!(model == null ? void 0 : model.parent) || !model.subKey) {
85
+ return model;
86
+ }
87
+ const mounted = (_a = model.parent.subModels) == null ? void 0 : _a[model.subKey];
88
+ const existing = forceReplace && model.subType !== "array" && mounted && !Array.isArray(mounted) ? mounted : model.parent.findSubModel(model.subKey, (m) => m.uid === model.uid);
89
+ if (existing) {
90
+ if (!forceReplace || existing === model) {
91
+ return model;
92
+ }
93
+ removeLoadedModelTree(existing);
94
+ }
95
+ if (model.subType === "array") {
96
+ model.parent.addSubModel(model.subKey, model);
97
+ } else {
98
+ model.parent.setSubModel(model.subKey, model);
99
+ }
100
+ return model;
101
+ }, "mountLoadedModelToParent");
102
+ const createLoadedPageCache = /* @__PURE__ */ __name(() => {
103
+ const dirtyKeys = /* @__PURE__ */ new Set();
104
+ return {
105
+ getDirtyKeyForModel(model, options) {
106
+ if (!(options == null ? void 0 : options.force) && !isFlowSettingsEnabledForModel(model)) {
107
+ return void 0;
108
+ }
109
+ return getLoadedPageKeyFromModel(model);
110
+ },
111
+ markDirty(key) {
112
+ if (key) {
113
+ dirtyKeys.add(key);
114
+ }
115
+ },
116
+ shouldBypass(options, isFlowSettingsEnabled) {
117
+ const key = getLoadedPageKey(options);
118
+ if (!key || !dirtyKeys.has(key)) {
119
+ return false;
120
+ }
121
+ try {
122
+ return !(isFlowSettingsEnabled == null ? void 0 : isFlowSettingsEnabled());
123
+ } catch (error) {
124
+ return true;
125
+ }
126
+ },
127
+ clear(options) {
128
+ const key = getLoadedPageKey(options);
129
+ if (key) {
130
+ dirtyKeys.delete(key);
131
+ }
132
+ },
133
+ mountModelToParent: mountLoadedModelToParent
134
+ };
135
+ }, "createLoadedPageCache");
136
+ // Annotate the CommonJS export names for ESM import in node:
137
+ 0 && (module.exports = {
138
+ createLoadedPageCache
139
+ });
@@ -16,6 +16,10 @@ export interface ViewParam {
16
16
  /** source Id */
17
17
  sourceId?: string;
18
18
  }
19
+ export interface ParsePathnameToViewParamsOptions {
20
+ rootPrefix?: string;
21
+ basePath?: string;
22
+ }
19
23
  /**
20
24
  * 解析路径名为视图参数数组
21
25
  *
@@ -31,4 +35,4 @@ export interface ViewParam {
31
35
  * parsePathnameToViewParams('/admin/xxx/view/yyy') // [{ viewUid: 'xxx' }, { viewUid: 'yyy' }]
32
36
  * ```
33
37
  */
34
- export declare const parsePathnameToViewParams: (pathname: string) => ViewParam[];
38
+ export declare const parsePathnameToViewParams: (pathname: string, options?: ParsePathnameToViewParamsOptions) => ViewParam[];
@@ -30,20 +30,44 @@ __export(parsePathnameToViewParams_exports, {
30
30
  parsePathnameToViewParams: () => parsePathnameToViewParams
31
31
  });
32
32
  module.exports = __toCommonJS(parsePathnameToViewParams_exports);
33
- const parsePathnameToViewParams = /* @__PURE__ */ __name((pathname) => {
33
+ const normalizePathname = /* @__PURE__ */ __name((pathname) => {
34
+ if (!pathname || pathname === "/") {
35
+ return "/";
36
+ }
37
+ return `/${pathname.replace(/^\/+/, "").replace(/\/+$/, "")}`;
38
+ }, "normalizePathname");
39
+ const normalizeBasePath = /* @__PURE__ */ __name((basePath) => `/${basePath.replace(/^\/+/, "").replace(/\/+$/, "")}`, "normalizeBasePath");
40
+ const stripBasePath = /* @__PURE__ */ __name((pathname, basePath) => {
41
+ const normalizedPathname = normalizePathname(pathname);
42
+ const normalizedBasePath = normalizeBasePath(basePath);
43
+ if (normalizedPathname === normalizedBasePath) {
44
+ return "";
45
+ }
46
+ if (normalizedPathname.startsWith(`${normalizedBasePath}/`)) {
47
+ return normalizedPathname.slice(normalizedBasePath.length + 1);
48
+ }
49
+ return "";
50
+ }, "stripBasePath");
51
+ const parsePathnameToViewParams = /* @__PURE__ */ __name((pathname, options = {}) => {
34
52
  if (!pathname || pathname === "/") {
35
53
  return [];
36
54
  }
37
- const segments = pathname.replace(/^\/+/, "").split("/").filter(Boolean);
38
- if (segments.length < 2) {
55
+ const rootPrefix = options.rootPrefix || "admin";
56
+ const relativePath = options.basePath ? stripBasePath(pathname, options.basePath) : "";
57
+ const segments = (options.basePath ? relativePath : pathname).replace(/^\/+/, "").split("/").filter(Boolean);
58
+ if (segments.length < (options.basePath ? 1 : 2)) {
39
59
  return [];
40
60
  }
41
61
  const result = [];
42
62
  let currentView = null;
43
63
  let i = 0;
64
+ if (options.basePath) {
65
+ currentView = { viewUid: segments[0] };
66
+ i = 1;
67
+ }
44
68
  while (i < segments.length) {
45
69
  const segment = segments[i];
46
- if (segment === "admin" || segment === "view") {
70
+ if (segment === rootPrefix || segment === "view") {
47
71
  if (currentView) {
48
72
  result.push(currentView);
49
73
  }
@@ -0,0 +1,39 @@
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
+ * Generate a random base36 identifier with an optional semantic prefix.
11
+ *
12
+ * Equivalent in shape to v1's `uid()` from `@formily/shared` (11 chars
13
+ * of `[0-9a-z]`), with an opt-in prefix appended at the front. v2 forbids
14
+ * direct `@formily/*` imports in `src/client-v2/`, so this helper is the
15
+ * single substitute the rest of the codebase should reach for.
16
+ *
17
+ * Common semantic prefixes observed across the codebase — pass the one
18
+ * that matches your domain rather than relying on a default, so the
19
+ * intent is explicit at the call site:
20
+ *
21
+ * - `s_` — service / settings record (authenticators, channels, …)
22
+ * - `v_` — verifier / variable / LLM service
23
+ * - `f_` — field
24
+ * - `t_` — through table
25
+ *
26
+ * Example:
27
+ *
28
+ * ```ts
29
+ * import { randomId } from '@nocobase/flow-engine';
30
+ *
31
+ * name: randomId('s_'), // → 's_keeoaui1ubi'
32
+ * name: randomId('v_'), // → 'v_a8f3kp2x9qm'
33
+ * name: randomId(), // → 'a8f3kp2x9qm'
34
+ * ```
35
+ *
36
+ * Not cryptographically secure — uses `Math.random()`. Good enough for
37
+ * unique form names / schema keys, NOT for security tokens.
38
+ */
39
+ export declare function randomId(prefix?: string, length?: number): string;
@@ -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 randomId_exports = {};
29
+ __export(randomId_exports, {
30
+ randomId: () => randomId
31
+ });
32
+ module.exports = __toCommonJS(randomId_exports);
33
+ const CHARSET = "0123456789abcdefghijklmnopqrstuvwxyz";
34
+ function randomId(prefix = "", length = 11) {
35
+ let id = "";
36
+ for (let i = 0; i < length; i++) {
37
+ id += CHARSET[Math.random() * CHARSET.length | 0];
38
+ }
39
+ return `${prefix}${id}`;
40
+ }
41
+ __name(randomId, "randomId");
42
+ // Annotate the CommonJS export names for ESM import in node:
43
+ 0 && (module.exports = {
44
+ randomId
45
+ });
@@ -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;
@@ -47,11 +47,21 @@ const _FlowViewer = class _FlowViewer {
47
47
  if (this.types[type]) {
48
48
  zIndex += 1;
49
49
  const onClose = others.onClose;
50
+ let zIndexReleased = false;
51
+ const releaseZIndex = /* @__PURE__ */ __name(() => {
52
+ if (!zIndexReleased) {
53
+ zIndexReleased = true;
54
+ zIndex -= 1;
55
+ }
56
+ }, "releaseZIndex");
50
57
  const _zIndex = others.zIndex;
51
58
  others.onClose = (...args) => {
52
59
  onClose == null ? void 0 : onClose(...args);
53
- zIndex -= 1;
60
+ releaseZIndex();
54
61
  };
62
+ if (type === "embed") {
63
+ others.onOpenCancelled = releaseZIndex;
64
+ }
55
65
  if (type !== "embed") {
56
66
  others.zIndex = _zIndex ?? this.getNextZIndex();
57
67
  }
@@ -55,8 +55,9 @@ const PageComponent = (0, import_react.forwardRef)((props, ref) => {
55
55
  hidden,
56
56
  title: _title,
57
57
  styles = {},
58
- zIndex = 4
58
+ zIndex = 4,
59
59
  // 这个默认值是为了防止表格的阴影显示到子页面上面
60
+ onClose
60
61
  } = mergedProps;
61
62
  const closedRef = (0, import_react.useRef)(false);
62
63
  const flowEngine = (0, import_provider.useFlowEngine)();
@@ -114,11 +115,12 @@ const PageComponent = (0, import_react.forwardRef)((props, ref) => {
114
115
  type: "text",
115
116
  size: "small",
116
117
  icon: /* @__PURE__ */ import_react.default.createElement(import_icons.CloseOutlined, null),
117
- onClick: () => {
118
- var _a;
118
+ onClick: async () => {
119
119
  if (!closedRef.current) {
120
- closedRef.current = true;
121
- (_a = props.onClose) == null ? void 0 : _a.call(props);
120
+ const closed = await (onClose == null ? void 0 : onClose());
121
+ if (closed !== false) {
122
+ closedRef.current = true;
123
+ }
122
124
  }
123
125
  },
124
126
  style: {
@@ -138,7 +140,7 @@ const PageComponent = (0, import_react.forwardRef)((props, ref) => {
138
140
  )),
139
141
  extra && /* @__PURE__ */ import_react.default.createElement("div", null, extra)
140
142
  );
141
- }, [header, _title, flowEngine.context.themeToken, styles.header, props.onClose]);
143
+ }, [header, _title, flowEngine.context.themeToken, styles.header, onClose]);
142
144
  const FooterComponent = (0, import_react.useMemo)(() => {
143
145
  if (!footer) return null;
144
146
  const token = flowEngine.context.themeToken;
@@ -11,6 +11,14 @@ import { ViewParam as SharedViewParam } from '../utils';
11
11
  type ViewParams = Omit<SharedViewParam, 'viewUid'> & {
12
12
  viewUid?: string;
13
13
  };
14
+ export interface GeneratePathnameFromViewParamsOptions {
15
+ prefix?: string;
16
+ basePath?: string;
17
+ }
18
+ export interface ViewNavigationOptions {
19
+ basePath?: string;
20
+ layoutBasePath?: string;
21
+ }
14
22
  /**
15
23
  * 将 ViewParam 数组转换为 pathname
16
24
  *
@@ -24,12 +32,13 @@ type ViewParams = Omit<SharedViewParam, 'viewUid'> & {
24
32
  * generatePathnameFromViewParams([{ viewUid: 'xxx' }, { viewUid: 'yyy' }]) // '/admin/xxx/view/yyy'
25
33
  * ```
26
34
  */
27
- export declare function generatePathnameFromViewParams(viewParams: ViewParams[]): string;
35
+ export declare function generatePathnameFromViewParams(viewParams: ViewParams[], options?: GeneratePathnameFromViewParamsOptions): string;
28
36
  export declare class ViewNavigation {
29
37
  viewStack: ReadonlyArray<ViewParams>;
30
38
  ctx: FlowEngineContext;
31
39
  viewParams: ViewParams;
32
- constructor(ctx: FlowEngineContext, viewParams: ViewParams[]);
40
+ private readonly basePath?;
41
+ constructor(ctx: FlowEngineContext, viewParams: ViewParams[], options?: ViewNavigationOptions);
33
42
  setViewStack(viewParams: ViewParams[]): void;
34
43
  changeTo(viewParam: ViewParams): void;
35
44
  navigateTo(viewParam: ViewParams, opts?: {
@@ -37,5 +46,6 @@ export declare class ViewNavigation {
37
46
  state?: any;
38
47
  }): void;
39
48
  back(): void;
49
+ private getLayoutBasePath;
40
50
  }
41
51
  export {};
@@ -43,11 +43,21 @@ function encodeFilterByTk(val) {
43
43
  return encodeURIComponent(String(val));
44
44
  }
45
45
  __name(encodeFilterByTk, "encodeFilterByTk");
46
- function generatePathnameFromViewParams(viewParams) {
46
+ function hasUsableSourceId(sourceId) {
47
+ return sourceId !== void 0 && sourceId !== null && String(sourceId) !== "";
48
+ }
49
+ __name(hasUsableSourceId, "hasUsableSourceId");
50
+ function normalizeBasePath(basePath) {
51
+ const value = basePath || "/admin";
52
+ return `/${value.replace(/^\/+/, "").replace(/\/+$/, "")}`;
53
+ }
54
+ __name(normalizeBasePath, "normalizeBasePath");
55
+ function generatePathnameFromViewParams(viewParams, options = {}) {
56
+ const basePath = normalizeBasePath(options.basePath || options.prefix);
47
57
  if (!viewParams || viewParams.length === 0) {
48
- return "/admin";
58
+ return basePath;
49
59
  }
50
- const segments = ["admin"];
60
+ const segments = basePath.replace(/^\/+/, "").split("/").filter(Boolean);
51
61
  viewParams.forEach((viewParam, index) => {
52
62
  if (index > 0) {
53
63
  segments.push("view");
@@ -62,8 +72,8 @@ function generatePathnameFromViewParams(viewParams) {
62
72
  segments.push("filterbytk", encoded);
63
73
  }
64
74
  }
65
- if (viewParam.sourceId) {
66
- segments.push("sourceid", viewParam.sourceId);
75
+ if (hasUsableSourceId(viewParam.sourceId)) {
76
+ segments.push("sourceid", String(viewParam.sourceId));
67
77
  }
68
78
  });
69
79
  return "/" + segments.join("/");
@@ -74,9 +84,11 @@ const _ViewNavigation = class _ViewNavigation {
74
84
  // 只能通过 setViewStack 修改
75
85
  ctx;
76
86
  viewParams;
77
- constructor(ctx, viewParams) {
87
+ basePath;
88
+ constructor(ctx, viewParams, options = {}) {
78
89
  this.setViewStack(viewParams);
79
90
  this.ctx = ctx;
91
+ this.basePath = options.basePath || options.layoutBasePath;
80
92
  (0, import_reactive.define)(this, {
81
93
  viewParams: import_reactive.observable
82
94
  });
@@ -92,19 +104,26 @@ const _ViewNavigation = class _ViewNavigation {
92
104
  }
93
105
  return { ...item };
94
106
  });
95
- const newPathname = generatePathnameFromViewParams(newViewStack);
107
+ const newPathname = generatePathnameFromViewParams(newViewStack, { basePath: this.getLayoutBasePath() });
96
108
  this.ctx.router.navigate(newPathname, { replace: true });
97
109
  }
98
110
  navigateTo(viewParam, opts) {
99
- const newViewPathname = generatePathnameFromViewParams([...this.viewStack, viewParam]);
111
+ const newViewPathname = generatePathnameFromViewParams([...this.viewStack, viewParam], {
112
+ basePath: this.getLayoutBasePath()
113
+ });
100
114
  const newPathname = newViewPathname;
101
115
  this.ctx.router.navigate(newPathname, opts);
102
116
  }
103
117
  back() {
104
118
  const prevStack = this.viewStack.slice(0, -1);
105
- const prevPath = generatePathnameFromViewParams(prevStack);
119
+ const prevPath = generatePathnameFromViewParams(prevStack, { basePath: this.getLayoutBasePath() });
106
120
  this.ctx.router.navigate(prevPath, { replace: true });
107
121
  }
122
+ getLayoutBasePath() {
123
+ var _a, _b;
124
+ const routePath = (_a = this.ctx.layout) == null ? void 0 : _a.routePath;
125
+ return this.basePath || ((_b = this.ctx.layoutRoute) == null ? void 0 : _b.basePathname) || ((routePath == null ? void 0 : routePath.startsWith("/")) ? routePath : "/admin");
126
+ }
108
127
  };
109
128
  __name(_ViewNavigation, "ViewNavigation");
110
129
  let ViewNavigation = _ViewNavigation;