@nocobase/flow-engine 2.0.0-alpha.3 → 2.0.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 (418) hide show
  1. package/lib/BlockScopedFlowEngine.d.ts +23 -0
  2. package/lib/BlockScopedFlowEngine.js +90 -0
  3. package/lib/FlowContextProvider.d.ts +2 -2
  4. package/lib/FlowContextProvider.js +3 -3
  5. package/lib/FlowDefinition.d.ts +4 -2
  6. package/lib/JSRunner.js +3 -0
  7. package/lib/ViewScopedFlowEngine.d.ts +1 -1
  8. package/lib/components/FieldModelRenderer.js +10 -4
  9. package/lib/components/FieldSkeleton.d.ts +10 -0
  10. package/lib/components/FieldSkeleton.js +64 -0
  11. package/lib/components/FlowContextSelector.js +7 -2
  12. package/lib/components/FlowModelRenderer.d.ts +2 -5
  13. package/lib/components/FlowModelRenderer.js +16 -47
  14. package/lib/components/FormItem.js +5 -1
  15. package/lib/{runjs-context/snippets/global/requireAsync.snippet.d.ts → components/dnd/findModelUidPosition.d.ts} +4 -7
  16. package/lib/{runjs-context/snippets/scene/jsblock/jsx-mount.snippet.js → components/dnd/findModelUidPosition.js} +23 -19
  17. package/lib/components/dnd/gridDragPlanner.d.ts +130 -0
  18. package/lib/components/dnd/gridDragPlanner.js +497 -0
  19. package/lib/components/dnd/index.d.ts +2 -2
  20. package/lib/components/dnd/index.js +5 -5
  21. package/lib/components/settings/independents/dropdown/FlowsDropdownButton.js +2 -2
  22. package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +17 -5
  23. package/lib/components/settings/wrappers/contextual/FlowsContextMenu.js +2 -2
  24. package/lib/components/settings/wrappers/contextual/StepSettingsDialog.js +7 -1
  25. package/lib/components/variables/VariableInput.js +16 -2
  26. package/lib/components/variables/VariableTag.js +43 -2
  27. package/lib/components/variables/types.d.ts +2 -0
  28. package/lib/data-source/index.d.ts +12 -4
  29. package/lib/data-source/index.js +19 -13
  30. package/lib/data-source/sortCollectionsByInherits.d.ts +10 -0
  31. package/lib/data-source/sortCollectionsByInherits.js +71 -0
  32. package/lib/executor/FlowExecutor.d.ts +4 -5
  33. package/lib/executor/FlowExecutor.js +135 -100
  34. package/lib/flowContext.d.ts +33 -5
  35. package/lib/flowContext.js +193 -76
  36. package/lib/flowEngine.d.ts +8 -1
  37. package/lib/flowEngine.js +18 -6
  38. package/lib/flowSettings.d.ts +2 -1
  39. package/lib/flowSettings.js +12 -8
  40. package/lib/hooks/useApplyAutoFlows.js +2 -1
  41. package/lib/index.d.ts +7 -1
  42. package/lib/index.js +32 -3
  43. package/lib/locale/en-US.json +4 -2
  44. package/lib/locale/index.d.ts +4 -0
  45. package/lib/locale/zh-CN.json +4 -2
  46. package/lib/models/CollectionFieldModel.d.ts +2 -0
  47. package/lib/models/CollectionFieldModel.js +43 -3
  48. package/lib/models/flowModel.d.ts +28 -29
  49. package/lib/models/flowModel.js +114 -92
  50. package/lib/models/forkFlowModel.d.ts +4 -4
  51. package/lib/models/forkFlowModel.js +32 -8
  52. package/lib/provider.d.ts +3 -1
  53. package/lib/provider.js +7 -5
  54. package/lib/resources/multiRecordResource.js +2 -0
  55. package/lib/resources/singleRecordResource.js +1 -0
  56. package/lib/resources/sqlResource.d.ts +1 -0
  57. package/lib/resources/sqlResource.js +20 -24
  58. package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.d.ts +1 -6
  59. package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.js +27 -20
  60. package/lib/runjs-context/contexts/JSBlockRunJSContext.d.ts +1 -6
  61. package/lib/runjs-context/contexts/JSBlockRunJSContext.js +46 -33
  62. package/lib/runjs-context/contexts/JSCollectionActionRunJSContext.d.ts +1 -2
  63. package/lib/runjs-context/contexts/JSCollectionActionRunJSContext.js +14 -15
  64. package/lib/runjs-context/contexts/{LinkageRunJSContext.d.ts → JSColumnRunJSContext.d.ts} +6 -3
  65. package/lib/runjs-context/contexts/JSColumnRunJSContext.js +78 -0
  66. package/lib/runjs-context/contexts/JSFieldRunJSContext.d.ts +1 -6
  67. package/lib/runjs-context/contexts/JSFieldRunJSContext.js +28 -24
  68. package/lib/runjs-context/contexts/JSItemRunJSContext.d.ts +1 -6
  69. package/lib/runjs-context/contexts/JSItemRunJSContext.js +24 -20
  70. package/lib/runjs-context/contexts/JSRecordActionRunJSContext.d.ts +1 -2
  71. package/lib/runjs-context/contexts/JSRecordActionRunJSContext.js +16 -17
  72. package/lib/runjs-context/contexts/base.d.ts +9 -0
  73. package/lib/runjs-context/contexts/base.js +183 -0
  74. package/lib/runjs-context/helpers.d.ts +5 -2
  75. package/lib/runjs-context/helpers.js +36 -27
  76. package/lib/runjs-context/registry.d.ts +7 -4
  77. package/lib/runjs-context/registry.js +10 -42
  78. package/lib/runjs-context/setup.d.ts +9 -0
  79. package/lib/runjs-context/setup.js +82 -0
  80. package/lib/runjs-context/snippets/global/{copy-record-json.snippet.js → api-request.snippet.js} +25 -10
  81. package/lib/runjs-context/snippets/global/clipboard-copy-text.snippet.js +61 -0
  82. package/lib/runjs-context/snippets/global/{view-navigation-push.snippet.js → import-esm.snippet.js} +26 -12
  83. package/lib/runjs-context/snippets/global/message-error.snippet.js +6 -0
  84. package/lib/runjs-context/snippets/global/message-success.snippet.js +6 -0
  85. package/lib/runjs-context/snippets/global/notification-open.snippet.d.ts +3 -8
  86. package/lib/runjs-context/snippets/global/notification-open.snippet.js +8 -1
  87. package/lib/runjs-context/snippets/global/open-view-dialog.snippet.js +10 -3
  88. package/lib/runjs-context/snippets/global/open-view-drawer.snippet.js +10 -3
  89. package/lib/runjs-context/snippets/global/query-selector.snippet.js +53 -0
  90. package/lib/runjs-context/snippets/global/require-amd.snippet.d.ts +11 -0
  91. package/lib/runjs-context/snippets/global/{requireAsync.snippet.js → require-amd.snippet.js} +16 -13
  92. package/lib/runjs-context/snippets/global/window-open.snippet.d.ts +3 -8
  93. package/lib/runjs-context/snippets/global/window-open.snippet.js +8 -1
  94. package/lib/runjs-context/snippets/index.d.ts +14 -3
  95. package/lib/runjs-context/snippets/index.js +161 -40
  96. package/lib/runjs-context/snippets/scene/block/add-event-listener.snippet.d.ts +11 -0
  97. package/lib/runjs-context/snippets/scene/{jsblock → block}/add-event-listener.snippet.js +11 -2
  98. package/lib/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.d.ts +11 -0
  99. package/lib/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.js +64 -0
  100. package/lib/runjs-context/snippets/scene/block/chartjs-bar.snippet.d.ts +11 -0
  101. package/lib/runjs-context/snippets/scene/block/chartjs-bar.snippet.js +99 -0
  102. package/lib/runjs-context/snippets/{libs → scene/block}/echarts-init.snippet.js +24 -7
  103. package/lib/runjs-context/snippets/scene/block/render-button-handler.snippet.d.ts +11 -0
  104. package/lib/runjs-context/snippets/scene/{jsblock → block}/render-button-handler.snippet.js +17 -9
  105. package/lib/runjs-context/snippets/scene/block/render-iframe.snippet.d.ts +11 -0
  106. package/lib/runjs-context/snippets/scene/block/render-iframe.snippet.js +57 -0
  107. package/lib/runjs-context/snippets/scene/block/render-info-card.snippet.d.ts +11 -0
  108. package/lib/runjs-context/snippets/scene/block/render-info-card.snippet.js +71 -0
  109. package/lib/runjs-context/snippets/scene/block/render-react-jsx.snippet.d.ts +11 -0
  110. package/lib/runjs-context/snippets/scene/{jsblock/render-card.snippet.js → block/render-react-jsx.snippet.js} +26 -13
  111. package/lib/runjs-context/snippets/scene/block/render-react.snippet.d.ts +11 -0
  112. package/lib/runjs-context/snippets/scene/{jsblock → block}/render-react.snippet.js +18 -17
  113. package/lib/runjs-context/snippets/scene/block/render-statistics.snippet.d.ts +11 -0
  114. package/lib/runjs-context/snippets/scene/block/render-statistics.snippet.js +95 -0
  115. package/lib/runjs-context/snippets/scene/block/render-timeline.snippet.d.ts +11 -0
  116. package/lib/runjs-context/snippets/scene/block/render-timeline.snippet.js +84 -0
  117. package/lib/runjs-context/snippets/scene/block/resource-example.snippet.d.ts +11 -0
  118. package/lib/runjs-context/snippets/scene/block/resource-example.snippet.js +60 -0
  119. package/lib/runjs-context/snippets/scene/block/three-users-orbit.snippet.d.ts +11 -0
  120. package/lib/runjs-context/snippets/scene/block/three-users-orbit.snippet.js +283 -0
  121. package/lib/runjs-context/snippets/scene/block/vue-component.snippet.d.ts +11 -0
  122. package/lib/runjs-context/snippets/scene/block/vue-component.snippet.js +124 -0
  123. package/lib/runjs-context/snippets/scene/detail/color-by-value.snippet.d.ts +11 -0
  124. package/lib/runjs-context/snippets/scene/{jsfield → detail}/color-by-value.snippet.js +13 -3
  125. package/lib/runjs-context/snippets/scene/detail/copy-to-clipboard.snippet.d.ts +11 -0
  126. package/lib/runjs-context/snippets/{global → scene/detail}/copy-to-clipboard.snippet.js +28 -6
  127. package/lib/runjs-context/snippets/scene/detail/format-number.snippet.d.ts +11 -0
  128. package/lib/runjs-context/snippets/scene/{jsfield → detail}/format-number.snippet.js +13 -3
  129. package/lib/runjs-context/snippets/scene/detail/innerHTML-value.snippet.d.ts +11 -0
  130. package/lib/runjs-context/snippets/scene/{jsfield → detail}/innerHTML-value.snippet.js +13 -3
  131. package/lib/runjs-context/snippets/scene/detail/percentage-bar.snippet.d.ts +11 -0
  132. package/lib/runjs-context/snippets/scene/detail/percentage-bar.snippet.js +82 -0
  133. package/lib/runjs-context/snippets/scene/detail/relative-time.snippet.d.ts +11 -0
  134. package/lib/runjs-context/snippets/scene/detail/relative-time.snippet.js +80 -0
  135. package/lib/runjs-context/snippets/scene/detail/status-tag.snippet.d.ts +11 -0
  136. package/lib/runjs-context/snippets/scene/detail/status-tag.snippet.js +74 -0
  137. package/lib/runjs-context/snippets/scene/form/calculate-total.snippet.d.ts +11 -0
  138. package/lib/runjs-context/snippets/scene/form/calculate-total.snippet.js +63 -0
  139. package/lib/runjs-context/snippets/scene/form/cascade-select.snippet.d.ts +11 -0
  140. package/lib/runjs-context/snippets/scene/form/cascade-select.snippet.js +81 -0
  141. package/lib/runjs-context/snippets/scene/form/conditional-required.snippet.d.ts +11 -0
  142. package/lib/runjs-context/snippets/scene/form/conditional-required.snippet.js +64 -0
  143. package/lib/runjs-context/snippets/scene/form/copy-field-values.snippet.d.ts +11 -0
  144. package/lib/runjs-context/snippets/scene/form/copy-field-values.snippet.js +74 -0
  145. package/lib/runjs-context/snippets/scene/form/render-basic.snippet.d.ts +11 -0
  146. package/lib/runjs-context/snippets/scene/{jsitem → form}/render-basic.snippet.js +11 -2
  147. package/lib/runjs-context/snippets/scene/form/set-disabled.snippet.d.ts +11 -0
  148. package/lib/runjs-context/snippets/scene/{linkage → form}/set-disabled.snippet.js +12 -3
  149. package/lib/runjs-context/snippets/scene/form/set-field-value.snippet.d.ts +11 -0
  150. package/lib/runjs-context/snippets/scene/{linkage → form}/set-field-value.snippet.js +12 -3
  151. package/lib/runjs-context/snippets/scene/form/set-required.snippet.d.ts +11 -0
  152. package/lib/runjs-context/snippets/scene/{linkage → form}/set-required.snippet.js +12 -3
  153. package/lib/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.d.ts +11 -0
  154. package/lib/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.js +67 -0
  155. package/lib/runjs-context/snippets/scene/form/toggle-visible.snippet.d.ts +11 -0
  156. package/lib/runjs-context/snippets/scene/{linkage → form}/toggle-visible.snippet.js +12 -3
  157. package/lib/runjs-context/snippets/scene/table/cell-open-dialog.snippet.d.ts +11 -0
  158. package/lib/runjs-context/snippets/scene/table/cell-open-dialog.snippet.js +64 -0
  159. package/lib/runjs-context/snippets/scene/table/collection-selected-count.snippet.d.ts +11 -0
  160. package/lib/runjs-context/snippets/scene/{actions → table}/collection-selected-count.snippet.js +11 -2
  161. package/lib/runjs-context/snippets/scene/table/concat-fields.snippet.d.ts +11 -0
  162. package/lib/runjs-context/snippets/scene/table/concat-fields.snippet.js +79 -0
  163. package/lib/runjs-context/snippets/scene/table/destroy-selected.snippet.d.ts +11 -0
  164. package/lib/runjs-context/snippets/{global/log-json-record.snippet.js → scene/table/destroy-selected.snippet.js} +24 -11
  165. package/lib/runjs-context/snippets/scene/table/export-selected-json.snippet.d.ts +11 -0
  166. package/lib/runjs-context/snippets/scene/table/export-selected-json.snippet.js +64 -0
  167. package/lib/runjs-context/snippets/scene/table/iterate-selected-rows.snippet.d.ts +11 -0
  168. package/lib/runjs-context/snippets/scene/{actions → table}/iterate-selected-rows.snippet.js +11 -2
  169. package/lib/runjs-context/snippets/types.d.ts +9 -1
  170. package/lib/types.d.ts +28 -3
  171. package/lib/types.js +4 -3
  172. package/lib/utils/buildSettingsViewInputArgs.d.ts +19 -0
  173. package/lib/utils/buildSettingsViewInputArgs.js +75 -0
  174. package/lib/utils/createEphemeralContext.d.ts +13 -0
  175. package/lib/utils/createEphemeralContext.js +140 -0
  176. package/lib/utils/index.d.ts +3 -2
  177. package/lib/utils/index.js +5 -2
  178. package/lib/utils/jsxTransform.d.ts +15 -0
  179. package/lib/utils/jsxTransform.js +68 -0
  180. package/lib/utils/params-resolvers.js +3 -3
  181. package/lib/utils/safeGlobals.d.ts +5 -3
  182. package/lib/utils/safeGlobals.js +40 -0
  183. package/lib/utils/schema-utils.js +2 -2
  184. package/lib/utils/serverContextParams.d.ts +1 -0
  185. package/lib/utils/variablesParams.d.ts +9 -5
  186. package/lib/utils/variablesParams.js +47 -36
  187. package/lib/views/PageComponent.js +2 -1
  188. package/lib/views/createViewMeta.d.ts +29 -1
  189. package/lib/views/createViewMeta.js +338 -72
  190. package/lib/views/index.d.ts +1 -0
  191. package/lib/views/index.js +3 -0
  192. package/lib/views/useDialog.d.ts +8 -8
  193. package/lib/views/useDialog.js +8 -7
  194. package/lib/views/useDrawer.d.ts +8 -8
  195. package/lib/views/useDrawer.js +40 -26
  196. package/lib/views/usePage.d.ts +8 -8
  197. package/lib/views/usePage.js +8 -7
  198. package/package.json +5 -3
  199. package/src/BlockScopedFlowEngine.ts +86 -0
  200. package/src/FlowContextProvider.tsx +4 -2
  201. package/src/JSRunner.ts +3 -0
  202. package/src/ViewScopedFlowEngine.ts +1 -1
  203. package/src/__tests__/JSRunner.test.ts +62 -53
  204. package/src/__tests__/blockScopedFlowEngine.test.ts +154 -0
  205. package/src/__tests__/createViewMeta.popup.test.ts +132 -0
  206. package/src/__tests__/flow-engine.test.ts +3 -0
  207. package/src/__tests__/flowContextCreateJSRunner.test.ts +163 -0
  208. package/src/__tests__/flowEngine.saveModel.test.ts +4 -0
  209. package/src/__tests__/flowRunJSContextDefine.test.ts +508 -0
  210. package/src/__tests__/globalFlowRegistry.test.ts +1 -1
  211. package/src/__tests__/runjsContext.test.ts +216 -35
  212. package/src/__tests__/runjsContextImplementations.test.ts +217 -0
  213. package/src/__tests__/runjsContextRuntime.test.ts +269 -0
  214. package/src/__tests__/runjsEdgeCases.test.ts +281 -0
  215. package/src/__tests__/runjsLocales.test.ts +36 -0
  216. package/src/__tests__/runjsRuntimeFeatures.test.ts +449 -0
  217. package/src/__tests__/runjsSnippets.test.ts +140 -0
  218. package/src/__tests__/viewScopedFlowEngine.test.ts +3 -3
  219. package/src/components/DynamicFlowsEditor.tsx +3 -4
  220. package/src/components/FieldModelRenderer.tsx +16 -5
  221. package/src/components/FieldSkeleton.tsx +27 -0
  222. package/src/components/FlowContextSelector.tsx +6 -2
  223. package/src/components/FlowModelRenderer.tsx +30 -78
  224. package/src/components/FormItem.tsx +8 -1
  225. package/src/components/__tests__/flow-model-render-error-fallback.test.tsx +5 -5
  226. package/src/components/__tests__/gridDragPlanner.test.ts +494 -0
  227. package/src/components/dnd/README.md +149 -0
  228. package/src/components/dnd/findModelUidPosition.ts +26 -0
  229. package/src/components/dnd/gridDragPlanner.ts +659 -0
  230. package/src/components/dnd/index.tsx +3 -3
  231. package/src/components/settings/independents/dropdown/FlowsDropdownButton.tsx +1 -1
  232. package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +17 -4
  233. package/src/components/settings/wrappers/contextual/FlowsContextMenu.tsx +1 -1
  234. package/src/components/settings/wrappers/contextual/StepSettingsDialog.tsx +14 -1
  235. package/src/components/settings/wrappers/contextual/__tests__/DefaultSettingsIcon.test.tsx +424 -0
  236. package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +5 -7
  237. package/src/components/variables/VariableInput.tsx +22 -2
  238. package/src/components/variables/VariableTag.tsx +54 -2
  239. package/src/components/variables/types.ts +2 -0
  240. package/src/data-source/__tests__/sortCollectionsByInherits.test.ts +125 -0
  241. package/src/data-source/index.ts +17 -11
  242. package/src/data-source/sortCollectionsByInherits.ts +61 -0
  243. package/src/executor/FlowExecutor.ts +178 -121
  244. package/src/executor/__tests__/ctx-defs-injection.test.ts +197 -0
  245. package/src/executor/__tests__/flowExecutor.test.ts +151 -5
  246. package/src/flowContext.ts +266 -97
  247. package/src/flowEngine.ts +21 -6
  248. package/src/flowSettings.ts +9 -4
  249. package/src/hooks/useApplyAutoFlows.ts +3 -1
  250. package/src/index.ts +12 -1
  251. package/src/locale/en-US.json +4 -2
  252. package/src/locale/zh-CN.json +4 -2
  253. package/src/models/CollectionFieldModel.tsx +43 -4
  254. package/src/models/__tests__/flowModel.getFlows.sort.test.ts +4 -4
  255. package/src/models/__tests__/flowModel.test.ts +234 -111
  256. package/src/models/__tests__/forkFlowModel.test.ts +22 -7
  257. package/src/models/flowModel.tsx +149 -125
  258. package/src/models/forkFlowModel.ts +41 -8
  259. package/src/provider.tsx +10 -7
  260. package/src/resources/multiRecordResource.ts +2 -0
  261. package/src/resources/singleRecordResource.ts +1 -0
  262. package/src/resources/sqlResource.ts +20 -25
  263. package/src/runjs-context/contexts/FormJSFieldItemRunJSContext.ts +28 -21
  264. package/src/runjs-context/contexts/JSBlockRunJSContext.ts +46 -34
  265. package/src/runjs-context/contexts/JSCollectionActionRunJSContext.ts +15 -16
  266. package/src/runjs-context/contexts/JSColumnRunJSContext.ts +58 -0
  267. package/src/runjs-context/contexts/JSFieldRunJSContext.ts +30 -25
  268. package/src/runjs-context/contexts/JSItemRunJSContext.ts +25 -21
  269. package/src/runjs-context/contexts/JSRecordActionRunJSContext.ts +17 -18
  270. package/src/runjs-context/contexts/base.ts +171 -0
  271. package/src/runjs-context/helpers.ts +32 -30
  272. package/src/runjs-context/registry.ts +16 -47
  273. package/src/runjs-context/setup.ts +51 -0
  274. package/src/runjs-context/snippets/global/api-request.snippet.ts +38 -0
  275. package/src/runjs-context/snippets/global/clipboard-copy-text.snippet.ts +42 -0
  276. package/src/runjs-context/snippets/global/import-esm.snippet.ts +39 -0
  277. package/src/runjs-context/snippets/global/message-error.snippet.ts +6 -0
  278. package/src/runjs-context/snippets/global/message-success.snippet.ts +6 -0
  279. package/src/runjs-context/snippets/global/notification-open.snippet.ts +11 -1
  280. package/src/runjs-context/snippets/global/open-view-dialog.snippet.ts +10 -3
  281. package/src/runjs-context/snippets/global/open-view-drawer.snippet.ts +10 -3
  282. package/src/runjs-context/snippets/global/query-selector.snippet.ts +34 -0
  283. package/src/runjs-context/snippets/global/require-amd.snippet.ts +30 -0
  284. package/src/runjs-context/snippets/global/window-open.snippet.ts +11 -1
  285. package/src/runjs-context/snippets/index.ts +177 -39
  286. package/src/runjs-context/snippets/scene/{jsblock → block}/add-event-listener.snippet.ts +14 -2
  287. package/src/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.ts +45 -0
  288. package/src/runjs-context/snippets/scene/block/chartjs-bar.snippet.ts +80 -0
  289. package/src/runjs-context/snippets/scene/block/echarts-init.snippet.ts +44 -0
  290. package/src/runjs-context/snippets/scene/block/render-button-handler.snippet.ts +35 -0
  291. package/src/runjs-context/snippets/scene/block/render-iframe.snippet.ts +38 -0
  292. package/src/runjs-context/snippets/scene/block/render-info-card.snippet.ts +52 -0
  293. package/src/runjs-context/snippets/scene/block/render-react-jsx.snippet.ts +39 -0
  294. package/src/runjs-context/snippets/scene/block/render-react.snippet.ts +38 -0
  295. package/src/runjs-context/snippets/scene/block/render-statistics.snippet.ts +76 -0
  296. package/src/runjs-context/snippets/scene/block/render-timeline.snippet.ts +65 -0
  297. package/src/runjs-context/snippets/scene/block/resource-example.snippet.ts +46 -0
  298. package/src/runjs-context/snippets/scene/block/three-users-orbit.snippet.ts +264 -0
  299. package/src/runjs-context/snippets/scene/block/vue-component.snippet.ts +105 -0
  300. package/src/runjs-context/snippets/scene/detail/color-by-value.snippet.ts +33 -0
  301. package/src/runjs-context/snippets/scene/detail/copy-to-clipboard.snippet.ts +45 -0
  302. package/src/runjs-context/snippets/scene/detail/format-number.snippet.ts +32 -0
  303. package/src/runjs-context/snippets/scene/detail/innerHTML-value.snippet.ts +31 -0
  304. package/src/runjs-context/snippets/scene/detail/percentage-bar.snippet.ts +63 -0
  305. package/src/runjs-context/snippets/scene/detail/relative-time.snippet.ts +61 -0
  306. package/src/runjs-context/snippets/scene/detail/status-tag.snippet.ts +55 -0
  307. package/src/runjs-context/snippets/scene/form/calculate-total.snippet.ts +44 -0
  308. package/src/runjs-context/snippets/scene/form/cascade-select.snippet.ts +62 -0
  309. package/src/runjs-context/snippets/scene/form/conditional-required.snippet.ts +45 -0
  310. package/src/runjs-context/snippets/scene/form/copy-field-values.snippet.ts +55 -0
  311. package/src/runjs-context/snippets/scene/{jsitem → form}/render-basic.snippet.ts +14 -2
  312. package/src/runjs-context/snippets/scene/{linkage → form}/set-disabled.snippet.ts +15 -3
  313. package/src/runjs-context/snippets/scene/{linkage → form}/set-field-value.snippet.ts +15 -3
  314. package/src/runjs-context/snippets/scene/{linkage → form}/set-required.snippet.ts +15 -3
  315. package/src/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.ts +48 -0
  316. package/src/runjs-context/snippets/scene/{linkage → form}/toggle-visible.snippet.ts +15 -3
  317. package/src/runjs-context/snippets/scene/table/cell-open-dialog.snippet.ts +45 -0
  318. package/src/runjs-context/snippets/scene/{actions → table}/collection-selected-count.snippet.ts +14 -2
  319. package/src/runjs-context/snippets/scene/table/concat-fields.snippet.ts +60 -0
  320. package/src/runjs-context/snippets/scene/table/destroy-selected.snippet.ts +36 -0
  321. package/src/runjs-context/snippets/scene/table/export-selected-json.snippet.ts +45 -0
  322. package/src/runjs-context/snippets/scene/{actions → table}/iterate-selected-rows.snippet.ts +14 -2
  323. package/src/runjs-context/snippets/types.ts +5 -1
  324. package/src/types.ts +34 -0
  325. package/src/utils/__tests__/jsxTransform.test.ts +38 -0
  326. package/src/utils/__tests__/safeGlobals.test.ts +22 -1
  327. package/src/utils/buildSettingsViewInputArgs.ts +72 -0
  328. package/src/utils/createEphemeralContext.ts +142 -0
  329. package/src/utils/index.ts +2 -2
  330. package/src/utils/jsxTransform.ts +39 -0
  331. package/src/utils/params-resolvers.ts +2 -2
  332. package/src/utils/safeGlobals.ts +49 -3
  333. package/src/utils/schema-utils.ts +1 -1
  334. package/src/utils/serverContextParams.ts +1 -0
  335. package/src/utils/variablesParams.ts +50 -38
  336. package/src/views/PageComponent.tsx +1 -1
  337. package/src/views/createViewMeta.ts +393 -70
  338. package/src/views/index.tsx +1 -0
  339. package/src/views/useDialog.tsx +12 -10
  340. package/src/views/useDrawer.tsx +60 -36
  341. package/src/views/usePage.tsx +13 -10
  342. package/lib/components/dnd/getMousePositionOnElement.d.ts +0 -50
  343. package/lib/components/dnd/getMousePositionOnElement.js +0 -95
  344. package/lib/components/dnd/moveBlock.d.ts +0 -33
  345. package/lib/components/dnd/moveBlock.js +0 -302
  346. package/lib/runjs-context/contexts/FlowRunJSContext.d.ts +0 -38
  347. package/lib/runjs-context/contexts/FlowRunJSContext.js +0 -217
  348. package/lib/runjs-context/contexts/LinkageRunJSContext.js +0 -62
  349. package/lib/runjs-context/index.d.ts +0 -19
  350. package/lib/runjs-context/index.js +0 -57
  351. package/lib/runjs-context/snippets/global/api-request-get.snippet.d.ts +0 -16
  352. package/lib/runjs-context/snippets/global/api-request-get.snippet.js +0 -42
  353. package/lib/runjs-context/snippets/global/api-request-post.snippet.d.ts +0 -16
  354. package/lib/runjs-context/snippets/global/api-request-post.snippet.js +0 -42
  355. package/lib/runjs-context/snippets/global/console-log-ctx.snippet.d.ts +0 -16
  356. package/lib/runjs-context/snippets/global/console-log-ctx.snippet.js +0 -41
  357. package/lib/runjs-context/snippets/global/sleep.snippet.d.ts +0 -16
  358. package/lib/runjs-context/snippets/global/sleep.snippet.js +0 -43
  359. package/lib/runjs-context/snippets/global/try-catch-async.snippet.d.ts +0 -16
  360. package/lib/runjs-context/snippets/global/try-catch-async.snippet.js +0 -44
  361. package/lib/runjs-context/snippets/libs/echarts-init.snippet.d.ts +0 -15
  362. package/lib/runjs-context/snippets/scene/actions/collection-selected-count.snippet.d.ts +0 -15
  363. package/lib/runjs-context/snippets/scene/actions/iterate-selected-rows.snippet.d.ts +0 -15
  364. package/lib/runjs-context/snippets/scene/actions/record-id-message.snippet.d.ts +0 -15
  365. package/lib/runjs-context/snippets/scene/actions/record-id-message.snippet.js +0 -43
  366. package/lib/runjs-context/snippets/scene/actions/run-action-basic.snippet.d.ts +0 -15
  367. package/lib/runjs-context/snippets/scene/actions/run-action-basic.snippet.js +0 -40
  368. package/lib/runjs-context/snippets/scene/jsblock/add-event-listener.snippet.d.ts +0 -15
  369. package/lib/runjs-context/snippets/scene/jsblock/append-style.snippet.d.ts +0 -15
  370. package/lib/runjs-context/snippets/scene/jsblock/append-style.snippet.js +0 -42
  371. package/lib/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.d.ts +0 -15
  372. package/lib/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.d.ts +0 -15
  373. package/lib/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.js +0 -41
  374. package/lib/runjs-context/snippets/scene/jsblock/render-basic.snippet.d.ts +0 -15
  375. package/lib/runjs-context/snippets/scene/jsblock/render-basic.snippet.js +0 -41
  376. package/lib/runjs-context/snippets/scene/jsblock/render-button-handler.snippet.d.ts +0 -15
  377. package/lib/runjs-context/snippets/scene/jsblock/render-react.snippet.d.ts +0 -15
  378. package/lib/runjs-context/snippets/scene/jsfield/color-by-value.snippet.d.ts +0 -15
  379. package/lib/runjs-context/snippets/scene/jsfield/format-number.snippet.d.ts +0 -15
  380. package/lib/runjs-context/snippets/scene/jsfield/innerHTML-value.snippet.d.ts +0 -15
  381. package/lib/runjs-context/snippets/scene/jsitem/render-basic.snippet.d.ts +0 -15
  382. package/lib/runjs-context/snippets/scene/linkage/set-disabled.snippet.d.ts +0 -15
  383. package/lib/runjs-context/snippets/scene/linkage/set-field-value.snippet.d.ts +0 -15
  384. package/lib/runjs-context/snippets/scene/linkage/set-required.snippet.d.ts +0 -15
  385. package/lib/runjs-context/snippets/scene/linkage/toggle-visible.snippet.d.ts +0 -15
  386. package/src/components/dnd/getMousePositionOnElement.ts +0 -115
  387. package/src/components/dnd/moveBlock.ts +0 -379
  388. package/src/runjs-context/contexts/FlowRunJSContext.ts +0 -190
  389. package/src/runjs-context/contexts/LinkageRunJSContext.ts +0 -35
  390. package/src/runjs-context/index.ts +0 -20
  391. package/src/runjs-context/snippets/global/api-request-get.snippet.ts +0 -20
  392. package/src/runjs-context/snippets/global/api-request-post.snippet.ts +0 -20
  393. package/src/runjs-context/snippets/global/console-log-ctx.snippet.ts +0 -19
  394. package/src/runjs-context/snippets/global/copy-record-json.snippet.ts +0 -21
  395. package/src/runjs-context/snippets/global/copy-to-clipboard.snippet.ts +0 -21
  396. package/src/runjs-context/snippets/global/log-json-record.snippet.ts +0 -21
  397. package/src/runjs-context/snippets/global/requireAsync.snippet.ts +0 -24
  398. package/src/runjs-context/snippets/global/sleep.snippet.ts +0 -21
  399. package/src/runjs-context/snippets/global/try-catch-async.snippet.ts +0 -22
  400. package/src/runjs-context/snippets/global/view-navigation-push.snippet.ts +0 -23
  401. package/src/runjs-context/snippets/libs/echarts-init.snippet.ts +0 -24
  402. package/src/runjs-context/snippets/scene/actions/record-id-message.snippet.ts +0 -21
  403. package/src/runjs-context/snippets/scene/actions/run-action-basic.snippet.ts +0 -18
  404. package/src/runjs-context/snippets/scene/jsblock/append-style.snippet.ts +0 -20
  405. package/src/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.ts +0 -24
  406. package/src/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.ts +0 -19
  407. package/src/runjs-context/snippets/scene/jsblock/render-basic.snippet.ts +0 -24
  408. package/src/runjs-context/snippets/scene/jsblock/render-button-handler.snippet.ts +0 -24
  409. package/src/runjs-context/snippets/scene/jsblock/render-card.snippet.ts +0 -30
  410. package/src/runjs-context/snippets/scene/jsblock/render-react.snippet.ts +0 -34
  411. package/src/runjs-context/snippets/scene/jsfield/color-by-value.snippet.ts +0 -20
  412. package/src/runjs-context/snippets/scene/jsfield/format-number.snippet.ts +0 -19
  413. package/src/runjs-context/snippets/scene/jsfield/innerHTML-value.snippet.ts +0 -18
  414. /package/lib/runjs-context/snippets/global/{copy-record-json.snippet.d.ts → api-request.snippet.d.ts} +0 -0
  415. /package/lib/runjs-context/snippets/global/{copy-to-clipboard.snippet.d.ts → clipboard-copy-text.snippet.d.ts} +0 -0
  416. /package/lib/runjs-context/snippets/global/{log-json-record.snippet.d.ts → import-esm.snippet.d.ts} +0 -0
  417. /package/lib/runjs-context/snippets/global/{view-navigation-push.snippet.d.ts → query-selector.snippet.d.ts} +0 -0
  418. /package/lib/runjs-context/snippets/scene/{jsblock/render-card.snippet.d.ts → block/echarts-init.snippet.d.ts} +0 -0
@@ -50,12 +50,31 @@ var import_DrawerComponent = __toESM(require("./DrawerComponent"));
50
50
  var import_usePatchElement = __toESM(require("./usePatchElement"));
51
51
  var import_provider = require("../provider");
52
52
  var import_ViewScopedFlowEngine = require("../ViewScopedFlowEngine");
53
- let uuid = 0;
54
53
  function useDrawer() {
55
54
  const holderRef = React.useRef(null);
55
+ const drawerList = React.useMemo(() => import__.observable.shallow({ value: [] }), []);
56
+ const RenderNestedDrawer = React.memo((props) => {
57
+ const { index } = props;
58
+ const [RenderDrawer, setRenderDrawer] = React.useState(null);
59
+ React.useEffect(() => {
60
+ (0, import__.autorun)(() => {
61
+ const list = drawerList.value;
62
+ if (list[index] && RenderDrawer !== list[index]) {
63
+ setRenderDrawer(list[index]);
64
+ }
65
+ if (!list[index]) {
66
+ setRenderDrawer(null);
67
+ }
68
+ });
69
+ }, [RenderDrawer, index]);
70
+ if (!RenderDrawer) {
71
+ return null;
72
+ }
73
+ return /* @__PURE__ */ React.createElement(RenderDrawer, null, /* @__PURE__ */ React.createElement(RenderNestedDrawer, { index: index + 1 }));
74
+ });
75
+ RenderNestedDrawer.displayName = "RenderNestedDrawer";
56
76
  const open = /* @__PURE__ */ __name((config, flowContext) => {
57
77
  var _a, _b;
58
- uuid += 1;
59
78
  const drawerRef = React.createRef();
60
79
  let closeFunc;
61
80
  let resolvePromise;
@@ -64,7 +83,7 @@ function useDrawer() {
64
83
  });
65
84
  let currentFooter = null;
66
85
  let currentHeader = null;
67
- const FooterComponent = /* @__PURE__ */ __name(({ children, ...props }) => {
86
+ const FooterComponent = /* @__PURE__ */ __name(({ children }) => {
68
87
  React.useEffect(() => {
69
88
  var _a2;
70
89
  currentFooter = children;
@@ -77,7 +96,7 @@ function useDrawer() {
77
96
  }, [children]);
78
97
  return null;
79
98
  }, "FooterComponent");
80
- const HeaderComponent = /* @__PURE__ */ __name(({ ...props }) => {
99
+ const HeaderComponent = /* @__PURE__ */ __name((props) => {
81
100
  React.useEffect(() => {
82
101
  var _a2;
83
102
  currentHeader = props;
@@ -126,11 +145,6 @@ function useDrawer() {
126
145
  navigation: (_a = config.inputArgs) == null ? void 0 : _a.navigation
127
146
  };
128
147
  const ctx = new import_flowContext.FlowContext();
129
- ctx.defineProperty("view", {
130
- get: /* @__PURE__ */ __name(() => currentDrawer, "get"),
131
- meta: (0, import_createViewMeta.createViewMeta)(ctx, () => currentDrawer),
132
- resolveOnServer: /* @__PURE__ */ __name((p) => p === "record" || p.startsWith("record."), "resolveOnServer")
133
- });
134
148
  const scopedEngine = (0, import_ViewScopedFlowEngine.createViewScopedEngine)(flowContext.engine);
135
149
  ctx.defineProperty("engine", { value: scopedEngine });
136
150
  ctx.addDelegate(scopedEngine.context);
@@ -139,8 +153,14 @@ function useDrawer() {
139
153
  } else {
140
154
  ctx.addDelegate(flowContext.engine.context);
141
155
  }
142
- const DrawerWithContext = (0, import__.observer)(
143
- (props) => {
156
+ ctx.defineProperty("view", {
157
+ get: /* @__PURE__ */ __name(() => currentDrawer, "get"),
158
+ // meta: createViewMeta(ctx),
159
+ resolveOnServer: /* @__PURE__ */ __name((p) => p === "record" || p.startsWith("record."), "resolveOnServer")
160
+ });
161
+ (0, import_createViewMeta.registerPopupVariable)(ctx, currentDrawer);
162
+ const DrawerWithContext = React.memo(
163
+ (0, import__.observer)((props) => {
144
164
  var _a2, _b2, _c, _d;
145
165
  const mountedRef = React.useRef(false);
146
166
  const rawContent = typeof config.content === "function" ? config.content(currentDrawer, ctx) : config.content;
@@ -172,13 +192,12 @@ function useDrawer() {
172
192
  content,
173
193
  props.children
174
194
  );
175
- },
176
- {
177
- displayName: "DrawerWithContext"
178
- }
195
+ })
179
196
  );
180
- const renderDrawer = /* @__PURE__ */ __name((children) => /* @__PURE__ */ React.createElement(import_provider.FlowEngineProvider, { engine: scopedEngine }, /* @__PURE__ */ React.createElement(import_FlowContextProvider.FlowViewContextProvider, { context: ctx }, /* @__PURE__ */ React.createElement(DrawerWithContext, null, children))), "renderDrawer");
181
- closeFunc = (_b = holderRef.current) == null ? void 0 : _b.patchElement(renderDrawer);
197
+ DrawerWithContext.displayName = "DrawerWithContext";
198
+ const RenderDrawer = React.memo(({ children }) => /* @__PURE__ */ React.createElement(import_provider.FlowEngineProvider, { engine: scopedEngine }, /* @__PURE__ */ React.createElement(import_FlowContextProvider.FlowViewContextProvider, { context: ctx }, /* @__PURE__ */ React.createElement(DrawerWithContext, null, children))));
199
+ RenderDrawer.displayName = "RenderDrawer";
200
+ closeFunc = (_b = holderRef.current) == null ? void 0 : _b.patchElement(RenderDrawer);
182
201
  return Object.assign(promise, currentDrawer);
183
202
  }, "open");
184
203
  const api = React.useMemo(() => ({ open }), []);
@@ -186,15 +205,10 @@ function useDrawer() {
186
205
  React.forwardRef((props, ref) => {
187
206
  const [elements, patchElement] = (0, import_usePatchElement.default)();
188
207
  React.useImperativeHandle(ref, () => ({ patchElement }), [patchElement]);
189
- const renderNestedElements = /* @__PURE__ */ __name(() => {
190
- if (elements.length === 0) {
191
- return null;
192
- }
193
- return elements.reduceRight((children, renderElement) => {
194
- return renderElement(children);
195
- }, null);
196
- }, "renderNestedElements");
197
- return /* @__PURE__ */ React.createElement(React.Fragment, null, renderNestedElements());
208
+ React.useEffect(() => {
209
+ drawerList.value = elements;
210
+ }, [elements]);
211
+ return /* @__PURE__ */ React.createElement(RenderNestedDrawer, { index: 0 });
198
212
  })
199
213
  );
200
214
  return [api, /* @__PURE__ */ React.createElement(ElementsHolder, { key: "drawer-holder", ref: holderRef })];
@@ -9,19 +9,19 @@
9
9
  import React from 'react';
10
10
  export declare function usePage(): (React.JSX.Element | {
11
11
  open: (config: any, flowContext: any) => Promise<unknown> & {
12
- type: string;
12
+ type: "embed";
13
13
  inputArgs: any;
14
14
  preventClose: boolean;
15
15
  destroy: () => void;
16
16
  update: (newConfig: any) => void;
17
17
  close: (result?: any, force?: boolean) => void;
18
- Header: ({ ...props }: {
19
- [x: string]: any;
20
- }) => any;
21
- Footer: ({ children, ...props }: {
22
- [x: string]: any;
23
- children: any;
24
- }) => any;
18
+ Header: React.FC<{
19
+ title?: React.ReactNode;
20
+ extra?: React.ReactNode;
21
+ }>;
22
+ Footer: React.FC<{
23
+ children?: React.ReactNode;
24
+ }>;
25
25
  setFooter: (footer: React.ReactNode) => void;
26
26
  setHeader: (header: {
27
27
  title?: React.ReactNode;
@@ -69,7 +69,7 @@ function usePage() {
69
69
  const promise = new Promise((resolve) => {
70
70
  resolvePromise = resolve;
71
71
  });
72
- const FooterComponent = /* @__PURE__ */ __name(({ children, ...props }) => {
72
+ const FooterComponent = /* @__PURE__ */ __name(({ children }) => {
73
73
  import_react.default.useEffect(() => {
74
74
  var _a2;
75
75
  (_a2 = pageRef.current) == null ? void 0 : _a2.setFooter(children);
@@ -80,7 +80,7 @@ function usePage() {
80
80
  }, [children]);
81
81
  return null;
82
82
  }, "FooterComponent");
83
- const HeaderComponent = /* @__PURE__ */ __name(({ ...props }) => {
83
+ const HeaderComponent = /* @__PURE__ */ __name((props) => {
84
84
  import_react.default.useEffect(() => {
85
85
  var _a2;
86
86
  (_a2 = pageRef.current) == null ? void 0 : _a2.setHeader(props);
@@ -126,11 +126,6 @@ function usePage() {
126
126
  navigation: (_a = config.inputArgs) == null ? void 0 : _a.navigation
127
127
  };
128
128
  const ctx = new import_flowContext.FlowContext();
129
- ctx.defineProperty("view", {
130
- get: /* @__PURE__ */ __name(() => currentPage, "get"),
131
- meta: (0, import_createViewMeta.createViewMeta)(ctx, () => currentPage),
132
- resolveOnServer: /* @__PURE__ */ __name((p) => p === "record" || p.startsWith("record."), "resolveOnServer")
133
- });
134
129
  const scopedEngine = (0, import_ViewScopedFlowEngine.createViewScopedEngine)(flowContext.engine);
135
130
  ctx.defineProperty("engine", { value: scopedEngine });
136
131
  ctx.addDelegate(scopedEngine.context);
@@ -139,6 +134,12 @@ function usePage() {
139
134
  } else {
140
135
  ctx.addDelegate(flowContext.engine.context);
141
136
  }
137
+ ctx.defineProperty("view", {
138
+ get: /* @__PURE__ */ __name(() => currentPage, "get"),
139
+ // meta: createViewMeta(ctx),
140
+ resolveOnServer: /* @__PURE__ */ __name((p) => p === "record" || p.startsWith("record."), "resolveOnServer")
141
+ });
142
+ (0, import_createViewMeta.registerPopupVariable)(ctx, currentPage);
142
143
  const PageWithContext = (0, import__.observer)(
143
144
  () => {
144
145
  var _a2, _b2, _c2, _d;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/flow-engine",
3
- "version": "2.0.0-alpha.3",
3
+ "version": "2.0.0-alpha.30",
4
4
  "private": false,
5
5
  "description": "A standalone flow engine for NocoBase, managing workflows, models, and actions.",
6
6
  "main": "lib/index.js",
@@ -8,7 +8,8 @@
8
8
  "dependencies": {
9
9
  "@formily/antd-v5": "1.x",
10
10
  "@formily/reactive": "2.x",
11
- "@nocobase/sdk": "1.8.0-beta.4",
11
+ "@nocobase/sdk": "2.0.0-alpha.30",
12
+ "@nocobase/shared": "2.0.0-alpha.30",
12
13
  "ahooks": "^3.7.2",
13
14
  "dompurify": "^3.0.2",
14
15
  "lodash": "^4.x",
@@ -17,6 +18,7 @@
17
18
  "slate": "^0.103.0",
18
19
  "slate-history": "^0.109.0",
19
20
  "slate-react": "^0.110.3",
21
+ "sucrase": "^3.35.0",
20
22
  "uid": "^2.0.2"
21
23
  },
22
24
  "peerDependencies": {
@@ -33,5 +35,5 @@
33
35
  ],
34
36
  "author": "NocoBase Team",
35
37
  "license": "AGPL-3.0",
36
- "gitHead": "8efc23aa78058d871e98a91419f3c4a61762cc15"
38
+ "gitHead": "cdac55c9cdf0dbdbe57a21815f323b975792bfc0"
37
39
  }
@@ -0,0 +1,86 @@
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 { FlowEngine } from './flowEngine';
11
+
12
+ /**
13
+ * BlockScopedFlowEngine(区块作用域引擎)
14
+ *
15
+ * 设计目标:
16
+ * - 仅在“区块”作用域内隔离“模型实例表”和“事件缓存”;
17
+ * - 其余能力(动作/事件/模型类/资源/仓库/设置/日志/翻译等)全部直接代理到父引擎;
18
+ * - 使用 Proxy 实现“最小代理”,保持与父引擎的全局一致性。
19
+ *
20
+ * 注意:
21
+ * - 本地化的字段仅有:`_modelInstances`、`_applyFlowCache`、`executor`、`context`、栈指针;
22
+ * - 其它字段/方法均通过 Proxy 转发到父引擎;
23
+ * - 这样可满足“同一 uid 的模型可在不同区块隔离出现(实例/缓存隔离)”与“共享全局注册/仓库”的诉求。
24
+ */
25
+ export function createBlockScopedEngine(parent: FlowEngine): FlowEngine {
26
+ const local = new FlowEngine();
27
+ if (parent.modelRepository) {
28
+ local.setModelRepository(parent.modelRepository);
29
+ }
30
+ // 继承父级上下文能力
31
+ local.context.addDelegate(parent.context);
32
+
33
+ // 覆盖 unlinkFromStack:BlockScoped 引擎被移除时,修复前后指针,避免“截断”后续视图/作用域
34
+ const originalUnlink = local.unlinkFromStack.bind(local);
35
+ local.unlinkFromStack = function () {
36
+ // 修复指针:prev -> next,next -> prev,然后清理自身指针
37
+ // 若不这么做,移除位于中间的 block 引擎会导致后续整段链丢失
38
+ const prev = (local as any)._previousEngine as FlowEngine | undefined;
39
+ const next = (local as any)._nextEngine as FlowEngine | undefined;
40
+ if (prev) (prev as any)._nextEngine = next;
41
+ if (next) (next as any)._previousEngine = prev;
42
+ (local as any)._previousEngine = undefined as any;
43
+ (local as any)._nextEngine = undefined as any;
44
+ };
45
+
46
+ // 默认全部代理到父引擎,只有少数字段(实例/缓存/执行器/上下文/链表指针)使用本地值
47
+ const localOnly = new Set<keyof FlowEngine | string>([
48
+ '_modelInstances',
49
+ '_applyFlowCache',
50
+ 'executor',
51
+ 'context',
52
+ 'previousEngine',
53
+ 'nextEngine',
54
+ // 栈指针维护方法需要在本地执行,而非代理到父引擎
55
+ 'unlinkFromStack',
56
+ 'linkAfter',
57
+ '_previousEngine',
58
+ '_nextEngine',
59
+ ]);
60
+
61
+ const handler: ProxyHandler<FlowEngine> = {
62
+ get(target, prop: string, receiver) {
63
+ if (localOnly.has(prop)) {
64
+ return Reflect.get(target, prop, receiver);
65
+ }
66
+ const value = Reflect.get(parent, prop, receiver);
67
+ if (prop === 'registerModels' && typeof value === 'function') {
68
+ return value.bind(parent);
69
+ }
70
+ return value;
71
+ },
72
+ set(target, prop: string, value: unknown) {
73
+ if (localOnly.has(prop)) {
74
+ return Reflect.set(target, prop, value);
75
+ }
76
+ return Reflect.set(parent, prop, value);
77
+ },
78
+ has(target, prop: string) {
79
+ return prop in target || prop in parent;
80
+ },
81
+ };
82
+
83
+ // 与父引擎形成栈式关系,便于在多层作用域间进行全局查找
84
+ local.linkAfter(parent);
85
+ return new Proxy(local, handler) as FlowEngine;
86
+ }
@@ -18,13 +18,15 @@ export function FlowContextProvider(props: { children: React.ReactNode; context:
18
18
  return <FlowReactContext.Provider value={props.context}>{props.children}</FlowReactContext.Provider>;
19
19
  }
20
20
 
21
- export function FlowViewContextProvider(props: { children: React.ReactNode; context: FlowContext }) {
21
+ export const FlowViewContextProvider = React.memo((props: { children: React.ReactNode; context: FlowContext }) => {
22
22
  return (
23
23
  <FlowViewContext.Provider value={props.context}>
24
24
  <FlowReactContext.Provider value={props.context}>{props.children}</FlowReactContext.Provider>
25
25
  </FlowViewContext.Provider>
26
26
  );
27
- }
27
+ });
28
+
29
+ FlowViewContextProvider.displayName = 'FlowViewContextProvider';
28
30
 
29
31
  export function useFlowContext<T = FlowEngineContext>() {
30
32
  return useContext(FlowReactContext) as T;
package/src/JSRunner.ts CHANGED
@@ -55,6 +55,9 @@ export class JSRunner {
55
55
  error?: any;
56
56
  timeout?: boolean;
57
57
  }> {
58
+ if (location?.search.includes('skipRunJs=true')) {
59
+ return { success: true, value: null };
60
+ }
58
61
  const wrapped = `(async () => {
59
62
  try {
60
63
  ${code};
@@ -13,7 +13,7 @@ import { FlowEngine } from './flowEngine';
13
13
  * ViewScopedFlowEngine(视图作用域引擎)
14
14
  *
15
15
  * 设计目标:
16
- * - 仅在视图(dialog/drawer/embed)作用域内隔离“模型实例表”和“自动流缓存”;
16
+ * - 仅在视图(dialog/drawer/embed)作用域内隔离“模型实例表”和“事件缓存”;
17
17
  * - 其余能力(动作/事件/模型类/资源/仓库/设置/日志/翻译等)全部直接代理到父引擎;
18
18
  * - 使用 Proxy 实现“最小代理”,保持与父引擎的全局一致性。
19
19
  *
@@ -7,86 +7,95 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
 
10
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
10
11
  import { JSRunner } from '../JSRunner';
11
12
 
12
13
  describe('JSRunner', () => {
13
- it('should run simple code successfully', async () => {
14
- const runner = new JSRunner();
15
- const result = await runner.run(`
16
- const x = 10;
17
- return x + 5;
18
- `);
19
- expect(result.success).toBe(true);
20
- expect(result.value).toBe(15);
14
+ let originalSearch: string;
15
+
16
+ beforeEach(() => {
17
+ originalSearch = globalThis.location?.search || '';
21
18
  });
22
19
 
23
- it('should handle syntax errors in the code', async () => {
24
- const runner = new JSRunner();
25
- const result = await runner.run('const x = 10 x + 5;'); // Syntax error
26
- expect(result.success).toBe(false);
27
- expect(result.error).toBeInstanceOf(SyntaxError);
20
+ afterEach(() => {
21
+ // 恢复 URL 查询参数,避免影响其他用例
22
+ try {
23
+ if (typeof window !== 'undefined' && typeof window.history?.replaceState === 'function') {
24
+ window.history.replaceState({}, '', originalSearch || '');
25
+ }
26
+ } catch (_) {
27
+ // ignore
28
+ }
29
+ vi.restoreAllMocks();
28
30
  });
29
31
 
30
- it('should handle runtime errors in the code', async () => {
32
+ it('executes simple code and returns value', async () => {
31
33
  const runner = new JSRunner();
32
- const result = await runner.run(`
33
- const x = 10;
34
- throw new Error('Test error');
35
- `);
36
- expect(result.success).toBe(false);
37
- expect(result.error).toBeInstanceOf(Error);
38
- expect(result.error.message).toBe('Test error');
34
+ const result = await runner.run('return 1 + 2 + 3');
35
+ expect(result.success).toBe(true);
36
+ expect(result.value).toBe(6);
39
37
  });
40
38
 
41
- it('should handle timeout errors', async () => {
42
- const runner = new JSRunner({ timeoutMs: 100 }); // Set a short timeout
43
- const result = await runner.run(`
44
- await new Promise(resolve => setTimeout(resolve, 500)); // Exceeds timeout
45
- return 'Done';
46
- `);
47
- console.log(result);
48
- expect(result.success).toBe(false);
49
- expect(result.timeout).toBe(true);
50
- expect(result.error.message).toBe('Execution timed out');
39
+ it('injects custom globals and supports register()', async () => {
40
+ const runner = new JSRunner({ globals: { foo: 42 } });
41
+ const res1 = await runner.run('return foo');
42
+ expect(res1.success).toBe(true);
43
+ expect(res1.value).toBe(42);
44
+
45
+ runner.register('bar', 'baz');
46
+ const res2 = await runner.run('return bar');
47
+ expect(res2.success).toBe(true);
48
+ expect(res2.value).toBe('baz');
51
49
  });
52
50
 
53
- it('should use registered globals', async () => {
51
+ it('exposes console in sandbox by default', async () => {
54
52
  const runner = new JSRunner();
55
- runner.register('globalVar', 42);
56
- const result = await runner.run(`
57
- return globalVar + 8;
58
- `);
53
+ const result = await runner.run('return typeof console !== "undefined"');
59
54
  expect(result.success).toBe(true);
60
- expect(result.value).toBe(50);
55
+ expect(result.value).toBe(true);
61
56
  });
62
57
 
63
- it('should handle code with async/await', async () => {
58
+ it('supports timers (setTimeout) inside evaluated code', async () => {
64
59
  const runner = new JSRunner();
65
60
  const result = await runner.run(`
66
- const fetchData = async () => {
67
- return new Promise(resolve => setTimeout(() => resolve(100), 50));
68
- };
69
- const data = await fetchData();
70
- return data + 50;
61
+ return new Promise((resolve) => {
62
+ setTimeout(() => resolve('ok'), 20);
63
+ });
71
64
  `);
72
65
  expect(result.success).toBe(true);
73
- expect(result.value).toBe(150);
66
+ expect(result.value).toBe('ok');
74
67
  });
75
68
 
76
- it('should handle empty code', async () => {
69
+ it('handles thrown errors and marks as non-timeout', async () => {
70
+ const spy = vi.spyOn(console, 'error').mockImplementation(() => {});
77
71
  const runner = new JSRunner();
78
- const result = await runner.run('');
79
- expect(result.success).toBe(true);
80
- expect(result.value).toBe(undefined);
72
+ const result = await runner.run('throw new Error("boom")');
73
+ expect(result.success).toBe(false);
74
+ expect(result.timeout).toBe(false);
75
+ expect(result.error).toBeInstanceOf(Error);
76
+ expect((result.error as Error).message).toBe('boom');
77
+ expect(spy).toHaveBeenCalled();
81
78
  });
82
79
 
83
- it('should handle code returning undefined explicitly', async () => {
84
- const runner = new JSRunner();
80
+ it('respects timeout setting and marks timeout=true', async () => {
81
+ const runner = new JSRunner({ timeoutMs: 10 });
85
82
  const result = await runner.run(`
86
- const x = 10;
87
- return undefined;
83
+ return new Promise((resolve) => setTimeout(() => resolve('late'), 100));
88
84
  `);
85
+ expect(result.success).toBe(false);
86
+ expect(result.timeout).toBe(true);
87
+ expect(result.error).toBeInstanceOf(Error);
88
+ expect((result.error as Error).message).toBe('Execution timed out');
89
+ });
90
+
91
+ it('skips execution when URL contains skipRunJs=true', async () => {
92
+ // 模拟预览模式下通过 URL 参数跳过代码执行
93
+ if (typeof window !== 'undefined' && typeof window.history?.pushState === 'function') {
94
+ window.history.pushState({}, '', '?skipRunJs=true');
95
+ }
96
+ const runner = new JSRunner();
97
+ const result = await runner.run('throw new Error("should not run")');
89
98
  expect(result.success).toBe(true);
90
- expect(result.value).toBe(undefined);
99
+ expect(result.value).toBeNull();
91
100
  });
92
101
  });
@@ -0,0 +1,154 @@
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 { describe, expect, it, vi } from 'vitest';
11
+ import { APIClient as SDKApiClient } from '@nocobase/sdk';
12
+ import { FlowEngine } from '../flowEngine';
13
+ import { createBlockScopedEngine } from '../BlockScopedFlowEngine';
14
+ import { FlowModel } from '../models';
15
+
16
+ describe('BlockScopedFlowEngine', () => {
17
+ it('shares global actions/events and model classes with parent', async () => {
18
+ const parent = new FlowEngine();
19
+ // 在运行时 host app 会注入 api,这里补一个最小 mock,避免偶发访问 ctx.auth 抛错
20
+ const api = new SDKApiClient({ storageType: 'memory' });
21
+ api.auth.role = 'guest';
22
+ api.auth.locale = 'en-US';
23
+ api.auth.token = 't';
24
+ parent.context.defineProperty('api', { value: api });
25
+ parent.registerActions({
26
+ ping: {
27
+ name: 'ping',
28
+ handler: () => 'pong',
29
+ },
30
+ });
31
+ const child = createBlockScopedEngine(parent);
32
+
33
+ // child can read parent's action
34
+ expect(child.getAction('ping')).toBeDefined();
35
+
36
+ // registering via child should affect parent
37
+ child.registerActions({ pong: { name: 'pong', handler: () => 'ok' } });
38
+ expect(parent.getAction('pong')).toBeDefined();
39
+
40
+ // model class resolution is proxied
41
+ class TestModel extends FlowModel {}
42
+ parent.registerModels({ TestModel });
43
+ expect(child.getModelClass('TestModel')).toBeDefined();
44
+ });
45
+
46
+ it('isolates model instances map and beforeRender cache across engines with identical model uid', async () => {
47
+ const parent = new FlowEngine();
48
+ // 提供最小 api mock,满足 ctx.auth 相关 getter
49
+ const api = new SDKApiClient({ storageType: 'memory' });
50
+ api.auth.role = 'guest';
51
+ api.auth.locale = 'en-US';
52
+ api.auth.token = 't';
53
+ parent.context.defineProperty('api', { value: api });
54
+ const child = createBlockScopedEngine(parent);
55
+
56
+ let count = 0;
57
+ class CounterModel extends FlowModel {}
58
+ CounterModel.registerFlow({
59
+ key: 'autoCounter',
60
+ steps: {
61
+ s1: {
62
+ handler: async () => {
63
+ count += 1;
64
+ return count;
65
+ },
66
+ },
67
+ },
68
+ });
69
+
70
+ const uid = 'model-uid-cache';
71
+ const pm = parent.createModel<CounterModel>({ use: CounterModel, uid });
72
+ const cm = child.createModel<CounterModel>({ use: CounterModel, uid });
73
+
74
+ await pm.dispatchEvent('beforeRender');
75
+ expect(count).toBe(1);
76
+
77
+ // If cache was shared, the next call would hit cache and not increment.
78
+ await cm.dispatchEvent('beforeRender');
79
+ expect(count).toBe(2);
80
+ });
81
+
82
+ it('stacks engines and repairs chain when unlinking a middle block-scoped engine', () => {
83
+ const root = new FlowEngine();
84
+ // 提供最小 api mock,满足 ctx.auth 相关 getter
85
+ const api = new SDKApiClient({ storageType: 'memory' });
86
+ api.auth.role = 'guest';
87
+ api.auth.locale = 'en-US';
88
+ api.auth.token = 't';
89
+ root.context.defineProperty('api', { value: api });
90
+ const c1 = createBlockScopedEngine(root);
91
+ const c2 = createBlockScopedEngine(root);
92
+ const c3 = createBlockScopedEngine(root);
93
+
94
+ // chain root -> c1 -> c2 -> c3
95
+ expect(root.nextEngine).toBeTruthy();
96
+ expect(root.nextEngine?.nextEngine).toBeTruthy();
97
+ expect(root.nextEngine?.nextEngine?.nextEngine).toBeTruthy();
98
+
99
+ // unlink middle (c2) should link c1 <-> c3 and keep the tail intact
100
+ c2.unlinkFromStack();
101
+
102
+ // root.nextEngine 指向的是被代理的本地 FlowEngine 实例,不与 c1 的 Proxy 引用相等
103
+ // 这里通过前后指针关系来校验链修复是否正确
104
+ const first = root.nextEngine;
105
+ const second = first?.nextEngine;
106
+ expect(first?.previousEngine).toBe(root);
107
+ expect(second?.previousEngine).toBe(first);
108
+ expect(second?.nextEngine).toBeUndefined();
109
+ });
110
+
111
+ it('global model lookup traverses from top to root across stack', () => {
112
+ const root = new FlowEngine();
113
+ // 提供最小 api mock,满足 ctx.auth 相关 getter
114
+ const api = new SDKApiClient({ storageType: 'memory' });
115
+ api.auth.role = 'guest';
116
+ api.auth.locale = 'en-US';
117
+ api.auth.token = 't';
118
+ root.context.defineProperty('api', { value: api });
119
+ const c1 = createBlockScopedEngine(root);
120
+ const c2 = createBlockScopedEngine(root);
121
+
122
+ class TM extends FlowModel {}
123
+ const uid = 'same-uid-global-lookup';
124
+ const mRoot = root.createModel<TM>({ use: TM, uid });
125
+ const m1 = c1.createModel<TM>({ use: TM, uid });
126
+ const m2 = c2.createModel<TM>({ use: TM, uid });
127
+
128
+ // sanity: each scope returns its own when not global
129
+ expect(root.getModel(uid)).toBe(mRoot);
130
+ expect(c1.getModel(uid)).toBe(m1);
131
+ expect(c2.getModel(uid)).toBe(m2);
132
+
133
+ // global search from any engine hits the top-most engine's instance first
134
+ expect(root.getModel(uid, true)).toBe(m2);
135
+ expect(c1.getModel(uid, true)).toBe(m2);
136
+ expect(c2.getModel(uid, true)).toBe(m2);
137
+ });
138
+
139
+ it('delegates saveModel to parent (concurrency gate sharing)', async () => {
140
+ const parent = new FlowEngine();
141
+ // 提供最小 api mock,满足 ctx.auth 相关 getter
142
+ const api = new SDKApiClient({ storageType: 'memory' });
143
+ api.auth.role = 'guest';
144
+ api.auth.locale = 'en-US';
145
+ api.auth.token = 't';
146
+ parent.context.defineProperty('api', { value: api });
147
+ const child = createBlockScopedEngine(parent);
148
+ const spy = vi.spyOn(parent, 'saveModel').mockResolvedValueOnce(true);
149
+ class T extends FlowModel {}
150
+ const m = child.createModel<T>({ use: T });
151
+ await child.saveModel(m);
152
+ expect(spy).toHaveBeenCalledOnce();
153
+ });
154
+ });