@nocobase/flow-engine 2.0.0-alpha.4 → 2.0.0-alpha.41

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 (466) 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/ViewScopedFlowEngine.js +12 -0
  9. package/lib/acl/Acl.d.ts +1 -0
  10. package/lib/acl/Acl.js +11 -0
  11. package/lib/components/FieldModelRenderer.js +14 -6
  12. package/lib/components/FieldSkeleton.d.ts +10 -0
  13. package/lib/components/FieldSkeleton.js +64 -0
  14. package/lib/components/FlowContextSelector.js +7 -2
  15. package/lib/components/FlowModelRenderer.d.ts +3 -6
  16. package/lib/components/FlowModelRenderer.js +16 -47
  17. package/lib/components/FormItem.js +5 -1
  18. package/lib/components/MobilePopup.d.ts +20 -0
  19. package/lib/components/MobilePopup.js +102 -0
  20. package/lib/components/MobilePopup.style.d.ts +17 -0
  21. package/lib/components/MobilePopup.style.js +186 -0
  22. package/lib/components/index.d.ts +1 -0
  23. package/lib/components/index.js +3 -1
  24. package/lib/components/settings/independents/dropdown/FlowsDropdownButton.js +2 -2
  25. package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +17 -5
  26. package/lib/components/settings/wrappers/contextual/FlowsContextMenu.js +2 -2
  27. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.d.ts +2 -2
  28. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +35 -6
  29. package/lib/components/settings/wrappers/contextual/StepSettingsDialog.js +7 -1
  30. package/lib/components/variables/VariableInput.js +19 -5
  31. package/lib/components/variables/VariableTag.js +43 -2
  32. package/lib/components/variables/types.d.ts +2 -0
  33. package/lib/data-source/index.d.ts +15 -4
  34. package/lib/data-source/index.js +42 -13
  35. package/lib/data-source/sortCollectionsByInherits.d.ts +10 -0
  36. package/lib/data-source/sortCollectionsByInherits.js +71 -0
  37. package/lib/emitter.d.ts +6 -0
  38. package/lib/emitter.js +12 -0
  39. package/lib/executor/FlowExecutor.d.ts +4 -5
  40. package/lib/executor/FlowExecutor.js +168 -99
  41. package/lib/flow-registry/GlobalFlowRegistry.d.ts +1 -0
  42. package/lib/flow-registry/GlobalFlowRegistry.js +3 -0
  43. package/lib/flow-registry/InstanceFlowRegistry.d.ts +1 -0
  44. package/lib/flow-registry/InstanceFlowRegistry.js +3 -0
  45. package/lib/flowContext.d.ts +37 -5
  46. package/lib/flowContext.js +224 -87
  47. package/lib/flowEngine.d.ts +24 -1
  48. package/lib/flowEngine.js +81 -8
  49. package/lib/flowSettings.d.ts +2 -1
  50. package/lib/flowSettings.js +16 -8
  51. package/lib/hooks/useApplyAutoFlows.js +2 -1
  52. package/lib/index.d.ts +7 -1
  53. package/lib/index.js +32 -3
  54. package/lib/locale/en-US.json +4 -2
  55. package/lib/locale/index.d.ts +4 -0
  56. package/lib/locale/zh-CN.json +4 -2
  57. package/lib/models/CollectionFieldModel.d.ts +3 -0
  58. package/lib/models/CollectionFieldModel.js +52 -6
  59. package/lib/models/flowModel.d.ts +30 -29
  60. package/lib/models/flowModel.js +153 -100
  61. package/lib/models/forkFlowModel.d.ts +8 -4
  62. package/lib/models/forkFlowModel.js +38 -8
  63. package/lib/provider.d.ts +3 -1
  64. package/lib/provider.js +7 -5
  65. package/lib/resources/multiRecordResource.js +25 -1
  66. package/lib/resources/singleRecordResource.js +19 -1
  67. package/lib/resources/sqlResource.d.ts +1 -0
  68. package/lib/resources/sqlResource.js +20 -24
  69. package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.d.ts +1 -6
  70. package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.js +27 -20
  71. package/lib/runjs-context/contexts/JSBlockRunJSContext.d.ts +1 -6
  72. package/lib/runjs-context/contexts/JSBlockRunJSContext.js +46 -33
  73. package/lib/runjs-context/contexts/JSCollectionActionRunJSContext.d.ts +1 -2
  74. package/lib/runjs-context/contexts/JSCollectionActionRunJSContext.js +14 -15
  75. package/lib/runjs-context/contexts/{LinkageRunJSContext.d.ts → JSColumnRunJSContext.d.ts} +6 -3
  76. package/lib/runjs-context/contexts/JSColumnRunJSContext.js +78 -0
  77. package/lib/runjs-context/contexts/JSFieldRunJSContext.d.ts +1 -6
  78. package/lib/runjs-context/contexts/JSFieldRunJSContext.js +28 -24
  79. package/lib/runjs-context/contexts/JSItemRunJSContext.d.ts +1 -6
  80. package/lib/runjs-context/contexts/JSItemRunJSContext.js +24 -20
  81. package/lib/runjs-context/contexts/JSRecordActionRunJSContext.d.ts +1 -2
  82. package/lib/runjs-context/contexts/JSRecordActionRunJSContext.js +16 -17
  83. package/lib/runjs-context/contexts/base.d.ts +9 -0
  84. package/lib/runjs-context/contexts/base.js +205 -0
  85. package/lib/runjs-context/helpers.d.ts +5 -2
  86. package/lib/runjs-context/helpers.js +36 -27
  87. package/lib/runjs-context/registry.d.ts +7 -4
  88. package/lib/runjs-context/registry.js +10 -42
  89. package/lib/runjs-context/setup.d.ts +9 -0
  90. package/lib/runjs-context/setup.js +82 -0
  91. package/lib/runjs-context/snippets/global/{copy-record-json.snippet.js → api-request.snippet.js} +25 -10
  92. package/lib/runjs-context/snippets/global/clipboard-copy-text.snippet.js +61 -0
  93. package/lib/runjs-context/snippets/global/{view-navigation-push.snippet.js → import-esm.snippet.js} +26 -12
  94. package/lib/runjs-context/snippets/global/message-error.snippet.js +6 -0
  95. package/lib/runjs-context/snippets/global/message-success.snippet.js +6 -0
  96. package/lib/runjs-context/snippets/global/notification-open.snippet.d.ts +3 -8
  97. package/lib/runjs-context/snippets/global/notification-open.snippet.js +8 -1
  98. package/lib/runjs-context/snippets/global/open-view-dialog.snippet.js +10 -3
  99. package/lib/runjs-context/snippets/global/open-view-drawer.snippet.js +10 -3
  100. package/lib/runjs-context/snippets/global/query-selector.snippet.js +53 -0
  101. package/lib/runjs-context/snippets/global/require-amd.snippet.d.ts +11 -0
  102. package/lib/runjs-context/snippets/global/{requireAsync.snippet.js → require-amd.snippet.js} +16 -13
  103. package/lib/runjs-context/snippets/global/window-open.snippet.d.ts +3 -8
  104. package/lib/runjs-context/snippets/global/window-open.snippet.js +8 -1
  105. package/lib/runjs-context/snippets/index.d.ts +14 -3
  106. package/lib/runjs-context/snippets/index.js +162 -40
  107. package/lib/runjs-context/snippets/scene/block/add-event-listener.snippet.d.ts +11 -0
  108. package/lib/runjs-context/snippets/scene/{jsblock → block}/add-event-listener.snippet.js +11 -2
  109. package/lib/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.d.ts +11 -0
  110. package/lib/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.js +64 -0
  111. package/lib/runjs-context/snippets/scene/block/chartjs-bar.snippet.d.ts +11 -0
  112. package/lib/runjs-context/snippets/scene/block/chartjs-bar.snippet.js +99 -0
  113. package/lib/runjs-context/snippets/{libs → scene/block}/echarts-init.snippet.js +24 -7
  114. package/lib/runjs-context/snippets/scene/block/render-antd-icons.snippet.d.ts +11 -0
  115. package/lib/runjs-context/snippets/scene/block/render-antd-icons.snippet.js +65 -0
  116. package/lib/runjs-context/snippets/scene/block/render-button-handler.snippet.d.ts +11 -0
  117. package/lib/runjs-context/snippets/scene/{jsblock → block}/render-button-handler.snippet.js +17 -9
  118. package/lib/runjs-context/snippets/scene/block/render-iframe.snippet.d.ts +11 -0
  119. package/lib/runjs-context/snippets/scene/block/render-iframe.snippet.js +57 -0
  120. package/lib/runjs-context/snippets/scene/block/render-info-card.snippet.d.ts +11 -0
  121. package/lib/runjs-context/snippets/scene/block/render-info-card.snippet.js +71 -0
  122. package/lib/runjs-context/snippets/scene/block/render-react-jsx.snippet.d.ts +11 -0
  123. package/lib/runjs-context/snippets/scene/{jsblock/render-card.snippet.js → block/render-react-jsx.snippet.js} +26 -13
  124. package/lib/runjs-context/snippets/scene/block/render-react.snippet.d.ts +11 -0
  125. package/lib/runjs-context/snippets/scene/{jsblock → block}/render-react.snippet.js +18 -17
  126. package/lib/runjs-context/snippets/scene/block/render-statistics.snippet.d.ts +11 -0
  127. package/lib/runjs-context/snippets/scene/block/render-statistics.snippet.js +95 -0
  128. package/lib/runjs-context/snippets/scene/block/render-timeline.snippet.d.ts +11 -0
  129. package/lib/runjs-context/snippets/scene/block/render-timeline.snippet.js +84 -0
  130. package/lib/runjs-context/snippets/scene/block/resource-example.snippet.d.ts +11 -0
  131. package/lib/runjs-context/snippets/scene/block/resource-example.snippet.js +60 -0
  132. package/lib/runjs-context/snippets/scene/block/three-users-orbit.snippet.d.ts +11 -0
  133. package/lib/runjs-context/snippets/scene/block/three-users-orbit.snippet.js +283 -0
  134. package/lib/runjs-context/snippets/scene/block/vue-component.snippet.d.ts +11 -0
  135. package/lib/runjs-context/snippets/scene/block/vue-component.snippet.js +124 -0
  136. package/lib/runjs-context/snippets/scene/detail/color-by-value.snippet.d.ts +11 -0
  137. package/lib/runjs-context/snippets/scene/{jsfield → detail}/color-by-value.snippet.js +13 -3
  138. package/lib/runjs-context/snippets/scene/detail/copy-to-clipboard.snippet.d.ts +11 -0
  139. package/lib/runjs-context/snippets/{global → scene/detail}/copy-to-clipboard.snippet.js +28 -6
  140. package/lib/runjs-context/snippets/scene/detail/format-number.snippet.d.ts +11 -0
  141. package/lib/runjs-context/snippets/scene/{jsfield → detail}/format-number.snippet.js +13 -3
  142. package/lib/runjs-context/snippets/scene/detail/innerHTML-value.snippet.d.ts +11 -0
  143. package/lib/runjs-context/snippets/scene/{jsfield → detail}/innerHTML-value.snippet.js +13 -3
  144. package/lib/runjs-context/snippets/scene/detail/percentage-bar.snippet.d.ts +11 -0
  145. package/lib/runjs-context/snippets/scene/detail/percentage-bar.snippet.js +82 -0
  146. package/lib/runjs-context/snippets/scene/detail/relative-time.snippet.d.ts +11 -0
  147. package/lib/runjs-context/snippets/scene/detail/relative-time.snippet.js +80 -0
  148. package/lib/runjs-context/snippets/scene/detail/status-tag.snippet.d.ts +11 -0
  149. package/lib/runjs-context/snippets/scene/detail/status-tag.snippet.js +74 -0
  150. package/lib/runjs-context/snippets/scene/form/calculate-total.snippet.d.ts +11 -0
  151. package/lib/runjs-context/snippets/scene/form/calculate-total.snippet.js +63 -0
  152. package/lib/runjs-context/snippets/scene/form/cascade-select.snippet.d.ts +11 -0
  153. package/lib/runjs-context/snippets/scene/form/cascade-select.snippet.js +81 -0
  154. package/lib/runjs-context/snippets/scene/form/conditional-required.snippet.d.ts +11 -0
  155. package/lib/runjs-context/snippets/scene/form/conditional-required.snippet.js +64 -0
  156. package/lib/runjs-context/snippets/scene/form/copy-field-values.snippet.d.ts +11 -0
  157. package/lib/runjs-context/snippets/scene/form/copy-field-values.snippet.js +74 -0
  158. package/lib/runjs-context/snippets/scene/form/render-basic.snippet.d.ts +11 -0
  159. package/lib/runjs-context/snippets/scene/{jsitem → form}/render-basic.snippet.js +11 -2
  160. package/lib/runjs-context/snippets/scene/form/set-disabled.snippet.d.ts +11 -0
  161. package/lib/runjs-context/snippets/scene/{linkage → form}/set-disabled.snippet.js +12 -3
  162. package/lib/runjs-context/snippets/scene/form/set-field-value.snippet.d.ts +11 -0
  163. package/lib/runjs-context/snippets/scene/{linkage → form}/set-field-value.snippet.js +12 -3
  164. package/lib/runjs-context/snippets/scene/form/set-required.snippet.d.ts +11 -0
  165. package/lib/runjs-context/snippets/scene/{linkage → form}/set-required.snippet.js +12 -3
  166. package/lib/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.d.ts +11 -0
  167. package/lib/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.js +67 -0
  168. package/lib/runjs-context/snippets/scene/form/toggle-visible.snippet.d.ts +11 -0
  169. package/lib/runjs-context/snippets/scene/{linkage → form}/toggle-visible.snippet.js +12 -3
  170. package/lib/runjs-context/snippets/scene/table/cell-open-dialog.snippet.d.ts +11 -0
  171. package/lib/runjs-context/snippets/scene/table/cell-open-dialog.snippet.js +64 -0
  172. package/lib/runjs-context/snippets/scene/table/collection-selected-count.snippet.d.ts +11 -0
  173. package/lib/runjs-context/snippets/scene/{actions → table}/collection-selected-count.snippet.js +11 -2
  174. package/lib/runjs-context/snippets/scene/table/concat-fields.snippet.d.ts +11 -0
  175. package/lib/runjs-context/snippets/scene/table/concat-fields.snippet.js +79 -0
  176. package/lib/runjs-context/snippets/scene/table/destroy-selected.snippet.d.ts +11 -0
  177. package/lib/runjs-context/snippets/{global/log-json-record.snippet.js → scene/table/destroy-selected.snippet.js} +24 -11
  178. package/lib/runjs-context/snippets/scene/table/export-selected-json.snippet.d.ts +11 -0
  179. package/lib/runjs-context/snippets/scene/table/export-selected-json.snippet.js +64 -0
  180. package/lib/runjs-context/snippets/scene/table/iterate-selected-rows.snippet.d.ts +11 -0
  181. package/lib/runjs-context/snippets/scene/{actions → table}/iterate-selected-rows.snippet.js +11 -2
  182. package/lib/runjs-context/snippets/types.d.ts +9 -1
  183. package/lib/scheduler/ModelOperationScheduler.d.ts +51 -0
  184. package/lib/scheduler/ModelOperationScheduler.js +262 -0
  185. package/lib/types.d.ts +28 -3
  186. package/lib/types.js +4 -3
  187. package/lib/utils/associationObjectVariable.d.ts +32 -0
  188. package/lib/utils/associationObjectVariable.js +157 -0
  189. package/lib/utils/buildSettingsViewInputArgs.d.ts +19 -0
  190. package/lib/utils/buildSettingsViewInputArgs.js +75 -0
  191. package/lib/utils/createEphemeralContext.d.ts +13 -0
  192. package/lib/utils/createEphemeralContext.js +140 -0
  193. package/lib/utils/flows.d.ts +10 -0
  194. package/lib/{runjs-context/snippets/global/api-request-post.snippet.js → utils/flows.js} +21 -15
  195. package/lib/utils/index.d.ts +7 -2
  196. package/lib/utils/index.js +21 -2
  197. package/lib/utils/jsxTransform.d.ts +15 -0
  198. package/lib/utils/jsxTransform.js +68 -0
  199. package/lib/utils/params-resolvers.js +3 -3
  200. package/lib/utils/parsePathnameToViewParams.d.ts +1 -1
  201. package/lib/utils/parsePathnameToViewParams.js +41 -5
  202. package/lib/utils/pruneFilter.d.ts +21 -0
  203. package/lib/{runjs-context/snippets/global/try-catch-async.snippet.js → utils/pruneFilter.js} +24 -16
  204. package/lib/utils/safeGlobals.d.ts +5 -3
  205. package/lib/utils/safeGlobals.js +40 -0
  206. package/lib/utils/schema-utils.js +2 -2
  207. package/lib/utils/serverContextParams.d.ts +1 -0
  208. package/lib/utils/translation.d.ts +4 -1
  209. package/lib/utils/translation.js +6 -2
  210. package/lib/utils/variablesParams.d.ts +22 -5
  211. package/lib/utils/variablesParams.js +132 -36
  212. package/lib/views/DrawerComponent.js +21 -2
  213. package/lib/views/PageComponent.js +2 -1
  214. package/lib/views/ViewNavigation.d.ts +3 -9
  215. package/lib/views/ViewNavigation.js +16 -2
  216. package/lib/views/createViewMeta.d.ts +29 -1
  217. package/lib/views/createViewMeta.js +338 -72
  218. package/lib/views/index.d.ts +1 -0
  219. package/lib/views/index.js +3 -0
  220. package/lib/views/useDialog.d.ts +9 -8
  221. package/lib/views/useDialog.js +19 -14
  222. package/lib/views/useDrawer.d.ts +9 -8
  223. package/lib/views/useDrawer.js +54 -35
  224. package/lib/views/usePage.d.ts +9 -8
  225. package/lib/views/usePage.js +20 -14
  226. package/package.json +6 -3
  227. package/src/BlockScopedFlowEngine.ts +86 -0
  228. package/src/FlowContextProvider.tsx +4 -2
  229. package/src/JSRunner.ts +3 -0
  230. package/src/ViewScopedFlowEngine.ts +15 -1
  231. package/src/__tests__/JSRunner.test.ts +62 -53
  232. package/src/__tests__/blockScopedFlowEngine.test.ts +154 -0
  233. package/src/__tests__/createViewMeta.popup.test.ts +132 -0
  234. package/src/__tests__/flow-engine.test.ts +3 -0
  235. package/src/__tests__/flowContext.test.ts +52 -0
  236. package/src/__tests__/flowContextCreateJSRunner.test.ts +163 -0
  237. package/src/__tests__/flowEngine.saveModel.test.ts +4 -0
  238. package/src/__tests__/flowRunJSContextDefine.test.ts +508 -0
  239. package/src/__tests__/flowSettings.open.test.tsx +2 -0
  240. package/src/__tests__/flowSettings.test.ts +2 -0
  241. package/src/__tests__/globalFlowRegistry.test.ts +1 -1
  242. package/src/__tests__/modelOperationScheduler.test.ts +346 -0
  243. package/src/__tests__/objectVariable.test.ts +464 -0
  244. package/src/__tests__/runjsContext.test.ts +216 -35
  245. package/src/__tests__/runjsContextImplementations.test.ts +217 -0
  246. package/src/__tests__/runjsContextRuntime.test.ts +269 -0
  247. package/src/__tests__/runjsEdgeCases.test.ts +281 -0
  248. package/src/__tests__/runjsLocales.test.ts +36 -0
  249. package/src/__tests__/runjsRuntimeFeatures.test.ts +461 -0
  250. package/src/__tests__/runjsSnippets.test.ts +140 -0
  251. package/src/__tests__/viewScopedFlowEngine.test.ts +3 -3
  252. package/src/acl/Acl.tsx +14 -0
  253. package/src/acl/__tests__/Acl.test.tsx +43 -0
  254. package/src/components/DynamicFlowsEditor.tsx +3 -4
  255. package/src/components/FieldModelRenderer.tsx +20 -7
  256. package/src/components/FieldSkeleton.tsx +27 -0
  257. package/src/components/FlowContextSelector.tsx +6 -2
  258. package/src/components/FlowModelRenderer.tsx +33 -81
  259. package/src/components/FormItem.tsx +8 -1
  260. package/src/components/MobilePopup.style.ts +220 -0
  261. package/src/components/MobilePopup.tsx +86 -0
  262. package/src/components/__tests__/flow-model-render-error-fallback.test.tsx +6 -6
  263. package/src/components/index.ts +1 -0
  264. package/src/components/settings/independents/dropdown/FlowsDropdownButton.tsx +1 -1
  265. package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +17 -4
  266. package/src/components/settings/wrappers/contextual/FlowsContextMenu.tsx +1 -1
  267. package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +39 -10
  268. package/src/components/settings/wrappers/contextual/StepSettingsDialog.tsx +14 -1
  269. package/src/components/settings/wrappers/contextual/__tests__/DefaultSettingsIcon.test.tsx +425 -0
  270. package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +5 -7
  271. package/src/components/variables/VariableInput.tsx +25 -5
  272. package/src/components/variables/VariableTag.tsx +54 -2
  273. package/src/components/variables/types.ts +2 -0
  274. package/src/data-source/__tests__/sortCollectionsByInherits.test.ts +125 -0
  275. package/src/data-source/index.ts +42 -11
  276. package/src/data-source/sortCollectionsByInherits.ts +61 -0
  277. package/src/emitter.ts +14 -0
  278. package/src/executor/FlowExecutor.ts +213 -119
  279. package/src/executor/__tests__/ctx-defs-injection.test.ts +197 -0
  280. package/src/executor/__tests__/flowExecutor.test.ts +151 -5
  281. package/src/flow-registry/GlobalFlowRegistry.ts +1 -0
  282. package/src/flow-registry/InstanceFlowRegistry.ts +1 -0
  283. package/src/flow-registry/__tests__/globalFlowRegistry.test.ts +54 -0
  284. package/src/flowContext.ts +303 -104
  285. package/src/flowEngine.ts +96 -6
  286. package/src/flowSettings.ts +12 -4
  287. package/src/hooks/useApplyAutoFlows.ts +3 -1
  288. package/src/index.ts +12 -1
  289. package/src/locale/en-US.json +4 -2
  290. package/src/locale/zh-CN.json +4 -2
  291. package/src/models/CollectionFieldModel.tsx +60 -8
  292. package/src/models/__tests__/dispatchEvent.behavior.test.ts +169 -0
  293. package/src/models/__tests__/flowModel.getFlows.sort.test.ts +33 -9
  294. package/src/models/__tests__/flowModel.scheduleModelOperation.test.tsx +129 -0
  295. package/src/models/__tests__/flowModel.test.ts +234 -111
  296. package/src/models/__tests__/forkFlowModel.test.ts +40 -7
  297. package/src/models/flowModel.tsx +197 -132
  298. package/src/models/forkFlowModel.ts +48 -8
  299. package/src/provider.tsx +10 -7
  300. package/src/resources/multiRecordResource.ts +28 -1
  301. package/src/resources/singleRecordResource.ts +19 -1
  302. package/src/resources/sqlResource.ts +20 -25
  303. package/src/runjs-context/contexts/FormJSFieldItemRunJSContext.ts +28 -21
  304. package/src/runjs-context/contexts/JSBlockRunJSContext.ts +46 -34
  305. package/src/runjs-context/contexts/JSCollectionActionRunJSContext.ts +15 -16
  306. package/src/runjs-context/contexts/JSColumnRunJSContext.ts +58 -0
  307. package/src/runjs-context/contexts/JSFieldRunJSContext.ts +30 -25
  308. package/src/runjs-context/contexts/JSItemRunJSContext.ts +25 -21
  309. package/src/runjs-context/contexts/JSRecordActionRunJSContext.ts +17 -18
  310. package/src/runjs-context/contexts/base.ts +196 -0
  311. package/src/runjs-context/helpers.ts +32 -30
  312. package/src/runjs-context/registry.ts +16 -47
  313. package/src/runjs-context/setup.ts +51 -0
  314. package/src/runjs-context/snippets/global/api-request.snippet.ts +38 -0
  315. package/src/runjs-context/snippets/global/clipboard-copy-text.snippet.ts +42 -0
  316. package/src/runjs-context/snippets/global/import-esm.snippet.ts +39 -0
  317. package/src/runjs-context/snippets/global/message-error.snippet.ts +6 -0
  318. package/src/runjs-context/snippets/global/message-success.snippet.ts +6 -0
  319. package/src/runjs-context/snippets/global/notification-open.snippet.ts +11 -1
  320. package/src/runjs-context/snippets/global/open-view-dialog.snippet.ts +10 -3
  321. package/src/runjs-context/snippets/global/open-view-drawer.snippet.ts +10 -3
  322. package/src/runjs-context/snippets/global/query-selector.snippet.ts +34 -0
  323. package/src/runjs-context/snippets/global/require-amd.snippet.ts +30 -0
  324. package/src/runjs-context/snippets/global/window-open.snippet.ts +11 -1
  325. package/src/runjs-context/snippets/index.ts +178 -39
  326. package/src/runjs-context/snippets/scene/{jsblock → block}/add-event-listener.snippet.ts +14 -2
  327. package/src/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.ts +45 -0
  328. package/src/runjs-context/snippets/scene/block/chartjs-bar.snippet.ts +80 -0
  329. package/src/runjs-context/snippets/scene/block/echarts-init.snippet.ts +44 -0
  330. package/src/runjs-context/snippets/scene/block/render-antd-icons.snippet.ts +46 -0
  331. package/src/runjs-context/snippets/scene/block/render-button-handler.snippet.ts +35 -0
  332. package/src/runjs-context/snippets/scene/block/render-iframe.snippet.ts +38 -0
  333. package/src/runjs-context/snippets/scene/block/render-info-card.snippet.ts +52 -0
  334. package/src/runjs-context/snippets/scene/block/render-react-jsx.snippet.ts +39 -0
  335. package/src/runjs-context/snippets/scene/block/render-react.snippet.ts +38 -0
  336. package/src/runjs-context/snippets/scene/block/render-statistics.snippet.ts +76 -0
  337. package/src/runjs-context/snippets/scene/block/render-timeline.snippet.ts +65 -0
  338. package/src/runjs-context/snippets/scene/block/resource-example.snippet.ts +46 -0
  339. package/src/runjs-context/snippets/scene/block/three-users-orbit.snippet.ts +264 -0
  340. package/src/runjs-context/snippets/scene/block/vue-component.snippet.ts +105 -0
  341. package/src/runjs-context/snippets/scene/detail/color-by-value.snippet.ts +33 -0
  342. package/src/runjs-context/snippets/scene/detail/copy-to-clipboard.snippet.ts +45 -0
  343. package/src/runjs-context/snippets/scene/detail/format-number.snippet.ts +32 -0
  344. package/src/runjs-context/snippets/scene/detail/innerHTML-value.snippet.ts +31 -0
  345. package/src/runjs-context/snippets/scene/detail/percentage-bar.snippet.ts +63 -0
  346. package/src/runjs-context/snippets/scene/detail/relative-time.snippet.ts +61 -0
  347. package/src/runjs-context/snippets/scene/detail/status-tag.snippet.ts +55 -0
  348. package/src/runjs-context/snippets/scene/form/calculate-total.snippet.ts +44 -0
  349. package/src/runjs-context/snippets/scene/form/cascade-select.snippet.ts +62 -0
  350. package/src/runjs-context/snippets/scene/form/conditional-required.snippet.ts +45 -0
  351. package/src/runjs-context/snippets/scene/form/copy-field-values.snippet.ts +55 -0
  352. package/src/runjs-context/snippets/scene/{jsitem → form}/render-basic.snippet.ts +14 -2
  353. package/src/runjs-context/snippets/scene/{linkage → form}/set-disabled.snippet.ts +15 -3
  354. package/src/runjs-context/snippets/scene/{linkage → form}/set-field-value.snippet.ts +15 -3
  355. package/src/runjs-context/snippets/scene/{linkage → form}/set-required.snippet.ts +15 -3
  356. package/src/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.ts +48 -0
  357. package/src/runjs-context/snippets/scene/{linkage → form}/toggle-visible.snippet.ts +15 -3
  358. package/src/runjs-context/snippets/scene/table/cell-open-dialog.snippet.ts +45 -0
  359. package/src/runjs-context/snippets/scene/{actions → table}/collection-selected-count.snippet.ts +14 -2
  360. package/src/runjs-context/snippets/scene/table/concat-fields.snippet.ts +60 -0
  361. package/src/runjs-context/snippets/scene/table/destroy-selected.snippet.ts +36 -0
  362. package/src/runjs-context/snippets/scene/table/export-selected-json.snippet.ts +45 -0
  363. package/src/runjs-context/snippets/scene/{actions → table}/iterate-selected-rows.snippet.ts +14 -2
  364. package/src/runjs-context/snippets/types.ts +5 -1
  365. package/src/scheduler/ModelOperationScheduler.ts +304 -0
  366. package/src/types.ts +34 -0
  367. package/src/utils/__tests__/flows.test.ts +65 -0
  368. package/src/utils/__tests__/jsxTransform.test.ts +38 -0
  369. package/src/utils/__tests__/parsePathnameToViewParams.test.ts +25 -0
  370. package/src/utils/__tests__/pruneFilter.test.ts +38 -0
  371. package/src/utils/__tests__/safeGlobals.test.ts +22 -1
  372. package/src/utils/__tests__/variablesParams.test.ts +63 -0
  373. package/src/utils/associationObjectVariable.ts +180 -0
  374. package/src/utils/buildSettingsViewInputArgs.ts +72 -0
  375. package/src/utils/createEphemeralContext.ts +142 -0
  376. package/src/utils/flows.ts +23 -0
  377. package/src/utils/index.ts +11 -2
  378. package/src/utils/jsxTransform.ts +39 -0
  379. package/src/utils/params-resolvers.ts +2 -2
  380. package/src/utils/parsePathnameToViewParams.ts +50 -6
  381. package/src/utils/pruneFilter.ts +41 -0
  382. package/src/utils/safeGlobals.ts +49 -3
  383. package/src/utils/schema-utils.ts +1 -1
  384. package/src/utils/serverContextParams.ts +1 -0
  385. package/src/utils/translation.ts +7 -2
  386. package/src/utils/variablesParams.ts +156 -38
  387. package/src/views/DrawerComponent.tsx +21 -2
  388. package/src/views/PageComponent.tsx +1 -1
  389. package/src/views/ViewNavigation.ts +20 -12
  390. package/src/views/__tests__/ViewNavigation.test.ts +10 -0
  391. package/src/views/createViewMeta.ts +393 -70
  392. package/src/views/index.tsx +1 -0
  393. package/src/views/useDialog.tsx +24 -18
  394. package/src/views/useDrawer.tsx +74 -45
  395. package/src/views/usePage.tsx +26 -17
  396. package/lib/runjs-context/contexts/FlowRunJSContext.d.ts +0 -38
  397. package/lib/runjs-context/contexts/FlowRunJSContext.js +0 -217
  398. package/lib/runjs-context/contexts/LinkageRunJSContext.js +0 -62
  399. package/lib/runjs-context/index.d.ts +0 -19
  400. package/lib/runjs-context/index.js +0 -57
  401. package/lib/runjs-context/snippets/global/api-request-get.snippet.d.ts +0 -16
  402. package/lib/runjs-context/snippets/global/api-request-get.snippet.js +0 -42
  403. package/lib/runjs-context/snippets/global/api-request-post.snippet.d.ts +0 -16
  404. package/lib/runjs-context/snippets/global/console-log-ctx.snippet.d.ts +0 -16
  405. package/lib/runjs-context/snippets/global/console-log-ctx.snippet.js +0 -41
  406. package/lib/runjs-context/snippets/global/requireAsync.snippet.d.ts +0 -16
  407. package/lib/runjs-context/snippets/global/sleep.snippet.d.ts +0 -16
  408. package/lib/runjs-context/snippets/global/sleep.snippet.js +0 -43
  409. package/lib/runjs-context/snippets/global/try-catch-async.snippet.d.ts +0 -16
  410. package/lib/runjs-context/snippets/libs/echarts-init.snippet.d.ts +0 -15
  411. package/lib/runjs-context/snippets/scene/actions/collection-selected-count.snippet.d.ts +0 -15
  412. package/lib/runjs-context/snippets/scene/actions/iterate-selected-rows.snippet.d.ts +0 -15
  413. package/lib/runjs-context/snippets/scene/actions/record-id-message.snippet.d.ts +0 -15
  414. package/lib/runjs-context/snippets/scene/actions/record-id-message.snippet.js +0 -43
  415. package/lib/runjs-context/snippets/scene/actions/run-action-basic.snippet.d.ts +0 -15
  416. package/lib/runjs-context/snippets/scene/actions/run-action-basic.snippet.js +0 -40
  417. package/lib/runjs-context/snippets/scene/jsblock/add-event-listener.snippet.d.ts +0 -15
  418. package/lib/runjs-context/snippets/scene/jsblock/append-style.snippet.d.ts +0 -15
  419. package/lib/runjs-context/snippets/scene/jsblock/append-style.snippet.js +0 -42
  420. package/lib/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.d.ts +0 -15
  421. package/lib/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.js +0 -46
  422. package/lib/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.d.ts +0 -15
  423. package/lib/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.js +0 -41
  424. package/lib/runjs-context/snippets/scene/jsblock/render-basic.snippet.d.ts +0 -15
  425. package/lib/runjs-context/snippets/scene/jsblock/render-basic.snippet.js +0 -41
  426. package/lib/runjs-context/snippets/scene/jsblock/render-button-handler.snippet.d.ts +0 -15
  427. package/lib/runjs-context/snippets/scene/jsblock/render-react.snippet.d.ts +0 -15
  428. package/lib/runjs-context/snippets/scene/jsfield/color-by-value.snippet.d.ts +0 -15
  429. package/lib/runjs-context/snippets/scene/jsfield/format-number.snippet.d.ts +0 -15
  430. package/lib/runjs-context/snippets/scene/jsfield/innerHTML-value.snippet.d.ts +0 -15
  431. package/lib/runjs-context/snippets/scene/jsitem/render-basic.snippet.d.ts +0 -15
  432. package/lib/runjs-context/snippets/scene/linkage/set-disabled.snippet.d.ts +0 -15
  433. package/lib/runjs-context/snippets/scene/linkage/set-field-value.snippet.d.ts +0 -15
  434. package/lib/runjs-context/snippets/scene/linkage/set-required.snippet.d.ts +0 -15
  435. package/lib/runjs-context/snippets/scene/linkage/toggle-visible.snippet.d.ts +0 -15
  436. package/src/runjs-context/contexts/FlowRunJSContext.ts +0 -190
  437. package/src/runjs-context/contexts/LinkageRunJSContext.ts +0 -35
  438. package/src/runjs-context/index.ts +0 -20
  439. package/src/runjs-context/snippets/global/api-request-get.snippet.ts +0 -20
  440. package/src/runjs-context/snippets/global/api-request-post.snippet.ts +0 -20
  441. package/src/runjs-context/snippets/global/console-log-ctx.snippet.ts +0 -19
  442. package/src/runjs-context/snippets/global/copy-record-json.snippet.ts +0 -21
  443. package/src/runjs-context/snippets/global/copy-to-clipboard.snippet.ts +0 -21
  444. package/src/runjs-context/snippets/global/log-json-record.snippet.ts +0 -21
  445. package/src/runjs-context/snippets/global/requireAsync.snippet.ts +0 -24
  446. package/src/runjs-context/snippets/global/sleep.snippet.ts +0 -21
  447. package/src/runjs-context/snippets/global/try-catch-async.snippet.ts +0 -22
  448. package/src/runjs-context/snippets/global/view-navigation-push.snippet.ts +0 -23
  449. package/src/runjs-context/snippets/libs/echarts-init.snippet.ts +0 -24
  450. package/src/runjs-context/snippets/scene/actions/record-id-message.snippet.ts +0 -21
  451. package/src/runjs-context/snippets/scene/actions/run-action-basic.snippet.ts +0 -18
  452. package/src/runjs-context/snippets/scene/jsblock/append-style.snippet.ts +0 -20
  453. package/src/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.ts +0 -24
  454. package/src/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.ts +0 -19
  455. package/src/runjs-context/snippets/scene/jsblock/render-basic.snippet.ts +0 -24
  456. package/src/runjs-context/snippets/scene/jsblock/render-button-handler.snippet.ts +0 -24
  457. package/src/runjs-context/snippets/scene/jsblock/render-card.snippet.ts +0 -30
  458. package/src/runjs-context/snippets/scene/jsblock/render-react.snippet.ts +0 -34
  459. package/src/runjs-context/snippets/scene/jsfield/color-by-value.snippet.ts +0 -20
  460. package/src/runjs-context/snippets/scene/jsfield/format-number.snippet.ts +0 -19
  461. package/src/runjs-context/snippets/scene/jsfield/innerHTML-value.snippet.ts +0 -18
  462. /package/lib/runjs-context/snippets/global/{copy-record-json.snippet.d.ts → api-request.snippet.d.ts} +0 -0
  463. /package/lib/runjs-context/snippets/global/{copy-to-clipboard.snippet.d.ts → clipboard-copy-text.snippet.d.ts} +0 -0
  464. /package/lib/runjs-context/snippets/global/{log-json-record.snippet.d.ts → import-esm.snippet.d.ts} +0 -0
  465. /package/lib/runjs-context/snippets/global/{view-navigation-push.snippet.d.ts → query-selector.snippet.d.ts} +0 -0
  466. /package/lib/runjs-context/snippets/scene/{jsblock/render-card.snippet.d.ts → block/echarts-init.snippet.d.ts} +0 -0
@@ -8,7 +8,12 @@
8
8
  */
9
9
 
10
10
  import type { FlowContext, PropertyMeta, PropertyMetaFactory } from '../flowContext';
11
- import { inferRecordRef, buildRecordMeta } from '../utils/variablesParams';
11
+ import { buildRecordMeta, inferViewRecordRef } from '../utils/variablesParams';
12
+ import type { RecordRef } from '../utils/serverContextParams';
13
+ import type { Collection } from '../data-source';
14
+ import type { FlowView } from './FlowView';
15
+
16
+ type PopupModelLike = { getStepParams?: (a: string, b: string) => any } | undefined;
12
17
 
13
18
  // 判断是否为普通对象(Plain Object),避免对类实例/代理等进行深度遍历
14
19
  function isPlainObject(val: any) {
@@ -65,88 +70,57 @@ function makeMetaFromValue(value: any, title?: string, seen?: WeakSet<any>): any
65
70
  return { type: 'any', title };
66
71
  }
67
72
 
68
- function buildNavigationMeta(ctx: FlowContext, getView: () => any): any {
69
- // 与运行时对象保持一致:无 current,仅暴露 viewStack;并动态展开 viewStack 项
70
- const t = (key: string) => (ctx as any)?.t?.(key) || key;
71
- return {
72
- type: 'object',
73
- title: t('导航'),
74
- properties: async () => {
75
- const view = getView();
76
- const nav = view?.navigation;
77
- const props: Record<string, any> = {};
78
-
79
- // 动态 viewStack:按索引展开,并为每个项提供字段
80
- const stack = Array.isArray(nav?.viewStack) ? nav.viewStack : [];
81
- const stackMeta: any = {
82
- type: 'array',
83
- title: t('视图堆栈'),
84
- properties: undefined as Record<string, any> | undefined,
85
- };
86
- if (stack.length) {
87
- const children: Record<string, any> = {};
88
- const max = Math.min(stack.length, 20);
89
- for (let i = 0; i < max; i++) {
90
- const item = stack[i] || {};
91
- children[String(i)] = {
92
- type: 'object',
93
- title: `#${i}`,
94
- properties: {
95
- viewUid: { type: 'string', title: 'viewUid' },
96
- tabUid: { type: 'string', title: 'tabUid' },
97
- filterByTk: { type: 'string', title: 'filterByTk' },
98
- sourceId: { type: 'string', title: 'sourceId' },
99
- },
100
- };
101
- }
102
- stackMeta.properties = children;
103
- }
104
-
105
- props.viewStack = stackMeta;
106
- return props;
107
- },
108
- };
109
- }
110
-
111
73
  /**
112
74
  * Create a meta factory for ctx.view that includes:
113
75
  * - buildVariablesParams: { record } via inferRecordRef
114
76
  * - properties.record: full collection meta via buildRecordMeta
115
77
  * - type/preventClose/inputArgs/navigation fields for better variable selection UX
116
78
  */
117
- export function createViewMeta(ctx: FlowContext, getView: () => any): PropertyMetaFactory {
118
- const viewTitle = (ctx as any)?.t?.('当前视图') || '当前视图';
79
+ export function createViewMeta(ctx: FlowContext): PropertyMetaFactory {
80
+ const viewTitle = ctx.t('当前视图');
119
81
  const factory: PropertyMetaFactory = async () => {
120
- const recordMeta = await buildRecordMeta(
121
- () => {
122
- try {
123
- const ref = inferRecordRef(ctx);
124
- if (!ref?.collection) return null;
125
- const ds = ctx.dataSourceManager?.getDataSource?.(ref.dataSourceKey || 'main');
126
- return ds?.collectionManager?.getCollection?.(ref.collection) || null;
127
- } catch (e) {
128
- return null;
129
- }
130
- },
131
- (ctx as any)?.t?.('当前视图记录') || '当前视图记录',
132
- (c) => inferRecordRef(c),
133
- );
134
-
135
- const view = getView();
82
+ const view = ctx.view;
136
83
  return {
137
84
  type: 'object',
138
- title: viewTitle,
85
+ title: ctx.t('当前视图'),
139
86
  buildVariablesParams: (c) => {
140
- const ref = inferRecordRef(c);
141
- return ref ? { record: ref } : undefined;
87
+ const params = inferViewRecordRef(c);
88
+ if (params) {
89
+ return {
90
+ record: params,
91
+ };
92
+ }
93
+ return undefined;
142
94
  },
143
95
  properties: async () => {
144
96
  const props: Record<string, any> = {};
145
- if (recordMeta) props.record = recordMeta;
146
- props.type = { type: 'string', title: (ctx as any)?.t?.('类型') || '类型' };
147
- props.preventClose = { type: 'boolean', title: (ctx as any)?.t?.('是否允许关闭') || '是否允许关闭' };
148
- props.inputArgs = makeMetaFromValue(view?.inputArgs, (ctx as any)?.t?.('输入参数') || '输入参数');
149
- props.navigation = buildNavigationMeta(ctx, getView);
97
+ // 仅当能推断到当前记录引用时,才暴露“当前视图记录”,避免出现空子菜单
98
+ const refNow = inferViewRecordRef(ctx);
99
+ if (refNow && refNow.collection) {
100
+ const recordFactory: PropertyMetaFactory = async () => {
101
+ try {
102
+ const ref = inferViewRecordRef(ctx);
103
+ if (!ref?.collection) return null;
104
+ const dsKey = ref.dataSourceKey || 'main';
105
+ const ds = ctx.dataSourceManager?.getDataSource?.(dsKey);
106
+ const col = ds?.collectionManager?.getCollection?.(ref.collection);
107
+ if (!col) return null;
108
+ return (await buildRecordMeta(
109
+ () => col,
110
+ ctx.t('当前视图记录'),
111
+ (c) => inferViewRecordRef(c),
112
+ )) as PropertyMeta;
113
+ } catch (e) {
114
+ return null;
115
+ }
116
+ };
117
+ recordFactory.title = ctx.t('当前视图记录');
118
+ recordFactory.hasChildren = true;
119
+ props.record = recordFactory;
120
+ }
121
+ props.type = { type: 'string', title: ctx.t?.('类型') || '类型' };
122
+ props.preventClose = { type: 'boolean', title: ctx.t?.('是否允许关闭') || '是否允许关闭' };
123
+ props.inputArgs = makeMetaFromValue(view?.inputArgs, ctx.t?.('输入参数') || '输入参数');
150
124
  return props;
151
125
  },
152
126
  } as PropertyMeta;
@@ -155,3 +129,352 @@ export function createViewMeta(ctx: FlowContext, getView: () => any): PropertyMe
155
129
  factory.title = viewTitle;
156
130
  return factory;
157
131
  }
132
+
133
+ /**
134
+ * 为 ctx.popup 构建元信息:
135
+ * - popup.record:当前弹窗记录(服务端解析)
136
+ * - popup.resource:数据源信息(前端解析)
137
+ * - popup.parent:上级弹窗(无限级,前端解析;不存在则禁用/为空)
138
+ */
139
+ export function createPopupMeta(ctx: FlowContext, anchorView?: FlowView): PropertyMetaFactory {
140
+ const t = (k: string) => ctx.t(k);
141
+
142
+ // 统一解析锚定视图下的 RecordRef,避免在设置弹窗等二级视图中被误导
143
+ const resolveRecordRef = async (flowCtx: FlowContext): Promise<RecordRef | undefined> => {
144
+ const view = anchorView ?? (flowCtx.view as any);
145
+ if (view) {
146
+ const base = await buildPopupRuntime(flowCtx, view);
147
+ const res = base?.resource;
148
+ if (res?.collectionName && res.filterByTk != null) {
149
+ return {
150
+ collection: res.collectionName,
151
+ dataSourceKey: res.dataSourceKey || 'main',
152
+ filterByTk: res.filterByTk,
153
+ };
154
+ }
155
+ }
156
+ return inferViewRecordRef(flowCtx);
157
+ };
158
+
159
+ const getCurrentCollection = async (): Promise<Collection | null> => {
160
+ const ref = await resolveRecordRef(ctx);
161
+ if (!ref?.collection) return null;
162
+ const ds = ctx.dataSourceManager?.getDataSource?.(ref.dataSourceKey || 'main');
163
+ return ds?.collectionManager?.getCollection?.(ref.collection) || null;
164
+ };
165
+
166
+ // 从视图堆栈推断 level 级父弹窗(level=1 上一层)
167
+ const getParentRecordRef = async (level: number, flowCtx?: FlowContext): Promise<RecordRef | undefined> => {
168
+ try {
169
+ const useCtx = flowCtx || ctx;
170
+ const nav = useCtx.view?.navigation;
171
+ const stack = Array.isArray(nav?.viewStack) ? nav.viewStack : [];
172
+ if (stack.length < 2 || level < 1) return undefined;
173
+ const idx = stack.length - 1 - level;
174
+ if (idx < 0) return undefined;
175
+ const parent = stack[idx];
176
+ if (!parent?.viewUid) return undefined;
177
+
178
+ let model = useCtx.engine?.getModel?.(parent.viewUid) as PopupModelLike;
179
+ if (!model) {
180
+ try {
181
+ model = (await useCtx.engine.loadModel({ uid: parent.viewUid })) as PopupModelLike;
182
+ } catch (e) {
183
+ (useCtx.logger || ctx.logger)?.warn?.({ err: e }, '[FlowEngine] popup.getParentRecordRef loadModel failed');
184
+ }
185
+ }
186
+ const params = model?.getStepParams?.('popupSettings', 'openView') || {};
187
+ const collection = params?.collectionName;
188
+ const dataSourceKey = params?.dataSourceKey || 'main';
189
+ const filterByTk = parent?.filterByTk ?? parent?.sourceId;
190
+ if (!collection || typeof filterByTk === 'undefined' || filterByTk === null) return undefined;
191
+ return { collection, dataSourceKey, filterByTk };
192
+ } catch (e) {
193
+ (flowCtx?.logger || ctx.logger)?.warn?.({ err: e }, '[FlowEngine] popup.getParentRecordRef failed');
194
+ return undefined;
195
+ }
196
+ };
197
+
198
+ const hasParentNow = (level: number): boolean => {
199
+ try {
200
+ const nav = (anchorView ?? ctx.view)?.navigation;
201
+ const stack = Array.isArray(nav?.viewStack) ? nav.viewStack : [];
202
+ return stack.length >= level + 1; // level=1 需要至少2层
203
+ } catch (_) {
204
+ return false;
205
+ }
206
+ };
207
+
208
+ const createParentFactory = (level: number): PropertyMetaFactory => {
209
+ const factory: PropertyMetaFactory = () => {
210
+ const meta: PropertyMeta = {
211
+ type: 'object',
212
+ title: t('Parent popup'),
213
+ disabled: () => !hasParentNow(level),
214
+ disabledReason: () => (!hasParentNow(level) ? t('No parent popup') : undefined),
215
+ properties: async () => {
216
+ const parentRef = await getParentRecordRef(level);
217
+ const props: Record<string, any> = {};
218
+ // 弹窗 UID(纯前端变量)
219
+ props.uid = { type: 'string', title: t('Popup uid') };
220
+
221
+ // 记录分组
222
+ if (parentRef) {
223
+ const parentCollection = (() => {
224
+ try {
225
+ const ds = ctx.dataSourceManager?.getDataSource?.(parentRef.dataSourceKey || 'main');
226
+ return ds?.collectionManager?.getCollection?.(parentRef.collection || '') || null;
227
+ } catch (_) {
228
+ return null;
229
+ }
230
+ })();
231
+ const base = await buildRecordMeta(
232
+ () => parentCollection,
233
+ t('Popup record'),
234
+ () => parentRef,
235
+ );
236
+ props.record = base || { type: 'object', title: t('Popup record') };
237
+ } else {
238
+ props.record = { type: 'object', title: t('Popup record') };
239
+ }
240
+
241
+ // 数据源分组(前端显示用)
242
+ const resourceMeta: PropertyMeta = {
243
+ type: 'object',
244
+ title: t('Data source'),
245
+ properties: async () => ({
246
+ dataSourceKey: { type: 'string', title: t('Data source key') },
247
+ collectionName: { type: 'string', title: t('Collection name') },
248
+ filterByTk: { type: 'string', title: t('filterByTk') },
249
+ sourceId: { type: 'string', title: t('sourceId') },
250
+ }),
251
+ };
252
+ props.resource = resourceMeta;
253
+
254
+ // 不在 "上级弹窗" 节点内继续渲染下一层,以避免列表中出现重复的“上级弹窗”层级
255
+ // 仍然保留运行时值中的 parent.parent... 链(buildPopupRuntime 会构建完整链),
256
+ // 以便用户手动输入时可以访问更深层级。
257
+ return props;
258
+ },
259
+ };
260
+ return meta;
261
+ };
262
+ factory.title = t('Parent popup');
263
+ return factory;
264
+ };
265
+
266
+ const factory: PropertyMetaFactory = () => {
267
+ const meta: PropertyMeta = {
268
+ type: 'object',
269
+ title: t('Current popup'),
270
+ buildVariablesParams: async (c) => {
271
+ const ref = await resolveRecordRef(c);
272
+ const inputArgs = c.view?.inputArgs;
273
+ type PopupVariableParams = {
274
+ record?: RecordRef;
275
+ sourceRecord?: RecordRef;
276
+ parent?: PopupVariableParams;
277
+ };
278
+ const params: PopupVariableParams = {};
279
+ if (ref) params.record = ref;
280
+
281
+ // 构建 parent 链(用于服务端解析 ctx.popup.parent[.parent...].record.*)
282
+ try {
283
+ const nav = c.view?.navigation;
284
+ const stack = Array.isArray(nav?.viewStack) ? nav.viewStack : [];
285
+ if (stack.length >= 2) {
286
+ let cur: Record<string, any> = params;
287
+ let level = 1;
288
+ let parentRef = await getParentRecordRef(level, c);
289
+ while (parentRef) {
290
+ if (!cur.parent) cur.parent = {};
291
+ cur.parent.record = parentRef;
292
+ cur = cur.parent;
293
+ level += 1;
294
+ parentRef = await getParentRecordRef(level, c);
295
+ }
296
+ }
297
+ } catch (err) {
298
+ c.logger?.debug?.({ err }, '[FlowEngine] buildVariablesParams: build parent-chain failed');
299
+ }
300
+
301
+ try {
302
+ const srcId = inputArgs?.sourceId;
303
+ const assoc: string | undefined = inputArgs?.associationName;
304
+ const dsKey: string = inputArgs?.dataSourceKey || 'main';
305
+ if (srcId != null && srcId !== '' && assoc && typeof assoc === 'string') {
306
+ // associationName 形如 `posts.comments`,父级集合为 `posts`
307
+ const parentCollectionName = String(assoc).split('.')[0];
308
+ if (parentCollectionName) {
309
+ params.sourceRecord = {
310
+ collection: parentCollectionName,
311
+ dataSourceKey: dsKey,
312
+ filterByTk: srcId,
313
+ };
314
+ }
315
+ }
316
+ } catch (err) {
317
+ c.logger?.debug?.({ err }, '[FlowEngine] buildVariablesParams: infer sourceRecord failed');
318
+ }
319
+ return params;
320
+ },
321
+ properties: async () => {
322
+ const props: Record<string, any> = {};
323
+ // 当前弹窗 UID(纯前端变量)
324
+ props.uid = { type: 'string', title: t('Popup uid') };
325
+ // 基于锚定视图计算“当前弹窗记录”的集合与 RecordRef
326
+ const recordFactory: PropertyMetaFactory = async () => {
327
+ const col = await getCurrentCollection();
328
+ if (!col) return null;
329
+ return await buildRecordMeta(
330
+ () => col,
331
+ t('Current popup record'),
332
+ (c) => resolveRecordRef(c),
333
+ );
334
+ };
335
+ recordFactory.title = t('Current popup record');
336
+ recordFactory.hasChildren = true;
337
+ props.record = recordFactory;
338
+ // 当 view.inputArgs 带有 sourceId + associationName 时,提供“上级记录”变量(基于 sourceId 推断)
339
+ try {
340
+ const inputArgs = ctx.view?.inputArgs;
341
+ const srcId = inputArgs?.sourceId;
342
+ let assoc: string | undefined = inputArgs?.associationName;
343
+ let dsKey: string = inputArgs?.dataSourceKey || 'main';
344
+
345
+ // 兜底:若 associationName 缺失或不含“.”,尝试从当前视图模型的 openView 参数推断
346
+ if (!assoc || typeof assoc !== 'string' || !assoc.includes('.')) {
347
+ const nav = ctx.view?.navigation;
348
+ const stack = Array.isArray(nav?.viewStack) ? nav.viewStack : [];
349
+ const last = stack?.[stack.length - 1];
350
+ if (last?.viewUid) {
351
+ let model = ctx?.engine?.getModel?.(last.viewUid) as PopupModelLike;
352
+ if (!model) {
353
+ model = (await ctx.engine.loadModel({ uid: last.viewUid })) as PopupModelLike;
354
+ }
355
+ const p = model?.getStepParams?.('popupSettings', 'openView') || {};
356
+ assoc = p?.associationName || assoc;
357
+ dsKey = p?.dataSourceKey || dsKey;
358
+ }
359
+ }
360
+
361
+ if (srcId != null && srcId !== '' && assoc && typeof assoc === 'string') {
362
+ const parentCollectionName = String(assoc).includes('.') ? String(assoc).split('.')[0] : undefined;
363
+ if (parentCollectionName) {
364
+ const parentCollectionAccessor = () => {
365
+ try {
366
+ const ds = ctx.dataSourceManager?.getDataSource?.(dsKey);
367
+ return ds?.collectionManager?.getCollection?.(parentCollectionName) || null;
368
+ } catch (_) {
369
+ return null;
370
+ }
371
+ };
372
+ const srcMeta = await buildRecordMeta(parentCollectionAccessor, t('Current popup parent record'), () => ({
373
+ collection: parentCollectionName,
374
+ dataSourceKey: dsKey,
375
+ filterByTk: srcId,
376
+ }));
377
+ if (srcMeta) {
378
+ props.sourceRecord = srcMeta;
379
+ }
380
+ }
381
+ }
382
+ } catch (err) {
383
+ ctx.logger?.debug?.({ err }, '[FlowEngine] popup.properties: build sourceRecord failed');
384
+ }
385
+ const resourceMeta: PropertyMeta = {
386
+ type: 'object',
387
+ title: t('Data source'),
388
+ properties: async () => ({
389
+ dataSourceKey: { type: 'string', title: t('Data source key') },
390
+ collectionName: { type: 'string', title: t('Collection name') },
391
+ filterByTk: { type: 'string', title: t('filterByTk') },
392
+ sourceId: { type: 'string', title: t('sourceId') },
393
+ }),
394
+ };
395
+ props.resource = resourceMeta;
396
+ // 是否展示“上级弹窗”应依据实际视图层级,而不是简单以配置态隐藏。
397
+ // 当存在父级弹窗(不含当前配置弹窗自身)时,展示“上级弹窗”节点。
398
+ const parentRef1 = await getParentRecordRef(1);
399
+ if (parentRef1) {
400
+ props.parent = createParentFactory(1);
401
+ }
402
+ return props;
403
+ },
404
+ };
405
+ return meta;
406
+ };
407
+ factory.title = t('Current popup');
408
+ factory.sort = 975;
409
+ return factory;
410
+ }
411
+
412
+ /**
413
+ * 根据视图堆栈构建 popup 运行时值(resource + parent 链)
414
+ */
415
+ interface PopupNodeResource {
416
+ dataSourceKey: string;
417
+ collectionName?: string;
418
+ filterByTk?: any;
419
+ sourceId?: any;
420
+ }
421
+
422
+ interface PopupNode {
423
+ uid?: string;
424
+ resource: PopupNodeResource;
425
+ parent?: PopupNode;
426
+ }
427
+
428
+ export async function buildPopupRuntime(ctx: FlowContext, view: FlowView): Promise<PopupNode | undefined> {
429
+ const nav = view?.navigation;
430
+ const stack = Array.isArray(nav?.viewStack) ? nav.viewStack : [];
431
+ const buildNode = async (idx: number): Promise<PopupNode | undefined> => {
432
+ if (idx < 0 || !stack[idx]?.viewUid) return undefined;
433
+ const viewUid = stack[idx].viewUid;
434
+ let model = ctx.engine?.getModel?.(viewUid) as PopupModelLike;
435
+ if (!model) {
436
+ model = (await ctx.engine?.loadModel({ uid: viewUid })) as PopupModelLike;
437
+ }
438
+ const p = model?.getStepParams?.('popupSettings', 'openView') || {};
439
+ const collectionName = p?.collectionName;
440
+ const dataSourceKey = p?.dataSourceKey || 'main';
441
+ const node: PopupNode = {
442
+ uid: viewUid,
443
+ resource: {
444
+ dataSourceKey,
445
+ collectionName,
446
+ filterByTk: stack[idx]?.filterByTk,
447
+ sourceId: stack[idx]?.sourceId,
448
+ },
449
+ };
450
+ const parentNode = await buildNode(idx - 1);
451
+ if (parentNode) node.parent = parentNode;
452
+ return node;
453
+ };
454
+ const currentNode = await buildNode((view?.navigation?.viewStack?.length || 1) - 1);
455
+ return currentNode;
456
+ }
457
+
458
+ /**
459
+ * 在视图上下文中注册 popup 变量(统一消除重复)
460
+ */
461
+ export function registerPopupVariable(ctx: FlowContext, view: FlowView) {
462
+ // - 顶层 record / sourceRecord 及其子字段
463
+ // - 任意层级 parent.parent... 下的 record / sourceRecord 及其子字段
464
+ const POPUP_SERVER_PATH_RE =
465
+ /^(?:record|sourceRecord)(?:\.|$)|^parent(?:\.parent)*(?:\.(?:record|sourceRecord))(?:\.|$)/;
466
+ // 始终注册 popup 变量:
467
+ // - 若当前视图无可推断记录,仅在元信息中不呈现 record 字段;
468
+ // - 但仍可依据 navigation 推断并展示上级弹窗信息。
469
+ ctx.defineProperty('popup', {
470
+ get: async () => buildPopupRuntime(ctx, view),
471
+ meta: createPopupMeta(ctx, view),
472
+ resolveOnServer: (p: string) => {
473
+ try {
474
+ return !!p && POPUP_SERVER_PATH_RE.test(p);
475
+ } catch (_) {
476
+ return false;
477
+ }
478
+ },
479
+ });
480
+ }
@@ -12,3 +12,4 @@ export { useDrawer } from './useDrawer';
12
12
  export { usePage } from './usePage';
13
13
  export { usePopover } from './usePopover';
14
14
  export { ViewNavigation } from './ViewNavigation';
15
+ export { createViewMeta } from './createViewMeta';
@@ -12,11 +12,12 @@ import DOMPurify from 'dompurify';
12
12
  import { observer } from '..';
13
13
  import { FlowContext } from '../flowContext';
14
14
  import { FlowViewContextProvider } from '../FlowContextProvider';
15
- import { createViewMeta } from './createViewMeta';
15
+ import { registerPopupVariable } from './createViewMeta';
16
16
  import DialogComponent from './DialogComponent';
17
17
  import usePatchElement from './usePatchElement';
18
18
  import { FlowEngineProvider } from '../provider';
19
19
  import { createViewScopedEngine } from '../ViewScopedFlowEngine';
20
+ import { createViewRecordResolveOnServer, getViewRecordFromParent } from '../utils/variablesParams';
20
21
 
21
22
  let uuid = 0;
22
23
 
@@ -44,7 +45,7 @@ export function useDialog() {
44
45
  let currentHeader: any = null;
45
46
 
46
47
  // Footer 组件实现
47
- const FooterComponent = ({ children, ...props }) => {
48
+ const FooterComponent: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
48
49
  React.useEffect(() => {
49
50
  currentFooter = children;
50
51
  dialogRef.current?.setFooter(children);
@@ -59,10 +60,10 @@ export function useDialog() {
59
60
  };
60
61
 
61
62
  // Header 组件实现
62
- const HeaderComponent = ({ ...props }) => {
63
+ const HeaderComponent: React.FC<{ title?: React.ReactNode; extra?: React.ReactNode }> = (props) => {
63
64
  React.useEffect(() => {
64
65
  currentHeader = props;
65
- dialogRef.current?.setHeader(props as any);
66
+ dialogRef.current?.setHeader(props);
66
67
 
67
68
  return () => {
68
69
  currentHeader = null;
@@ -73,9 +74,20 @@ export function useDialog() {
73
74
  return null; // Header 组件本身不渲染内容
74
75
  };
75
76
 
77
+ const ctx = new FlowContext();
78
+ // 为当前视图创建作用域引擎(隔离实例与缓存)
79
+ const scopedEngine = createViewScopedEngine(flowContext.engine);
80
+ ctx.defineProperty('engine', { value: scopedEngine });
81
+ ctx.addDelegate(scopedEngine.context);
82
+ if (config.inheritContext !== false) {
83
+ ctx.addDelegate(flowContext);
84
+ } else {
85
+ ctx.addDelegate(flowContext.engine.context);
86
+ }
87
+
76
88
  // 构造 currentDialog 实例
77
89
  const currentDialog = {
78
- type: 'dialog',
90
+ type: 'dialog' as const,
79
91
  inputArgs: config.inputArgs || {},
80
92
  preventClose: !!config.preventClose,
81
93
  destroy: () => dialogRef.current?.destroy(),
@@ -99,24 +111,18 @@ export function useDialog() {
99
111
  dialogRef.current?.setHeader(header);
100
112
  },
101
113
  navigation: config.inputArgs?.navigation,
114
+ get record() {
115
+ return getViewRecordFromParent(flowContext, ctx);
116
+ },
102
117
  };
103
118
 
104
- const ctx = new FlowContext();
105
119
  ctx.defineProperty('view', {
106
120
  get: () => currentDialog,
107
- meta: createViewMeta(ctx, () => currentDialog),
108
- resolveOnServer: (p: string) => p === 'record' || p.startsWith('record.'),
121
+ // meta: createViewMeta(ctx),
122
+ resolveOnServer: createViewRecordResolveOnServer(ctx, () => getViewRecordFromParent(flowContext, ctx)),
109
123
  });
110
- // 为当前视图创建作用域引擎(隔离实例与缓存)
111
- const scopedEngine = createViewScopedEngine(flowContext.engine);
112
- ctx.defineProperty('engine', { value: scopedEngine });
113
- ctx.addDelegate(scopedEngine.context);
114
- if (config.inheritContext !== false) {
115
- ctx.addDelegate(flowContext);
116
- } else {
117
- ctx.addDelegate(flowContext.engine.context);
118
- }
119
-
124
+ // 顶层 popup 变量:弹窗记录/数据源/上级弹窗链(去重封装)
125
+ registerPopupVariable(ctx, currentDialog);
120
126
  // 内部组件,在 Provider 内部计算 content
121
127
  const DialogWithContext = observer(
122
128
  () => {