@nocobase/flow-engine 2.0.0-alpha.7 → 2.0.0-alpha.71

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 (589) hide show
  1. package/lib/BlockScopedFlowEngine.d.ts +23 -0
  2. package/lib/BlockScopedFlowEngine.js +91 -0
  3. package/lib/FlowContextProvider.d.ts +2 -2
  4. package/lib/FlowContextProvider.js +3 -3
  5. package/lib/FlowDefinition.d.ts +6 -4
  6. package/lib/JSRunner.d.ts +6 -0
  7. package/lib/JSRunner.js +27 -1
  8. package/lib/ViewScopedFlowEngine.d.ts +1 -1
  9. package/lib/ViewScopedFlowEngine.js +18 -1
  10. package/lib/acl/Acl.d.ts +12 -12
  11. package/lib/acl/Acl.js +88 -30
  12. package/lib/components/DynamicFlowsEditor.js +2 -4
  13. package/lib/components/FieldModelRenderer.js +17 -9
  14. package/lib/components/FieldSkeleton.d.ts +10 -0
  15. package/lib/components/FieldSkeleton.js +64 -0
  16. package/lib/components/FlowContextSelector.js +19 -3
  17. package/lib/components/FlowModelRenderer.d.ts +4 -6
  18. package/lib/components/FlowModelRenderer.js +35 -53
  19. package/lib/components/FormItem.js +5 -1
  20. package/lib/components/MobilePopup.d.ts +20 -0
  21. package/lib/components/MobilePopup.js +102 -0
  22. package/lib/components/MobilePopup.style.d.ts +17 -0
  23. package/lib/components/MobilePopup.style.js +186 -0
  24. package/lib/components/common/withFlowDesignMode.d.ts +1 -1
  25. package/lib/components/common/withFlowDesignMode.js +5 -5
  26. package/lib/components/dnd/gridDragPlanner.d.ts +1 -0
  27. package/lib/components/dnd/gridDragPlanner.js +53 -1
  28. package/lib/components/index.d.ts +1 -0
  29. package/lib/components/index.js +3 -1
  30. package/lib/components/settings/independents/dropdown/FlowsDropdownButton.js +71 -53
  31. package/lib/components/settings/wrappers/component/SelectWithTitle.d.ts +19 -0
  32. package/lib/components/settings/wrappers/component/SelectWithTitle.js +136 -0
  33. package/lib/components/settings/wrappers/component/SwitchWithTitle.d.ts +10 -0
  34. package/lib/components/settings/wrappers/component/SwitchWithTitle.js +111 -0
  35. package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +233 -97
  36. package/lib/components/settings/wrappers/contextual/FlowsContextMenu.js +71 -54
  37. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.d.ts +2 -2
  38. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +63 -23
  39. package/lib/components/settings/wrappers/contextual/StepSettingsDialog.js +13 -2
  40. package/lib/components/settings/wrappers/embedded/FlowSettings.js +42 -28
  41. package/lib/components/settings/wrappers/embedded/FlowsSettings.js +3 -3
  42. package/lib/components/settings/wrappers/embedded/FlowsSettingsContent.js +52 -32
  43. package/lib/components/subModel/AddSubModelButton.d.ts +7 -0
  44. package/lib/components/subModel/AddSubModelButton.js +78 -8
  45. package/lib/components/subModel/LazyDropdown.js +14 -15
  46. package/lib/components/subModel/utils.d.ts +1 -1
  47. package/lib/components/subModel/utils.js +21 -11
  48. package/lib/components/variables/VariableInput.js +26 -6
  49. package/lib/components/variables/VariableTag.js +43 -2
  50. package/lib/components/variables/types.d.ts +2 -0
  51. package/lib/components/variables/utils.js +4 -2
  52. package/lib/data-source/index.d.ts +23 -4
  53. package/lib/data-source/index.js +135 -14
  54. package/lib/data-source/jioToJoiSchema.js +1 -0
  55. package/lib/emitter.d.ts +6 -0
  56. package/lib/emitter.js +12 -0
  57. package/lib/executor/FlowExecutor.d.ts +6 -6
  58. package/lib/executor/FlowExecutor.js +302 -99
  59. package/lib/flow-registry/GlobalFlowRegistry.d.ts +1 -0
  60. package/lib/flow-registry/GlobalFlowRegistry.js +3 -0
  61. package/lib/flow-registry/InstanceFlowRegistry.d.ts +1 -0
  62. package/lib/flow-registry/InstanceFlowRegistry.js +3 -0
  63. package/lib/flowContext.d.ts +105 -6
  64. package/lib/flowContext.js +447 -139
  65. package/lib/flowEngine.d.ts +71 -1
  66. package/lib/flowEngine.js +319 -16
  67. package/lib/flowSettings.d.ts +4 -3
  68. package/lib/flowSettings.js +45 -21
  69. package/lib/hooks/useApplyAutoFlows.d.ts +1 -0
  70. package/lib/hooks/useApplyAutoFlows.js +3 -2
  71. package/lib/index.d.ts +14 -3
  72. package/lib/index.js +54 -7
  73. package/lib/locale/de-DE.json +62 -0
  74. package/lib/locale/en-US.json +57 -45
  75. package/lib/locale/es-ES.json +62 -0
  76. package/lib/locale/fr-FR.json +62 -0
  77. package/lib/locale/hu-HU.json +62 -0
  78. package/lib/locale/id-ID.json +62 -0
  79. package/lib/locale/index.d.ts +114 -90
  80. package/lib/locale/it-IT.json +62 -0
  81. package/lib/locale/ja-JP.json +62 -0
  82. package/lib/locale/ko-KR.json +62 -0
  83. package/lib/locale/nl-NL.json +62 -0
  84. package/lib/locale/pt-BR.json +62 -0
  85. package/lib/locale/ru-RU.json +62 -0
  86. package/lib/locale/tr-TR.json +62 -0
  87. package/lib/locale/uk-UA.json +62 -0
  88. package/lib/locale/vi-VN.json +62 -0
  89. package/lib/locale/zh-CN.json +58 -46
  90. package/lib/locale/zh-TW.json +62 -0
  91. package/lib/models/CollectionFieldModel.d.ts +7 -2
  92. package/lib/models/CollectionFieldModel.js +63 -16
  93. package/lib/models/flowModel.d.ts +76 -32
  94. package/lib/models/flowModel.js +300 -112
  95. package/lib/models/forkFlowModel.d.ts +8 -4
  96. package/lib/models/forkFlowModel.js +38 -8
  97. package/lib/provider.d.ts +3 -1
  98. package/lib/provider.js +14 -11
  99. package/lib/reactive/index.d.ts +10 -0
  100. package/lib/{runjs-context/snippets/global/api-request-post.snippet.js → reactive/index.js} +14 -15
  101. package/lib/reactive/observer.d.ts +19 -0
  102. package/lib/reactive/observer.js +109 -0
  103. package/lib/resources/baseRecordResource.d.ts +6 -0
  104. package/lib/resources/baseRecordResource.js +38 -3
  105. package/lib/resources/multiRecordResource.d.ts +5 -2
  106. package/lib/resources/multiRecordResource.js +26 -10
  107. package/lib/resources/singleRecordResource.js +8 -3
  108. package/lib/resources/sqlResource.d.ts +5 -3
  109. package/lib/resources/sqlResource.js +30 -28
  110. package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.d.ts +1 -6
  111. package/lib/runjs-context/contexts/FormJSFieldItemRunJSContext.js +37 -20
  112. package/lib/runjs-context/contexts/JSBlockRunJSContext.d.ts +1 -6
  113. package/lib/runjs-context/contexts/JSBlockRunJSContext.js +46 -33
  114. package/lib/runjs-context/contexts/JSCollectionActionRunJSContext.d.ts +1 -2
  115. package/lib/runjs-context/contexts/JSCollectionActionRunJSContext.js +14 -15
  116. package/lib/runjs-context/contexts/{LinkageRunJSContext.d.ts → JSColumnRunJSContext.d.ts} +6 -3
  117. package/lib/runjs-context/contexts/JSColumnRunJSContext.js +78 -0
  118. package/lib/runjs-context/contexts/JSEditableFieldRunJSContext.d.ts +16 -0
  119. package/lib/runjs-context/contexts/JSEditableFieldRunJSContext.js +125 -0
  120. package/lib/runjs-context/contexts/JSFieldRunJSContext.d.ts +1 -6
  121. package/lib/runjs-context/contexts/JSFieldRunJSContext.js +28 -24
  122. package/lib/runjs-context/contexts/JSItemRunJSContext.d.ts +1 -6
  123. package/lib/runjs-context/contexts/JSItemRunJSContext.js +34 -20
  124. package/lib/runjs-context/contexts/JSRecordActionRunJSContext.d.ts +1 -2
  125. package/lib/runjs-context/contexts/JSRecordActionRunJSContext.js +16 -17
  126. package/lib/runjs-context/contexts/base.d.ts +9 -0
  127. package/lib/runjs-context/contexts/base.js +879 -0
  128. package/lib/runjs-context/contributions.d.ts +33 -0
  129. package/lib/runjs-context/contributions.js +88 -0
  130. package/lib/runjs-context/helpers.d.ts +5 -2
  131. package/lib/runjs-context/helpers.js +36 -27
  132. package/lib/runjs-context/registry.d.ts +7 -4
  133. package/lib/runjs-context/registry.js +10 -42
  134. package/lib/runjs-context/setup.d.ts +9 -0
  135. package/lib/runjs-context/setup.js +88 -0
  136. package/lib/runjs-context/snippets/global/{copy-record-json.snippet.js → api-request.snippet.js} +25 -10
  137. package/lib/runjs-context/snippets/global/clipboard-copy-text.snippet.js +61 -0
  138. package/lib/runjs-context/snippets/global/{view-navigation-push.snippet.js → import-esm.snippet.js} +26 -12
  139. package/lib/runjs-context/snippets/global/message-error.snippet.js +6 -0
  140. package/lib/runjs-context/snippets/global/message-success.snippet.js +6 -0
  141. package/lib/runjs-context/snippets/global/notification-open.snippet.d.ts +3 -8
  142. package/lib/runjs-context/snippets/global/notification-open.snippet.js +8 -1
  143. package/lib/runjs-context/snippets/global/open-view-dialog.snippet.js +10 -3
  144. package/lib/runjs-context/snippets/global/open-view-drawer.snippet.js +10 -3
  145. package/lib/runjs-context/snippets/global/query-selector.snippet.js +53 -0
  146. package/lib/runjs-context/snippets/global/require-amd.snippet.d.ts +11 -0
  147. package/lib/runjs-context/snippets/global/{requireAsync.snippet.js → require-amd.snippet.js} +16 -13
  148. package/lib/runjs-context/snippets/global/window-open.snippet.d.ts +3 -8
  149. package/lib/runjs-context/snippets/global/window-open.snippet.js +8 -1
  150. package/lib/runjs-context/snippets/index.d.ts +24 -3
  151. package/lib/runjs-context/snippets/index.js +183 -40
  152. package/lib/runjs-context/snippets/scene/block/add-event-listener.snippet.d.ts +11 -0
  153. package/lib/runjs-context/snippets/scene/{jsblock → block}/add-event-listener.snippet.js +11 -2
  154. package/lib/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.d.ts +11 -0
  155. package/lib/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.js +64 -0
  156. package/lib/runjs-context/snippets/scene/block/chartjs-bar.snippet.d.ts +11 -0
  157. package/lib/runjs-context/snippets/scene/block/chartjs-bar.snippet.js +99 -0
  158. package/lib/runjs-context/snippets/{libs → scene/block}/echarts-init.snippet.js +24 -7
  159. package/lib/runjs-context/snippets/scene/block/render-antd-icons.snippet.d.ts +11 -0
  160. package/lib/runjs-context/snippets/scene/block/render-antd-icons.snippet.js +65 -0
  161. package/lib/runjs-context/snippets/scene/block/render-button-handler.snippet.d.ts +11 -0
  162. package/lib/runjs-context/snippets/scene/{jsblock → block}/render-button-handler.snippet.js +17 -9
  163. package/lib/runjs-context/snippets/scene/block/render-iframe.snippet.d.ts +11 -0
  164. package/lib/runjs-context/snippets/scene/block/render-iframe.snippet.js +57 -0
  165. package/lib/runjs-context/snippets/scene/block/render-info-card.snippet.d.ts +11 -0
  166. package/lib/runjs-context/snippets/scene/block/render-info-card.snippet.js +71 -0
  167. package/lib/runjs-context/snippets/scene/block/render-react-jsx.snippet.d.ts +11 -0
  168. package/lib/runjs-context/snippets/scene/{jsblock/render-card.snippet.js → block/render-react-jsx.snippet.js} +26 -13
  169. package/lib/runjs-context/snippets/scene/block/render-react.snippet.d.ts +11 -0
  170. package/lib/runjs-context/snippets/scene/{jsblock → block}/render-react.snippet.js +18 -17
  171. package/lib/runjs-context/snippets/scene/block/render-statistics.snippet.d.ts +11 -0
  172. package/lib/runjs-context/snippets/scene/block/render-statistics.snippet.js +95 -0
  173. package/lib/runjs-context/snippets/scene/block/render-timeline.snippet.d.ts +11 -0
  174. package/lib/runjs-context/snippets/scene/block/render-timeline.snippet.js +84 -0
  175. package/lib/runjs-context/snippets/scene/block/resource-example.snippet.d.ts +11 -0
  176. package/lib/runjs-context/snippets/scene/block/resource-example.snippet.js +60 -0
  177. package/lib/runjs-context/snippets/scene/block/three-users-orbit.snippet.d.ts +11 -0
  178. package/lib/runjs-context/snippets/scene/block/three-users-orbit.snippet.js +283 -0
  179. package/lib/runjs-context/snippets/scene/block/vue-component.snippet.d.ts +11 -0
  180. package/lib/runjs-context/snippets/scene/block/vue-component.snippet.js +124 -0
  181. package/lib/runjs-context/snippets/scene/detail/color-by-value.snippet.d.ts +11 -0
  182. package/lib/runjs-context/snippets/scene/{jsfield → detail}/color-by-value.snippet.js +13 -3
  183. package/lib/runjs-context/snippets/scene/detail/copy-to-clipboard.snippet.d.ts +11 -0
  184. package/lib/runjs-context/snippets/{global → scene/detail}/copy-to-clipboard.snippet.js +28 -6
  185. package/lib/runjs-context/snippets/scene/detail/format-number.snippet.d.ts +11 -0
  186. package/lib/runjs-context/snippets/scene/{jsfield → detail}/format-number.snippet.js +13 -3
  187. package/lib/runjs-context/snippets/scene/detail/innerHTML-value.snippet.d.ts +11 -0
  188. package/lib/runjs-context/snippets/scene/{jsfield → detail}/innerHTML-value.snippet.js +13 -3
  189. package/lib/runjs-context/snippets/scene/detail/percentage-bar.snippet.d.ts +11 -0
  190. package/lib/runjs-context/snippets/scene/detail/percentage-bar.snippet.js +82 -0
  191. package/lib/runjs-context/snippets/scene/detail/relative-time.snippet.d.ts +11 -0
  192. package/lib/runjs-context/snippets/scene/detail/relative-time.snippet.js +80 -0
  193. package/lib/runjs-context/snippets/scene/detail/status-tag.snippet.d.ts +11 -0
  194. package/lib/runjs-context/snippets/scene/detail/status-tag.snippet.js +74 -0
  195. package/lib/runjs-context/snippets/scene/form/calculate-total.snippet.d.ts +11 -0
  196. package/lib/runjs-context/snippets/scene/form/calculate-total.snippet.js +63 -0
  197. package/lib/runjs-context/snippets/scene/form/cascade-select.snippet.d.ts +11 -0
  198. package/lib/runjs-context/snippets/scene/form/cascade-select.snippet.js +81 -0
  199. package/lib/runjs-context/snippets/scene/form/conditional-required.snippet.d.ts +11 -0
  200. package/lib/runjs-context/snippets/scene/form/conditional-required.snippet.js +64 -0
  201. package/lib/runjs-context/snippets/scene/form/copy-field-values.snippet.d.ts +11 -0
  202. package/lib/runjs-context/snippets/scene/form/copy-field-values.snippet.js +74 -0
  203. package/lib/runjs-context/snippets/scene/form/render-basic.snippet.d.ts +11 -0
  204. package/lib/runjs-context/snippets/scene/{jsitem → form}/render-basic.snippet.js +11 -2
  205. package/lib/runjs-context/snippets/scene/form/set-disabled.snippet.d.ts +11 -0
  206. package/lib/runjs-context/snippets/scene/{linkage → form}/set-disabled.snippet.js +12 -3
  207. package/lib/runjs-context/snippets/scene/form/set-field-value.snippet.d.ts +11 -0
  208. package/lib/runjs-context/snippets/scene/{linkage → form}/set-field-value.snippet.js +12 -3
  209. package/lib/runjs-context/snippets/scene/form/set-required.snippet.d.ts +11 -0
  210. package/lib/runjs-context/snippets/scene/{linkage → form}/set-required.snippet.js +12 -3
  211. package/lib/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.d.ts +11 -0
  212. package/lib/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.js +67 -0
  213. package/lib/runjs-context/snippets/scene/form/toggle-visible.snippet.d.ts +11 -0
  214. package/lib/runjs-context/snippets/scene/{linkage → form}/toggle-visible.snippet.js +12 -3
  215. package/lib/runjs-context/snippets/scene/table/cell-open-dialog.snippet.d.ts +11 -0
  216. package/lib/runjs-context/snippets/scene/table/cell-open-dialog.snippet.js +64 -0
  217. package/lib/runjs-context/snippets/scene/table/collection-selected-count.snippet.d.ts +11 -0
  218. package/lib/runjs-context/snippets/scene/{actions → table}/collection-selected-count.snippet.js +11 -2
  219. package/lib/runjs-context/snippets/scene/table/concat-fields.snippet.d.ts +11 -0
  220. package/lib/runjs-context/snippets/scene/table/concat-fields.snippet.js +79 -0
  221. package/lib/runjs-context/snippets/scene/table/destroy-selected.snippet.d.ts +11 -0
  222. package/lib/runjs-context/snippets/{global/log-json-record.snippet.js → scene/table/destroy-selected.snippet.js} +24 -11
  223. package/lib/runjs-context/snippets/scene/table/export-selected-json.snippet.d.ts +11 -0
  224. package/lib/runjs-context/snippets/scene/table/export-selected-json.snippet.js +64 -0
  225. package/lib/runjs-context/snippets/scene/table/iterate-selected-rows.snippet.d.ts +11 -0
  226. package/lib/runjs-context/snippets/scene/{actions → table}/iterate-selected-rows.snippet.js +11 -2
  227. package/lib/runjs-context/snippets/types.d.ts +9 -1
  228. package/lib/runjsLibs.d.ts +28 -0
  229. package/lib/runjsLibs.js +532 -0
  230. package/lib/scheduler/ModelOperationScheduler.d.ts +53 -0
  231. package/lib/scheduler/ModelOperationScheduler.js +262 -0
  232. package/lib/types.d.ts +66 -7
  233. package/lib/types.js +4 -3
  234. package/lib/utils/associationObjectVariable.d.ts +32 -0
  235. package/lib/utils/associationObjectVariable.js +157 -0
  236. package/lib/utils/createCollectionContextMeta.d.ts +1 -1
  237. package/lib/utils/createCollectionContextMeta.js +9 -4
  238. package/lib/utils/createEphemeralContext.d.ts +13 -0
  239. package/lib/utils/createEphemeralContext.js +140 -0
  240. package/lib/utils/flows.d.ts +10 -0
  241. package/lib/{runjs-context/snippets/global/console-log-ctx.snippet.js → utils/flows.js} +21 -14
  242. package/lib/utils/index.d.ts +9 -3
  243. package/lib/utils/index.js +30 -2
  244. package/lib/utils/jsxTransform.d.ts +15 -0
  245. package/lib/utils/jsxTransform.js +68 -0
  246. package/lib/utils/params-resolvers.js +19 -12
  247. package/lib/utils/parsePathnameToViewParams.d.ts +1 -1
  248. package/lib/utils/parsePathnameToViewParams.js +41 -5
  249. package/lib/utils/pruneFilter.d.ts +21 -0
  250. package/lib/{runjs-context/snippets/global/try-catch-async.snippet.js → utils/pruneFilter.js} +24 -16
  251. package/lib/utils/resolveModuleUrl.d.ts +58 -0
  252. package/lib/utils/resolveModuleUrl.js +65 -0
  253. package/lib/utils/runjsModuleLoader.d.ts +58 -0
  254. package/lib/utils/runjsModuleLoader.js +422 -0
  255. package/lib/utils/runjsTemplateCompat.d.ts +35 -0
  256. package/lib/utils/runjsTemplateCompat.js +743 -0
  257. package/lib/utils/safeGlobals.d.ts +6 -8
  258. package/lib/utils/safeGlobals.js +169 -14
  259. package/lib/utils/schema-utils.d.ts +6 -0
  260. package/lib/utils/schema-utils.js +71 -6
  261. package/lib/utils/serverContextParams.d.ts +4 -0
  262. package/lib/utils/serverContextParams.js +2 -0
  263. package/lib/utils/translation.d.ts +4 -1
  264. package/lib/utils/translation.js +6 -2
  265. package/lib/utils/variablesParams.d.ts +22 -5
  266. package/lib/utils/variablesParams.js +141 -61
  267. package/lib/views/DialogComponent.js +1 -5
  268. package/lib/views/DrawerComponent.js +18 -9
  269. package/lib/views/PageComponent.js +5 -5
  270. package/lib/views/ViewNavigation.d.ts +11 -15
  271. package/lib/views/ViewNavigation.js +37 -19
  272. package/lib/views/createViewMeta.d.ts +27 -5
  273. package/lib/views/createViewMeta.js +338 -72
  274. package/lib/views/index.d.ts +1 -1
  275. package/lib/views/index.js +4 -0
  276. package/lib/views/useDialog.d.ts +10 -9
  277. package/lib/views/useDialog.js +46 -34
  278. package/lib/views/useDrawer.d.ts +10 -9
  279. package/lib/views/useDrawer.js +74 -48
  280. package/lib/views/usePage.d.ts +14 -9
  281. package/lib/views/usePage.js +82 -33
  282. package/lib/views/usePopover.js +4 -1
  283. package/lib/views/viewEvents.d.ts +17 -0
  284. package/lib/views/viewEvents.js +90 -0
  285. package/package.json +6 -3
  286. package/src/BlockScopedFlowEngine.ts +85 -0
  287. package/src/FlowContextProvider.tsx +4 -2
  288. package/src/JSRunner.ts +39 -1
  289. package/src/ViewScopedFlowEngine.ts +21 -1
  290. package/src/__tests__/JSRunner.test.ts +125 -52
  291. package/src/__tests__/blockScopedFlowEngine.test.ts +154 -0
  292. package/src/__tests__/createViewMeta.popup.test.ts +203 -0
  293. package/src/__tests__/flow-engine.test.ts +3 -0
  294. package/src/__tests__/flowContext.test.ts +160 -0
  295. package/src/__tests__/flowContextCreateJSRunner.test.ts +163 -0
  296. package/src/__tests__/flowEngine.dataSourceDirty.test.ts +63 -0
  297. package/src/__tests__/flowEngine.destroyModel.test.ts +74 -0
  298. package/src/__tests__/flowEngine.moveModel.test.ts +43 -0
  299. package/src/__tests__/flowEngine.removeModel.test.ts +72 -0
  300. package/src/__tests__/flowEngine.saveModel.test.ts +4 -0
  301. package/src/__tests__/flowModel.openView.navigation.test.ts +31 -2
  302. package/src/__tests__/flowRunJSContextDefine.test.ts +508 -0
  303. package/src/__tests__/flowSettings.open.test.tsx +71 -15
  304. package/src/__tests__/flowSettings.test.ts +2 -0
  305. package/src/__tests__/globalFlowRegistry.test.ts +1 -1
  306. package/src/__tests__/modelOperationScheduler.test.ts +346 -0
  307. package/src/__tests__/objectVariable.test.ts +464 -0
  308. package/src/__tests__/provider.test.tsx +0 -5
  309. package/src/__tests__/runjsContext.test.ts +219 -35
  310. package/src/__tests__/runjsContextImplementations.test.ts +217 -0
  311. package/src/__tests__/runjsContextRuntime.test.ts +269 -0
  312. package/src/__tests__/runjsEdgeCases.test.ts +281 -0
  313. package/src/__tests__/runjsExternalLibs.test.ts +242 -0
  314. package/src/__tests__/runjsLibsLazyLoading.test.ts +44 -0
  315. package/src/__tests__/runjsLocales.test.ts +39 -0
  316. package/src/__tests__/runjsPreprocessDefault.test.ts +49 -0
  317. package/src/__tests__/runjsRuntimeFeatures.test.ts +461 -0
  318. package/src/__tests__/runjsSnippets.test.ts +140 -0
  319. package/src/__tests__/viewScopedFlowEngine.test.ts +101 -3
  320. package/src/acl/Acl.tsx +85 -31
  321. package/src/acl/__tests__/Acl.test.tsx +43 -1
  322. package/src/components/DynamicFlowsEditor.tsx +0 -10
  323. package/src/components/FieldModelRenderer.tsx +22 -9
  324. package/src/components/FieldSkeleton.tsx +27 -0
  325. package/src/components/FlowContextSelector.tsx +20 -2
  326. package/src/components/FlowModelRenderer.tsx +52 -84
  327. package/src/components/FormItem.tsx +8 -1
  328. package/src/components/MobilePopup.style.ts +220 -0
  329. package/src/components/MobilePopup.tsx +86 -0
  330. package/src/components/__tests__/FlowModelRenderer.test.tsx +89 -0
  331. package/src/components/__tests__/flow-model-render-error-fallback.test.tsx +6 -6
  332. package/src/components/__tests__/gridDragPlanner.test.ts +141 -1
  333. package/src/components/common/withFlowDesignMode.tsx +5 -5
  334. package/src/components/dnd/gridDragPlanner.ts +60 -0
  335. package/src/components/index.ts +1 -0
  336. package/src/components/settings/independents/dropdown/FlowsDropdownButton.tsx +34 -17
  337. package/src/components/settings/wrappers/component/SelectWithTitle.tsx +110 -0
  338. package/src/components/settings/wrappers/component/SwitchWithTitle.tsx +83 -0
  339. package/src/components/settings/wrappers/component/__tests__/InlineControls.test.tsx +74 -0
  340. package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +272 -125
  341. package/src/components/settings/wrappers/contextual/FlowsContextMenu.tsx +34 -18
  342. package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +56 -18
  343. package/src/components/settings/wrappers/contextual/StepSettings.tsx +1 -2
  344. package/src/components/settings/wrappers/contextual/StepSettingsDialog.tsx +13 -1
  345. package/src/components/settings/wrappers/contextual/__tests__/DefaultSettingsIcon.test.tsx +624 -0
  346. package/src/components/settings/wrappers/embedded/FlowSettings.tsx +47 -35
  347. package/src/components/settings/wrappers/embedded/FlowsSettings.tsx +1 -1
  348. package/src/components/settings/wrappers/embedded/FlowsSettingsContent.tsx +64 -42
  349. package/src/components/subModel/AddSubModelButton.tsx +104 -9
  350. package/src/components/subModel/LazyDropdown.tsx +14 -14
  351. package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +168 -7
  352. package/src/components/subModel/__tests__/utils.test.ts +12 -12
  353. package/src/components/subModel/utils.ts +25 -6
  354. package/src/components/variables/VariableInput.tsx +32 -6
  355. package/src/components/variables/VariableTag.tsx +54 -2
  356. package/src/components/variables/types.ts +2 -0
  357. package/src/components/variables/utils.ts +7 -3
  358. package/src/data-source/index.ts +143 -12
  359. package/src/data-source/jioToJoiSchema.ts +1 -0
  360. package/src/emitter.ts +14 -0
  361. package/src/executor/FlowExecutor.ts +383 -119
  362. package/src/executor/__tests__/ctx-defs-injection.test.ts +197 -0
  363. package/src/executor/__tests__/flowExecutor.test.ts +217 -5
  364. package/src/flow-registry/GlobalFlowRegistry.ts +1 -0
  365. package/src/flow-registry/InstanceFlowRegistry.ts +1 -0
  366. package/src/flow-registry/__tests__/globalFlowRegistry.test.ts +54 -0
  367. package/src/flowContext.ts +646 -158
  368. package/src/flowEngine.ts +385 -14
  369. package/src/flowSettings.ts +59 -30
  370. package/src/hooks/useApplyAutoFlows.ts +5 -3
  371. package/src/index.ts +26 -3
  372. package/src/locale/de-DE.json +62 -0
  373. package/src/locale/en-US.json +57 -45
  374. package/src/locale/es-ES.json +62 -0
  375. package/src/locale/fr-FR.json +62 -0
  376. package/src/locale/hu-HU.json +62 -0
  377. package/src/locale/id-ID.json +62 -0
  378. package/src/locale/it-IT.json +62 -0
  379. package/src/locale/ja-JP.json +62 -0
  380. package/src/locale/ko-KR.json +62 -0
  381. package/src/locale/nl-NL.json +62 -0
  382. package/src/locale/pt-BR.json +62 -0
  383. package/src/locale/ru-RU.json +62 -0
  384. package/src/locale/tr-TR.json +62 -0
  385. package/src/locale/uk-UA.json +62 -0
  386. package/src/locale/vi-VN.json +62 -0
  387. package/src/locale/zh-CN.json +58 -46
  388. package/src/locale/zh-TW.json +62 -0
  389. package/src/models/CollectionFieldModel.tsx +82 -18
  390. package/src/models/__tests__/dispatchEvent.behavior.test.ts +169 -0
  391. package/src/models/__tests__/dispatchEvent.when.test.ts +356 -0
  392. package/src/models/__tests__/flowEngine.resolveUse.test.ts +170 -0
  393. package/src/models/__tests__/flowModel.clone.test.ts +416 -0
  394. package/src/models/__tests__/flowModel.getFlows.sort.test.ts +33 -9
  395. package/src/models/__tests__/flowModel.scheduleModelOperation.test.tsx +129 -0
  396. package/src/models/__tests__/flowModel.test.ts +296 -119
  397. package/src/models/__tests__/forkFlowModel.test.ts +40 -7
  398. package/src/models/flowModel.tsx +426 -148
  399. package/src/models/forkFlowModel.ts +48 -8
  400. package/src/provider.tsx +18 -14
  401. package/src/reactive/__tests__/observer.test.tsx +211 -0
  402. package/src/reactive/index.ts +11 -0
  403. package/src/reactive/observer.tsx +101 -0
  404. package/src/resources/__tests__/multiRecordResource.test.ts +44 -0
  405. package/src/resources/__tests__/sqlResource.test.ts +60 -0
  406. package/src/resources/baseRecordResource.ts +46 -3
  407. package/src/resources/multiRecordResource.ts +28 -12
  408. package/src/resources/singleRecordResource.ts +9 -3
  409. package/src/resources/sqlResource.ts +33 -32
  410. package/src/runjs-context/contexts/FormJSFieldItemRunJSContext.ts +38 -21
  411. package/src/runjs-context/contexts/JSBlockRunJSContext.ts +50 -34
  412. package/src/runjs-context/contexts/JSCollectionActionRunJSContext.ts +15 -16
  413. package/src/runjs-context/contexts/JSColumnRunJSContext.ts +58 -0
  414. package/src/runjs-context/contexts/JSEditableFieldRunJSContext.ts +106 -0
  415. package/src/runjs-context/contexts/JSFieldRunJSContext.ts +30 -25
  416. package/src/runjs-context/contexts/JSItemRunJSContext.ts +35 -21
  417. package/src/runjs-context/contexts/JSRecordActionRunJSContext.ts +17 -18
  418. package/src/runjs-context/contexts/base.ts +871 -0
  419. package/src/runjs-context/contributions.ts +88 -0
  420. package/src/runjs-context/helpers.ts +32 -30
  421. package/src/runjs-context/registry.ts +16 -47
  422. package/src/runjs-context/setup.ts +57 -0
  423. package/src/runjs-context/snippets/global/api-request.snippet.ts +38 -0
  424. package/src/runjs-context/snippets/global/clipboard-copy-text.snippet.ts +42 -0
  425. package/src/runjs-context/snippets/global/import-esm.snippet.ts +39 -0
  426. package/src/runjs-context/snippets/global/message-error.snippet.ts +6 -0
  427. package/src/runjs-context/snippets/global/message-success.snippet.ts +6 -0
  428. package/src/runjs-context/snippets/global/notification-open.snippet.ts +11 -1
  429. package/src/runjs-context/snippets/global/open-view-dialog.snippet.ts +10 -3
  430. package/src/runjs-context/snippets/global/open-view-drawer.snippet.ts +10 -3
  431. package/src/runjs-context/snippets/global/query-selector.snippet.ts +34 -0
  432. package/src/runjs-context/snippets/global/require-amd.snippet.ts +30 -0
  433. package/src/runjs-context/snippets/global/window-open.snippet.ts +11 -1
  434. package/src/runjs-context/snippets/index.ts +212 -39
  435. package/src/runjs-context/snippets/scene/{jsblock → block}/add-event-listener.snippet.ts +14 -2
  436. package/src/runjs-context/snippets/scene/block/api-fetch-render-list.snippet.ts +45 -0
  437. package/src/runjs-context/snippets/scene/block/chartjs-bar.snippet.ts +80 -0
  438. package/src/runjs-context/snippets/scene/block/echarts-init.snippet.ts +44 -0
  439. package/src/runjs-context/snippets/scene/block/render-antd-icons.snippet.ts +46 -0
  440. package/src/runjs-context/snippets/scene/block/render-button-handler.snippet.ts +35 -0
  441. package/src/runjs-context/snippets/scene/block/render-iframe.snippet.ts +38 -0
  442. package/src/runjs-context/snippets/scene/block/render-info-card.snippet.ts +52 -0
  443. package/src/runjs-context/snippets/scene/block/render-react-jsx.snippet.ts +39 -0
  444. package/src/runjs-context/snippets/scene/block/render-react.snippet.ts +38 -0
  445. package/src/runjs-context/snippets/scene/block/render-statistics.snippet.ts +76 -0
  446. package/src/runjs-context/snippets/scene/block/render-timeline.snippet.ts +65 -0
  447. package/src/runjs-context/snippets/scene/block/resource-example.snippet.ts +46 -0
  448. package/src/runjs-context/snippets/scene/block/three-users-orbit.snippet.ts +264 -0
  449. package/src/runjs-context/snippets/scene/block/vue-component.snippet.ts +105 -0
  450. package/src/runjs-context/snippets/scene/detail/color-by-value.snippet.ts +33 -0
  451. package/src/runjs-context/snippets/scene/detail/copy-to-clipboard.snippet.ts +45 -0
  452. package/src/runjs-context/snippets/scene/detail/format-number.snippet.ts +32 -0
  453. package/src/runjs-context/snippets/scene/detail/innerHTML-value.snippet.ts +31 -0
  454. package/src/runjs-context/snippets/scene/detail/percentage-bar.snippet.ts +63 -0
  455. package/src/runjs-context/snippets/scene/detail/relative-time.snippet.ts +61 -0
  456. package/src/runjs-context/snippets/scene/detail/status-tag.snippet.ts +55 -0
  457. package/src/runjs-context/snippets/scene/form/calculate-total.snippet.ts +44 -0
  458. package/src/runjs-context/snippets/scene/form/cascade-select.snippet.ts +62 -0
  459. package/src/runjs-context/snippets/scene/form/conditional-required.snippet.ts +45 -0
  460. package/src/runjs-context/snippets/scene/form/copy-field-values.snippet.ts +55 -0
  461. package/src/runjs-context/snippets/scene/{jsitem → form}/render-basic.snippet.ts +14 -2
  462. package/src/runjs-context/snippets/scene/{linkage → form}/set-disabled.snippet.ts +15 -3
  463. package/src/runjs-context/snippets/scene/{linkage → form}/set-field-value.snippet.ts +15 -3
  464. package/src/runjs-context/snippets/scene/{linkage → form}/set-required.snippet.ts +15 -3
  465. package/src/runjs-context/snippets/scene/form/toggle-multiple-fields.snippet.ts +48 -0
  466. package/src/runjs-context/snippets/scene/{linkage → form}/toggle-visible.snippet.ts +15 -3
  467. package/src/runjs-context/snippets/scene/table/cell-open-dialog.snippet.ts +45 -0
  468. package/src/runjs-context/snippets/scene/{actions → table}/collection-selected-count.snippet.ts +14 -2
  469. package/src/runjs-context/snippets/scene/table/concat-fields.snippet.ts +60 -0
  470. package/src/runjs-context/snippets/scene/table/destroy-selected.snippet.ts +36 -0
  471. package/src/runjs-context/snippets/scene/table/export-selected-json.snippet.ts +45 -0
  472. package/src/runjs-context/snippets/scene/{actions → table}/iterate-selected-rows.snippet.ts +14 -2
  473. package/src/runjs-context/snippets/types.ts +5 -1
  474. package/src/runjsLibs.ts +622 -0
  475. package/src/scheduler/ModelOperationScheduler.ts +306 -0
  476. package/src/types.ts +86 -5
  477. package/src/utils/__tests__/createCollectionContextMeta.test.ts +51 -0
  478. package/src/utils/__tests__/flows.test.ts +65 -0
  479. package/src/utils/__tests__/jsxTransform.test.ts +38 -0
  480. package/src/utils/__tests__/params-resolvers.test.ts +40 -0
  481. package/src/utils/__tests__/parsePathnameToViewParams.test.ts +25 -0
  482. package/src/utils/__tests__/pruneFilter.test.ts +38 -0
  483. package/src/utils/__tests__/runjsRequireAsyncAutoWhitelist.test.ts +38 -0
  484. package/src/utils/__tests__/runjsTemplateCompat.test.ts +159 -0
  485. package/src/utils/__tests__/safeGlobals.test.ts +79 -2
  486. package/src/utils/__tests__/utils.test.ts +114 -15
  487. package/src/utils/__tests__/variablesParams.test.ts +120 -0
  488. package/src/utils/associationObjectVariable.ts +180 -0
  489. package/src/utils/createCollectionContextMeta.ts +9 -3
  490. package/src/utils/createEphemeralContext.ts +142 -0
  491. package/src/utils/flows.ts +23 -0
  492. package/src/utils/index.ts +17 -3
  493. package/src/utils/jsxTransform.ts +39 -0
  494. package/src/utils/params-resolvers.ts +25 -11
  495. package/src/utils/parsePathnameToViewParams.ts +50 -6
  496. package/src/utils/pruneFilter.ts +41 -0
  497. package/src/utils/resolveModuleUrl.ts +91 -0
  498. package/src/utils/runjsModuleLoader.ts +553 -0
  499. package/src/utils/runjsTemplateCompat.ts +828 -0
  500. package/src/utils/safeGlobals.ts +181 -15
  501. package/src/utils/schema-utils.ts +81 -3
  502. package/src/utils/serverContextParams.ts +6 -0
  503. package/src/utils/translation.ts +7 -2
  504. package/src/utils/variablesParams.ts +164 -72
  505. package/src/views/DialogComponent.tsx +1 -4
  506. package/src/views/DrawerComponent.tsx +19 -7
  507. package/src/views/PageComponent.tsx +3 -5
  508. package/src/views/ViewNavigation.ts +49 -43
  509. package/src/views/__tests__/FlowView.usePage.test.tsx +186 -0
  510. package/src/views/__tests__/ViewNavigation.test.ts +54 -34
  511. package/src/views/__tests__/useDialog.closeDestroy.test.tsx +159 -0
  512. package/src/views/__tests__/viewEvents.resolveOpenerEngine.test.ts +28 -0
  513. package/src/views/createViewMeta.ts +402 -73
  514. package/src/views/index.tsx +1 -1
  515. package/src/views/useDialog.tsx +52 -31
  516. package/src/views/useDrawer.tsx +99 -55
  517. package/src/views/usePage.tsx +101 -33
  518. package/src/views/usePopover.tsx +4 -1
  519. package/src/views/viewEvents.ts +55 -0
  520. package/lib/runjs-context/contexts/FlowRunJSContext.d.ts +0 -38
  521. package/lib/runjs-context/contexts/FlowRunJSContext.js +0 -217
  522. package/lib/runjs-context/contexts/LinkageRunJSContext.js +0 -62
  523. package/lib/runjs-context/index.d.ts +0 -19
  524. package/lib/runjs-context/index.js +0 -57
  525. package/lib/runjs-context/snippets/global/api-request-get.snippet.d.ts +0 -16
  526. package/lib/runjs-context/snippets/global/api-request-get.snippet.js +0 -42
  527. package/lib/runjs-context/snippets/global/api-request-post.snippet.d.ts +0 -16
  528. package/lib/runjs-context/snippets/global/console-log-ctx.snippet.d.ts +0 -16
  529. package/lib/runjs-context/snippets/global/requireAsync.snippet.d.ts +0 -16
  530. package/lib/runjs-context/snippets/global/sleep.snippet.d.ts +0 -16
  531. package/lib/runjs-context/snippets/global/sleep.snippet.js +0 -43
  532. package/lib/runjs-context/snippets/global/try-catch-async.snippet.d.ts +0 -16
  533. package/lib/runjs-context/snippets/libs/echarts-init.snippet.d.ts +0 -15
  534. package/lib/runjs-context/snippets/scene/actions/collection-selected-count.snippet.d.ts +0 -15
  535. package/lib/runjs-context/snippets/scene/actions/iterate-selected-rows.snippet.d.ts +0 -15
  536. package/lib/runjs-context/snippets/scene/actions/record-id-message.snippet.d.ts +0 -15
  537. package/lib/runjs-context/snippets/scene/actions/record-id-message.snippet.js +0 -43
  538. package/lib/runjs-context/snippets/scene/actions/run-action-basic.snippet.d.ts +0 -15
  539. package/lib/runjs-context/snippets/scene/actions/run-action-basic.snippet.js +0 -40
  540. package/lib/runjs-context/snippets/scene/jsblock/add-event-listener.snippet.d.ts +0 -15
  541. package/lib/runjs-context/snippets/scene/jsblock/append-style.snippet.d.ts +0 -15
  542. package/lib/runjs-context/snippets/scene/jsblock/append-style.snippet.js +0 -42
  543. package/lib/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.d.ts +0 -15
  544. package/lib/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.js +0 -46
  545. package/lib/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.d.ts +0 -15
  546. package/lib/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.js +0 -41
  547. package/lib/runjs-context/snippets/scene/jsblock/render-basic.snippet.d.ts +0 -15
  548. package/lib/runjs-context/snippets/scene/jsblock/render-basic.snippet.js +0 -41
  549. package/lib/runjs-context/snippets/scene/jsblock/render-button-handler.snippet.d.ts +0 -15
  550. package/lib/runjs-context/snippets/scene/jsblock/render-react.snippet.d.ts +0 -15
  551. package/lib/runjs-context/snippets/scene/jsfield/color-by-value.snippet.d.ts +0 -15
  552. package/lib/runjs-context/snippets/scene/jsfield/format-number.snippet.d.ts +0 -15
  553. package/lib/runjs-context/snippets/scene/jsfield/innerHTML-value.snippet.d.ts +0 -15
  554. package/lib/runjs-context/snippets/scene/jsitem/render-basic.snippet.d.ts +0 -15
  555. package/lib/runjs-context/snippets/scene/linkage/set-disabled.snippet.d.ts +0 -15
  556. package/lib/runjs-context/snippets/scene/linkage/set-field-value.snippet.d.ts +0 -15
  557. package/lib/runjs-context/snippets/scene/linkage/set-required.snippet.d.ts +0 -15
  558. package/lib/runjs-context/snippets/scene/linkage/toggle-visible.snippet.d.ts +0 -15
  559. package/src/runjs-context/contexts/FlowRunJSContext.ts +0 -190
  560. package/src/runjs-context/contexts/LinkageRunJSContext.ts +0 -35
  561. package/src/runjs-context/index.ts +0 -20
  562. package/src/runjs-context/snippets/global/api-request-get.snippet.ts +0 -20
  563. package/src/runjs-context/snippets/global/api-request-post.snippet.ts +0 -20
  564. package/src/runjs-context/snippets/global/console-log-ctx.snippet.ts +0 -19
  565. package/src/runjs-context/snippets/global/copy-record-json.snippet.ts +0 -21
  566. package/src/runjs-context/snippets/global/copy-to-clipboard.snippet.ts +0 -21
  567. package/src/runjs-context/snippets/global/log-json-record.snippet.ts +0 -21
  568. package/src/runjs-context/snippets/global/requireAsync.snippet.ts +0 -24
  569. package/src/runjs-context/snippets/global/sleep.snippet.ts +0 -21
  570. package/src/runjs-context/snippets/global/try-catch-async.snippet.ts +0 -22
  571. package/src/runjs-context/snippets/global/view-navigation-push.snippet.ts +0 -23
  572. package/src/runjs-context/snippets/libs/echarts-init.snippet.ts +0 -24
  573. package/src/runjs-context/snippets/scene/actions/record-id-message.snippet.ts +0 -21
  574. package/src/runjs-context/snippets/scene/actions/run-action-basic.snippet.ts +0 -18
  575. package/src/runjs-context/snippets/scene/jsblock/append-style.snippet.ts +0 -20
  576. package/src/runjs-context/snippets/scene/jsblock/jsx-mount.snippet.ts +0 -24
  577. package/src/runjs-context/snippets/scene/jsblock/jsx-unmount.snippet.ts +0 -19
  578. package/src/runjs-context/snippets/scene/jsblock/render-basic.snippet.ts +0 -24
  579. package/src/runjs-context/snippets/scene/jsblock/render-button-handler.snippet.ts +0 -24
  580. package/src/runjs-context/snippets/scene/jsblock/render-card.snippet.ts +0 -30
  581. package/src/runjs-context/snippets/scene/jsblock/render-react.snippet.ts +0 -34
  582. package/src/runjs-context/snippets/scene/jsfield/color-by-value.snippet.ts +0 -20
  583. package/src/runjs-context/snippets/scene/jsfield/format-number.snippet.ts +0 -19
  584. package/src/runjs-context/snippets/scene/jsfield/innerHTML-value.snippet.ts +0 -18
  585. /package/lib/runjs-context/snippets/global/{copy-record-json.snippet.d.ts → api-request.snippet.d.ts} +0 -0
  586. /package/lib/runjs-context/snippets/global/{copy-to-clipboard.snippet.d.ts → clipboard-copy-text.snippet.d.ts} +0 -0
  587. /package/lib/runjs-context/snippets/global/{log-json-record.snippet.d.ts → import-esm.snippet.d.ts} +0 -0
  588. /package/lib/runjs-context/snippets/global/{view-navigation-push.snippet.d.ts → query-selector.snippet.d.ts} +0 -0
  589. /package/lib/runjs-context/snippets/scene/{jsblock/render-card.snippet.d.ts → block/echarts-init.snippet.d.ts} +0 -0
@@ -101,4 +101,29 @@ describe('parsePathnameToViewParams', () => {
101
101
  const result = parsePathnameToViewParams('///admin//xxx//tab//yyy//');
102
102
  expect(result).toEqual([{ viewUid: 'xxx', tabUid: 'yyy' }]);
103
103
  });
104
+
105
+ test('should parse filterByTk from key-value encoded segment into object', () => {
106
+ const kv = encodeURIComponent('id=1&tenant=ac');
107
+ const path = `/admin/xxx/filterbytk/${kv}`;
108
+ const result = parsePathnameToViewParams(path);
109
+ expect(result).toEqual([{ viewUid: 'xxx', filterByTk: { id: '1', tenant: 'ac' } }]);
110
+ });
111
+
112
+ test('should parse filterByTk from JSON object segment', () => {
113
+ const json = encodeURIComponent('{"id":"1","tenant":"ac"}');
114
+ const path = `/admin/xxx/filterbytk/${json}`;
115
+ const result = parsePathnameToViewParams(path);
116
+ expect(result).toEqual([{ viewUid: 'xxx', filterByTk: { id: '1', tenant: 'ac' } }]);
117
+ });
118
+
119
+ test('should keep non-object JSON (array/number) as string for filterByTk', () => {
120
+ const arr = encodeURIComponent('["a"]');
121
+ const num = encodeURIComponent('123');
122
+ const t = encodeURIComponent('true');
123
+ expect(parsePathnameToViewParams(`/admin/xxx/filterbytk/${arr}`)).toEqual([
124
+ { viewUid: 'xxx', filterByTk: '["a"]' },
125
+ ]);
126
+ expect(parsePathnameToViewParams(`/admin/xxx/filterbytk/${num}`)).toEqual([{ viewUid: 'xxx', filterByTk: '123' }]);
127
+ expect(parsePathnameToViewParams(`/admin/xxx/filterbytk/${t}`)).toEqual([{ viewUid: 'xxx', filterByTk: 'true' }]);
128
+ });
104
129
  });
@@ -0,0 +1,38 @@
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, it, expect } from 'vitest';
11
+ import { pruneFilter } from '../pruneFilter';
12
+
13
+ describe('pruneFilter', () => {
14
+ it('keeps boolean false and number 0', () => {
15
+ const input = { a: { $eq: false }, b: { $eq: 0 } };
16
+ const out = pruneFilter(input);
17
+ expect(out).toEqual(input);
18
+ });
19
+
20
+ it('removes null/undefined/empty string and empty containers', () => {
21
+ const input = { a: null, b: undefined, c: '', d: [], e: {} } as any;
22
+ const out = pruneFilter(input);
23
+ expect(out).toBeUndefined();
24
+ });
25
+
26
+ it('works recursively with nested objects/arrays', () => {
27
+ const input = {
28
+ $and: [{ isRead: { $eq: false } }, { name: { $eq: '' } }, {}, [], { nested: { empty: {}, ok: 1 } }],
29
+ } as any;
30
+ const out = pruneFilter(input);
31
+ expect(out).toEqual({ $and: [{ isRead: { $eq: false } }, { nested: { ok: 1 } }] });
32
+ });
33
+
34
+ it('returns undefined for empty arrays/objects produced by pruning', () => {
35
+ expect(pruneFilter([null, undefined, '', [], {}] as any)).toBeUndefined();
36
+ expect(pruneFilter({ a: { b: '' } } as any)).toBeUndefined();
37
+ });
38
+ });
@@ -0,0 +1,38 @@
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 { beforeEach, describe, expect, it } from 'vitest';
11
+ import { runjsRequireAsync } from '../runjsModuleLoader';
12
+ import { __resetRunJSSafeGlobalsRegistryForTests, createSafeWindow } from '../safeGlobals';
13
+
14
+ beforeEach(() => {
15
+ __resetRunJSSafeGlobalsRegistryForTests();
16
+ });
17
+
18
+ describe('runjsRequireAsync auto whitelist', () => {
19
+ it('should allow safeWindow to access globals introduced during requireAsync', async () => {
20
+ const key = '__nb_require_async_added_global__';
21
+ delete (window as any)[key];
22
+
23
+ const safeWin: any = createSafeWindow();
24
+ expect(() => safeWin[key]).toThrow(/not allowed/);
25
+
26
+ const requirejs: any = (deps: string[], onLoad: (...args: any[]) => void) => {
27
+ // Simulate a remote library attaching itself to the real window.
28
+ (window as any)[key] = { ok: true };
29
+ onLoad(undefined);
30
+ };
31
+
32
+ await runjsRequireAsync(requirejs, 'https://example.com/fake-lib.js');
33
+
34
+ expect(safeWin[key]).toEqual({ ok: true });
35
+
36
+ delete (window as any)[key];
37
+ });
38
+ });
@@ -0,0 +1,159 @@
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, it, expect, vi } from 'vitest';
11
+ import * as jsxTransform from '../../utils/jsxTransform';
12
+ import { prepareRunJsCode, preprocessRunJsTemplates } from '../runjsTemplateCompat';
13
+
14
+ describe('runjsTemplateCompat', () => {
15
+ describe('preprocessRunJsTemplates', () => {
16
+ it('hoists bare {{ }} placeholders into top-level resolved vars', () => {
17
+ const src = `const a = {{ctx.user.id}};`;
18
+ const out = preprocessRunJsTemplates(src);
19
+ expect(out).toContain(`const __runjs_ctx_tpl_0 = await ctx.resolveJsonTemplate("{{ctx.user.id}}");`);
20
+ expect(out).toContain(`const a = __runjs_ctx_tpl_0;`);
21
+ });
22
+
23
+ it('replaces string literals containing {{ }} via split/join, without injecting await into nested functions', () => {
24
+ const src = `const s = '{{ctx.user.id}}';`;
25
+ const out = preprocessRunJsTemplates(src);
26
+ expect(out).toContain(`const __runjs_ctx_tpl_0 = await ctx.resolveJsonTemplate("{{ctx.user.id}}");`);
27
+ expect(out).toContain(`__runjs_templateValueToString(__runjs_ctx_tpl_0, "{{ctx.user.id}}")`);
28
+ expect(out).toContain(`.split("{{ctx.user.id}}").join(`);
29
+ });
30
+
31
+ it('does not transform arguments inside explicit ctx.resolveJsonTemplate(...) call', () => {
32
+ const src = `const v = await ctx.resolveJsonTemplate('{{ctx.user.id}}');\nconst s = '{{ctx.user.id}}';`;
33
+ const out = preprocessRunJsTemplates(src);
34
+ // inside call: keep raw
35
+ expect(out).toContain(`await ctx.resolveJsonTemplate('{{ctx.user.id}}')`);
36
+ // outside call: transform
37
+ expect(out).toContain(`__runjs_templateValueToString(__runjs_ctx_tpl_0, "{{ctx.user.id}}")`);
38
+ });
39
+
40
+ it('keeps template markers in comments unchanged', () => {
41
+ const src = `// {{ctx.user.id}}\nconst a = 1;`;
42
+ const out = preprocessRunJsTemplates(src);
43
+ expect(out).toBe(src);
44
+ });
45
+
46
+ it('supports template literals containing {{ }}', () => {
47
+ const src = 'const s = `hi {{ctx.user.name}}`;';
48
+ const out = preprocessRunJsTemplates(src);
49
+ expect(out).toContain(`const __runjs_ctx_tpl_0 = await ctx.resolveJsonTemplate("{{ctx.user.name}}");`);
50
+ expect(out).toContain(`\`hi {{ctx.user.name}}\``);
51
+ expect(out).toContain(`.split("{{ctx.user.name}}").join(`);
52
+ });
53
+
54
+ it('does not rewrite non-ctx {{ }} patterns (e.g. JSX style object) while still rewriting ctx placeholders', () => {
55
+ const src = `const id = {{ctx.user.id}};\nctx.render(<div style={{ width: '100%' }} />);`;
56
+ const out = preprocessRunJsTemplates(src);
57
+ expect(out).toContain(`const __runjs_ctx_tpl_0 = await ctx.resolveJsonTemplate("{{ctx.user.id}}");`);
58
+ expect(out).toContain(`style={{ width: '100%' }}`);
59
+ expect(out).not.toContain(`resolveJsonTemplate("{{ width: '100%' }}")`);
60
+ });
61
+
62
+ it('avoids injecting await into non-async nested function bodies', () => {
63
+ const src = `
64
+ function f() {
65
+ return {{ctx.user.id}};
66
+ }
67
+ return f();
68
+ `.trim();
69
+ const out = preprocessRunJsTemplates(src);
70
+ // The only await should be in the top-level preamble
71
+ expect(out).toContain(`const __runjs_ctx_tpl_0 = await ctx.resolveJsonTemplate("{{ctx.user.id}}");`);
72
+ expect(out).toContain(`return __runjs_ctx_tpl_0;`);
73
+ expect(out).not.toContain(`return (await ctx.resolveJsonTemplate`);
74
+ });
75
+
76
+ it('is tolerant to already-preprocessed code (idempotent heuristic)', () => {
77
+ const src =
78
+ `const __runjs_ctx_tpl_0 = await ctx.resolveJsonTemplate("{{ctx.user.id}}");\n` +
79
+ `const s = ("{{ctx.user.id}}").split("{{ctx.user.id}}").join(__runjs_templateValueToString(__runjs_ctx_tpl_0, "{{ctx.user.id}}"));`;
80
+ const out = preprocessRunJsTemplates(src);
81
+ expect(out).toBe(src);
82
+ });
83
+
84
+ it('rewrites object literal string keys via computed property to keep syntax valid', () => {
85
+ const src = `const o = { '{{ctx.user.id}}': 1 };`;
86
+ const out = preprocessRunJsTemplates(src);
87
+ expect(out).toContain(`const __runjs_ctx_tpl_0 = await ctx.resolveJsonTemplate("{{ctx.user.id}}");`);
88
+ expect(out).toContain(`{ [`);
89
+ expect(out).toContain(`]: 1 }`);
90
+ expect(out).toContain(`.split("{{ctx.user.id}}").join(`);
91
+ });
92
+ });
93
+
94
+ describe('prepareRunJsCode', () => {
95
+ it('preprocesses templates and compiles JSX', async () => {
96
+ const src = `
97
+ const name = '{{ctx.user.name}}';
98
+ ctx.render(<div className="x">{name}</div>);
99
+ `.trim();
100
+ const out = await prepareRunJsCode(src, { preprocessTemplates: true });
101
+ expect(out).toMatch(/ctx\.React\.createElement/);
102
+ expect(out).toMatch(/ctx\.resolveJsonTemplate/);
103
+ });
104
+
105
+ it('injects ctx.libs ensure preamble for member access', async () => {
106
+ const src = `return ctx.libs.lodash;`;
107
+ const out = await prepareRunJsCode(src, { preprocessTemplates: false });
108
+ expect(out).toContain(`/* __runjs_ensure_libs */`);
109
+ expect(out).toContain(`await ctx.__ensureLibs(["lodash"]);`);
110
+ });
111
+
112
+ it('injects ctx.libs ensure preamble for bracket access with string literal', async () => {
113
+ const src = `return ctx.libs['lodash'];`;
114
+ const out = await prepareRunJsCode(src, { preprocessTemplates: false });
115
+ expect(out).toContain(`await ctx.__ensureLibs(["lodash"]);`);
116
+ });
117
+
118
+ it('injects ctx.libs ensure preamble for object destructuring', async () => {
119
+ const src = `const { lodash } = ctx.libs;\nreturn lodash;`;
120
+ const out = await prepareRunJsCode(src, { preprocessTemplates: false });
121
+ expect(out).toContain(`await ctx.__ensureLibs(["lodash"]);`);
122
+ });
123
+
124
+ it('does not inject ctx.libs preamble when ctx.libs only appears in string/comment', async () => {
125
+ const src = `// ctx.libs.lodash\nconst s = "ctx.libs.lodash";\nreturn s;`;
126
+ const out = await prepareRunJsCode(src, { preprocessTemplates: false });
127
+ expect(out).not.toContain(`__runjs_ensure_libs`);
128
+ });
129
+
130
+ it('is idempotent for already-prepared code', async () => {
131
+ const src = `return ctx.libs['lodash'];`;
132
+ const out1 = await prepareRunJsCode(src, { preprocessTemplates: false });
133
+ const out2 = await prepareRunJsCode(out1, { preprocessTemplates: false });
134
+ expect(out2).toBe(out1);
135
+ expect(out2.match(/__runjs_ensure_libs/g)?.length ?? 0).toBe(1);
136
+ });
137
+
138
+ it('does not break JSX attribute string values when preprocessing templates', async () => {
139
+ const src = `ctx.render(<Input title="{{ctx.user.name}}" />);`;
140
+ const out = await prepareRunJsCode(src, { preprocessTemplates: true });
141
+ expect(out).toMatch(/ctx\.React\.createElement/);
142
+ expect(out).toMatch(/title:\s*\(/);
143
+ expect(out).toContain(`.split("{{ctx.user.name}}").join(`);
144
+ });
145
+
146
+ it('caches prepared code by source and preprocessTemplates option', async () => {
147
+ const spy = vi.spyOn(jsxTransform, 'compileRunJs');
148
+ const src = `/* cache-test */\nconst a = 1;\nreturn a;`;
149
+
150
+ await prepareRunJsCode(src, { preprocessTemplates: false });
151
+ await prepareRunJsCode(src, { preprocessTemplates: false });
152
+ await prepareRunJsCode(src, { preprocessTemplates: true });
153
+ await prepareRunJsCode(src, { preprocessTemplates: true });
154
+
155
+ expect(spy).toHaveBeenCalledTimes(2);
156
+ spy.mockRestore();
157
+ });
158
+ });
159
+ });
@@ -7,8 +7,19 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
 
10
- import { describe, expect, it } from 'vitest';
11
- import { createSafeDocument, createSafeWindow } from '../safeGlobals';
10
+ import { beforeEach, describe, expect, it } from 'vitest';
11
+ import {
12
+ __resetRunJSSafeGlobalsRegistryForTests,
13
+ createSafeDocument,
14
+ createSafeNavigator,
15
+ createSafeWindow,
16
+ registerRunJSSafeDocumentGlobals,
17
+ registerRunJSSafeWindowGlobals,
18
+ } from '../safeGlobals';
19
+
20
+ beforeEach(() => {
21
+ __resetRunJSSafeGlobalsRegistryForTests();
22
+ });
12
23
 
13
24
  describe('safeGlobals', () => {
14
25
  it('createSafeWindow exposes only allowed globals and extras', () => {
@@ -16,14 +27,80 @@ describe('safeGlobals', () => {
16
27
  expect(typeof win.setTimeout).toBe('function');
17
28
  expect(win.console).toBeDefined();
18
29
  expect(win.foo).toBe(123);
30
+ expect(new win.FormData()).toBeInstanceOf(window.FormData);
31
+ if (typeof window.Blob !== 'undefined') {
32
+ expect(typeof win.Blob).toBe('function');
33
+ expect(new win.Blob(['x'])).toBeInstanceOf(window.Blob);
34
+ }
35
+ if (typeof window.URL !== 'undefined') {
36
+ expect(win.URL).toBe(window.URL);
37
+ expect(typeof win.URL.createObjectURL).toBe('function');
38
+ }
19
39
  // access to location proxy is allowed, but sensitive props throw
20
40
  expect(() => win.location.href).toThrow(/not allowed/);
21
41
  });
22
42
 
43
+ it('createSafeWindow allows writing new props and reading them back', () => {
44
+ const win: any = createSafeWindow();
45
+ win.someLib = { ok: true };
46
+ expect(win.someLib).toEqual({ ok: true });
47
+ expect('someLib' in win).toBe(true);
48
+ });
49
+
50
+ it('createSafeWindow can access dynamically registered globals from real window', () => {
51
+ const key = '__nb_safe_window_global__';
52
+ (window as any)[key] = { v: 1 };
53
+ registerRunJSSafeWindowGlobals([key]);
54
+
55
+ const win: any = createSafeWindow();
56
+ expect(win[key]).toEqual({ v: 1 });
57
+
58
+ delete (window as any)[key];
59
+ });
60
+
23
61
  it('createSafeDocument exposes whitelisted methods and extras', () => {
24
62
  const doc: any = createSafeDocument({ bar: true });
25
63
  expect(typeof doc.createElement).toBe('function');
26
64
  expect(doc.bar).toBe(true);
27
65
  expect(() => doc.cookie).toThrow(/not allowed/);
28
66
  });
67
+
68
+ it('createSafeDocument allows writing new props and reading them back', () => {
69
+ const doc: any = createSafeDocument();
70
+ doc.someLib = { ok: true };
71
+ expect(doc.someLib).toEqual({ ok: true });
72
+ expect('someLib' in doc).toBe(true);
73
+ });
74
+
75
+ it('createSafeDocument can access dynamically registered globals from real document', () => {
76
+ const key = '__nb_safe_document_global__';
77
+ (document as any)[key] = 123;
78
+ registerRunJSSafeDocumentGlobals([key]);
79
+
80
+ const doc: any = createSafeDocument();
81
+ expect(doc[key]).toBe(123);
82
+
83
+ delete (document as any)[key];
84
+ });
85
+
86
+ it('createSafeNavigator exposes limited props and guards others', () => {
87
+ const nav: any = createSafeNavigator();
88
+ // clipboard object should always exist
89
+ expect(typeof nav.clipboard).toBe('object');
90
+ // writeText may or may not exist depending on environment
91
+ if (typeof navigator !== 'undefined' && (navigator as any).clipboard?.writeText) {
92
+ expect(typeof nav.clipboard.writeText).toBe('function');
93
+ } else {
94
+ expect(typeof nav.clipboard.writeText === 'undefined' || typeof nav.clipboard.writeText === 'function').toBe(
95
+ true,
96
+ );
97
+ }
98
+ // readable properties
99
+ expect(() => void nav.onLine).not.toThrow();
100
+ expect(() => void nav.language).not.toThrow();
101
+ expect(() => void nav.languages).not.toThrow();
102
+ // blocked properties
103
+ expect(() => (nav as any).geolocation).toThrow(/not allowed/);
104
+ expect(() => (nav as any).userAgent).toThrow(/not allowed/);
105
+ });
29
106
  });
@@ -13,6 +13,7 @@ import {
13
13
  isInheritedFrom,
14
14
  resolveDefaultParams,
15
15
  resolveStepUiSchema,
16
+ shouldHideStepInSettings,
16
17
  FlowExitException,
17
18
  defineAction,
18
19
  compileUiSchema,
@@ -30,6 +31,7 @@ import type {
30
31
  StepDefinition,
31
32
  } from '../../types';
32
33
  import { FlowRuntimeContext } from '../../flowContext';
34
+ import { ContextPathProxy } from '../../ContextPathProxy';
33
35
 
34
36
  // Helper functions
35
37
  const createMockFlowEngine = (): FlowEngine => {
@@ -996,26 +998,123 @@ describe('Utils', () => {
996
998
 
997
999
  consoleSpy.mockRestore();
998
1000
  });
1001
+ });
1002
+ });
999
1003
 
1000
- test('should handle missing getAction method', async () => {
1001
- // Mock a flowEngine without getAction method
1002
- const originalGetAction = mockModel.flowEngine.getAction;
1003
- mockModel.flowEngine.getAction = undefined;
1004
+ // ==================== shouldHideStepInSettings() FUNCTION ====================
1005
+ describe('shouldHideStepInSettings()', () => {
1006
+ let mockFlow: any;
1007
+ let mockStep: StepDefinition;
1004
1008
 
1005
- mockStep.use = 'testAction';
1006
- mockStep.uiSchema = {
1007
- field1: { type: 'string', title: 'Field 1' },
1008
- };
1009
+ beforeEach(() => {
1010
+ mockFlow = {
1011
+ key: 'testFlow',
1012
+ title: 'Test Flow',
1013
+ steps: {},
1014
+ };
1009
1015
 
1010
- const result = await resolveStepUiSchema(mockModel, mockFlow, mockStep);
1016
+ mockStep = {
1017
+ key: 'testStep',
1018
+ handler: vi.fn(),
1019
+ };
1020
+ });
1011
1021
 
1012
- expect(result).toEqual({
1013
- field1: { type: 'string', title: 'Field 1' },
1014
- });
1022
+ test('returns true when step is falsy', async () => {
1023
+ const result = await shouldHideStepInSettings(mockModel, mockFlow, null);
1024
+ expect(result).toBe(true);
1025
+ });
1015
1026
 
1016
- // Restore the original method
1017
- mockModel.flowEngine.getAction = originalGetAction;
1018
- });
1027
+ test('respects static step.hideInSettings=true', async () => {
1028
+ mockStep.hideInSettings = true;
1029
+
1030
+ const result = await shouldHideStepInSettings(mockModel, mockFlow, mockStep);
1031
+ expect(result).toBe(true);
1032
+ });
1033
+
1034
+ test('respects static step.hideInSettings=false', async () => {
1035
+ mockStep.hideInSettings = false;
1036
+
1037
+ const result = await shouldHideStepInSettings(mockModel, mockFlow, mockStep);
1038
+ expect(result).toBe(false);
1039
+ });
1040
+
1041
+ test('falls back to action.hideInSettings when step.hideInSettings is undefined', async () => {
1042
+ const action: ActionDefinition = {
1043
+ name: 'testAction',
1044
+ handler: vi.fn(),
1045
+ hideInSettings: true,
1046
+ } as any;
1047
+
1048
+ mockStep.use = 'testAction';
1049
+ mockModel.flowEngine.getAction = vi.fn().mockReturnValue(action);
1050
+
1051
+ const result = await shouldHideStepInSettings(mockModel, mockFlow, mockStep);
1052
+ expect(mockModel.flowEngine.getAction).toHaveBeenCalledWith('testAction');
1053
+ expect(result).toBe(true);
1054
+ });
1055
+
1056
+ test('prefers step.hideInSettings over action.hideInSettings', async () => {
1057
+ const action: ActionDefinition = {
1058
+ name: 'testAction',
1059
+ handler: vi.fn(),
1060
+ hideInSettings: true,
1061
+ } as any;
1062
+
1063
+ mockStep.use = 'testAction';
1064
+ mockStep.hideInSettings = false;
1065
+ mockModel.flowEngine.getAction = vi.fn().mockReturnValue(action);
1066
+
1067
+ const result = await shouldHideStepInSettings(mockModel, mockFlow, mockStep);
1068
+ expect(result).toBe(false);
1069
+ });
1070
+
1071
+ test('evaluates function step.hideInSettings with FlowRuntimeContext', async () => {
1072
+ const hideFn = vi.fn().mockResolvedValue(true);
1073
+ mockStep.hideInSettings = hideFn as any;
1074
+
1075
+ const result = await shouldHideStepInSettings(mockModel, mockFlow, mockStep);
1076
+
1077
+ expect(hideFn).toHaveBeenCalledTimes(1);
1078
+ const ctx = hideFn.mock.calls[0][0] as FlowRuntimeContext;
1079
+ expect(ctx).toBeInstanceOf(FlowRuntimeContext);
1080
+ expect((ctx as any).model).toBe(mockModel);
1081
+ expect((ctx as any).flowKey).toBe('testFlow');
1082
+ expect((ctx as any).mode).toBe('settings');
1083
+ expect((ctx as any).currentStep).toBeInstanceOf(ContextPathProxy);
1084
+ expect(String((ctx as any).currentStep)).toBe('{{ctx.currentStep}}');
1085
+ expect(result).toBe(true);
1086
+ });
1087
+
1088
+ test('evaluates function action.hideInSettings when step.hideInSettings is undefined', async () => {
1089
+ const hideFn = vi.fn().mockResolvedValue(false);
1090
+ const action: ActionDefinition = {
1091
+ name: 'testAction',
1092
+ handler: vi.fn(),
1093
+ hideInSettings: hideFn as any,
1094
+ } as any;
1095
+
1096
+ mockStep.use = 'testAction';
1097
+ mockModel.flowEngine.getAction = vi.fn().mockReturnValue(action);
1098
+
1099
+ const result = await shouldHideStepInSettings(mockModel, mockFlow, mockStep);
1100
+
1101
+ expect(hideFn).toHaveBeenCalledTimes(1);
1102
+ const ctx = hideFn.mock.calls[0][0] as FlowRuntimeContext;
1103
+ expect((ctx as any).currentStep).toBeInstanceOf(ContextPathProxy);
1104
+ expect(String((ctx as any).currentStep)).toBe('{{ctx.currentStep}}');
1105
+ expect(result).toBe(false);
1106
+ });
1107
+
1108
+ test('returns false and logs warning when function hideInSettings throws', async () => {
1109
+ const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
1110
+ const hideFn = vi.fn().mockRejectedValue(new Error('boom'));
1111
+ mockStep.hideInSettings = hideFn as any;
1112
+
1113
+ const result = await shouldHideStepInSettings(mockModel, mockFlow, mockStep);
1114
+
1115
+ expect(consoleSpy).toHaveBeenCalled();
1116
+ expect(result).toBe(false);
1117
+ consoleSpy.mockRestore();
1019
1118
  });
1020
1119
  });
1021
1120
  });
@@ -11,9 +11,11 @@ import { describe, expect, it } from 'vitest';
11
11
  import {
12
12
  collectContextParamsForTemplate,
13
13
  createRecordMetaFactory,
14
+ createRecordResolveOnServerWithLocal,
14
15
  inferParentRecordRef,
15
16
  inferRecordRef,
16
17
  } from '../variablesParams';
18
+ import { FlowEngine, SingleRecordResource } from '../..';
17
19
 
18
20
  describe('variablesParams helpers', () => {
19
21
  it('inferRecordRef and inferParentRecordRef from FlowContext-like object', () => {
@@ -30,6 +32,29 @@ describe('variablesParams helpers', () => {
30
32
  expect(inferParentRecordRef(ctx)).toEqual({ collection: 'posts', dataSourceKey: 'main', filterByTk: 9 });
31
33
  });
32
34
 
35
+ it('inferRecordRef fallback to collection.getFilterByTK when resource has no filterByTk', () => {
36
+ const engine = new FlowEngine();
37
+ const ds = engine.context.dataSourceManager.getDataSource('main')!;
38
+ ds.addCollection({
39
+ name: 'users',
40
+ filterTargetKey: 'id',
41
+ fields: [
42
+ { name: 'id', type: 'integer', interface: 'number' },
43
+ { name: 'roles', type: 'belongsToMany', target: 'roles', interface: 'm2m' },
44
+ ],
45
+ });
46
+ const collection = ds.getCollection('users');
47
+ const resource = engine.context.createResource(SingleRecordResource);
48
+ resource.setResourceName('main.users');
49
+ // 不设置 filterByTk,模拟资源无 filter 时的 fallback
50
+ const ctx: any = engine.context;
51
+ ctx.defineProperty('resource', { value: resource });
52
+ ctx.defineProperty('collection', { value: collection });
53
+ ctx.defineProperty('record', { value: { id: 5 } });
54
+
55
+ expect(inferRecordRef(ctx)).toEqual({ collection: 'users', dataSourceKey: 'main', filterByTk: 5 });
56
+ });
57
+
33
58
  it('collectContextParamsForTemplate builds input for used variables only', async () => {
34
59
  const ctx: any = {
35
60
  getPropertyOptions: (k: string) => ({
@@ -49,4 +74,99 @@ describe('variablesParams helpers', () => {
49
74
  expect(res).toHaveProperty('record');
50
75
  expect(res).not.toHaveProperty('user');
51
76
  });
77
+
78
+ it('collectContextParamsForTemplate keeps associationName/sourceId from RecordRef', async () => {
79
+ const ctx: any = {
80
+ getPropertyOptions: (k: string) => ({
81
+ meta:
82
+ k === 'popup'
83
+ ? async () => ({
84
+ type: 'object',
85
+ title: 'Popup',
86
+ buildVariablesParams: () => ({
87
+ record: {
88
+ collection: 'posts',
89
+ dataSourceKey: 'main',
90
+ filterByTk: 1,
91
+ associationName: 'users.posts',
92
+ sourceId: 9,
93
+ },
94
+ }),
95
+ })
96
+ : undefined,
97
+ }),
98
+ };
99
+
100
+ const tpl = { value: '{{ ctx.popup.record.id }}' } as any;
101
+ const res = await collectContextParamsForTemplate(ctx, tpl);
102
+ expect(res?.['popup.record']).toMatchObject({
103
+ collection: 'posts',
104
+ dataSourceKey: 'main',
105
+ filterByTk: 1,
106
+ associationName: 'users.posts',
107
+ sourceId: 9,
108
+ });
109
+ });
110
+
111
+ it('createRecordResolveOnServerWithLocal: no local record => always use server', () => {
112
+ const resolver = createRecordResolveOnServerWithLocal(
113
+ () => ({ name: 'posts', dataSourceKey: 'main' }) as any,
114
+ () => undefined,
115
+ );
116
+ expect(resolver('')).toBe(true);
117
+ expect(resolver('title')).toBe(true);
118
+ expect(resolver('author.name')).toBe(true);
119
+ });
120
+
121
+ it('createRecordResolveOnServerWithLocal: local record + non-association subpaths => use local', () => {
122
+ const collection: any = {
123
+ getField: (name: string) => {
124
+ if (name === 'id') return { name: 'id', isAssociationField: () => false };
125
+ if (name === 'title') return { name: 'title', isAssociationField: () => false };
126
+ return undefined;
127
+ },
128
+ };
129
+ const record = { id: 1, title: 'Hello' };
130
+ const resolver = createRecordResolveOnServerWithLocal(
131
+ () => collection,
132
+ () => record,
133
+ );
134
+ expect(resolver('')).toBe(false);
135
+ expect(resolver('id')).toBe(false);
136
+ expect(resolver('title')).toBe(false);
137
+ });
138
+
139
+ it('createRecordResolveOnServerWithLocal: association with local value => still use local', () => {
140
+ const collection: any = {
141
+ getField: (name: string) => {
142
+ if (name === 'author') return { name: 'author', isAssociationField: () => true };
143
+ if (name === 'title') return { name: 'title', isAssociationField: () => false };
144
+ return undefined;
145
+ },
146
+ };
147
+ const record = { title: 'Hello', author: { id: 1, name: 'Alice' } };
148
+ const resolver = createRecordResolveOnServerWithLocal(
149
+ () => collection,
150
+ () => record,
151
+ );
152
+ expect(resolver('author')).toBe(false);
153
+ expect(resolver('author.name')).toBe(false);
154
+ });
155
+
156
+ it('createRecordResolveOnServerWithLocal: association without local value => use server', () => {
157
+ const collection: any = {
158
+ getField: (name: string) => {
159
+ if (name === 'author') return { name: 'author', isAssociationField: () => true };
160
+ if (name === 'title') return { name: 'title', isAssociationField: () => false };
161
+ return undefined;
162
+ },
163
+ };
164
+ const record = { title: 'Hello', author: null };
165
+ const resolver = createRecordResolveOnServerWithLocal(
166
+ () => collection,
167
+ () => record,
168
+ );
169
+ expect(resolver('author')).toBe(true);
170
+ expect(resolver('author.name')).toBe(true);
171
+ });
52
172
  });