@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
@@ -57,12 +57,11 @@ function getItemLabel(itemModel: any, t: (key: string) => string): string {
57
57
  return '';
58
58
  }
59
59
 
60
- function getLastPathSegment(path: string): string {
61
- const segs = String(path || '')
60
+ function splitFieldPath(path: string): string[] {
61
+ return String(path || '')
62
62
  .split('.')
63
63
  .map((s) => s.trim())
64
64
  .filter(Boolean);
65
- return segs.length ? segs[segs.length - 1] : '';
66
65
  }
67
66
 
68
67
  type CollectionLike = {
@@ -70,6 +69,15 @@ type CollectionLike = {
70
69
  getFields?: () => unknown[];
71
70
  };
72
71
 
72
+ type CollectionFieldLike = {
73
+ name?: unknown;
74
+ title?: unknown;
75
+ interface?: unknown;
76
+ target?: unknown;
77
+ isAssociationField?: () => boolean;
78
+ targetCollection?: CollectionLike | null;
79
+ };
80
+
73
81
  function getCollectionFromFormBlockModel(model: any): CollectionLike | null {
74
82
  if (!model || typeof model !== 'object') return null;
75
83
  const collection = (model as any)?.collection || (model as any)?.context?.collection;
@@ -89,14 +97,7 @@ export function buildFieldAssignCascaderOptionsFromCollection(
89
97
  const out: FieldAssignCascaderOption[] = [];
90
98
  for (const rawField of fields) {
91
99
  if (!rawField) continue;
92
- const f = rawField as {
93
- name?: unknown;
94
- title?: unknown;
95
- interface?: unknown;
96
- target?: unknown;
97
- isAssociationField?: () => boolean;
98
- targetCollection?: any;
99
- };
100
+ const f = rawField as CollectionFieldLike;
100
101
  const fieldInterface = typeof f.interface === 'string' ? f.interface : undefined;
101
102
  if (!fieldInterface) continue;
102
103
  if (fieldInterface === 'formula') continue;
@@ -123,23 +124,143 @@ export function buildFieldAssignCascaderOptionsFromCollection(
123
124
  function mergeRootOptions(
124
125
  configured: FieldAssignCascaderOption[],
125
126
  allFields: FieldAssignCascaderOption[],
127
+ ): FieldAssignCascaderOption[] {
128
+ return mergeCascaderOptions(configured, allFields);
129
+ }
130
+
131
+ function mergeCascaderOptions(
132
+ configured: FieldAssignCascaderOption[],
133
+ allFields: FieldAssignCascaderOption[],
126
134
  ): FieldAssignCascaderOption[] {
127
135
  const configuredList = Array.isArray(configured) ? configured : [];
128
136
  const allList = Array.isArray(allFields) ? allFields : [];
137
+ const result = configuredList.map((item) => cloneCascaderOption(item));
129
138
 
130
- const configuredValues = new Set<string>();
131
- for (const it of configuredList) {
132
- const v = it?.value ? String(it.value) : '';
133
- if (v) configuredValues.add(v);
139
+ for (const item of allList) {
140
+ mergeCascaderOptionInto(result, item);
134
141
  }
135
142
 
136
- const extra = allList.filter((it) => {
137
- const v = it?.value ? String(it.value) : '';
138
- if (!v) return false;
139
- return !configuredValues.has(v);
140
- });
143
+ return result;
144
+ }
145
+
146
+ function cloneCascaderOption(option: FieldAssignCascaderOption): FieldAssignCascaderOption {
147
+ return {
148
+ ...option,
149
+ children: option.children?.map((child) => cloneCascaderOption(child)),
150
+ };
151
+ }
152
+
153
+ function mergeCascaderOptionInto(options: FieldAssignCascaderOption[], source: FieldAssignCascaderOption) {
154
+ const value = source?.value ? String(source.value) : '';
155
+ if (!value) return;
156
+
157
+ const existing = options.find((item) => String(item?.value || '') === value);
158
+ if (!existing) {
159
+ options.push(cloneCascaderOption(source));
160
+ return;
161
+ }
162
+
163
+ if (!existing.label && source.label) {
164
+ existing.label = source.label;
165
+ }
166
+ if (source.isLeaf === false || existing.children?.length || source.children?.length) {
167
+ existing.isLeaf = false;
168
+ }
169
+ if (source.loading) {
170
+ existing.loading = source.loading;
171
+ }
172
+ if (source.children?.length) {
173
+ existing.children = mergeCascaderOptions(existing.children || [], source.children);
174
+ }
175
+ }
176
+
177
+ function getCollectionField(collection: CollectionLike | null, name: string): CollectionFieldLike | undefined {
178
+ const field = typeof collection?.getField === 'function' ? collection.getField(name) : undefined;
179
+ return field && typeof field === 'object' ? (field as CollectionFieldLike) : undefined;
180
+ }
181
+
182
+ function isAssociationFieldLike(field?: CollectionFieldLike | null) {
183
+ return !!(field?.isAssociationField?.() || field?.target || field?.targetCollection);
184
+ }
185
+
186
+ function getFieldLabelFromCollection(collection: CollectionLike | null, name: string, t: (key: string) => string) {
187
+ const field = getCollectionField(collection, name);
188
+ const title = typeof field?.title === 'string' && field.title ? field.title : name;
189
+ return t(title);
190
+ }
191
+
192
+ function getAssociationDepthFromFieldPath(
193
+ rootCollection: CollectionLike | null,
194
+ segments: string[],
195
+ ): number | undefined {
196
+ if (!rootCollection) return undefined;
197
+
198
+ let collection: CollectionLike | null = rootCollection;
199
+ let associationDepth = 0;
200
+ for (let index = 0; index < segments.length; index++) {
201
+ const field = getCollectionField(collection, segments[index]);
202
+ if (!field) return undefined;
203
+
204
+ if (isAssociationFieldLike(field)) {
205
+ associationDepth += 1;
206
+ collection = field.targetCollection || null;
207
+ continue;
208
+ }
209
+
210
+ if (index < segments.length - 1) return undefined;
211
+ }
212
+
213
+ return associationDepth;
214
+ }
215
+
216
+ function shouldIncludeConfiguredFieldPath(options: {
217
+ segments: string[];
218
+ rootCollection: CollectionLike | null;
219
+ leafField?: CollectionFieldLike | null;
220
+ maxAssociationFieldDepth: number;
221
+ }) {
222
+ const resolvedAssociationDepth = getAssociationDepthFromFieldPath(options.rootCollection, options.segments);
223
+ if (typeof resolvedAssociationDepth === 'number') {
224
+ return resolvedAssociationDepth <= options.maxAssociationFieldDepth;
225
+ }
226
+
227
+ const leafIsAssociation = isAssociationFieldLike(options.leafField);
228
+ const maxPathLength = leafIsAssociation ? options.maxAssociationFieldDepth : options.maxAssociationFieldDepth + 1;
229
+ return options.segments.length <= maxPathLength;
230
+ }
231
+
232
+ function buildNestedOptionFromFieldPath(options: {
233
+ targetPath: string;
234
+ leaf: FieldAssignCascaderOption;
235
+ rootCollection: CollectionLike | null;
236
+ t: (key: string) => string;
237
+ }): FieldAssignCascaderOption {
238
+ const segments = splitFieldPath(options.targetPath);
239
+ if (segments.length <= 1) {
240
+ return options.leaf;
241
+ }
242
+
243
+ const build = (index: number, collection: CollectionLike | null): FieldAssignCascaderOption => {
244
+ const value = segments[index];
245
+ const isLast = index === segments.length - 1;
246
+ if (isLast) {
247
+ return {
248
+ ...options.leaf,
249
+ value,
250
+ };
251
+ }
252
+
253
+ const field = getCollectionField(collection, value);
254
+ const nextCollection = field?.targetCollection || null;
255
+ return {
256
+ label: getFieldLabelFromCollection(collection, value, options.t),
257
+ value,
258
+ isLeaf: false,
259
+ children: [build(index + 1, nextCollection)],
260
+ };
261
+ };
141
262
 
142
- return [...configuredList, ...extra];
263
+ return build(0, options.rootCollection);
143
264
  }
144
265
 
145
266
  export function collectFieldAssignCascaderOptions(options: {
@@ -167,7 +288,8 @@ export function collectFieldAssignCascaderOptions(options: {
167
288
  const targetPath = getItemFieldPath(item);
168
289
  if (!targetPath) continue;
169
290
 
170
- const seg = getLastPathSegment(targetPath);
291
+ const segments = splitFieldPath(targetPath);
292
+ const seg = segments[segments.length - 1];
171
293
  if (!seg) continue;
172
294
 
173
295
  const node: FieldAssignCascaderOption = {
@@ -179,10 +301,16 @@ export function collectFieldAssignCascaderOptions(options: {
179
301
  const childItems = fieldModel?.subModels?.grid?.subModels?.items;
180
302
  const cf: (CollectionField & { target?: unknown; targetCollection?: unknown }) | undefined =
181
303
  fieldModel?.context?.collectionField;
182
- const isAssociation = !!(cf?.isAssociationField?.() || cf?.target || cf?.targetCollection);
304
+ const isAssociation = isAssociationFieldLike(cf);
183
305
  const hasTargetCollection = !!cf?.targetCollection;
184
- const associationDepth = isAssociation ? targetPath.split('.').filter(Boolean).length : 0;
185
- if (isAssociation && associationDepth > maxAssociationFieldDepth) {
306
+ if (
307
+ !shouldIncludeConfiguredFieldPath({
308
+ segments,
309
+ rootCollection,
310
+ leafField: cf,
311
+ maxAssociationFieldDepth,
312
+ })
313
+ ) {
186
314
  continue;
187
315
  }
188
316
 
@@ -203,7 +331,7 @@ export function collectFieldAssignCascaderOptions(options: {
203
331
  node.isLeaf = true;
204
332
  }
205
333
  }
206
- out.push(node);
334
+ mergeCascaderOptionInto(out, buildNestedOptionFromFieldPath({ targetPath, leaf: node, rootCollection, t }));
207
335
  continue;
208
336
  }
209
337
 
@@ -215,7 +343,7 @@ export function collectFieldAssignCascaderOptions(options: {
215
343
  node.isLeaf = true;
216
344
  }
217
345
 
218
- out.push(node);
346
+ mergeCascaderOptionInto(out, buildNestedOptionFromFieldPath({ targetPath, leaf: node, rootCollection, t }));
219
347
  }
220
348
 
221
349
  return out;
@@ -45,6 +45,7 @@ interface FilterGroupProps {
45
45
  value: Record<string, any>;
46
46
  /** 自定义筛选项组件 */
47
47
  FilterItem?: React.FC<FilterItemProps>;
48
+ disabled?: boolean;
48
49
  closeIcon?: ReactNode;
49
50
  /** 是否显示边框 */
50
51
  showBorder?: boolean;
@@ -89,6 +90,7 @@ export const FilterGroup: FC<FilterGroupProps> = observer(
89
90
  const {
90
91
  value = { logic: '$and', items: [] },
91
92
  FilterItem,
93
+ disabled = false,
92
94
  showBorder = false,
93
95
  onRemove,
94
96
  onChange,
@@ -120,11 +122,17 @@ export const FilterGroup: FC<FilterGroupProps> = observer(
120
122
  };
121
123
 
122
124
  const handleLogicChange = (newLogic: '$and' | '$or') => {
125
+ if (disabled) {
126
+ return;
127
+ }
123
128
  value.logic = newLogic;
124
129
  onChange?.(value);
125
130
  };
126
131
 
127
132
  const handleAddCondition = () => {
133
+ if (disabled) {
134
+ return;
135
+ }
128
136
  items.push({
129
137
  path: '',
130
138
  operator: '',
@@ -134,6 +142,9 @@ export const FilterGroup: FC<FilterGroupProps> = observer(
134
142
  };
135
143
 
136
144
  const handleAddConditionGroup = () => {
145
+ if (disabled) {
146
+ return;
147
+ }
137
148
  items.push({
138
149
  logic: '$and',
139
150
  items: [],
@@ -142,6 +153,9 @@ export const FilterGroup: FC<FilterGroupProps> = observer(
142
153
  };
143
154
 
144
155
  const handleRemoveItem = (index: number) => {
156
+ if (disabled) {
157
+ return;
158
+ }
145
159
  items.splice(index, 1);
146
160
  onChange?.(value);
147
161
  };
@@ -160,11 +174,12 @@ export const FilterGroup: FC<FilterGroupProps> = observer(
160
174
  <button
161
175
  type="button"
162
176
  aria-label="icon-close"
177
+ disabled={disabled}
163
178
  style={{
164
179
  position: 'absolute',
165
180
  right: 10,
166
181
  top: 10,
167
- cursor: 'pointer',
182
+ cursor: disabled ? 'not-allowed' : 'pointer',
168
183
  background: 'transparent',
169
184
  border: 0,
170
185
  padding: 0,
@@ -182,6 +197,7 @@ export const FilterGroup: FC<FilterGroupProps> = observer(
182
197
  data-testid="filter-select-all-or-any"
183
198
  style={{ width: 'auto' }}
184
199
  value={logic}
200
+ disabled={disabled}
185
201
  onChange={handleLogicChange}
186
202
  >
187
203
  <Select.Option value="$and">{t('All')}</Select.Option>
@@ -200,6 +216,7 @@ export const FilterGroup: FC<FilterGroupProps> = observer(
200
216
  key={getFilterItemKey(item)}
201
217
  value={item}
202
218
  FilterItem={FilterItem}
219
+ disabled={disabled}
203
220
  showBorder={true}
204
221
  onRemove={() => handleRemoveItem(index)}
205
222
  onChange={(v) => {
@@ -221,11 +238,12 @@ export const FilterGroup: FC<FilterGroupProps> = observer(
221
238
  <button
222
239
  type="button"
223
240
  aria-label="icon-close"
241
+ disabled={disabled}
224
242
  style={{
225
243
  marginLeft: 8,
226
244
  marginRight: 8,
227
245
  flex: '0 0 auto',
228
- cursor: 'pointer',
246
+ cursor: disabled ? 'not-allowed' : 'pointer',
229
247
  background: 'transparent',
230
248
  border: 0,
231
249
  padding: 0,
@@ -251,11 +269,12 @@ export const FilterGroup: FC<FilterGroupProps> = observer(
251
269
  <button
252
270
  type="button"
253
271
  aria-label="icon-close"
272
+ disabled={disabled}
254
273
  style={{
255
274
  marginLeft: 8,
256
275
  marginRight: 8,
257
276
  flex: '0 0 auto',
258
- cursor: 'pointer',
277
+ cursor: disabled ? 'not-allowed' : 'pointer',
259
278
  background: 'transparent',
260
279
  border: 0,
261
280
  padding: 0,
@@ -277,11 +296,12 @@ export const FilterGroup: FC<FilterGroupProps> = observer(
277
296
  <button
278
297
  type="button"
279
298
  aria-label="icon-close"
299
+ disabled={disabled}
280
300
  style={{
281
301
  marginLeft: 8,
282
302
  marginRight: 8,
283
303
  flex: '0 0 auto',
284
- cursor: 'pointer',
304
+ cursor: disabled ? 'not-allowed' : 'pointer',
285
305
  background: 'transparent',
286
306
  border: 0,
287
307
  padding: 0,
@@ -298,7 +318,14 @@ export const FilterGroup: FC<FilterGroupProps> = observer(
298
318
  </div>
299
319
 
300
320
  <Space size={16} style={{ marginTop: 8, marginBottom: 8 }}>
301
- <Button style={{ padding: 0 }} type="link" size="small" icon={<PlusOutlined />} onClick={handleAddCondition}>
321
+ <Button
322
+ style={{ padding: 0 }}
323
+ type="link"
324
+ size="small"
325
+ icon={<PlusOutlined />}
326
+ onClick={handleAddCondition}
327
+ disabled={disabled}
328
+ >
302
329
  {t('Add condition')}
303
330
  </Button>
304
331
  <Button
@@ -307,6 +334,7 @@ export const FilterGroup: FC<FilterGroupProps> = observer(
307
334
  size="small"
308
335
  icon={<PlusOutlined />}
309
336
  onClick={handleAddConditionGroup}
337
+ disabled={disabled}
310
338
  >
311
339
  {t('Add condition group')}
312
340
  </Button>
@@ -62,6 +62,51 @@ async function buildCollectionLeftMetaTreeLocal(ctx: any): Promise<MetaTreeNode[
62
62
  return await resolve(subTree);
63
63
  }
64
64
 
65
+ function buildCollectionFieldMetaNode(collection: any, path: string[]): MetaTreeNode | null {
66
+ if (!collection || !path.length) {
67
+ return null;
68
+ }
69
+
70
+ const normalizedPath = path[0] === 'collection' ? path.slice(1) : path;
71
+ if (!normalizedPath.length) {
72
+ return null;
73
+ }
74
+
75
+ const parentTitles: string[] = [];
76
+ let currentCollection = collection;
77
+ let currentNode: MetaTreeNode | null = null;
78
+
79
+ for (const segment of normalizedPath) {
80
+ const field =
81
+ currentCollection?.getField?.(segment) ??
82
+ currentCollection?.getFields?.()?.find?.((candidate: any) => candidate?.name === segment);
83
+ if (!field) {
84
+ return null;
85
+ }
86
+
87
+ const title = field.title || field.uiSchema?.title || field.name || segment;
88
+ currentNode = {
89
+ name: field.name || segment,
90
+ title,
91
+ type: field.type,
92
+ interface: field.interface,
93
+ uiSchema: field.uiSchema,
94
+ options: field.options,
95
+ paths: ['collection', ...normalizedPath.slice(0, parentTitles.length + 1)],
96
+ parentTitles: [...parentTitles],
97
+ } as MetaTreeNode;
98
+
99
+ if (field.targetCollection) {
100
+ parentTitles.push(title);
101
+ currentCollection = field.targetCollection;
102
+ } else {
103
+ currentCollection = null;
104
+ }
105
+ }
106
+
107
+ return currentNode;
108
+ }
109
+
65
110
  export interface VariableFilterItemValue {
66
111
  path: string;
67
112
  operator: string;
@@ -75,6 +120,7 @@ export interface VariableFilterItemProps {
75
120
  /** 筛选条件值对象 */
76
121
  value: VariableFilterItemValue;
77
122
  model: FlowModel;
123
+ disabled?: boolean;
78
124
  /**
79
125
  * 是否启用右侧 VariableInput(变量或静态值二合一)。
80
126
  * 默认 false:保持原有行为,右侧仅静态输入组件。
@@ -85,6 +131,10 @@ export interface VariableFilterItemProps {
85
131
  * 默认使用整棵 ctx 的 metaTree:model.context.getPropertyMetaTree()
86
132
  */
87
133
  rightMetaTree?: MetaTreeNode[] | (() => MetaTreeNode[] | Promise<MetaTreeNode[]>);
134
+ /**
135
+ * 右侧变量的领域转换器。常量和空值仍由 VariableFilterItem 处理,未匹配的值回退到 FlowEngine 默认转换器。
136
+ */
137
+ rightVariableConverters?: Pick<Converters, 'resolvePathFromValue' | 'resolveValueFromPath'>;
88
138
  ignoreFieldNames?: string[];
89
139
  maxAssociationFieldDepth?: number;
90
140
  }
@@ -265,11 +315,57 @@ function normalizeRightValueInput(input: unknown) {
265
315
  return input;
266
316
  }
267
317
 
318
+ function findMetaTreeNodeByPath(metaTree: MetaTreeNode[], targetPath: string[]): MetaTreeNode | null {
319
+ if (!Array.isArray(metaTree) || !targetPath.length) {
320
+ return null;
321
+ }
322
+
323
+ const traverseByName = (nodes: MetaTreeNode[], path: string[]): MetaTreeNode | null => {
324
+ if (!path.length) {
325
+ return null;
326
+ }
327
+
328
+ const [head, ...rest] = path;
329
+ const matched = nodes.find((node) => String(node.name) === String(head));
330
+ if (!matched) {
331
+ return null;
332
+ }
333
+ if (!rest.length) {
334
+ return matched;
335
+ }
336
+ if (!Array.isArray(matched.children)) {
337
+ return null;
338
+ }
339
+ return traverseByName(matched.children as MetaTreeNode[], rest);
340
+ };
341
+
342
+ const byNames = traverseByName(metaTree, targetPath);
343
+ if (byNames) {
344
+ return byNames;
345
+ }
346
+
347
+ const topNames = new Set(metaTree.map((node) => String(node.name)));
348
+ if (!topNames.has(String(targetPath[0]))) {
349
+ return traverseByName(metaTree, targetPath.slice(1));
350
+ }
351
+
352
+ return null;
353
+ }
354
+
268
355
  /**
269
356
  * 上下文筛选项组件
270
357
  */
271
358
  export const VariableFilterItem: React.FC<VariableFilterItemProps> = observer(
272
- ({ value, model, rightAsVariable, rightMetaTree, ignoreFieldNames, maxAssociationFieldDepth }) => {
359
+ ({
360
+ value,
361
+ model,
362
+ disabled = false,
363
+ rightAsVariable,
364
+ rightMetaTree,
365
+ rightVariableConverters,
366
+ ignoreFieldNames,
367
+ maxAssociationFieldDepth,
368
+ }) => {
273
369
  // 使用 View 上下文,确保可访问 ctx.view 的异步子树
274
370
  const ctx = useFlowViewContext();
275
371
  const t = model.translate;
@@ -334,6 +430,9 @@ export const VariableFilterItem: React.FC<VariableFilterItemProps> = observer(
334
430
  // 处理左侧值变化(值由 converters 决定如何解析)
335
431
  const handleLeftChange = useCallback(
336
432
  (variableValue: string, meta?: MetaTreeNode) => {
433
+ if (disabled) {
434
+ return;
435
+ }
337
436
  const prevPath = value.path || '';
338
437
  const nextPath = variableValue || '';
339
438
  const changed = nextPath !== prevPath;
@@ -348,7 +447,7 @@ export const VariableFilterItem: React.FC<VariableFilterItemProps> = observer(
348
447
  setLeftMeta(meta);
349
448
  }
350
449
  },
351
- [value],
450
+ [disabled, value],
352
451
  );
353
452
 
354
453
  // 自定义转换器来捕获 MetaTreeNode,并在选择左值时设置默认操作符
@@ -376,6 +475,9 @@ export const VariableFilterItem: React.FC<VariableFilterItemProps> = observer(
376
475
  // 处理操作符变化
377
476
  const handleOperatorChange = useCallback(
378
477
  (operatorValue: string) => {
478
+ if (disabled) {
479
+ return;
480
+ }
379
481
  value.operator = operatorValue;
380
482
  const cur = operatorMetaList.find((op) => op.value === operatorValue);
381
483
  if (cur?.noValue) {
@@ -386,7 +488,7 @@ export const VariableFilterItem: React.FC<VariableFilterItemProps> = observer(
386
488
  value.noValue = false;
387
489
  }
388
490
  },
389
- [operatorMetaList, value],
491
+ [disabled, operatorMetaList, value],
390
492
  );
391
493
 
392
494
  // 使用公共静态输入渲染器(抽取到 utils)
@@ -464,9 +566,12 @@ export const VariableFilterItem: React.FC<VariableFilterItemProps> = observer(
464
566
 
465
567
  const setRightValue = useCallback(
466
568
  (next: unknown) => {
569
+ if (disabled) {
570
+ return;
571
+ }
467
572
  value.value = normalizeRightValueInput(next) as VariableFilterItemValue['value'];
468
573
  },
469
- [value],
574
+ [disabled, value],
470
575
  );
471
576
 
472
577
  // 右侧静态输入(无变量模式)与右侧 VariableInput 的静态渲染组件,统一复用
@@ -520,6 +625,7 @@ export const VariableFilterItem: React.FC<VariableFilterItemProps> = observer(
520
625
  {...nextProps}
521
626
  style={{ width: '100%', ...pickStyle(nextProps.style) }}
522
627
  value={normalized}
628
+ disabled={disabled}
523
629
  onChange={(vals: any) => setRightValue(vals)}
524
630
  />
525
631
  </div>
@@ -529,10 +635,19 @@ export const VariableFilterItem: React.FC<VariableFilterItemProps> = observer(
529
635
  const Comp = staticInputRenderer;
530
636
  return (
531
637
  <div style={{ flex: '1 1 40%', minWidth: 160, maxWidth: '100%' }}>
532
- <Comp value={rightValue} onChange={(val) => setRightValue(val)} />
638
+ <Comp value={rightValue} onChange={(val) => setRightValue(val)} disabled={disabled} />
533
639
  </div>
534
640
  );
535
- }, [operator, operatorMetaList, rightValue, staticInputRenderer, model.context.app, setRightValue, enumOptions]);
641
+ }, [
642
+ disabled,
643
+ operator,
644
+ operatorMetaList,
645
+ rightValue,
646
+ staticInputRenderer,
647
+ model.context.app,
648
+ setRightValue,
649
+ enumOptions,
650
+ ]);
536
651
 
537
652
  // Null 占位组件(仿照 DefaultValue.tsx 的实现)
538
653
  const NullComponent = useMemo(() => {
@@ -582,17 +697,19 @@ export const VariableFilterItem: React.FC<VariableFilterItemProps> = observer(
582
697
  const first = meta?.paths?.[0];
583
698
  if (first === 'constant') return '';
584
699
  if (first === 'null') return null;
585
- return undefined; // 交给默认逻辑格式化变量表达式
700
+ return rightVariableConverters?.resolveValueFromPath?.(meta);
586
701
  },
587
702
  resolvePathFromValue: (val) => {
588
703
  if (val === null) return ['null'];
589
- // 变量表达式:使用内置解析;其他静态值走 constant
590
- const parsed = typeof val === 'string' ? parseValueToPath(val) : undefined;
704
+ // 变量表达式:优先使用领域转换器,再回退内置解析;其他静态值走 constant
705
+ const parsed =
706
+ rightVariableConverters?.resolvePathFromValue?.(val) ??
707
+ (typeof val === 'string' ? parseValueToPath(val) : undefined);
591
708
  if (parsed) return parsed;
592
709
  return ['constant'];
593
710
  },
594
711
  };
595
- }, [NullComponent, staticInputRenderer]);
712
+ }, [NullComponent, rightVariableConverters, staticInputRenderer]);
596
713
 
597
714
  // 为 2.0 左侧字段选择器追加“接口 filterable.children”定义(如 chinaRegion 的“省市区名称”子项),
598
715
  // 以恢复 1.0 左侧子菜单的能力。
@@ -652,6 +769,34 @@ export const VariableFilterItem: React.FC<VariableFilterItemProps> = observer(
652
769
  };
653
770
  }, [getFieldInterface, model, maxAssociationFieldDepth]);
654
771
 
772
+ useEffect(() => {
773
+ if (leftMeta || !value.path) {
774
+ return;
775
+ }
776
+
777
+ let cancelled = false;
778
+ const restore = async () => {
779
+ const nodes = await enhancedMetaTree();
780
+ if (cancelled) {
781
+ return;
782
+ }
783
+ const path = customConverters.resolvePathFromValue(value.path);
784
+ if (!path?.length) {
785
+ return;
786
+ }
787
+ const matched =
788
+ findMetaTreeNodeByPath(nodes, path) || buildCollectionFieldMetaNode(model.context.collection, path);
789
+ if (matched) {
790
+ setLeftMeta(matched);
791
+ }
792
+ };
793
+
794
+ restore();
795
+ return () => {
796
+ cancelled = true;
797
+ };
798
+ }, [customConverters, enhancedMetaTree, leftMeta, model.context.collection, value.path]);
799
+
655
800
  return (
656
801
  <Space wrap style={{ width: '100%' }}>
657
802
  <VariableInput
@@ -659,6 +804,7 @@ export const VariableFilterItem: React.FC<VariableFilterItemProps> = observer(
659
804
  metaTree={enhancedMetaTree}
660
805
  onChange={handleLeftChange}
661
806
  converters={customConverters}
807
+ disabled={disabled}
662
808
  showValueComponent={false}
663
809
  style={{ flex: '1 1 40%', minWidth: 160, maxWidth: '100%' }}
664
810
  onlyLeafSelectable={true}
@@ -670,6 +816,7 @@ export const VariableFilterItem: React.FC<VariableFilterItemProps> = observer(
670
816
  style={{ flex: '0 0 140px', minWidth: 120, maxWidth: '100%' }}
671
817
  placeholder={t('Comparison')}
672
818
  value={operator || undefined}
819
+ disabled={disabled}
673
820
  onChange={handleOperatorChange}
674
821
  >
675
822
  {operatorOptions.map((op) => (
@@ -686,6 +833,7 @@ export const VariableFilterItem: React.FC<VariableFilterItemProps> = observer(
686
833
  onChange={(v) => setRightValue(v)}
687
834
  metaTree={mergedRightMetaTree}
688
835
  converters={rightConverters}
836
+ disabled={disabled}
689
837
  showValueComponent
690
838
  style={{ flex: '1 1 40%', minWidth: 160, maxWidth: '100%' }}
691
839
  placeholder={t('Enter value')}