@nocobase/client-v2 2.2.0-alpha.1 → 2.2.0-alpha.10

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 (334) hide show
  1. package/es/APIClient.d.ts +1 -3
  2. package/es/BaseApplication.d.ts +3 -0
  3. package/es/PluginSettingsManager.d.ts +33 -0
  4. package/es/RouteRepository.d.ts +29 -6
  5. package/es/RouterManager.d.ts +15 -0
  6. package/es/authRedirect.d.ts +1 -0
  7. package/es/collection-field-interface/CollectionFieldInterface.d.ts +1 -0
  8. package/es/collection-field-interface/CollectionFieldInterfaceManager.d.ts +1 -0
  9. package/es/components/category-tabs/SortableCategoryTabs.d.ts +55 -0
  10. package/es/components/category-tabs/index.d.ts +9 -0
  11. package/es/components/form/JsonTextArea.d.ts +2 -1
  12. package/es/components/form/ScanInput/useCodeScanner.d.ts +3 -2
  13. package/es/components/form/TypedVariableInput.d.ts +31 -5
  14. package/es/components/form/VariableJsonTextArea.d.ts +19 -0
  15. package/es/components/form/filter/CollectionFilter.d.ts +2 -0
  16. package/es/components/form/filter/CollectionFilterItem.d.ts +11 -1
  17. package/es/components/form/filter/CollectionFilterPanel.d.ts +2 -0
  18. package/es/components/form/filter/index.d.ts +2 -0
  19. package/es/components/form/filter/useFilterActionProps.d.ts +2 -0
  20. package/es/components/form/index.d.ts +1 -0
  21. package/es/components/index.d.ts +2 -0
  22. package/es/entry-actions/EntryActionManager.d.ts +24 -0
  23. package/es/entry-actions/index.d.ts +9 -0
  24. package/es/flow/actions/afterSuccess.d.ts +8 -1
  25. package/es/flow/actions/index.d.ts +2 -2
  26. package/es/flow/actions/linkageRules.d.ts +2 -0
  27. package/es/flow/admin-shell/BaseLayoutModel.d.ts +6 -0
  28. package/es/flow/admin-shell/BaseLayoutRouteCoordinator.d.ts +7 -0
  29. package/es/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.d.ts +2 -0
  30. package/es/flow/admin-shell/admin-layout/AdminLayoutMenuFlowUtils.d.ts +2 -1
  31. package/es/flow/admin-shell/admin-layout/AdminLayoutMenuModels.d.ts +3 -0
  32. package/es/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.d.ts +3 -2
  33. package/es/flow/admin-shell/admin-layout/AdminLayoutSlotModels.d.ts +5 -0
  34. package/es/flow/admin-shell/admin-layout/AppListRender.d.ts +2 -1
  35. package/es/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.d.ts +24 -0
  36. package/es/flow/admin-shell/admin-layout/index.d.ts +1 -0
  37. package/es/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.d.ts +6 -0
  38. package/es/flow/admin-shell/admin-layout/useApplications.d.ts +7 -2
  39. package/es/flow/components/FieldAssignExactDatePicker.d.ts +1 -0
  40. package/es/flow/components/FieldAssignRulesEditor.d.ts +3 -1
  41. package/es/flow/components/FieldAssignValueInput.d.ts +9 -0
  42. package/es/flow/components/FlowRoute.d.ts +2 -2
  43. package/es/flow/components/RunJSValueEditor.d.ts +1 -0
  44. package/es/flow/components/filter/FilterGroup.d.ts +1 -0
  45. package/es/flow/components/filter/VariableFilterItem.d.ts +6 -1
  46. package/es/flow/index.d.ts +1 -0
  47. package/es/flow/internal/registerDeviceTypeContext.d.ts +10 -0
  48. package/es/flow/models/base/ActionModelCore.d.ts +2 -0
  49. package/es/flow/models/base/BlockGridModel.d.ts +3 -0
  50. package/es/flow/models/base/GridModel.d.ts +1 -1
  51. package/es/flow/models/base/PageModel/PageModel.d.ts +12 -0
  52. package/es/flow/models/base/PageModel/PageModelTabBar.d.ts +22 -0
  53. package/es/flow/models/base/PageModel/PageTabModel.d.ts +12 -0
  54. package/es/flow/models/blocks/filter-form/FilterFormBlockModel.d.ts +5 -0
  55. package/es/flow/models/blocks/form/FormBlockModel.d.ts +4 -0
  56. package/es/flow/models/blocks/form/QuickEditFormModel.d.ts +17 -2
  57. package/es/flow/models/blocks/form/submitHandler.d.ts +1 -1
  58. package/es/flow/models/blocks/form/value-runtime/rules.d.ts +21 -0
  59. package/es/flow/models/blocks/form/value-runtime/runtime.d.ts +30 -0
  60. package/es/flow/models/blocks/form/value-runtime/types.d.ts +2 -2
  61. package/es/flow/models/blocks/js-block/JSBlock.d.ts +1 -0
  62. package/es/flow/models/blocks/table/TableActionsColumnModel.d.ts +1 -0
  63. package/es/flow/models/blocks/table/TableBlockModel.d.ts +1 -0
  64. package/es/flow/models/blocks/table/TableColumnModel.d.ts +1 -0
  65. package/es/flow/models/blocks/table/dragSort/dragSortHooks.d.ts +1 -1
  66. package/es/flow/models/blocks/table/dragSort/dragSortSettings.d.ts +2 -1
  67. package/es/flow/models/blocks/table/dragSort/dragSortUtils.d.ts +6 -4
  68. package/es/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.d.ts +2 -0
  69. package/es/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.d.ts +6 -0
  70. package/es/flow/models/fields/DateTimeFieldModel/dateLimit.d.ts +15 -7
  71. package/es/flow/resolveViewParamsToViewList.d.ts +1 -1
  72. package/es/flow/routeTransientInputArgs.d.ts +14 -0
  73. package/es/flow/utils/dataScopeRowSnapshot.d.ts +59 -0
  74. package/es/flow/utils/dateTimeDisplayProps.d.ts +49 -0
  75. package/es/flow/utils/formValueDeps.d.ts +32 -0
  76. package/es/flow-compat/FieldValidation.d.ts +2 -1
  77. package/es/flow-compat/fieldValidationConstants.d.ts +1 -1
  78. package/es/flow-compat/routeTypes.d.ts +1 -0
  79. package/es/index.d.ts +8 -1
  80. package/es/index.mjs +367 -181
  81. package/es/utils/getRouteRuntimeVersion.d.ts +23 -0
  82. package/es/utils/index.d.ts +1 -0
  83. package/es/utils/markdownSanitize.d.ts +11 -0
  84. package/lib/index.js +367 -181
  85. package/lib/locale/languageCodes.js +3 -1
  86. package/package.json +9 -7
  87. package/src/APIClient.ts +1 -10
  88. package/src/Application.tsx +4 -0
  89. package/src/BaseApplication.tsx +13 -6
  90. package/src/PluginSettingsManager.ts +53 -0
  91. package/src/RouteRepository.ts +151 -24
  92. package/src/RouterManager.tsx +142 -1
  93. package/src/__tests__/PluginSettingsManager.test.ts +13 -0
  94. package/src/__tests__/RouteRepository.test.ts +239 -0
  95. package/src/__tests__/RouterManager.test.ts +125 -0
  96. package/src/__tests__/app.test.tsx +73 -0
  97. package/src/__tests__/authRedirect.test.ts +17 -0
  98. package/src/__tests__/browserChecker.test.ts +61 -0
  99. package/src/__tests__/exports.test.ts +16 -0
  100. package/src/__tests__/getRouteRuntimeVersion.test.ts +68 -0
  101. package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +234 -2
  102. package/src/__tests__/plugin-manager.test.tsx +44 -2
  103. package/src/__tests__/settings-center.test.tsx +40 -1
  104. package/src/authRedirect.ts +38 -0
  105. package/src/collection-field-interface/CollectionFieldInterface.ts +1 -0
  106. package/src/collection-field-interface/CollectionFieldInterfaceManager.ts +1 -0
  107. package/src/collection-manager/field-configure.ts +1 -1
  108. package/src/collection-manager/field-validation.ts +1 -1
  109. package/src/collection-manager/interfaces/id.ts +1 -1
  110. package/src/collection-manager/interfaces/m2m.tsx +2 -2
  111. package/src/collection-manager/interfaces/m2o.tsx +2 -2
  112. package/src/collection-manager/interfaces/nanoid.ts +1 -1
  113. package/src/collection-manager/interfaces/o2m.tsx +2 -2
  114. package/src/collection-manager/interfaces/obo.tsx +2 -2
  115. package/src/collection-manager/interfaces/oho.tsx +2 -2
  116. package/src/collection-manager/interfaces/properties/index.ts +2 -2
  117. package/src/collection-manager/interfaces/uuid.ts +1 -1
  118. package/src/components/AppComponents.tsx +19 -3
  119. package/src/components/README.md +7 -1
  120. package/src/components/README.zh-CN.md +6 -1
  121. package/src/components/category-tabs/SortableCategoryTabs.tsx +210 -0
  122. package/src/components/category-tabs/index.ts +10 -0
  123. package/src/components/form/JsonTextArea.tsx +25 -11
  124. package/src/components/form/ScanInput/CodeScanner.tsx +79 -35
  125. package/src/components/form/ScanInput/__tests__/CodeScanner.test.tsx +101 -0
  126. package/src/components/form/ScanInput/__tests__/useCodeScanner.test.tsx +284 -11
  127. package/src/components/form/ScanInput/useCodeScanner.ts +332 -24
  128. package/src/components/form/TypedVariableInput.tsx +452 -101
  129. package/src/components/form/VariableJsonTextArea.tsx +175 -0
  130. package/src/components/form/__tests__/JsonTextArea.test.tsx +43 -0
  131. package/src/components/form/__tests__/TypedVariableInput.test.tsx +364 -12
  132. package/src/components/form/__tests__/VariableJsonTextArea.test.tsx +86 -0
  133. package/src/components/form/filter/CollectionFilter.tsx +4 -0
  134. package/src/components/form/filter/CollectionFilterItem.tsx +32 -7
  135. package/src/components/form/filter/CollectionFilterPanel.tsx +4 -0
  136. package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +38 -0
  137. package/src/components/form/filter/__tests__/useFilterActionProps.test.tsx +95 -0
  138. package/src/components/form/filter/index.ts +2 -0
  139. package/src/components/form/filter/useFilterActionProps.ts +37 -6
  140. package/src/components/form/index.tsx +1 -0
  141. package/src/components/index.ts +2 -0
  142. package/src/entry-actions/EntryActionManager.ts +76 -0
  143. package/src/entry-actions/index.ts +10 -0
  144. package/src/flow/FlowPage.tsx +38 -3
  145. package/src/flow/__tests__/FlowPage.test.tsx +201 -27
  146. package/src/flow/__tests__/FlowRoute.test.tsx +1181 -80
  147. package/src/flow/__tests__/PluginFlowEngine.test.ts +58 -0
  148. package/src/flow/__tests__/getKey.test.ts +7 -0
  149. package/src/flow/__tests__/resolveViewParamsToViewList.test.ts +34 -0
  150. package/src/flow/actions/__tests__/actionLinkageRules.forkProps.test.ts +115 -0
  151. package/src/flow/actions/__tests__/afterSuccess.test.ts +73 -0
  152. package/src/flow/actions/__tests__/dataScopeFilter.test.ts +120 -0
  153. package/src/flow/actions/__tests__/dataScopeFormValueClear.test.ts +1124 -0
  154. package/src/flow/actions/__tests__/fieldLinkageRules.scopeDepth.test.ts +150 -1
  155. package/src/flow/actions/__tests__/linkageAssignField.legacy.test.ts +135 -0
  156. package/src/flow/actions/__tests__/linkageRules.hiddenSync.restore.test.ts +19 -5
  157. package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +92 -0
  158. package/src/flow/actions/__tests__/linkageRules.tab.test.ts +171 -0
  159. package/src/flow/actions/__tests__/linkageRulesRefresh.test.ts +7 -3
  160. package/src/flow/actions/__tests__/openView.defineProps.route.test.tsx +164 -0
  161. package/src/flow/actions/__tests__/subFormFieldLinkageRules.inputArgs.test.ts +2 -2
  162. package/src/flow/actions/afterSuccess.tsx +142 -3
  163. package/src/flow/actions/customVariable.tsx +1 -2
  164. package/src/flow/actions/dataScopeFilter.ts +20 -1
  165. package/src/flow/actions/dateTimeFormat.tsx +42 -28
  166. package/src/flow/actions/index.ts +3 -1
  167. package/src/flow/actions/linkageRules.tsx +209 -47
  168. package/src/flow/actions/linkageRulesFormValueRefresh.ts +22 -130
  169. package/src/flow/actions/linkageRulesRefresh.tsx +2 -6
  170. package/src/flow/actions/openView.tsx +59 -5
  171. package/src/flow/actions/runjs.tsx +2 -14
  172. package/src/flow/actions/validation.tsx +62 -30
  173. package/src/flow/admin-shell/BaseLayoutModel.tsx +149 -3
  174. package/src/flow/admin-shell/BaseLayoutRouteCoordinator.ts +187 -42
  175. package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +1020 -110
  176. package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +74 -14
  177. package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.test.tsx +486 -0
  178. package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +64 -8
  179. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuFlowUtils.ts +5 -3
  180. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuModels.tsx +61 -9
  181. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.tsx +71 -8
  182. package/src/flow/admin-shell/admin-layout/AdminLayoutModel.tsx +1 -1
  183. package/src/flow/admin-shell/admin-layout/AdminLayoutSlotModels.tsx +23 -9
  184. package/src/flow/admin-shell/admin-layout/AppListRender.tsx +13 -2
  185. package/src/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.tsx +289 -0
  186. package/src/flow/admin-shell/admin-layout/HelpLite.tsx +1 -3
  187. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutComponent.test.tsx +435 -0
  188. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +99 -0
  189. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutModel.test.tsx +518 -2
  190. package/src/flow/admin-shell/admin-layout/__tests__/TopbarActionsBar.test.tsx +214 -2
  191. package/src/flow/admin-shell/admin-layout/index.ts +1 -0
  192. package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.test.ts +20 -0
  193. package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.ts +33 -5
  194. package/src/flow/admin-shell/admin-layout/useApplications.tsx +81 -12
  195. package/src/flow/common/Markdown/Display.tsx +14 -3
  196. package/src/flow/common/Markdown/Edit.tsx +19 -7
  197. package/src/flow/common/Markdown/style.ts +4 -0
  198. package/src/flow/components/BlockItemCard.tsx +2 -2
  199. package/src/flow/components/DefaultValue.tsx +1 -2
  200. package/src/flow/components/DynamicFlowsIcon.tsx +447 -126
  201. package/src/flow/components/FieldAssignExactDatePicker.tsx +25 -11
  202. package/src/flow/components/FieldAssignRulesEditor.tsx +128 -21
  203. package/src/flow/components/FieldAssignValueInput.tsx +91 -20
  204. package/src/flow/components/FlowRoute.tsx +256 -53
  205. package/src/flow/components/RunJSValueEditor.tsx +9 -1
  206. package/src/flow/components/__tests__/DynamicFlowsIcon.test.tsx +148 -2
  207. package/src/flow/components/__tests__/FieldAssignRulesEditor.test.tsx +508 -4
  208. package/src/flow/components/__tests__/FieldAssignValueInput.context.test.tsx +216 -0
  209. package/src/flow/components/__tests__/fieldAssignOptions.test.ts +151 -3
  210. package/src/flow/components/code-editor/__tests__/useCodeRunner.test.tsx +2 -17
  211. package/src/flow/components/code-editor/hooks/useCodeRunner.ts +2 -14
  212. package/src/flow/components/code-editor/runjsDiagnostics.ts +8 -45
  213. package/src/flow/components/fieldAssignOptions.ts +155 -27
  214. package/src/flow/components/filter/FilterGroup.tsx +33 -5
  215. package/src/flow/components/filter/VariableFilterItem.tsx +158 -10
  216. package/src/flow/components/filter/__tests__/FilterGroup.test.tsx +45 -0
  217. package/src/flow/components/filter/__tests__/VariableFilterItem.leftMetaTree.test.tsx +9 -0
  218. package/src/flow/components/filter/__tests__/VariableFilterItem.test.tsx +70 -1
  219. package/src/flow/flows/editMarkdownFlow.tsx +1 -1
  220. package/src/flow/getViewDiffAndUpdateHidden.tsx +1 -0
  221. package/src/flow/index.ts +4 -1
  222. package/src/flow/internal/components/Markdown/util.ts +2 -1
  223. package/src/flow/internal/registerDeviceTypeContext.ts +39 -0
  224. package/src/flow/internal/utils/operatorSchemaHelper.ts +15 -1
  225. package/src/flow/models/actions/JSActionModel.tsx +2 -7
  226. package/src/flow/models/actions/JSCollectionActionModel.tsx +2 -7
  227. package/src/flow/models/actions/JSItemActionModel.tsx +2 -7
  228. package/src/flow/models/actions/JSRecordActionModel.tsx +2 -7
  229. package/src/flow/models/base/ActionModel.tsx +21 -8
  230. package/src/flow/models/base/ActionModelCore.tsx +11 -4
  231. package/src/flow/models/base/BlockGridModel.tsx +26 -0
  232. package/src/flow/models/base/CollectionBlockModel.tsx +6 -2
  233. package/src/flow/models/base/GridModel.tsx +38 -7
  234. package/src/flow/models/base/PageModel/PageModel.tsx +387 -50
  235. package/src/flow/models/base/PageModel/PageModelTabBar.tsx +114 -0
  236. package/src/flow/models/base/PageModel/PageTabModel.tsx +249 -18
  237. package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +817 -13
  238. package/src/flow/models/base/PageModel/__tests__/PageModelTabBar.module-isolation.test.tsx +130 -0
  239. package/src/flow/models/base/PageModel/__tests__/PageModelTabBar.test.tsx +118 -0
  240. package/src/flow/models/base/PageModel/__tests__/PageTabModel.test.ts +1075 -7
  241. package/src/flow/models/base/__tests__/ActionModel.test.ts +83 -0
  242. package/src/flow/models/base/__tests__/ActionModelCore.render.test.tsx +37 -0
  243. package/src/flow/models/base/__tests__/BlockGridModel.selectSceneActivation.test.ts +124 -0
  244. package/src/flow/models/base/__tests__/CollectionBlockModel.addAppends.test.ts +41 -0
  245. package/src/flow/models/base/__tests__/GridModel.dragSnapshotContainer.test.ts +239 -1
  246. package/src/flow/models/base/__tests__/transformRowsToSingleColumn.test.ts +48 -0
  247. package/src/flow/models/blocks/filter-form/FilterFormBlockModel.tsx +59 -6
  248. package/src/flow/models/blocks/filter-form/FilterFormItemModel.tsx +27 -12
  249. package/src/flow/models/blocks/filter-form/FilterFormJSActionModel.tsx +2 -7
  250. package/src/flow/models/blocks/filter-form/__tests__/FilterFormItemModel.defineChildren.test.ts +36 -0
  251. package/src/flow/models/blocks/filter-form/__tests__/defaultValues.wiring.test.ts +143 -4
  252. package/src/flow/models/blocks/filter-form/fields/FilterFormCustomFieldModel.tsx +1 -1
  253. package/src/flow/models/blocks/filter-manager/flow-actions/__tests__/customizeFilterRender.test.tsx +56 -1
  254. package/src/flow/models/blocks/form/EditFormModel.tsx +1 -0
  255. package/src/flow/models/blocks/form/FormActionModel.tsx +1 -1
  256. package/src/flow/models/blocks/form/FormBlockModel.tsx +7 -0
  257. package/src/flow/models/blocks/form/JSFormActionModel.tsx +2 -7
  258. package/src/flow/models/blocks/form/QuickEditFormModel.tsx +189 -36
  259. package/src/flow/models/blocks/form/__tests__/FormBlockModel.test.tsx +17 -0
  260. package/src/flow/models/blocks/form/__tests__/QuickEditFormModel.quickEdit.test.ts +350 -2
  261. package/src/flow/models/blocks/form/__tests__/submitHandler.test.ts +54 -1
  262. package/src/flow/models/blocks/form/submitHandler.ts +17 -3
  263. package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +940 -75
  264. package/src/flow/models/blocks/form/value-runtime/rules.ts +445 -13
  265. package/src/flow/models/blocks/form/value-runtime/runtime.ts +348 -13
  266. package/src/flow/models/blocks/form/value-runtime/types.ts +2 -2
  267. package/src/flow/models/blocks/js-block/JSBlock.tsx +225 -9
  268. package/src/flow/models/blocks/js-block/__tests__/JSBlockModel.test.tsx +150 -0
  269. package/src/flow/models/blocks/table/JSColumnModel.tsx +1 -9
  270. package/src/flow/models/blocks/table/TableActionsColumnModel.tsx +38 -14
  271. package/src/flow/models/blocks/table/TableBlockModel.tsx +42 -19
  272. package/src/flow/models/blocks/table/TableColumnModel.tsx +72 -6
  273. package/src/flow/models/blocks/table/__tests__/TableActionsColumnModel.test.tsx +111 -1
  274. package/src/flow/models/blocks/table/__tests__/TableBlockModel.dragSort.test.ts +127 -0
  275. package/src/flow/models/blocks/table/__tests__/TableBlockModel.mobileSettingsButtons.test.tsx +78 -0
  276. package/src/flow/models/blocks/table/__tests__/TableBlockModel.quickEditRefresh.test.ts +12 -0
  277. package/src/flow/models/blocks/table/__tests__/TableBlockModel.rowSelection.test.tsx +1 -0
  278. package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +243 -1
  279. package/src/flow/models/blocks/table/dragSort/dragSortHooks.tsx +28 -17
  280. package/src/flow/models/blocks/table/dragSort/dragSortSettings.ts +13 -6
  281. package/src/flow/models/blocks/table/dragSort/dragSortUtils.ts +15 -2
  282. package/src/flow/models/fields/AssociationFieldModel/AssociationFieldModel.tsx +1 -1
  283. package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/PopupSubTableFieldModel.tsx +31 -7
  284. package/src/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.tsx +61 -17
  285. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.tsx +141 -19
  286. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableField.tsx +13 -1
  287. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableColumnModel.rowRecord.test.ts +197 -0
  288. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableFieldModel.reset.test.ts +180 -0
  289. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.tsx +6 -4
  290. package/src/flow/models/fields/AssociationFieldModel/__tests__/AssociationFieldModel.updateAssociation.test.ts +72 -0
  291. package/src/flow/models/fields/AssociationFieldModel/__tests__/RecordPickerFieldModel.itemContext.test.ts +23 -0
  292. package/src/flow/models/fields/ClickableFieldModel.tsx +5 -0
  293. package/src/flow/models/fields/DateTimeFieldModel/__tests__/DateTimeNoTzFieldModel.dateLimit.test.tsx +149 -0
  294. package/src/flow/models/fields/DateTimeFieldModel/dateLimit.ts +149 -113
  295. package/src/flow/models/fields/DisplayDateTimeFieldModel.tsx +29 -1
  296. package/src/flow/models/fields/InputFieldModel.tsx +40 -2
  297. package/src/flow/models/fields/JSEditableFieldModel.tsx +2 -11
  298. package/src/flow/models/fields/JSFieldModel.tsx +2 -7
  299. package/src/flow/models/fields/JSItemModel.tsx +2 -14
  300. package/src/flow/models/fields/SelectFieldModel.tsx +6 -4
  301. package/src/flow/models/fields/TextareaFieldModel.tsx +72 -3
  302. package/src/flow/models/fields/VariableFieldFormModel.tsx +3 -3
  303. package/src/flow/models/fields/__tests__/DisplayDateTimeFieldModel.test.tsx +96 -0
  304. package/src/flow/models/fields/__tests__/InputFieldModel.test.tsx +117 -1
  305. package/src/flow/models/fields/__tests__/SelectFieldModel.test.tsx +43 -0
  306. package/src/flow/models/fields/__tests__/TextareaFieldModel.test.tsx +131 -0
  307. package/src/flow/models/fields/__tests__/VariableFieldFormModel.test.tsx +51 -0
  308. package/src/flow/models/fields/mobile-components/MobileLazySelect.tsx +20 -10
  309. package/src/flow/models/fields/mobile-components/MobileSelect.tsx +24 -12
  310. package/src/flow/models/topbar/TopbarActionModel.tsx +168 -10
  311. package/src/flow/resolveViewParamsToViewList.tsx +11 -3
  312. package/src/flow/routeTransientInputArgs.ts +27 -0
  313. package/src/flow/utils/__tests__/dateTimeFormat.test.ts +300 -0
  314. package/src/flow/utils/dataScopeFormValueClear.ts +219 -81
  315. package/src/flow/utils/dataScopeRowSnapshot.ts +616 -0
  316. package/src/flow/utils/dateTimeDisplayProps.ts +135 -0
  317. package/src/flow/utils/formValueDeps.ts +170 -0
  318. package/src/flow-compat/FieldValidation.tsx +122 -60
  319. package/src/flow-compat/Popover.tsx +43 -4
  320. package/src/flow-compat/__tests__/Popover.test.tsx +34 -0
  321. package/src/flow-compat/fieldValidationConstants.ts +1 -1
  322. package/src/flow-compat/routeTypes.ts +1 -0
  323. package/src/index.ts +14 -1
  324. package/src/layout-manager/__tests__/LayoutRoute.test.tsx +41 -1
  325. package/src/locale/languageCodes.ts +3 -1
  326. package/src/nocobase-buildin-plugin/index.tsx +63 -15
  327. package/src/settings-center/AdminSettingsLayout.tsx +10 -2
  328. package/src/settings-center/SystemSettingsPage.tsx +1 -2
  329. package/src/settings-center/plugin-manager/PluginCard.tsx +2 -2
  330. package/src/settings-center/plugin-manager/index.tsx +3 -0
  331. package/src/settings-center/utils.tsx +0 -6
  332. package/src/utils/getRouteRuntimeVersion.ts +185 -0
  333. package/src/utils/index.tsx +1 -0
  334. package/src/utils/markdownSanitize.ts +88 -0
@@ -0,0 +1,435 @@
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, FlowEngineProvider } from '@nocobase/flow-engine';
11
+ import { act, render, screen, waitFor } from '@testing-library/react';
12
+ import React, { useEffect } from 'react';
13
+ import { createMemoryRouter, RouterProvider, useParams } from 'react-router-dom';
14
+ import { afterEach, describe, expect, it, vi } from 'vitest';
15
+ import { NocoBaseDesktopRouteType, type NocoBaseDesktopRoute } from '../../../../flow-compat';
16
+ import type { LayoutDefinition } from '../../../../layout-manager/types';
17
+ import { AdminLayoutComponent } from '../AdminLayoutComponent';
18
+ import { AdminLayoutModel } from '../AdminLayoutModel';
19
+ import { AdminLayoutMenuItemModel } from '../AdminLayoutMenuModels';
20
+ import { AdminLayoutContent } from '../AdminLayoutSlotModels';
21
+
22
+ const proLayoutLifecycle = vi.hoisted(() => ({
23
+ events: [] as string[],
24
+ routes: [] as Array<{ children?: Array<{ name?: React.ReactNode }> }>,
25
+ }));
26
+
27
+ vi.mock('@ant-design/pro-layout', async () => {
28
+ const ReactModule = await import('react');
29
+ const RouteContext = ReactModule.createContext({ isMobile: false });
30
+ const ProLayoutMock = (props: {
31
+ children?: React.ReactNode;
32
+ route?: { children?: Array<{ name?: React.ReactNode }> };
33
+ }) => {
34
+ ReactModule.useEffect(() => {
35
+ proLayoutLifecycle.events.push('pro-layout:mount');
36
+ return () => {
37
+ proLayoutLifecycle.events.push('pro-layout:unmount');
38
+ };
39
+ }, []);
40
+ proLayoutLifecycle.routes.push(props.route || {});
41
+
42
+ return ReactModule.createElement(
43
+ RouteContext.Provider,
44
+ { value: { isMobile: false } },
45
+ ReactModule.createElement(
46
+ 'div',
47
+ { 'data-testid': 'pro-layout' },
48
+ ReactModule.createElement(
49
+ 'nav',
50
+ { 'data-testid': 'pro-layout-menu' },
51
+ (props.route?.children || []).map((item) =>
52
+ ReactModule.createElement(
53
+ 'span',
54
+ { key: String(item.name), 'data-testid': 'pro-layout-menu-item' },
55
+ item.name,
56
+ ),
57
+ ),
58
+ ),
59
+ props.children,
60
+ ),
61
+ );
62
+ };
63
+
64
+ return {
65
+ default: ProLayoutMock,
66
+ RouteContext,
67
+ };
68
+ });
69
+
70
+ vi.mock('../../../system-settings', () => ({
71
+ useSystemSettings: () => ({
72
+ loading: false,
73
+ data: {
74
+ data: {
75
+ title: 'NocoBase',
76
+ },
77
+ },
78
+ }),
79
+ }));
80
+
81
+ vi.mock('../useApplications', () => ({
82
+ useApplications: () => ({
83
+ appList: [],
84
+ }),
85
+ }));
86
+
87
+ vi.mock('../AppListRender', () => ({
88
+ useAppListRender: () => undefined,
89
+ }));
90
+
91
+ afterEach(() => {
92
+ delete (window as Window & { __nocobase_modern_client_prefix__?: string }).__nocobase_modern_client_prefix__;
93
+ });
94
+
95
+ describe('AdminLayoutComponent', () => {
96
+ it('keeps custom admin layout pages alive by layout route name', async () => {
97
+ const layout: LayoutDefinition = {
98
+ routeName: 'admin2',
99
+ routePath: '/admin2',
100
+ rootRouteName: 'admin2',
101
+ uid: 'custom-admin-layout-model',
102
+ layoutModelClass: 'AdminLayoutModel',
103
+ rootPageModelClass: 'RootPageModel',
104
+ childPageModelClass: 'ChildPageModel',
105
+ authCheck: true,
106
+ };
107
+ const events: string[] = [];
108
+ const engine = new FlowEngine();
109
+ engine.context.defineProperty('routeRepository', {
110
+ value: {
111
+ listAccessible: () => [],
112
+ },
113
+ });
114
+
115
+ const Page = () => {
116
+ const { name } = useParams();
117
+ useEffect(() => {
118
+ events.push(`mount:${name}`);
119
+ return () => {
120
+ events.push(`unmount:${name}`);
121
+ };
122
+ }, [name]);
123
+
124
+ return <div data-testid={`admin-layout-page-${name}`}>page {name}</div>;
125
+ };
126
+
127
+ const router = createMemoryRouter(
128
+ [
129
+ {
130
+ id: layout.routeName,
131
+ path: layout.routePath,
132
+ element: <AdminLayoutContent layout={layout} />,
133
+ children: [
134
+ {
135
+ id: 'admin2.__page',
136
+ path: ':name',
137
+ element: <Page />,
138
+ },
139
+ ],
140
+ },
141
+ ],
142
+ {
143
+ initialEntries: ['/admin2/page-a'],
144
+ },
145
+ );
146
+
147
+ render(
148
+ <FlowEngineProvider engine={engine}>
149
+ <RouterProvider router={router} />
150
+ </FlowEngineProvider>,
151
+ );
152
+
153
+ expect(await screen.findByTestId('admin-layout-page-page-a')).toBeInTheDocument();
154
+
155
+ await act(async () => {
156
+ await router.navigate('/admin2/page-b');
157
+ });
158
+
159
+ expect(await screen.findByTestId('admin-layout-page-page-b')).toBeInTheDocument();
160
+ expect(screen.getByTestId('admin-layout-page-page-a')).toBeInTheDocument();
161
+ expect(events).toEqual(['mount:page-a', 'mount:page-b']);
162
+ });
163
+
164
+ it('activates the current layout before loading accessible routes', async () => {
165
+ const layout: LayoutDefinition = {
166
+ routeName: 'admin2',
167
+ routePath: '/admin2',
168
+ rootRouteName: 'admin2',
169
+ uid: 'custom-admin-layout-model',
170
+ layoutModelClass: 'AdminLayoutModel',
171
+ rootPageModelClass: 'RootPageModel',
172
+ childPageModelClass: 'ChildPageModel',
173
+ authCheck: true,
174
+ };
175
+ const deactivateLayout = vi.fn();
176
+ const activateLayout = vi.fn(() => deactivateLayout);
177
+ const ensureAccessibleLoaded = vi.fn(async () => []);
178
+ const engine = new FlowEngine();
179
+ engine.context.defineProperty('routeRepository', {
180
+ value: {
181
+ activateLayout,
182
+ ensureAccessibleLoaded,
183
+ listAccessible: () => [],
184
+ subscribe: vi.fn(),
185
+ unsubscribe: vi.fn(),
186
+ },
187
+ });
188
+ engine.context.defineProperty('t', {
189
+ value: (key: string) => key,
190
+ });
191
+ const model = engine.createModel<AdminLayoutModel>({
192
+ uid: layout.uid,
193
+ use: AdminLayoutModel,
194
+ props: {
195
+ layout,
196
+ },
197
+ });
198
+
199
+ const router = createMemoryRouter(
200
+ [
201
+ {
202
+ id: layout.routeName,
203
+ path: layout.routePath,
204
+ element: <AdminLayoutComponent model={model} />,
205
+ },
206
+ ],
207
+ {
208
+ initialEntries: ['/admin2'],
209
+ },
210
+ );
211
+ const { unmount } = render(
212
+ <FlowEngineProvider engine={engine}>
213
+ <RouterProvider router={router} />
214
+ </FlowEngineProvider>,
215
+ );
216
+
217
+ await waitFor(() => {
218
+ expect(ensureAccessibleLoaded).toHaveBeenCalled();
219
+ });
220
+ expect(activateLayout).toHaveBeenCalledWith(layout);
221
+ expect(activateLayout.mock.invocationCallOrder[0]).toBeLessThan(ensureAccessibleLoaded.mock.invocationCallOrder[0]);
222
+
223
+ unmount();
224
+
225
+ expect(deactivateLayout).toHaveBeenCalledTimes(1);
226
+ });
227
+
228
+ it('keeps layout content mounted when the menu route tree refreshes', async () => {
229
+ proLayoutLifecycle.events = [];
230
+ proLayoutLifecycle.routes = [];
231
+ const layout: LayoutDefinition = {
232
+ routeName: 'admin',
233
+ routePath: '/admin',
234
+ rootRouteName: 'admin',
235
+ uid: 'admin-layout-model',
236
+ layoutModelClass: 'AdminLayoutModel',
237
+ rootPageModelClass: 'RootPageModel',
238
+ childPageModelClass: 'ChildPageModel',
239
+ authCheck: true,
240
+ };
241
+ const events: string[] = [];
242
+ const engine = new FlowEngine();
243
+ engine.context.defineProperty('routeRepository', {
244
+ value: {
245
+ activateLayout: vi.fn(() => vi.fn()),
246
+ ensureAccessibleLoaded: vi.fn(async () => []),
247
+ listAccessible: () => [],
248
+ subscribe: vi.fn(),
249
+ unsubscribe: vi.fn(),
250
+ },
251
+ });
252
+ engine.context.defineProperty('t', {
253
+ value: (key: string) => key,
254
+ });
255
+ const model = engine.createModel<AdminLayoutModel>({
256
+ uid: layout.uid,
257
+ use: AdminLayoutModel,
258
+ props: {
259
+ layout,
260
+ },
261
+ });
262
+
263
+ const Page = () => {
264
+ useEffect(() => {
265
+ events.push('page:mount');
266
+ return () => {
267
+ events.push('page:unmount');
268
+ };
269
+ }, []);
270
+
271
+ return <div data-testid="custom-admin-route">Workflow tasks</div>;
272
+ };
273
+
274
+ const router = createMemoryRouter(
275
+ [
276
+ {
277
+ id: layout.routeName,
278
+ path: layout.routePath,
279
+ element: <AdminLayoutComponent model={model} />,
280
+ children: [
281
+ {
282
+ id: 'admin.workflow.tasks',
283
+ path: 'workflow/tasks/:taskType?/:status?/:popupId?',
284
+ element: <Page />,
285
+ },
286
+ ],
287
+ },
288
+ ],
289
+ {
290
+ initialEntries: ['/admin/workflow/tasks/approval-apply/pending'],
291
+ },
292
+ );
293
+
294
+ render(
295
+ <FlowEngineProvider engine={engine}>
296
+ <RouterProvider router={router} />
297
+ </FlowEngineProvider>,
298
+ );
299
+
300
+ expect(await screen.findByTestId('custom-admin-route')).toBeInTheDocument();
301
+ expect(proLayoutLifecycle.events).toEqual(['pro-layout:mount']);
302
+
303
+ act(() => {
304
+ model.refreshMenuRouteTree();
305
+ });
306
+
307
+ await act(async () => {
308
+ await router.navigate('/admin/workflow/tasks/approval-apply/pending/1');
309
+ });
310
+
311
+ expect(screen.getByTestId('custom-admin-route')).toBeInTheDocument();
312
+ expect(proLayoutLifecycle.events).toEqual(['pro-layout:mount']);
313
+ expect(events).toEqual(['page:mount']);
314
+ });
315
+
316
+ it('updates ProLayout menu routes after accessible routes change without remounting the layout', async () => {
317
+ proLayoutLifecycle.events = [];
318
+ proLayoutLifecycle.routes = [];
319
+ (window as Window & { __nocobase_modern_client_prefix__?: string }).__nocobase_modern_client_prefix__ = 'v2';
320
+ const layout: LayoutDefinition = {
321
+ routeName: 'admin',
322
+ routePath: '/admin',
323
+ rootRouteName: 'admin',
324
+ uid: 'admin-layout-model',
325
+ layoutModelClass: 'AdminLayoutModel',
326
+ rootPageModelClass: 'RootPageModel',
327
+ childPageModelClass: 'ChildPageModel',
328
+ authCheck: true,
329
+ };
330
+ let accessibleRoutes: NocoBaseDesktopRoute[] = [
331
+ {
332
+ id: 1,
333
+ title: 'Visible page',
334
+ schemaUid: 'visible-page',
335
+ type: NocoBaseDesktopRouteType.flowPage,
336
+ },
337
+ ];
338
+ let routeRepositorySubscriber: (() => void) | undefined;
339
+ const events: string[] = [];
340
+ const engine = new FlowEngine();
341
+ engine.registerModels({
342
+ AdminLayoutMenuItemModel,
343
+ });
344
+ engine.context.defineProperty('routeRepository', {
345
+ value: {
346
+ activateLayout: vi.fn(() => vi.fn()),
347
+ ensureAccessibleLoaded: vi.fn(async () => accessibleRoutes),
348
+ listAccessible: () => accessibleRoutes,
349
+ subscribe: vi.fn((subscriber: () => void) => {
350
+ routeRepositorySubscriber = subscriber;
351
+ }),
352
+ unsubscribe: vi.fn(),
353
+ },
354
+ });
355
+ engine.context.defineProperty('app', {
356
+ value: {
357
+ getPublicPath: () => '/v/',
358
+ router: {
359
+ getBasename: () => '/v',
360
+ },
361
+ },
362
+ });
363
+ engine.context.defineProperty('t', {
364
+ value: (key: string) => key,
365
+ });
366
+ const model = engine.createModel<AdminLayoutModel>({
367
+ uid: layout.uid,
368
+ use: AdminLayoutModel,
369
+ props: {
370
+ layout,
371
+ },
372
+ });
373
+
374
+ const Page = () => {
375
+ useEffect(() => {
376
+ events.push('page:mount');
377
+ return () => {
378
+ events.push('page:unmount');
379
+ };
380
+ }, []);
381
+
382
+ return <div data-testid="custom-admin-route">Workflow tasks</div>;
383
+ };
384
+
385
+ const router = createMemoryRouter(
386
+ [
387
+ {
388
+ id: layout.routeName,
389
+ path: layout.routePath,
390
+ element: <AdminLayoutComponent model={model} />,
391
+ children: [
392
+ {
393
+ id: 'admin.workflow.tasks',
394
+ path: 'workflow/tasks/:taskType?/:status?/:popupId?',
395
+ element: <Page />,
396
+ },
397
+ ],
398
+ },
399
+ ],
400
+ {
401
+ initialEntries: ['/admin/workflow/tasks/approval-apply/pending'],
402
+ },
403
+ );
404
+
405
+ render(
406
+ <FlowEngineProvider engine={engine}>
407
+ <RouterProvider router={router} />
408
+ </FlowEngineProvider>,
409
+ );
410
+
411
+ expect(await screen.findByText('Visible page')).toBeInTheDocument();
412
+ expect(proLayoutLifecycle.events).toEqual(['pro-layout:mount']);
413
+
414
+ act(() => {
415
+ accessibleRoutes = [];
416
+ routeRepositorySubscriber?.();
417
+ });
418
+
419
+ await waitFor(() => {
420
+ expect(screen.queryByText('Visible page')).not.toBeInTheDocument();
421
+ });
422
+
423
+ await act(async () => {
424
+ await router.navigate('/admin/workflow/tasks/approval-apply/pending/1');
425
+ });
426
+
427
+ expect(screen.getByTestId('custom-admin-route')).toBeInTheDocument();
428
+ expect(proLayoutLifecycle.events).toEqual(['pro-layout:mount']);
429
+ expect(events).toEqual(['page:mount']);
430
+ expect(
431
+ proLayoutLifecycle.routes.some((route) => route.children?.some((item) => item.name === 'Visible page')),
432
+ ).toBe(true);
433
+ expect(proLayoutLifecycle.routes.at(-1)?.children?.some((item) => item.name === 'Visible page')).toBe(false);
434
+ });
435
+ });
@@ -318,6 +318,50 @@ describe('AdminLayoutModel menu items', () => {
318
318
  expect(route.children[1]._model).toBe(adminLayoutModel.subModels.menuItems?.[1]);
319
319
  });
320
320
 
321
+ it('should generate ProLayout route tree under a custom admin layout route path', () => {
322
+ const adminLayoutModel = engine.createModel<AdminLayoutModel>({
323
+ uid: 'admin2-layout-model',
324
+ use: AdminLayoutModel,
325
+ props: {
326
+ layout: {
327
+ routeName: 'admin2',
328
+ routePath: '/admin2',
329
+ uid: 'admin2-layout-model',
330
+ layoutModelClass: 'AdminLayoutModel',
331
+ },
332
+ },
333
+ });
334
+
335
+ adminLayoutModel.syncMenuRoutes([
336
+ {
337
+ id: 1,
338
+ title: 'Group',
339
+ type: NocoBaseDesktopRouteType.group,
340
+ children: [
341
+ {
342
+ id: 11,
343
+ title: 'Page 1',
344
+ schemaUid: 'page-1',
345
+ type: NocoBaseDesktopRouteType.flowPage,
346
+ },
347
+ ],
348
+ },
349
+ ]);
350
+
351
+ const route = adminLayoutModel.toProLayoutRoute({
352
+ designable: false,
353
+ isMobile: false,
354
+ t: (title) => title,
355
+ });
356
+
357
+ expect(route.children[0].path).toBe('/admin2/1');
358
+ expect(route.children[0].redirect).toBe('/admin2/page-1');
359
+ expect(route.children[0]._runtimePath).toBe('/apps/demo/v2/admin2/page-1');
360
+ expect(route.children[0].routes?.[0].path).toBe('/admin2/page-1');
361
+ expect(route.children[0].routes?.[0].redirect).toBe('/admin2/page-1');
362
+ expect(route.children[0].routes?.[0]._runtimePath).toBe('/apps/demo/v2/admin2/page-1');
363
+ });
364
+
321
365
  it('should filter legacy page menu routes but keep empty groups in v2 admin layout', () => {
322
366
  const adminLayoutModel = engine.createModel<AdminLayoutModel>({
323
367
  uid: 'admin-layout-model',
@@ -1128,6 +1172,46 @@ describe('AdminLayoutModel menu items', () => {
1128
1172
  expect(adminLayoutModel.menuRouteRefreshVersion).toBe(refreshBefore + 1);
1129
1173
  });
1130
1174
 
1175
+ it('should refresh the owning admin layout when hiding custom layout menu routes dynamically', () => {
1176
+ const defaultAdminLayoutModel = engine.createModel<AdminLayoutModel>({
1177
+ uid: ADMIN_LAYOUT_MODEL_UID,
1178
+ use: AdminLayoutModel,
1179
+ });
1180
+ const customAdminLayoutModel = engine.createModel<AdminLayoutModel>({
1181
+ uid: 'custom-admin-layout-model',
1182
+ use: AdminLayoutModel,
1183
+ props: {
1184
+ layout: {
1185
+ routeName: 'admin2',
1186
+ routePath: '/admin2',
1187
+ rootRouteName: 'admin2',
1188
+ uid: 'custom-admin-layout-model',
1189
+ layoutModelClass: 'AdminLayoutModel',
1190
+ rootPageModelClass: 'RootPageModel',
1191
+ childPageModelClass: 'ChildPageModel',
1192
+ authCheck: true,
1193
+ },
1194
+ },
1195
+ });
1196
+ const model = engine.createModel<AdminLayoutMenuItemModel>({
1197
+ uid: 'menu-item-custom-layout-dynamic-hidden',
1198
+ use: AdminLayoutMenuItemModel,
1199
+ props: {
1200
+ route: createRoute(),
1201
+ },
1202
+ });
1203
+
1204
+ model.setParent(customAdminLayoutModel);
1205
+
1206
+ const defaultRefreshBefore = defaultAdminLayoutModel.menuRouteRefreshVersion;
1207
+ const customRefreshBefore = customAdminLayoutModel.menuRouteRefreshVersion;
1208
+
1209
+ model.setHidden(true);
1210
+
1211
+ expect(customAdminLayoutModel.menuRouteRefreshVersion).toBe(customRefreshBefore + 1);
1212
+ expect(defaultAdminLayoutModel.menuRouteRefreshVersion).toBe(defaultRefreshBefore);
1213
+ });
1214
+
1131
1215
  it('should render hidden menu item with opacity and keep original title in config mode', () => {
1132
1216
  const model = engine.createModel<AdminLayoutMenuItemModel>({
1133
1217
  uid: 'menu-item-hidden-in-config',
@@ -2222,6 +2306,21 @@ describe('AdminLayoutModel menu items', () => {
2222
2306
  );
2223
2307
  });
2224
2308
 
2309
+ it('should include router basename when opening same-origin links in a new window', async () => {
2310
+ await openAdminLayoutMenuLink({
2311
+ context: engine.context as any,
2312
+ href: '/admin2/page',
2313
+ params: [{ name: 'from', value: 'admin' }],
2314
+ openInNewWindow: true,
2315
+ isMobile: false,
2316
+ closeMobileMenu: vi.fn(),
2317
+ navigate: navigateMock,
2318
+ basenameOfCurrentRouter: '/v',
2319
+ });
2320
+
2321
+ expect(window.open).toHaveBeenCalledWith('/v/admin2/page?from=admin', '_blank', 'noopener,noreferrer');
2322
+ });
2323
+
2225
2324
  it('should resolve sibling move options for non-group drag target', () => {
2226
2325
  const activeModel = engine.createModel<AdminLayoutMenuItemModel>({
2227
2326
  uid: 'drag-source-page',