@nocobase/client-v2 2.1.0-alpha.40 → 2.1.0-alpha.46

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 (338) hide show
  1. package/es/Application.d.ts +7 -0
  2. package/es/BaseApplication.d.ts +13 -0
  3. package/es/RouterManager.d.ts +1 -0
  4. package/es/authRedirect.d.ts +12 -0
  5. package/es/collection-field-interface/CollectionFieldInterface.d.ts +51 -15
  6. package/es/collection-field-interface/CollectionFieldInterfaceManager.d.ts +82 -3
  7. package/es/collection-manager/field-configure.d.ts +80 -0
  8. package/es/collection-manager/field-validation.d.ts +43 -0
  9. package/es/collection-manager/filter-operators/index.d.ts +46 -0
  10. package/es/collection-manager/filter-operators/operators.d.ts +30 -0
  11. package/es/collection-manager/interfaces/checkbox.d.ts +1 -41
  12. package/es/collection-manager/interfaces/checkboxGroup.d.ts +12 -44
  13. package/es/collection-manager/interfaces/collection.d.ts +12 -51
  14. package/es/collection-manager/interfaces/color.d.ts +1 -16
  15. package/es/collection-manager/interfaces/createdAt.d.ts +1 -44
  16. package/es/collection-manager/interfaces/createdBy.d.ts +0 -4
  17. package/es/collection-manager/interfaces/dateOnly.d.ts +7 -44
  18. package/es/collection-manager/interfaces/datetime.d.ts +1 -44
  19. package/es/collection-manager/interfaces/datetimeNoTz.d.ts +1 -44
  20. package/es/collection-manager/interfaces/email.d.ts +1 -29
  21. package/es/collection-manager/interfaces/id.d.ts +1 -16
  22. package/es/collection-manager/interfaces/index.d.ts +2 -3
  23. package/es/collection-manager/interfaces/input.d.ts +1 -102
  24. package/es/collection-manager/interfaces/integer.d.ts +1 -95
  25. package/es/collection-manager/interfaces/json.d.ts +16 -7
  26. package/es/collection-manager/interfaces/m2m.d.ts +11 -19
  27. package/es/collection-manager/interfaces/m2o.d.ts +11 -19
  28. package/es/collection-manager/interfaces/markdown.d.ts +1 -63
  29. package/es/collection-manager/interfaces/multipleSelect.d.ts +12 -44
  30. package/es/collection-manager/interfaces/nanoid.d.ts +1 -34
  31. package/es/collection-manager/interfaces/number.d.ts +1 -87
  32. package/es/collection-manager/interfaces/o2m.d.ts +12 -24
  33. package/es/collection-manager/interfaces/obo.d.ts +207 -0
  34. package/es/collection-manager/interfaces/oho.d.ts +207 -0
  35. package/es/collection-manager/interfaces/password.d.ts +1 -56
  36. package/es/collection-manager/interfaces/percent.d.ts +1 -84
  37. package/es/collection-manager/interfaces/phone.d.ts +1 -25
  38. package/es/collection-manager/interfaces/properties/index.d.ts +0 -28
  39. package/es/collection-manager/interfaces/radioGroup.d.ts +1 -29
  40. package/es/collection-manager/interfaces/richText.d.ts +1 -63
  41. package/es/collection-manager/interfaces/select.d.ts +12 -44
  42. package/es/collection-manager/interfaces/snowflake-id.d.ts +1 -34
  43. package/es/collection-manager/interfaces/tableoid.d.ts +1 -10
  44. package/es/collection-manager/interfaces/textarea.d.ts +1 -51
  45. package/es/collection-manager/interfaces/time.d.ts +1 -16
  46. package/es/collection-manager/interfaces/types.d.ts +3 -12
  47. package/es/collection-manager/interfaces/unixTimestamp.d.ts +1 -44
  48. package/es/collection-manager/interfaces/updatedAt.d.ts +1 -44
  49. package/es/collection-manager/interfaces/updatedBy.d.ts +0 -4
  50. package/es/collection-manager/interfaces/url.d.ts +1 -20
  51. package/es/collection-manager/interfaces/uuid.d.ts +1 -34
  52. package/es/collection-manager/template-fields.d.ts +53 -0
  53. package/es/components/KeepAlive.d.ts +22 -0
  54. package/es/components/RouterBridge.d.ts +9 -0
  55. package/es/components/form/DialogFormLayout.d.ts +5 -29
  56. package/es/components/form/TypedVariableInput.d.ts +75 -0
  57. package/es/components/form/VariableInput.d.ts +53 -2
  58. package/es/components/form/filter/CollectionFilter.d.ts +49 -0
  59. package/es/components/form/filter/CollectionFilterItem.d.ts +49 -0
  60. package/es/components/form/filter/DateFilterDynamicComponent.d.ts +57 -0
  61. package/es/components/form/filter/FilterValueInput.d.ts +29 -0
  62. package/es/components/form/filter/index.d.ts +11 -0
  63. package/es/components/form/filter/useFilterActionProps.d.ts +96 -0
  64. package/es/components/form/index.d.ts +2 -0
  65. package/es/data-source/ExtendCollectionsProvider.d.ts +50 -0
  66. package/es/data-source/index.d.ts +9 -0
  67. package/es/flow/FlowPage.d.ts +2 -1
  68. package/es/flow/admin-shell/AdminLayoutRouteCoordinator.d.ts +8 -40
  69. package/es/flow/admin-shell/BaseLayoutModel.d.ts +89 -0
  70. package/es/flow/admin-shell/BaseLayoutRouteCoordinator.d.ts +74 -0
  71. package/es/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.d.ts +12 -0
  72. package/es/flow/admin-shell/admin-layout/AdminLayoutMenuModels.d.ts +1 -0
  73. package/es/flow/admin-shell/admin-layout/AdminLayoutModel.d.ts +7 -92
  74. package/es/flow/admin-shell/admin-layout/AppListRender.d.ts +11 -0
  75. package/es/flow/admin-shell/admin-layout/index.d.ts +3 -0
  76. package/es/flow/admin-shell/admin-layout/useApplications.d.ts +3 -2
  77. package/es/flow/admin-shell/useAdminLayoutRoutePage.d.ts +2 -2
  78. package/es/flow/admin-shell/useLayoutRoutePage.d.ts +23 -0
  79. package/es/flow/components/ConditionBuilder.d.ts +1 -0
  80. package/es/flow/components/FieldAssignRulesEditor.d.ts +3 -1
  81. package/es/flow/components/FieldAssignValueInput.d.ts +1 -0
  82. package/es/flow/components/FlowRoute.d.ts +10 -1
  83. package/es/flow/components/fieldAssignOptions.d.ts +10 -0
  84. package/es/flow/components/filter/LinkageFilterItem.d.ts +1 -0
  85. package/es/flow/components/filter/VariableFilterItem.d.ts +1 -0
  86. package/es/flow/components/filter/index.d.ts +2 -0
  87. package/es/flow/components/filter/metaTreeAssociationDepth.d.ts +13 -0
  88. package/es/flow/components/filter/useFilterOptions.d.ts +66 -0
  89. package/es/flow/index.d.ts +4 -0
  90. package/es/flow/models/base/AssociationFieldGroupModel.d.ts +2 -33
  91. package/es/flow/models/base/PageModel/PageModel.d.ts +3 -1
  92. package/es/flow/models/blocks/assign-form/assignFieldValuesFlow.d.ts +92 -0
  93. package/es/flow/models/blocks/assign-form/index.d.ts +1 -0
  94. package/es/flow/models/blocks/form/FormActionGroupModel.d.ts +1 -0
  95. package/es/flow/models/blocks/form/FormActionModel.d.ts +9 -2
  96. package/es/flow/models/blocks/table/TableBlockModel.d.ts +10 -0
  97. package/es/flow/models/blocks/table/TableColumnModel.d.ts +2 -0
  98. package/es/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.d.ts +1 -1
  99. package/es/flow-compat/passwordUtils.d.ts +1 -1
  100. package/es/index.d.ts +6 -0
  101. package/es/index.mjs +552 -459
  102. package/es/layout-manager/LayoutContentRoute.d.ts +14 -0
  103. package/es/layout-manager/LayoutManager.d.ts +22 -0
  104. package/es/layout-manager/LayoutRoute.d.ts +14 -0
  105. package/es/layout-manager/index.d.ts +13 -0
  106. package/es/layout-manager/types.d.ts +20 -0
  107. package/es/layout-manager/utils.d.ts +14 -0
  108. package/es/nocobase-buildin-plugin/index.d.ts +3 -10
  109. package/es/settings-center/index.d.ts +1 -1
  110. package/es/settings-center/plugin-manager/BulkEnableButton.d.ts +15 -0
  111. package/es/settings-center/plugin-manager/PluginCard.d.ts +15 -0
  112. package/es/settings-center/plugin-manager/PluginDetail.d.ts +16 -0
  113. package/es/settings-center/{PluginManagerPage.d.ts → plugin-manager/index.d.ts} +1 -7
  114. package/es/settings-center/plugin-manager/types.d.ts +34 -0
  115. package/lib/index.js +552 -459
  116. package/package.json +8 -7
  117. package/src/Application.tsx +51 -12
  118. package/src/BaseApplication.tsx +32 -0
  119. package/src/PluginSettingsManager.ts +1 -1
  120. package/src/RouterManager.tsx +17 -1
  121. package/src/__tests__/PluginSettingsManager.test.ts +41 -2
  122. package/src/__tests__/app.test.tsx +17 -1
  123. package/src/__tests__/globalDeps.test.ts +1 -0
  124. package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +50 -2
  125. package/src/__tests__/plugin-manager.test.tsx +177 -0
  126. package/src/__tests__/settings-center.test.tsx +24 -2
  127. package/src/authRedirect.ts +43 -0
  128. package/src/collection-field-interface/CollectionFieldInterface.ts +71 -77
  129. package/src/collection-field-interface/CollectionFieldInterfaceManager.ts +201 -4
  130. package/src/collection-manager/field-configure.ts +548 -0
  131. package/src/collection-manager/field-validation.ts +195 -0
  132. package/src/collection-manager/filter-operators/index.ts +176 -0
  133. package/src/collection-manager/{interfaces/properties → filter-operators}/operators.ts +24 -13
  134. package/src/collection-manager/interfaces/checkbox.ts +2 -9
  135. package/src/collection-manager/interfaces/checkboxGroup.ts +2 -10
  136. package/src/collection-manager/interfaces/collection.ts +2 -15
  137. package/src/collection-manager/interfaces/color.ts +2 -2
  138. package/src/collection-manager/interfaces/createdAt.ts +2 -2
  139. package/src/collection-manager/interfaces/createdBy.ts +1 -12
  140. package/src/collection-manager/interfaces/dateOnly.ts +8 -2
  141. package/src/collection-manager/interfaces/datetime.ts +2 -2
  142. package/src/collection-manager/interfaces/datetimeNoTz.ts +2 -2
  143. package/src/collection-manager/interfaces/email.ts +2 -9
  144. package/src/collection-manager/interfaces/id.ts +1 -2
  145. package/src/collection-manager/interfaces/index.ts +2 -3
  146. package/src/collection-manager/interfaces/input.ts +2 -133
  147. package/src/collection-manager/interfaces/integer.ts +2 -71
  148. package/src/collection-manager/interfaces/json.tsx +17 -11
  149. package/src/collection-manager/interfaces/m2m.tsx +0 -21
  150. package/src/collection-manager/interfaces/m2o.tsx +0 -22
  151. package/src/collection-manager/interfaces/markdown.ts +2 -51
  152. package/src/collection-manager/interfaces/multipleSelect.ts +2 -14
  153. package/src/collection-manager/interfaces/nanoid.ts +2 -2
  154. package/src/collection-manager/interfaces/number.ts +2 -85
  155. package/src/collection-manager/interfaces/o2m.tsx +1 -22
  156. package/src/collection-manager/interfaces/obo.tsx +145 -0
  157. package/src/collection-manager/interfaces/oho.tsx +145 -0
  158. package/src/collection-manager/interfaces/password.ts +2 -44
  159. package/src/collection-manager/interfaces/percent.ts +2 -74
  160. package/src/collection-manager/interfaces/phone.ts +2 -2
  161. package/src/collection-manager/interfaces/properties/index.ts +0 -133
  162. package/src/collection-manager/interfaces/radioGroup.ts +2 -2
  163. package/src/collection-manager/interfaces/richText.ts +2 -51
  164. package/src/collection-manager/interfaces/select.ts +2 -14
  165. package/src/collection-manager/interfaces/snowflake-id.ts +2 -2
  166. package/src/collection-manager/interfaces/tableoid.ts +1 -2
  167. package/src/collection-manager/interfaces/textarea.ts +2 -51
  168. package/src/collection-manager/interfaces/time.ts +2 -2
  169. package/src/collection-manager/interfaces/types.ts +4 -12
  170. package/src/collection-manager/interfaces/unixTimestamp.tsx +2 -2
  171. package/src/collection-manager/interfaces/updatedAt.ts +2 -2
  172. package/src/collection-manager/interfaces/updatedBy.ts +1 -12
  173. package/src/collection-manager/interfaces/url.ts +2 -4
  174. package/src/collection-manager/interfaces/uuid.ts +2 -2
  175. package/src/collection-manager/template-fields.ts +109 -0
  176. package/src/components/KeepAlive.tsx +131 -0
  177. package/src/components/README.md +138 -6
  178. package/src/components/README.zh-CN.md +138 -7
  179. package/src/components/RouterBridge.tsx +28 -4
  180. package/src/components/__tests__/KeepAlive.test.tsx +63 -0
  181. package/src/components/__tests__/RouterBridge.test.tsx +27 -0
  182. package/src/components/form/DialogFormLayout.tsx +5 -29
  183. package/src/components/form/TypedVariableInput.tsx +441 -0
  184. package/src/components/form/VariableInput.tsx +101 -28
  185. package/src/components/form/__tests__/TypedVariableInput.test.tsx +152 -0
  186. package/src/components/form/__tests__/VariableInput.test.ts +85 -0
  187. package/src/components/form/filter/CollectionFilter.tsx +111 -0
  188. package/src/components/form/filter/CollectionFilterItem.tsx +184 -0
  189. package/src/components/form/filter/DateFilterDynamicComponent.tsx +283 -0
  190. package/src/components/form/filter/FilterValueInput.tsx +198 -0
  191. package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +247 -0
  192. package/src/components/form/filter/__tests__/DateFilterDynamicComponent.test.tsx +148 -0
  193. package/src/components/form/filter/__tests__/FilterValueInput.test.tsx +243 -0
  194. package/src/components/form/filter/__tests__/compileFilterGroup.test.ts +146 -0
  195. package/src/components/form/filter/index.ts +13 -0
  196. package/src/components/form/filter/useFilterActionProps.ts +203 -0
  197. package/src/components/form/index.tsx +2 -0
  198. package/src/data-source/ExtendCollectionsProvider.tsx +144 -0
  199. package/src/data-source/__tests__/ExtendCollectionsProvider.test.tsx +264 -0
  200. package/src/data-source/index.ts +10 -0
  201. package/src/flow/FlowPage.tsx +35 -7
  202. package/src/flow/__tests__/FlowPage.test.tsx +79 -0
  203. package/src/flow/__tests__/FlowRoute.test.tsx +537 -3
  204. package/src/flow/actions/__tests__/linkageRules.hiddenSync.restore.test.ts +100 -0
  205. package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +191 -0
  206. package/src/flow/actions/__tests__/linkageRulesRefresh.test.ts +23 -1
  207. package/src/flow/actions/__tests__/openView.subModelKey.test.tsx +33 -0
  208. package/src/flow/actions/aclCheck.tsx +4 -0
  209. package/src/flow/actions/aclCheckRefresh.tsx +4 -0
  210. package/src/flow/actions/dataScope.tsx +8 -1
  211. package/src/flow/actions/dateTimeFormat.tsx +12 -8
  212. package/src/flow/actions/linkageRules.tsx +127 -2
  213. package/src/flow/actions/linkageRulesRefresh.tsx +2 -3
  214. package/src/flow/actions/openView.tsx +28 -4
  215. package/src/flow/actions/setTargetDataScope.tsx +1 -1
  216. package/src/flow/admin-shell/AdminLayoutRouteCoordinator.ts +11 -329
  217. package/src/flow/admin-shell/BaseLayoutModel.tsx +455 -0
  218. package/src/flow/admin-shell/BaseLayoutRouteCoordinator.ts +502 -0
  219. package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +547 -3
  220. package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +35 -7
  221. package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +160 -0
  222. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuModels.tsx +15 -13
  223. package/src/flow/admin-shell/admin-layout/AdminLayoutModel.tsx +28 -201
  224. package/src/flow/admin-shell/admin-layout/AdminLayoutSlotModels.tsx +11 -2
  225. package/src/flow/admin-shell/admin-layout/AppListRender.tsx +139 -0
  226. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +76 -27
  227. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutModel.test.tsx +149 -27
  228. package/src/flow/admin-shell/admin-layout/index.ts +3 -0
  229. package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.test.ts +11 -0
  230. package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.ts +2 -4
  231. package/src/flow/admin-shell/admin-layout/useApplications.tsx +34 -1
  232. package/src/flow/admin-shell/useAdminLayoutRoutePage.ts +10 -26
  233. package/src/flow/admin-shell/useLayoutRoutePage.ts +61 -0
  234. package/src/flow/common/Markdown/Edit.tsx +32 -4
  235. package/src/flow/components/AdminLayout.tsx +4 -154
  236. package/src/flow/components/ConditionBuilder.tsx +12 -2
  237. package/src/flow/components/FieldAssignRulesEditor.tsx +37 -46
  238. package/src/flow/components/FieldAssignValueInput.tsx +8 -4
  239. package/src/flow/components/FlowRoute.tsx +105 -15
  240. package/src/flow/components/__tests__/FieldAssignRulesEditor.test.tsx +112 -1
  241. package/src/flow/components/__tests__/fieldAssignOptions.test.ts +71 -1
  242. package/src/flow/components/code-editor/__tests__/runjsCompletions.test.ts +272 -27
  243. package/src/flow/components/code-editor/runjsCompletions.ts +490 -9
  244. package/src/flow/components/fieldAssignOptions.ts +23 -6
  245. package/src/flow/components/filter/LinkageFilterItem.tsx +22 -9
  246. package/src/flow/components/filter/VariableFilterItem.tsx +27 -9
  247. package/src/flow/components/filter/__tests__/fieldsToOptions.test.ts +48 -0
  248. package/src/flow/components/filter/__tests__/metaTreeAssociationDepth.test.ts +60 -0
  249. package/src/flow/components/filter/fieldsToOptions.ts +9 -4
  250. package/src/flow/components/filter/index.ts +3 -0
  251. package/src/flow/components/filter/metaTreeAssociationDepth.ts +69 -0
  252. package/src/flow/components/filter/useFilterOptions.ts +102 -0
  253. package/src/flow/index.ts +4 -0
  254. package/src/flow/models/actions/FilterActionModel.tsx +15 -3
  255. package/src/flow/models/actions/UpdateRecordActionModel.tsx +14 -95
  256. package/src/flow/models/actions/UpdateRecordActionUtils.ts +4 -7
  257. package/src/flow/models/actions/__tests__/AssignFormRefill.test.ts +116 -1
  258. package/src/flow/models/base/ActionModel.tsx +8 -1
  259. package/src/flow/models/base/AssociationFieldGroupModel.tsx +20 -3
  260. package/src/flow/models/base/GridModel.tsx +1 -1
  261. package/src/flow/models/base/PageModel/ChildPageModel.tsx +5 -1
  262. package/src/flow/models/base/PageModel/PageModel.tsx +51 -18
  263. package/src/flow/models/base/PageModel/RootPageModel.tsx +6 -13
  264. package/src/flow/models/base/PageModel/__tests__/ChildPageModel.test.ts +12 -0
  265. package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +102 -1
  266. package/src/flow/models/base/RouteModel.tsx +1 -1
  267. package/src/flow/models/base/__tests__/AssociationFieldGroupModel.test.ts +86 -0
  268. package/src/flow/models/base/__tests__/GridModel.render.test.tsx +53 -0
  269. package/src/flow/models/blocks/assign-form/AssignFormGridModel.tsx +12 -3
  270. package/src/flow/models/blocks/assign-form/AssignFormItemModel.tsx +77 -6
  271. package/src/flow/models/blocks/assign-form/__tests__/assignFieldValuesFlow.editor.test.tsx +216 -0
  272. package/src/flow/models/blocks/assign-form/assignFieldValuesFlow.tsx +308 -0
  273. package/src/flow/models/blocks/assign-form/index.ts +1 -0
  274. package/src/flow/models/blocks/filter-form/FilterFormItemModel.tsx +1 -1
  275. package/src/flow/models/blocks/filter-form/__tests__/FilterFormItemModel.defineChildren.test.ts +6 -1
  276. package/src/flow/models/blocks/filter-manager/flow-actions/connectFields.tsx +48 -6
  277. package/src/flow/models/blocks/form/FormActionGroupModel.tsx +14 -0
  278. package/src/flow/models/blocks/form/FormActionModel.tsx +30 -3
  279. package/src/flow/models/blocks/form/FormAssociationItemModel.tsx +9 -0
  280. package/src/flow/models/blocks/form/FormItemModel.tsx +17 -1
  281. package/src/flow/models/blocks/form/__tests__/FormActionGroupModel.test.ts +46 -0
  282. package/src/flow/models/blocks/form/__tests__/FormBlockModel.test.tsx +17 -0
  283. package/src/flow/models/blocks/form/__tests__/FormItemModel.defineChildren.test.ts +27 -2
  284. package/src/flow/models/blocks/form/__tests__/submitHandler.test.ts +71 -0
  285. package/src/flow/models/blocks/form/submitHandler.ts +8 -1
  286. package/src/flow/models/blocks/form/submitValues.ts +4 -1
  287. package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +29 -0
  288. package/src/flow/models/blocks/form/value-runtime/runtime.ts +5 -1
  289. package/src/flow/models/blocks/table/TableBlockModel.tsx +118 -16
  290. package/src/flow/models/blocks/table/TableColumnModel.tsx +15 -5
  291. package/src/flow/models/blocks/table/TableCustomColumnModel.tsx +2 -2
  292. package/src/flow/models/blocks/table/__tests__/TableBlockModel.rowSelection.test.tsx +114 -0
  293. package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +18 -0
  294. package/src/flow/models/fields/AssociationFieldModel/SubFormFieldModel.tsx +7 -1
  295. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.tsx +6 -7
  296. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableField.tsx +1 -1
  297. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.tsx +6 -5
  298. package/src/flow/models/fields/ClickableFieldModel.tsx +9 -1
  299. package/src/flow/models/fields/CollectionSelectorFieldModel.tsx +8 -2
  300. package/src/flow/models/fields/DisplayEnumFieldModel.tsx +8 -2
  301. package/src/flow/models/fields/DisplayTimeFieldModel.tsx +1 -1
  302. package/src/flow/models/fields/TimeFieldModel.tsx +1 -1
  303. package/src/flow/models/fields/__tests__/TimeFieldModel.test.tsx +61 -0
  304. package/src/flow/models/fields/mobile-components/MobileDatePicker.tsx +19 -3
  305. package/src/flow/models/fields/mobile-components/MobileLazySelect.tsx +5 -3
  306. package/src/flow/models/fields/mobile-components/__tests__/MobileDatePicker.test.tsx +94 -0
  307. package/src/flow/models/fields/mobile-components/__tests__/MobileSelect.test.tsx +70 -0
  308. package/src/flow/models/topbar/TopbarActionModel.tsx +1 -1
  309. package/src/flow/utils/__tests__/dateTimeFormat.test.ts +91 -0
  310. package/src/index.ts +6 -0
  311. package/src/layout-manager/LayoutContentRoute.tsx +90 -0
  312. package/src/layout-manager/LayoutManager.tsx +185 -0
  313. package/src/layout-manager/LayoutRoute.tsx +138 -0
  314. package/src/layout-manager/__tests__/LayoutManager.test.tsx +335 -0
  315. package/src/layout-manager/__tests__/LayoutRoute.test.tsx +473 -0
  316. package/src/layout-manager/index.ts +14 -0
  317. package/src/layout-manager/types.ts +22 -0
  318. package/src/layout-manager/utils.ts +37 -0
  319. package/src/nocobase-buildin-plugin/index.tsx +69 -67
  320. package/src/nocobase-buildin-plugin/plugins/LocalePlugin.ts +1 -0
  321. package/src/settings-center/index.ts +1 -1
  322. package/src/settings-center/plugin-manager/BulkEnableButton.tsx +111 -0
  323. package/src/settings-center/plugin-manager/PluginCard.tsx +270 -0
  324. package/src/settings-center/plugin-manager/PluginDetail.tsx +195 -0
  325. package/src/settings-center/plugin-manager/index.tsx +254 -0
  326. package/src/settings-center/plugin-manager/types.ts +35 -0
  327. package/src/settings-center/utils.tsx +8 -1
  328. package/src/theme/__tests__/globalStyles.test.ts +24 -0
  329. package/src/theme/globalStyles.ts +10 -0
  330. package/src/utils/globalDeps.ts +2 -0
  331. package/es/collection-manager/interfaces/linkTo.d.ts +0 -90
  332. package/es/collection-manager/interfaces/o2o.d.ts +0 -621
  333. package/es/collection-manager/interfaces/properties/operators.d.ts +0 -294
  334. package/es/collection-manager/interfaces/subTable.d.ts +0 -172
  335. package/src/collection-manager/interfaces/linkTo.ts +0 -120
  336. package/src/collection-manager/interfaces/o2o.tsx +0 -561
  337. package/src/collection-manager/interfaces/subTable.ts +0 -218
  338. package/src/settings-center/PluginManagerPage.tsx +0 -162
@@ -0,0 +1,308 @@
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 {
11
+ FlowModelRenderer,
12
+ resolveRunJSObjectValues,
13
+ tExpr,
14
+ type FlowModelContext,
15
+ useFlowEngine,
16
+ useFlowSettingsContext,
17
+ } from '@nocobase/flow-engine';
18
+ import React, { useEffect } from 'react';
19
+ import { CollectionActionModel } from '../../base/CollectionActionModel';
20
+ import { RecordActionModel } from '../../base/RecordActionModel';
21
+ import { AssignFormModel } from './AssignFormModel';
22
+
23
+ export const ASSIGN_FIELD_VALUES_STEP_KEY = 'assignFieldValues';
24
+
25
+ type AssignedValues = Record<string, unknown>;
26
+
27
+ type AssignFieldValuesCollection = {
28
+ dataSourceKey?: string;
29
+ name?: string;
30
+ };
31
+
32
+ type AssignFieldValuesContext = FlowModelContext & {
33
+ collection?: AssignFieldValuesCollection;
34
+ flowSettingsEnabled?: boolean;
35
+ };
36
+
37
+ type AssignFieldValuesModel = {
38
+ uid: string;
39
+ assignFormUid?: string;
40
+ context?: AssignFieldValuesContext;
41
+ subModels?: {
42
+ assignForm?: AssignFormModel;
43
+ };
44
+ getStepParams?: (flowKey: string, stepKey: string) => { assignedValues?: AssignedValues } | undefined;
45
+ setStepParams?: (flowKey: string, stepKey: string, params: { assignedValues: AssignedValues }) => void;
46
+ };
47
+
48
+ type AssignFieldValuesStepOptions = {
49
+ settingsFlowKey: string;
50
+ title?: string;
51
+ tipComponent?: React.ComponentType;
52
+ validateBeforeSave?: boolean;
53
+ clearRecordContext?: boolean;
54
+ };
55
+
56
+ function getContextCollection(ctx: AssignFieldValuesContext | undefined): AssignFieldValuesCollection | undefined {
57
+ const collection = ctx?.collection;
58
+ return collection && typeof collection === 'object' ? collection : undefined;
59
+ }
60
+
61
+ function getResourceInit(ctx: AssignFieldValuesContext): { dataSourceKey: string; collectionName: string } | undefined {
62
+ const collection = getContextCollection(ctx);
63
+ const dsKey = collection?.dataSourceKey;
64
+ const collName = collection?.name;
65
+ return dsKey && collName ? { dataSourceKey: dsKey, collectionName: collName } : undefined;
66
+ }
67
+
68
+ function resolveInitFromFlowSettings(
69
+ blockModel: unknown,
70
+ actionContext: AssignFieldValuesContext | undefined,
71
+ ): { dataSourceKey: string; collectionName: string } | undefined {
72
+ const maybeBlockCollection = (blockModel as { collection?: { dataSourceKey?: string; name?: string } } | undefined)
73
+ ?.collection;
74
+ const collection = maybeBlockCollection || getContextCollection(actionContext);
75
+ const dsKey = collection?.dataSourceKey;
76
+ const collName = collection?.name;
77
+ return dsKey && collName ? { dataSourceKey: dsKey, collectionName: collName } : undefined;
78
+ }
79
+
80
+ function isValidResourceInit(init: unknown): init is {
81
+ dataSourceKey: string;
82
+ collectionName: string;
83
+ } {
84
+ if (!init || typeof init !== 'object') return false;
85
+ const obj = init as { dataSourceKey?: unknown; collectionName?: unknown };
86
+ return (
87
+ typeof obj.dataSourceKey === 'string' &&
88
+ !!obj.dataSourceKey &&
89
+ typeof obj.collectionName === 'string' &&
90
+ !!obj.collectionName
91
+ );
92
+ }
93
+
94
+ type LocalCacheContext = {
95
+ _observableCache?: Record<string, unknown>;
96
+ _cache?: Record<string, unknown>;
97
+ _pending?: Record<string, unknown>;
98
+ };
99
+
100
+ function toLocalCacheContext(context: unknown): LocalCacheContext | undefined {
101
+ return context && typeof context === 'object' ? (context as LocalCacheContext) : undefined;
102
+ }
103
+
104
+ function clearOwnContextCache(context: unknown, key: string) {
105
+ const localContext = toLocalCacheContext(context);
106
+ if (!localContext) {
107
+ return;
108
+ }
109
+ delete localContext._observableCache?.[key];
110
+ delete localContext._cache?.[key];
111
+ delete localContext._pending?.[key];
112
+ }
113
+
114
+ function clearResourceContextCache(model: { context?: unknown } | undefined) {
115
+ clearOwnContextCache(model?.context, 'dataSource');
116
+ clearOwnContextCache(model?.context, 'collection');
117
+ clearOwnContextCache(model?.context, 'resource');
118
+ clearOwnContextCache(model?.context, 'association');
119
+ }
120
+
121
+ function resolveAssignFormModel(ctx: {
122
+ model: AssignFieldValuesModel;
123
+ engine: {
124
+ getModel?: (uid: string, fromRoot?: boolean) => AssignFormModel | undefined;
125
+ findModelByParentId?: (parentId: string, subKey: string) => AssignFormModel | undefined | null;
126
+ };
127
+ }) {
128
+ if (ctx.model.assignFormUid) {
129
+ const form = ctx.engine.getModel?.(ctx.model.assignFormUid, true);
130
+ if (form) {
131
+ return form;
132
+ }
133
+ }
134
+
135
+ const localForm = ctx.model.subModels?.assignForm;
136
+ if (localForm) {
137
+ return localForm;
138
+ }
139
+
140
+ return ctx.engine.findModelByParentId?.(ctx.model.uid, 'assignForm') || undefined;
141
+ }
142
+
143
+ export function createAssignFormSubModelOptions(ctx: AssignFieldValuesContext) {
144
+ return {
145
+ async: true,
146
+ use: 'AssignFormModel',
147
+ stepParams: { resourceSettings: { init: getResourceInit(ctx) } },
148
+ };
149
+ }
150
+
151
+ export function getAssignFieldValuesDefaultParams(
152
+ ctx: {
153
+ model: Pick<AssignFieldValuesModel, 'getStepParams'>;
154
+ },
155
+ settingsFlowKey: string,
156
+ ): { assignedValues: AssignedValues } {
157
+ const step = ctx.model.getStepParams?.(settingsFlowKey, ASSIGN_FIELD_VALUES_STEP_KEY) || {};
158
+ return { assignedValues: step?.assignedValues || {} };
159
+ }
160
+
161
+ export async function resolveAssignFieldValues(
162
+ ctx: {
163
+ message?: { error?: (message: string) => void };
164
+ t?: (message: string) => string;
165
+ },
166
+ rawAssignedValues: unknown,
167
+ logName = 'AssignFieldValues',
168
+ ): Promise<AssignedValues | null> {
169
+ try {
170
+ return await resolveRunJSObjectValues(ctx, rawAssignedValues);
171
+ } catch (error) {
172
+ console.error(`[${logName}] RunJS execution failed`, error);
173
+ ctx.message?.error?.(ctx.t?.('RunJS execution failed') || 'RunJS execution failed');
174
+ return null;
175
+ }
176
+ }
177
+
178
+ export function mergeAssignFieldValues<T extends Record<string, unknown>>(
179
+ values: T,
180
+ assignedValues?: AssignedValues | null,
181
+ ): T {
182
+ if (!assignedValues || typeof assignedValues !== 'object' || !Object.keys(assignedValues).length) {
183
+ return values;
184
+ }
185
+ return {
186
+ ...values,
187
+ ...assignedValues,
188
+ } as T;
189
+ }
190
+
191
+ function AssignFieldsEditor(props: { settingsFlowKey: string; clearRecordContext?: boolean }) {
192
+ const { model, blockModel } = useFlowSettingsContext();
193
+ const action = model as AssignFieldValuesModel;
194
+ const engine = useFlowEngine();
195
+ const [formModel, setFormModel] = React.useState<AssignFormModel | null>(null);
196
+
197
+ useEffect(() => {
198
+ let cancelled = false;
199
+ const loadAssignForm = async () => {
200
+ const init = resolveInitFromFlowSettings(blockModel, action?.context);
201
+ const loaded = (await engine.loadOrCreateModel(
202
+ init
203
+ ? {
204
+ parentId: action.uid,
205
+ subKey: 'assignForm',
206
+ use: 'AssignFormModel',
207
+ stepParams: { resourceSettings: { init } },
208
+ }
209
+ : {
210
+ parentId: action.uid,
211
+ subKey: 'assignForm',
212
+ use: 'AssignFormModel',
213
+ },
214
+ { skipSave: !model.context.flowSettingsEnabled },
215
+ )) as AssignFormModel;
216
+ if (cancelled) return;
217
+
218
+ if (isValidResourceInit(init)) {
219
+ const existingInit = loaded.getStepParams?.('resourceSettings', 'init');
220
+ // Ensure `resourceSettings.init` is available before first render to avoid cached undefined `collection`
221
+ if (
222
+ !isValidResourceInit(existingInit) ||
223
+ existingInit.dataSourceKey !== init.dataSourceKey ||
224
+ existingInit.collectionName !== init.collectionName
225
+ ) {
226
+ loaded.setStepParams?.('resourceSettings', 'init', init);
227
+ }
228
+ clearResourceContextCache(loaded);
229
+ clearResourceContextCache(loaded.subModels?.grid);
230
+ }
231
+
232
+ const prev = action.getStepParams?.(props.settingsFlowKey, ASSIGN_FIELD_VALUES_STEP_KEY) || {};
233
+ loaded.setInitialAssignedValues(prev?.assignedValues || {});
234
+
235
+ const isBulkCollectionAction = model instanceof CollectionActionModel && !(model instanceof RecordActionModel);
236
+ const isBulk = props.clearRecordContext || isBulkCollectionAction;
237
+ if (isBulk && loaded.context?.defineProperty) {
238
+ loaded.context.defineProperty('record', { get: () => undefined, cache: false });
239
+ }
240
+
241
+ setFormModel(loaded);
242
+ action.assignFormUid = loaded?.uid || action.assignFormUid;
243
+ };
244
+ loadAssignForm();
245
+ return () => {
246
+ cancelled = true;
247
+ };
248
+ }, [
249
+ action,
250
+ blockModel,
251
+ engine,
252
+ model,
253
+ model.context.flowSettingsEnabled,
254
+ props.clearRecordContext,
255
+ props.settingsFlowKey,
256
+ ]);
257
+
258
+ return formModel ? <FlowModelRenderer model={formModel} showFlowSettings={false} /> : null;
259
+ }
260
+
261
+ export function createAssignFieldValuesStep(options: AssignFieldValuesStepOptions) {
262
+ return {
263
+ title: options.title || tExpr('Assign field values'),
264
+ uiSchema() {
265
+ return {
266
+ tip: options.tipComponent
267
+ ? {
268
+ 'x-decorator': 'FormItem',
269
+ 'x-component': options.tipComponent,
270
+ }
271
+ : undefined,
272
+ editor: {
273
+ 'x-decorator': 'FormItem',
274
+ 'x-component': () => (
275
+ <AssignFieldsEditor
276
+ settingsFlowKey={options.settingsFlowKey}
277
+ clearRecordContext={options.clearRecordContext}
278
+ />
279
+ ),
280
+ },
281
+ };
282
+ },
283
+ async beforeParamsSave(
284
+ ctx: {
285
+ model: AssignFieldValuesModel;
286
+ engine: {
287
+ getModel?: (uid: string, fromRoot?: boolean) => AssignFormModel | undefined;
288
+ findModelByParentId?: (parentId: string, subKey: string) => AssignFormModel | undefined | null;
289
+ };
290
+ },
291
+ params?: { assignedValues?: AssignedValues },
292
+ previousParams?: { assignedValues?: AssignedValues },
293
+ ) {
294
+ const form = resolveAssignFormModel(ctx);
295
+ if (!form) {
296
+ const assignedValues = params?.assignedValues || previousParams?.assignedValues || {};
297
+ ctx.model.setStepParams?.(options.settingsFlowKey, ASSIGN_FIELD_VALUES_STEP_KEY, { assignedValues });
298
+ return;
299
+ }
300
+ if (options.validateBeforeSave) {
301
+ await form.form?.validateFields?.();
302
+ }
303
+ const assignedValues = form.getAssignedValues?.() || {};
304
+ ctx.model.setStepParams?.(options.settingsFlowKey, ASSIGN_FIELD_VALUES_STEP_KEY, { assignedValues });
305
+ },
306
+ handler() {},
307
+ };
308
+ }
@@ -10,3 +10,4 @@
10
10
  export * from './AssignFormModel';
11
11
  export * from './AssignFormGridModel';
12
12
  export * from './AssignFormItemModel';
13
+ export * from './assignFieldValuesFlow';
@@ -51,7 +51,7 @@ const getTargetFilterableFields = (field: any, collection?: Collection, model?:
51
51
  return (targetCollection.getFields() || []).filter((childField: any) => childField?.filterable);
52
52
  };
53
53
 
54
- const MAX_ASSOCIATION_DEPTH = 5;
54
+ const MAX_ASSOCIATION_DEPTH = 2;
55
55
 
56
56
  const normalizeAssociationDefaultFilterValue = (value: any, fieldModel: any) => {
57
57
  const collectionField = fieldModel?.context?.collectionField;
@@ -136,9 +136,13 @@ describe('FilterFormItemModel defineChildren association fields', () => {
136
136
  );
137
137
  const managerGroups = await managerAssociation.children();
138
138
  const managerFieldsGroup = managerGroups.find((group: any) => group.key === 'department.manager-fields');
139
+ const managerAssociationGroup = managerGroups.find(
140
+ (group: any) => group.key === 'department.manager-relation-fields',
141
+ );
139
142
 
140
143
  const managerFieldKeys = (managerFieldsGroup?.children || []).map((item: any) => item.key);
141
144
  expect(managerFieldKeys).toContain('department.manager.name');
145
+ expect(managerAssociationGroup).toBeUndefined();
142
146
 
143
147
  const targetItem = managerFieldsGroup?.children?.find((item: any) => item.key === 'department.manager.name');
144
148
  const createOptions = await targetItem.createModelOptions();
@@ -200,7 +204,8 @@ describe('FilterFormItemModel defineChildren association fields', () => {
200
204
  });
201
205
 
202
206
  const ds = engine.dataSourceManager.getDataSource('main');
203
- ds!.addCollection({
207
+ expect(ds).toBeTruthy();
208
+ ds?.addCollection({
204
209
  name: 'users',
205
210
  filterTargetKey: 'id',
206
211
  fields: [{ name: 'id', type: 'integer', interface: 'number', filterable: { operators: [] } }],
@@ -40,7 +40,20 @@ export const connectFields = defineAction({
40
40
  });
41
41
 
42
42
  // 构建级联选项数据结构
43
- const buildCascaderOptions = (ctx, fields: any[], prefix = '', selectedPaths: string[] = [], labelPrefix = '') => {
43
+ const MAX_ASSOCIATION_FIELD_DEPTH = 2;
44
+
45
+ const isAssociationField = (field: any) => {
46
+ return Boolean(field?.target || field?.targetCollection);
47
+ };
48
+
49
+ const buildCascaderOptions = (
50
+ ctx,
51
+ fields: any[],
52
+ prefix = '',
53
+ selectedPaths: string[] = [],
54
+ labelPrefix = '',
55
+ associationDepth = 0,
56
+ ) => {
44
57
  const selectedPathsArray = selectedPaths.filter(Boolean);
45
58
 
46
59
  return fields
@@ -48,7 +61,13 @@ const buildCascaderOptions = (ctx, fields: any[], prefix = '', selectedPaths: st
48
61
  const currentPath = prefix ? `${prefix}.${field.name}` : field.name;
49
62
  const label = field.title || field.name;
50
63
  const fullLabel = labelPrefix ? `${labelPrefix} / ${label}` : label;
51
- const isLeaf = !field.target;
64
+ const isAssociation = isAssociationField(field);
65
+ const nextAssociationDepth = associationDepth + (isAssociation ? 1 : 0);
66
+ if (isAssociation && nextAssociationDepth > MAX_ASSOCIATION_FIELD_DEPTH) {
67
+ return null;
68
+ }
69
+
70
+ const isLeaf = !isAssociation;
52
71
 
53
72
  const option: any = {
54
73
  label,
@@ -59,6 +78,7 @@ const buildCascaderOptions = (ctx, fields: any[], prefix = '', selectedPaths: st
59
78
  field,
60
79
  fullPath: currentPath,
61
80
  fullLabel,
81
+ associationDepth: nextAssociationDepth,
62
82
  },
63
83
  };
64
84
 
@@ -68,18 +88,33 @@ const buildCascaderOptions = (ctx, fields: any[], prefix = '', selectedPaths: st
68
88
 
69
89
  if (shouldLoadChildren) {
70
90
  if (field.filterable?.children?.length) {
71
- option.children = buildCascaderOptions(ctx, field.filterable.children, currentPath, selectedPaths, fullLabel);
91
+ option.children = buildCascaderOptions(
92
+ ctx,
93
+ field.filterable.children,
94
+ currentPath,
95
+ selectedPaths,
96
+ fullLabel,
97
+ nextAssociationDepth,
98
+ );
72
99
  } else {
73
100
  const targetCollection = field.targetCollection;
74
101
  if (targetCollection) {
75
102
  const targetFields = targetCollection.getFields?.() || [];
76
- option.children = buildCascaderOptions(ctx, targetFields, currentPath, selectedPaths, fullLabel);
103
+ option.children = buildCascaderOptions(
104
+ ctx,
105
+ targetFields,
106
+ currentPath,
107
+ selectedPaths,
108
+ fullLabel,
109
+ nextAssociationDepth,
110
+ );
77
111
  }
78
112
  }
79
113
  }
80
114
 
81
115
  return option;
82
116
  })
117
+ .filter(Boolean)
83
118
  .sort((a, b) => {
84
119
  // isLeaf 为 true 的节点排在前面
85
120
  if (a.isLeaf && !b.isLeaf) return -1;
@@ -259,7 +294,7 @@ function ConnectFields(
259
294
  <li>{ctx.t('Available "target blocks" are all data blocks on the current page')}</li>
260
295
  <li>
261
296
  {ctx.t(
262
- 'Support filtering multiple blocks simultaneously, support deep selection of relationship fields (e.g.: User/Department/Name)',
297
+ 'Support filtering multiple blocks simultaneously, support selection of relationship fields up to two levels (e.g.: User/Department/Name)',
263
298
  )}
264
299
  </li>
265
300
  </ul>
@@ -469,7 +504,14 @@ function CascaderWrapper(
469
504
  return;
470
505
  }
471
506
 
472
- target.children = buildCascaderOptions(ctx, childFields, fullPath, [], meta.fullLabel || target.label);
507
+ target.children = buildCascaderOptions(
508
+ ctx,
509
+ childFields,
510
+ fullPath,
511
+ [],
512
+ meta.fullLabel || target.label,
513
+ meta.associationDepth || 0,
514
+ );
473
515
  setOptions((prev) => [...prev]);
474
516
  };
475
517
 
@@ -12,4 +12,18 @@ import { FormActionModel } from './FormActionModel';
12
12
 
13
13
  export class FormActionGroupModel extends ActionGroupModel {
14
14
  static baseClass = FormActionModel;
15
+
16
+ static async defineChildren(ctx) {
17
+ const allowedModelNames = ctx.allowedFormActionModelNames;
18
+
19
+ if (!Array.isArray(allowedModelNames) || allowedModelNames.length === 0) {
20
+ return super.defineChildren(ctx);
21
+ }
22
+
23
+ await Promise.all(allowedModelNames.map((name) => ctx.engine?.getModelClassAsync?.(name)));
24
+
25
+ const items = await super.defineChildren(ctx);
26
+ const allowedSet = new Set(allowedModelNames);
27
+ return items.filter((item) => allowedSet.has(item.useModel || item.key));
28
+ }
15
29
  }
@@ -7,15 +7,27 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
 
10
- import { tExpr } from '@nocobase/flow-engine';
10
+ import { DefaultStructure, FlowExitAllException, tExpr } from '@nocobase/flow-engine';
11
11
  import { ButtonProps } from 'antd';
12
12
  import { AxiosRequestConfig } from 'axios';
13
13
  import { ActionModel } from '../../base/ActionModelCore';
14
+ import { AssignFormModel } from '../assign-form/AssignFormModel';
15
+ import {
16
+ createAssignFieldValuesStep,
17
+ createAssignFormSubModelOptions,
18
+ getAssignFieldValuesDefaultParams,
19
+ } from '../assign-form/assignFieldValuesFlow';
14
20
  import { shouldSkipSubmitValidation, validateSubmitForm } from './submitValues';
15
21
 
16
- export class FormActionModel extends ActionModel {}
22
+ export class FormActionModel<T extends DefaultStructure = DefaultStructure> extends ActionModel<T> {}
23
+
24
+ export class FormSubmitActionModel extends FormActionModel<{
25
+ subModels: {
26
+ assignForm: AssignFormModel;
27
+ };
28
+ }> {
29
+ assignFormUid?: string;
17
30
 
18
- export class FormSubmitActionModel extends FormActionModel {
19
31
  defaultProps: ButtonProps = {
20
32
  title: tExpr('Submit'),
21
33
  type: 'primary',
@@ -35,6 +47,11 @@ export class FormSubmitActionModel extends FormActionModel {
35
47
 
36
48
  FormSubmitActionModel.define({
37
49
  label: tExpr('Submit'),
50
+ createModelOptions: (ctx) => ({
51
+ subModels: {
52
+ assignForm: createAssignFormSubModelOptions(ctx),
53
+ },
54
+ }),
38
55
  });
39
56
 
40
57
  FormSubmitActionModel.registerFlow({
@@ -82,7 +99,14 @@ FormSubmitActionModel.registerFlow({
82
99
  },
83
100
  handler() {},
84
101
  },
102
+ assignFieldValues: createAssignFieldValuesStep({
103
+ settingsFlowKey: 'submitSettings',
104
+ title: tExpr('Assign field values'),
105
+ }),
85
106
  saveResource: {
107
+ async defaultParams(ctx) {
108
+ return getAssignFieldValuesDefaultParams(ctx, 'submitSettings');
109
+ },
86
110
  async handler(ctx, params) {
87
111
  if (!ctx?.resource) {
88
112
  throw new Error('Resource is not initialized');
@@ -96,6 +120,9 @@ FormSubmitActionModel.registerFlow({
96
120
  await submitHandler(ctx, params);
97
121
  } catch (error) {
98
122
  ctx.model.setProps('loading', false);
123
+ if (error instanceof FlowExitAllException) {
124
+ throw error;
125
+ }
99
126
  // 显示保存失败提示
100
127
  ctx.message.error(ctx.t('Save failed'));
101
128
  console.error('Form submission error:', error);
@@ -22,6 +22,8 @@ import { FieldModel } from '../../base/FieldModel';
22
22
  import { rebuildFieldSubModel } from '../../../internal/utils/rebuildFieldSubModel';
23
23
  import { useJsonTemplateResolver } from '../../../utils/useJsonTemplateResolver';
24
24
 
25
+ const MAX_FORM_ASSOCIATION_FIELD_DEPTH = 2;
26
+
25
27
  function mergeArrays(a, b) {
26
28
  if (!b) {
27
29
  return a;
@@ -84,10 +86,17 @@ const AssociationItem = (props) => {
84
86
  export class FormAssociationItemModel extends DisplayItemModel {
85
87
  static defineChildren(ctx: FlowModelContext) {
86
88
  const collection = ctx.collection as Collection;
89
+ const associationDepth = ctx.prefixFieldPath ? ctx.prefixFieldPath.split('.').filter(Boolean).length : 0;
87
90
 
88
91
  return collection
89
92
  .getFields()
90
93
  .map((field) => {
94
+ if (
95
+ associationDepth >= MAX_FORM_ASSOCIATION_FIELD_DEPTH &&
96
+ (field.isAssociationField?.() || field.target || field.targetCollection)
97
+ ) {
98
+ return null;
99
+ }
91
100
  const binding = this.getDefaultBindingByField(ctx, field, { fallbackToTargetTitleField: true });
92
101
  if (!binding) return null;
93
102
  const fieldModel = binding.modelName;
@@ -42,12 +42,21 @@ const interfacesOfUnsupportedDefaultValue = [
42
42
  'formula',
43
43
  ];
44
44
 
45
+ const MAX_FORM_ASSOCIATION_FIELD_DEPTH = 2;
46
+
45
47
  export class FormItemModel<T extends DefaultStructure = DefaultStructure> extends EditableItemModel<T> {
46
48
  static defineChildren(ctx: FlowModelContext) {
47
49
  const collection = ctx.collection as Collection;
50
+ const associationDepth = ctx.prefixFieldPath ? ctx.prefixFieldPath.split('.').filter(Boolean).length : 0;
48
51
  return collection
49
52
  .getFields()
50
53
  .map((field) => {
54
+ if (
55
+ associationDepth >= MAX_FORM_ASSOCIATION_FIELD_DEPTH &&
56
+ (field.isAssociationField?.() || field.target || field.targetCollection)
57
+ ) {
58
+ return;
59
+ }
51
60
  const binding = this.getDefaultBindingByField(ctx, field);
52
61
  if (!binding) {
53
62
  return;
@@ -138,6 +147,10 @@ export class FormItemModel<T extends DefaultStructure = DefaultStructure> extend
138
147
  });
139
148
  }
140
149
  }
150
+ fork.context.defineProperty('fieldPathArray', {
151
+ get: () => this.context.fieldPathArray,
152
+ cache: false,
153
+ });
141
154
  if (isHiddenReservedValuePreview) {
142
155
  fork.setProps({ hidden: false });
143
156
  }
@@ -151,7 +164,10 @@ export class FormItemModel<T extends DefaultStructure = DefaultStructure> extend
151
164
  : { hidden, ...mergedPropsWithoutInitial };
152
165
  const fieldPath = buildDynamicNamePath(this.props.name, idx);
153
166
  this.context.defineProperty('fieldPathArray', {
154
- value: [...parentFieldPathArray, ..._.castArray(fieldPath)],
167
+ get: () => {
168
+ return [...parentFieldPathArray, ..._.castArray(fieldPath)];
169
+ },
170
+ cache: false,
155
171
  });
156
172
  const record = this.context.item?.value || this.context.record;
157
173
  const content = (
@@ -0,0 +1,46 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ import { FlowEngine } from '@nocobase/flow-engine';
11
+ import { describe, expect, it } from 'vitest';
12
+ import { FormActionGroupModel, FormActionModel } from '../../../..';
13
+
14
+ describe('FormActionGroupModel', () => {
15
+ it('filters addable form actions by allowedFormActionModelNames', async () => {
16
+ class AllowedFormActionModel extends FormActionModel {}
17
+ class HiddenFormActionModel extends FormActionModel {}
18
+
19
+ AllowedFormActionModel.define({
20
+ label: 'Allowed action',
21
+ sort: 10,
22
+ });
23
+ HiddenFormActionModel.define({
24
+ label: 'Hidden action',
25
+ sort: 20,
26
+ });
27
+
28
+ const engine = new FlowEngine();
29
+ engine.registerModels({
30
+ FormActionModel,
31
+ HiddenFormActionModel,
32
+ });
33
+ engine.registerModelLoaders({
34
+ AllowedFormActionModel: {
35
+ loader: async () => ({ AllowedFormActionModel }),
36
+ },
37
+ });
38
+
39
+ const items = await FormActionGroupModel.defineChildren({
40
+ engine,
41
+ allowedFormActionModelNames: ['AllowedFormActionModel'],
42
+ } as any);
43
+
44
+ expect(items.map((item: any) => item.useModel)).toEqual(['AllowedFormActionModel']);
45
+ });
46
+ });
@@ -221,6 +221,23 @@ describe('FlowModel core behaviors (collected)', () => {
221
221
  expect(i1).toEqual({ ping: 1 });
222
222
  });
223
223
 
224
+ it('unchanged stepParams do not trigger a beforeRender rerun', async () => {
225
+ vi.useFakeTimers();
226
+ const spy = vi.fn().mockResolvedValue([]);
227
+ (engine as any).executor.dispatchEvent = spy;
228
+ const model = engine.createModel<FlowModel>({
229
+ use: 'FlowModel',
230
+ uid: 'm-flow-3-noop',
231
+ stepParams: { anyFlow: { anyStep: { x: 1 } } },
232
+ });
233
+
234
+ await model.dispatchEvent('beforeRender', { ping: 1 });
235
+ model.setStepParams('anyFlow', 'anyStep', { x: 1 });
236
+ await vi.advanceTimersByTimeAsync(150);
237
+
238
+ expect(spy).toHaveBeenCalledTimes(1);
239
+ });
240
+
224
241
  it('applyFlow delegates to executor.runFlow', async () => {
225
242
  const spyRun = vi.fn().mockResolvedValue('ok');
226
243
  (engine as any).executor.runFlow = spyRun;