@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
@@ -108,6 +108,54 @@ describe('FieldAssignRulesEditor', () => {
108
108
  };
109
109
  };
110
110
 
111
+ const createAssociationFixtureWithoutIsAssociationField = () => {
112
+ const profileCollection = {
113
+ titleField: 'name',
114
+ filterTargetKey: 'id',
115
+ getField: (name: string) => {
116
+ if (name === 'name') {
117
+ return { name: 'name', title: 'Name', interface: 'input' };
118
+ }
119
+ if (name === 'nickname') {
120
+ return { name: 'nickname', title: 'Nickname', interface: 'input' };
121
+ }
122
+ return null;
123
+ },
124
+ getFields: () => [
125
+ {
126
+ name: 'name',
127
+ title: 'Name',
128
+ interface: 'input',
129
+ },
130
+ {
131
+ name: 'nickname',
132
+ title: 'Nickname',
133
+ interface: 'input',
134
+ },
135
+ ],
136
+ };
137
+
138
+ const profileField: any = {
139
+ name: 'profile',
140
+ title: 'Profile',
141
+ type: 'belongsTo',
142
+ interface: 'm2o',
143
+ target: 'profiles',
144
+ targetKey: 'id',
145
+ targetCollection: profileCollection,
146
+ };
147
+
148
+ const rootCollection = {
149
+ getField: (name: string) => (name === 'profile' ? profileField : null),
150
+ getFields: () => [profileField],
151
+ };
152
+
153
+ return {
154
+ profileCollection,
155
+ rootCollection,
156
+ };
157
+ };
158
+
111
159
  const openAdvancedPanel = async () => {
112
160
  await userEvent.click(screen.getByRole('button', { name: /Advanced/i }));
113
161
  await screen.findByText('Title field');
@@ -175,6 +223,68 @@ describe('FieldAssignRulesEditor', () => {
175
223
  });
176
224
  });
177
225
 
226
+ it('recognizes lightweight association fields without isAssociationField()', async () => {
227
+ const { rootCollection } = createAssociationFixtureWithoutIsAssociationField();
228
+ const value: FieldAssignRuleItem[] = [
229
+ {
230
+ key: 'rule-profile',
231
+ enable: true,
232
+ targetPath: 'profile',
233
+ mode: 'assign',
234
+ },
235
+ ];
236
+
237
+ const { container } = render(
238
+ wrap(
239
+ <FieldAssignRulesEditor
240
+ t={t}
241
+ fieldOptions={[]}
242
+ rootCollection={rootCollection}
243
+ value={value}
244
+ showCondition={false}
245
+ isTitleFieldCandidate={() => true}
246
+ />,
247
+ ),
248
+ );
249
+
250
+ await waitFor(() => {
251
+ const input = container.querySelector('[data-testid="mock-value-input"]');
252
+ expect(input?.getAttribute('data-assoc-label')).toBe('name');
253
+ expect(input?.getAttribute('data-assoc-value')).toBe('id');
254
+ });
255
+ });
256
+
257
+ it('resolves nested labels and item meta tree through lightweight association fields', async () => {
258
+ const { rootCollection } = createAssociationFixtureWithoutIsAssociationField();
259
+ const value: FieldAssignRuleItem[] = [
260
+ {
261
+ key: 'rule-profile-nickname',
262
+ enable: true,
263
+ targetPath: 'profile.nickname',
264
+ mode: 'assign',
265
+ },
266
+ ];
267
+
268
+ const { container } = render(
269
+ wrap(
270
+ <FieldAssignRulesEditor
271
+ t={t}
272
+ fieldOptions={[]}
273
+ rootCollection={rootCollection}
274
+ value={value}
275
+ showCondition={false}
276
+ isTitleFieldCandidate={() => true}
277
+ />,
278
+ ),
279
+ );
280
+
281
+ await waitFor(() => {
282
+ expect(container.textContent).toContain('Profile / Nickname');
283
+ const input = container.querySelector('[data-testid="mock-value-input"]');
284
+ expect(input?.getAttribute('data-extra')).toBe('yes');
285
+ });
286
+ });
287
+
178
288
  it('saves selected title field into current assign rule without syncing', async () => {
179
289
  const { rootCollection, value } = createAssociationFixture();
180
290
  const onChange = vi.fn();
@@ -785,7 +895,8 @@ describe('FieldAssignRulesEditor', () => {
785
895
  expect(merged.map((node) => node.name)).toEqual(['formValues', 'item', 'user']);
786
896
  expect(merged.filter((node) => node.name === 'item')).toHaveLength(1);
787
897
 
788
- const itemNode = merged.find((node) => node.name === 'item')!;
898
+ const itemNode = merged.find((node) => node.name === 'item');
899
+ expect(itemNode).toBeTruthy();
789
900
  const parent = (itemNode.children as MetaTreeNode[]).find((node) => node.name === 'parentItem');
790
901
  expect(parent).toBeTruthy();
791
902
 
@@ -9,7 +9,10 @@
9
9
 
10
10
  import { describe, expect, it } from 'vitest';
11
11
  import { buildCustomFieldTargetPath } from '../../internal/utils/modelUtils';
12
- import { collectFieldAssignCascaderOptions } from '../fieldAssignOptions';
12
+ import {
13
+ buildFieldAssignCascaderOptionsFromCollection,
14
+ collectFieldAssignCascaderOptions,
15
+ } from '../fieldAssignOptions';
13
16
 
14
17
  describe('fieldAssignOptions', () => {
15
18
  it('marks subform node as non-leaf so Cascader can lazy-load target collection fields', () => {
@@ -94,4 +97,71 @@ describe('fieldAssignOptions', () => {
94
97
  options.some((o: any) => o?.value === customTargetPath && o?.label === 'Custom age' && o?.isLeaf === true),
95
98
  ).toBe(true);
96
99
  });
100
+
101
+ it('hides configured association fields deeper than relation / relation / field', () => {
102
+ const makeItem = (fieldPath: string, field: any, label: string) => ({
103
+ props: { label },
104
+ getStepParams: (flowKey: string, stepKey: string) => {
105
+ if (flowKey === 'fieldSettings' && stepKey === 'init') return { fieldPath };
106
+ return {};
107
+ },
108
+ subModels: {
109
+ field: {
110
+ context: { collectionField: field },
111
+ },
112
+ },
113
+ });
114
+
115
+ const companyField = {
116
+ name: 'company',
117
+ title: 'Company',
118
+ interface: 'm2o',
119
+ target: 'companies',
120
+ isAssociationField: () => true,
121
+ targetCollection: { getFields: () => [] },
122
+ };
123
+ const nameField = {
124
+ name: 'name',
125
+ title: 'Name',
126
+ interface: 'input',
127
+ isAssociationField: () => false,
128
+ };
129
+ const formBlockModel = {
130
+ context: { collection: null },
131
+ subModels: {
132
+ grid: {
133
+ subModels: {
134
+ items: [
135
+ makeItem('users.department.name', nameField, 'Department name'),
136
+ makeItem('users.department.company', companyField, 'Company'),
137
+ ],
138
+ },
139
+ },
140
+ },
141
+ };
142
+
143
+ const options = collectFieldAssignCascaderOptions({ formBlockModel, t: (s) => s });
144
+
145
+ expect(options.map((item) => item.value)).toContain('name');
146
+ expect(options.map((item) => item.value)).not.toContain('company');
147
+ });
148
+
149
+ it('hides lazy-loaded association selector options after two association levels', () => {
150
+ const collection = {
151
+ getFields: () => [
152
+ { name: 'name', title: 'Name', interface: 'input' },
153
+ {
154
+ name: 'company',
155
+ title: 'Company',
156
+ interface: 'm2o',
157
+ target: 'companies',
158
+ targetCollection: { getFields: () => [] },
159
+ },
160
+ ],
161
+ };
162
+
163
+ const options = buildFieldAssignCascaderOptionsFromCollection(collection, (s) => s, { associationDepth: 2 });
164
+
165
+ expect(options.map((item) => item.value)).toEqual(['name']);
166
+ });
97
167
  });
@@ -11,44 +11,97 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
11
11
 
12
12
  // Mock engine api provider
13
13
  vi.mock('@nocobase/flow-engine', () => {
14
- const doc = {
15
- properties: {
16
- foo: 'foo prop',
17
- api: {
18
- description: 'api client',
19
- completion: { insertText: 'ctx.api' },
20
- properties: {
21
- request: {
22
- description: 'send request',
23
- completion: { insertText: "await ctx.api.request({ url: '', method: 'get' })" },
14
+ const baseDocProperties = {
15
+ foo: 'foo prop',
16
+ api: {
17
+ description: 'api client',
18
+ completion: { insertText: 'ctx.api' },
19
+ properties: {
20
+ request: {
21
+ description: 'send request',
22
+ completion: { insertText: "await ctx.api.request({ url: '', method: 'get' })" },
23
+ },
24
+ },
25
+ },
26
+ viewer: {
27
+ description: 'viewer helpers',
28
+ properties: {
29
+ popover: {
30
+ type: 'function',
31
+ description: 'open popover',
32
+ completion: {
33
+ insertText: 'await ctx.viewer.popover({ target: ctx.element?.__el, content: <div /> })',
34
+ requires: ['element'],
35
+ },
36
+ },
37
+ embed: {
38
+ type: 'function',
39
+ description: 'open embed',
40
+ completion: {
41
+ insertText: 'await ctx.viewer.embed({ target: ctx.element?.__el, content: <div /> })',
42
+ requires: ['element'],
24
43
  },
25
44
  },
26
45
  },
27
- popup: {
28
- description: 'popup context (async)',
29
- detail: 'Promise<any>',
30
- hidden: async (ctx: any) => !(await ctx?.popup)?.uid,
31
- properties: {
32
- uid: 'popup uid',
33
- record: 'popup record',
34
- parent: {
35
- properties: {
36
- record: 'parent record',
37
- },
46
+ },
47
+ popup: {
48
+ description: 'popup context (async)',
49
+ detail: 'Promise<any>',
50
+ hidden: async (ctx: any) => !(await ctx?.popup)?.uid,
51
+ properties: {
52
+ uid: 'popup uid',
53
+ record: 'popup record',
54
+ parent: {
55
+ properties: {
56
+ record: 'parent record',
38
57
  },
39
58
  },
40
59
  },
41
60
  },
42
- methods: {
43
- bar: {
44
- description: 'bar method',
45
- completion: { insertText: "ctx.bar('value')" },
61
+ };
62
+ const methods = {
63
+ bar: {
64
+ description: 'bar method',
65
+ completion: { insertText: "ctx.bar('value')" },
66
+ },
67
+ render: {
68
+ description: 'render react content',
69
+ completion: { insertText: 'ctx.render(<div />)', requires: ['element'] },
70
+ },
71
+ };
72
+ const baseDoc = {
73
+ properties: baseDocProperties,
74
+ methods,
75
+ };
76
+ const domDoc = {
77
+ properties: {
78
+ ...baseDocProperties,
79
+ element: {
80
+ description: 'DOM container',
81
+ detail: 'ElementProxy',
82
+ properties: {
83
+ innerHTML: 'inner html',
84
+ setAttribute: {
85
+ type: 'function',
86
+ detail: '(name: string, value: string) => void',
87
+ completion: { insertText: "ctx.element.setAttribute('data-key', 'value')" },
88
+ },
89
+ },
46
90
  },
47
91
  },
92
+ methods,
48
93
  };
94
+ const domModels = new Set([
95
+ 'JSBlockModel',
96
+ 'JSFieldModel',
97
+ 'JSEditableFieldModel',
98
+ 'JSItemModel',
99
+ 'JSColumnModel',
100
+ 'FormJSFieldItemModel',
101
+ ]);
49
102
  return {
50
- getRunJSDocFor: () => doc,
51
- FlowRunJSContext: { getDoc: () => doc },
103
+ getRunJSDocFor: (ctx: any) => (domModels.has(ctx?.model?.constructor?.name) ? domDoc : baseDoc),
104
+ FlowRunJSContext: { getDoc: () => baseDoc },
52
105
  // New cohesive APIs
53
106
  listSnippetsForContext: async () => [
54
107
  {
@@ -69,6 +122,17 @@ vi.mock('@nocobase/flow-engine', () => {
69
122
  import { buildRunJSCompletions } from '../runjsCompletions';
70
123
 
71
124
  describe('buildRunJSCompletions', () => {
125
+ const labelsOf = (completions: any[]) => new Set(completions.map((c: any) => c.label));
126
+
127
+ const appliedTextsOf = (completions: any[]) =>
128
+ completions.flatMap((completion: any) => {
129
+ const mockView = { dispatch: vi.fn() } as any;
130
+ if (typeof completion.apply === 'function') {
131
+ completion.apply(mockView, completion, 0, 0);
132
+ }
133
+ return mockView.dispatch.mock.calls.map((call: any[]) => String(call[0]?.changes?.insert || ''));
134
+ });
135
+
72
136
  it('builds ctx property/method completions and snippets', async () => {
73
137
  const hostCtx = { popup: Promise.resolve({ uid: 'p1' }) }; // not used since engine doc is mocked
74
138
  const { completions, entries } = await buildRunJSCompletions(hostCtx, 'v1', 'block');
@@ -242,4 +306,185 @@ describe('buildRunJSCompletions', () => {
242
306
  // restore
243
307
  engineDoc.properties.popup.hidden = prev;
244
308
  });
309
+
310
+ it('adds safe browser/runtime global completions and excludes blocked globals', async () => {
311
+ const { completions } = await buildRunJSCompletions({}, 'v1', 'block');
312
+ const labels = new Set(completions.map((c: any) => c.label));
313
+
314
+ expect(labels.has('window.location.reload()')).toBe(true);
315
+ expect(labels.has('document.createElement()')).toBe(true);
316
+ expect(labels.has('navigator.clipboard.writeText()')).toBe(true);
317
+ expect(labels.has('console.log()')).toBe(true);
318
+ expect(labels.has('setTimeout()')).toBe(true);
319
+ expect(labels.has('Blob')).toBe(true);
320
+ expect(labels.has('URL')).toBe(true);
321
+
322
+ expect(labels.has('navigator.userAgent')).toBe(false);
323
+ expect(labels.has('navigator.geolocation')).toBe(false);
324
+ expect(labels.has('document.cookie')).toBe(false);
325
+ expect(labels.has('document.body')).toBe(false);
326
+ expect(labels.has('document.getElementById()')).toBe(false);
327
+ expect(labels.has('window.location.href')).toBe(false);
328
+ expect(labels.has('window.location.href =')).toBe(true);
329
+ });
330
+
331
+ it('adds stable ctx runtime namespace completions', async () => {
332
+ const hostCtx = {
333
+ model: {
334
+ constructor: {
335
+ name: 'JSBlockModel',
336
+ },
337
+ },
338
+ };
339
+ const { completions } = await buildRunJSCompletions(hostCtx, 'v1', 'block');
340
+ const labels = labelsOf(completions);
341
+
342
+ expect(labels.has('ctx.runjs()')).toBe(true);
343
+ expect(labels.has('ctx.sql.run()')).toBe(true);
344
+ expect(labels.has('ctx.logger.info()')).toBe(true);
345
+ expect(labels.has('ctx.element.setAttribute()')).toBe(true);
346
+ expect(labels.has('ctx.libs.React.createElement()')).toBe(true);
347
+ expect(labels.has('ctx.libs.lodash.get()')).toBe(true);
348
+ });
349
+
350
+ it('does not expose ctx.element for generic base completions', async () => {
351
+ const { completions } = await buildRunJSCompletions({}, 'v1', 'block');
352
+ const labels = labelsOf(completions);
353
+ const appliedTexts = appliedTextsOf(completions);
354
+
355
+ expect([...labels].some((label) => String(label).startsWith('ctx.element'))).toBe(false);
356
+ expect(labels.has('ctx.render()')).toBe(false);
357
+ expect(appliedTexts.some((text) => /\bctx\.element\b/.test(text))).toBe(false);
358
+ expect(appliedTexts.some((text) => text === 'ctx.render(<div />)')).toBe(false);
359
+ });
360
+
361
+ it('keeps ctx.element completions for DOM container models', async () => {
362
+ const hostCtx = {
363
+ model: {
364
+ constructor: {
365
+ name: 'JSBlockModel',
366
+ },
367
+ },
368
+ };
369
+ const { completions } = await buildRunJSCompletions(hostCtx, 'v1', 'block');
370
+ const labels = labelsOf(completions);
371
+
372
+ expect(labels.has('ctx.element.innerHTML')).toBe(true);
373
+ expect(labels.has('ctx.element.setAttribute()')).toBe(true);
374
+ expect(labels.has('ctx.libs.ReactDOM.createRoot()')).toBe(true);
375
+ expect(labels.has('ctx.render()')).toBe(true);
376
+
377
+ const renderCompletion = completions.find((c: any) => c.label === 'ctx.render()');
378
+ const mockView = { dispatch: vi.fn() } as any;
379
+ (renderCompletion as any).apply?.(mockView, renderCompletion, 0, 0);
380
+ expect(mockView.dispatch.mock.calls[0][0]?.changes?.insert).toBe('ctx.render(<div />)');
381
+ });
382
+
383
+ it('hides ctx.element-dependent completions for eventFlow', async () => {
384
+ const hostCtx = {
385
+ model: {
386
+ constructor: {
387
+ name: 'JSBlockModel',
388
+ },
389
+ },
390
+ };
391
+ const { completions } = await buildRunJSCompletions(hostCtx, 'v1', 'eventFlow');
392
+ const labels = labelsOf(completions);
393
+ const appliedTexts = appliedTextsOf(completions);
394
+
395
+ expect([...labels].some((label) => String(label).startsWith('ctx.element'))).toBe(false);
396
+ expect(labels.has('ctx.libs.ReactDOM.createRoot()')).toBe(false);
397
+ expect(labels.has('ctx.ReactDOM.createRoot()')).toBe(false);
398
+ expect(labels.has('ctx.viewer.popover()')).toBe(false);
399
+ expect(labels.has('ctx.viewer.embed()')).toBe(false);
400
+ expect(labels.has('ctx.render()')).toBe(false);
401
+ expect(appliedTexts.some((text) => /\bctx\.element\b/.test(text))).toBe(false);
402
+ expect(appliedTexts.some((text) => text === 'ctx.render(<div />)')).toBe(false);
403
+ });
404
+
405
+ it('hides ctx.element-dependent completions for non-DOM action models', async () => {
406
+ for (const [modelName, scene] of [
407
+ ['JSRecordActionModel', 'table'],
408
+ ['JSFormActionModel', 'form'],
409
+ ['FilterFormJSActionModel', 'form'],
410
+ ]) {
411
+ const hostCtx = {
412
+ model: {
413
+ constructor: {
414
+ name: modelName,
415
+ },
416
+ },
417
+ };
418
+ const { completions } = await buildRunJSCompletions(hostCtx, 'v1', scene);
419
+ const labels = labelsOf(completions);
420
+ const appliedTexts = appliedTextsOf(completions);
421
+
422
+ expect([...labels].some((label) => String(label).startsWith('ctx.element'))).toBe(false);
423
+ expect(labels.has('ctx.libs.ReactDOM.createRoot()')).toBe(false);
424
+ expect(labels.has('ctx.ReactDOM.createRoot()')).toBe(false);
425
+ expect(labels.has('ctx.render()')).toBe(false);
426
+ expect(appliedTexts.some((text) => /\bctx\.element\b/.test(text))).toBe(false);
427
+ expect(appliedTexts.some((text) => text === 'ctx.render(<div />)')).toBe(false);
428
+ }
429
+ });
430
+
431
+ it('uses friendly insertText for ctx.loadCSS and ctx.previewRunJS', async () => {
432
+ const { completions } = await buildRunJSCompletions({}, 'v1', 'block');
433
+
434
+ for (const [label, expected] of [
435
+ ['ctx.loadCSS()', "await ctx.loadCSS('https://example.com/style.css')"],
436
+ ['ctx.previewRunJS()', "await ctx.previewRunJS('console.log(1)', 'v2')"],
437
+ ['ctx.resolveJsonTemplate()', "await ctx.resolveJsonTemplate({ value: '{{ctx.record.id}}' })"],
438
+ ]) {
439
+ const completion = completions.find((c: any) => c.label === label);
440
+ expect(completion).toBeTruthy();
441
+ expect(typeof (completion as any).apply).toBe('function');
442
+
443
+ const mockView = { dispatch: vi.fn() } as any;
444
+ (completion as any).apply?.(mockView, completion, 0, 0);
445
+ expect(mockView.dispatch.mock.calls[0][0]?.changes?.insert).toBe(expected);
446
+ expect(mockView.dispatch.mock.calls[0][0]?.changes?.insert).not.toBe(label);
447
+ }
448
+ });
449
+
450
+ it('requests completion metadata from ctx.getApiInfos() for editor completions', async () => {
451
+ const getApiInfos = vi.fn(async (options?: any) => ({
452
+ customRuntime: {
453
+ type: 'function',
454
+ description: 'custom runtime helper',
455
+ completion: {
456
+ insertText: options?.includeCompletion ? "await ctx.customRuntime('value')" : undefined,
457
+ },
458
+ },
459
+ }));
460
+
461
+ const { completions } = await buildRunJSCompletions({ getApiInfos }, 'v1', 'block');
462
+
463
+ expect(getApiInfos).toHaveBeenCalledWith({ version: 'v1', includeCompletion: true });
464
+ const completion = completions.find((c: any) => c.label === 'ctx.customRuntime()');
465
+ expect(completion).toBeTruthy();
466
+
467
+ const mockView = { dispatch: vi.fn() } as any;
468
+ (completion as any).apply?.(mockView, completion, 0, 0);
469
+ expect(mockView.dispatch.mock.calls[0][0]?.changes?.insert).toBe("await ctx.customRuntime('value')");
470
+ });
471
+
472
+ it('keeps friendly insertText for ctx.resolveJsonTemplate with Chinese docs', async () => {
473
+ const hostCtx = {
474
+ api: {
475
+ auth: {
476
+ locale: 'zh-CN',
477
+ },
478
+ },
479
+ };
480
+ const { completions } = await buildRunJSCompletions(hostCtx, 'v1', 'block');
481
+ const completion = completions.find((c: any) => c.label === 'ctx.resolveJsonTemplate()');
482
+ expect(completion).toBeTruthy();
483
+
484
+ const mockView = { dispatch: vi.fn() } as any;
485
+ (completion as any).apply?.(mockView, completion, 0, 0);
486
+ expect(mockView.dispatch.mock.calls[0][0]?.changes?.insert).toBe(
487
+ "await ctx.resolveJsonTemplate({ value: '{{ctx.record.id}}' })",
488
+ );
489
+ });
245
490
  });