@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
@@ -7,7 +7,7 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
 
10
- import React, { useMemo, useState } from 'react';
10
+ import React, { useCallback, useMemo, useState } from 'react';
11
11
  import { DatePicker, Select, Space } from 'antd';
12
12
  import { inferPickerType } from '../../flow-compat';
13
13
  import { dayjs, getDateTimeFormat, getPickerFormat } from '@nocobase/utils/client';
@@ -29,6 +29,7 @@ export interface FieldAssignExactDatePickerProps {
29
29
  isRange?: boolean;
30
30
  onChange?: (value: ExactDatePickerValue) => void;
31
31
  style?: React.CSSProperties;
32
+ disabled?: boolean;
32
33
  }
33
34
 
34
35
  function getRawSingleValue(value: unknown, isRange: boolean): unknown {
@@ -114,7 +115,7 @@ function parseRangeValue(value: unknown, format: string): [dayjs.Dayjs, dayjs.Da
114
115
  }
115
116
 
116
117
  export const FieldAssignExactDatePicker: React.FC<FieldAssignExactDatePickerProps> = (props) => {
117
- const { picker = 'date', format, showTime, timeFormat, value, isRange = false, onChange, style } = props;
118
+ const { picker = 'date', format, showTime, timeFormat, value, isRange = false, onChange, style, disabled } = props;
118
119
  const flowCtx = useFlowContext();
119
120
  const t = flowCtx.model.translate.bind(flowCtx.model);
120
121
 
@@ -124,17 +125,17 @@ export const FieldAssignExactDatePicker: React.FC<FieldAssignExactDatePickerProp
124
125
  return inferPickerFromRawValue(rawSingleValue, picker);
125
126
  });
126
127
 
127
- const getResolvedFormat = (nextPicker: ExactDatePickerMode) => {
128
- const baseFormat = nextPicker === picker && format ? format : getPickerFormat(nextPicker);
129
- const dateFormat = nextPicker === 'date' ? stripTimeFromFormat(baseFormat) : baseFormat;
130
- return getDateTimeFormat(nextPicker, dateFormat, showTime, timeFormat);
131
- };
132
-
133
- const resolvedFormat = useMemo(
134
- () => getResolvedFormat(targetPicker),
135
- [targetPicker, format, picker, showTime, timeFormat],
128
+ const getResolvedFormat = useCallback(
129
+ (nextPicker: ExactDatePickerMode) => {
130
+ const baseFormat = nextPicker === picker && format ? format : getPickerFormat(nextPicker);
131
+ const dateFormat = nextPicker === 'date' ? stripTimeFromFormat(baseFormat) : baseFormat;
132
+ return getDateTimeFormat(nextPicker, dateFormat, showTime, timeFormat);
133
+ },
134
+ [format, picker, showTime, timeFormat],
136
135
  );
137
136
 
137
+ const resolvedFormat = useMemo(() => getResolvedFormat(targetPicker), [getResolvedFormat, targetPicker]);
138
+
138
139
  const singleValue = useMemo(() => {
139
140
  if (isRange) return null;
140
141
  return parseDateFromRawValue(value, resolvedFormat);
@@ -156,6 +157,10 @@ export const FieldAssignExactDatePicker: React.FC<FieldAssignExactDatePickerProp
156
157
  );
157
158
 
158
159
  const handlePickerTypeChange = (nextPicker: ExactDatePickerMode) => {
160
+ if (disabled) {
161
+ return;
162
+ }
163
+
159
164
  setTargetPicker(nextPicker);
160
165
 
161
166
  if (!onChange) {
@@ -182,7 +187,11 @@ export const FieldAssignExactDatePicker: React.FC<FieldAssignExactDatePickerProp
182
187
  inputReadOnly: flowCtx.isMobileLayout,
183
188
  showTime: showTime ? { defaultValue: dayjs('00:00:00', 'HH:mm:ss') } : false,
184
189
  value: singleValue,
190
+ disabled,
185
191
  onChange: (nextDate: dayjs.Dayjs | null) => {
192
+ if (disabled) {
193
+ return;
194
+ }
186
195
  if (nextDate && dayjs.isDayjs(nextDate)) {
187
196
  onChange?.(nextDate);
188
197
  return;
@@ -200,7 +209,11 @@ export const FieldAssignExactDatePicker: React.FC<FieldAssignExactDatePickerProp
200
209
  inputReadOnly: flowCtx.isMobileLayout,
201
210
  showTime: showTime ? { defaultValue: [dayjs('00:00:00', 'HH:mm:ss'), dayjs('23:59:59', 'HH:mm:ss')] } : false,
202
211
  value: rangeValue,
212
+ disabled,
203
213
  onChange: (nextDates: [dayjs.Dayjs | null, dayjs.Dayjs | null] | null) => {
214
+ if (disabled) {
215
+ return;
216
+ }
204
217
  if (Array.isArray(nextDates) && nextDates[0] && nextDates[1]) {
205
218
  onChange?.([nextDates[0], nextDates[1]]);
206
219
  return;
@@ -218,6 +231,7 @@ export const FieldAssignExactDatePicker: React.FC<FieldAssignExactDatePickerProp
218
231
  value={targetPicker}
219
232
  options={pickerOptions}
220
233
  onChange={handlePickerTypeChange}
234
+ disabled={disabled}
221
235
  />
222
236
  {isRange ? <DatePicker.RangePicker {...rangePickerProps} /> : <DatePicker {...singlePickerProps} />}
223
237
  </Space.Compact>
@@ -28,7 +28,7 @@ import { buildFieldAssignCascaderOptionsFromCollection, type FieldAssignCascader
28
28
  import { isRunJSValue, isVariableExpression, type MetaTreeNode } from '@nocobase/flow-engine';
29
29
  import { isToManyAssociationField } from '../internal/utils/modelUtils';
30
30
 
31
- export type AssignMode = 'default' | 'assign';
31
+ export type AssignMode = 'default' | 'assign' | 'override';
32
32
 
33
33
  type CollectionFieldLike = {
34
34
  name?: unknown;
@@ -89,6 +89,8 @@ export interface FieldAssignRulesEditorProps {
89
89
  defaultMode?: AssignMode;
90
90
  /** 固定 mode:用于“仅默认值/仅赋值”的场景 */
91
91
  fixedMode?: AssignMode;
92
+ /** 可选 mode 列表;fixedMode 优先级更高 */
93
+ allowedModes?: AssignMode[];
92
94
  /** 是否显示 condition */
93
95
  showCondition?: boolean;
94
96
  /** 是否显示 enable 开关 */
@@ -109,6 +111,65 @@ export interface FieldAssignRulesEditorProps {
109
111
  maxAssociationFieldDepth?: number;
110
112
  }
111
113
 
114
+ const ALL_ASSIGN_MODES: AssignMode[] = ['default', 'override', 'assign'];
115
+
116
+ function cloneCascaderOption(option: FieldAssignCascaderOption): FieldAssignCascaderOption {
117
+ return {
118
+ ...option,
119
+ children: option.children?.map((child) => cloneCascaderOption(child)),
120
+ };
121
+ }
122
+
123
+ function mergeCascaderOptionInto(options: FieldAssignCascaderOption[], source: FieldAssignCascaderOption) {
124
+ const value = source?.value ? String(source.value) : '';
125
+ if (!value) return;
126
+
127
+ const existing = options.find((item) => String(item?.value || '') === value);
128
+ if (!existing) {
129
+ options.push(cloneCascaderOption(source));
130
+ return;
131
+ }
132
+
133
+ if (!existing.label && source.label) {
134
+ existing.label = source.label;
135
+ }
136
+ if (source.isLeaf === false || existing.children?.length || source.children?.length) {
137
+ existing.isLeaf = false;
138
+ }
139
+ if (source.loading) {
140
+ existing.loading = source.loading;
141
+ }
142
+ if (source.children?.length) {
143
+ existing.children = mergeCascaderOptions(existing.children || [], source.children);
144
+ }
145
+ }
146
+
147
+ function mergeCascaderOptions(
148
+ configured: FieldAssignCascaderOption[],
149
+ allFields: FieldAssignCascaderOption[],
150
+ ): FieldAssignCascaderOption[] {
151
+ const result = (Array.isArray(configured) ? configured : []).map((item) => cloneCascaderOption(item));
152
+ for (const item of Array.isArray(allFields) ? allFields : []) {
153
+ mergeCascaderOptionInto(result, item);
154
+ }
155
+ return result;
156
+ }
157
+
158
+ function isAssignMode(mode: unknown): mode is AssignMode {
159
+ return mode === 'default' || mode === 'override' || mode === 'assign';
160
+ }
161
+
162
+ function normalizeAssignModes(modes?: AssignMode[]): AssignMode[] {
163
+ const source = Array.isArray(modes) && modes.length ? modes : ALL_ASSIGN_MODES;
164
+ const out: AssignMode[] = [];
165
+ for (const mode of source) {
166
+ if (!isAssignMode(mode)) continue;
167
+ if (out.includes(mode)) continue;
168
+ out.push(mode);
169
+ }
170
+ return out.length ? out : ALL_ASSIGN_MODES;
171
+ }
172
+
112
173
  export const FieldAssignRulesEditor: React.FC<FieldAssignRulesEditorProps> = (props) => {
113
174
  const {
114
175
  t,
@@ -118,6 +179,7 @@ export const FieldAssignRulesEditor: React.FC<FieldAssignRulesEditorProps> = (pr
118
179
  onChange,
119
180
  defaultMode = 'assign',
120
181
  fixedMode,
182
+ allowedModes: rawAllowedModes,
121
183
  showCondition = true,
122
184
  showEnable = true,
123
185
  showValueEditorWhenNoField = false,
@@ -129,13 +191,43 @@ export const FieldAssignRulesEditor: React.FC<FieldAssignRulesEditorProps> = (pr
129
191
  } = props;
130
192
 
131
193
  const value = React.useMemo(() => (Array.isArray(rawValue) ? rawValue : []), [rawValue]);
194
+ const allowedModes = React.useMemo(
195
+ () => normalizeAssignModes(fixedMode ? [fixedMode] : rawAllowedModes),
196
+ [fixedMode, rawAllowedModes],
197
+ );
198
+ const getDefaultMode = React.useCallback((): AssignMode => {
199
+ if (fixedMode) return fixedMode;
200
+ if (isAssignMode(defaultMode) && allowedModes.includes(defaultMode)) return defaultMode;
201
+ return allowedModes[0] || 'assign';
202
+ }, [allowedModes, defaultMode, fixedMode]);
203
+ const normalizeItemMode = React.useCallback(
204
+ (item: FieldAssignRuleItem): FieldAssignRuleItem => {
205
+ const mode = isAssignMode(item?.mode) && allowedModes.includes(item.mode) ? item.mode : getDefaultMode();
206
+ return item?.mode === mode ? item : { ...item, mode };
207
+ },
208
+ [allowedModes, getDefaultMode],
209
+ );
210
+ const emitChange = React.useCallback(
211
+ (next: FieldAssignRuleItem[]) => {
212
+ onChange?.(next.map((item) => normalizeItemMode(item)));
213
+ },
214
+ [normalizeItemMode, onChange],
215
+ );
216
+
217
+ const normalizeFieldOptions = React.useCallback((options: FieldAssignRulesEditorProps['fieldOptions']) => {
218
+ return Array.isArray(options)
219
+ ? (options as FieldAssignCascaderOption[]).map((option) => cloneCascaderOption(option))
220
+ : [];
221
+ }, []);
132
222
  const [cascaderOptions, setCascaderOptions] = React.useState<FieldAssignCascaderOption[]>(() =>
133
- Array.isArray(fieldOptions) ? (fieldOptions as FieldAssignCascaderOption[]) : [],
223
+ normalizeFieldOptions(fieldOptions),
134
224
  );
225
+ const loadedCascaderOptionsRef = React.useRef<WeakSet<FieldAssignCascaderOption>>(new WeakSet());
135
226
 
136
227
  React.useEffect(() => {
137
- setCascaderOptions(Array.isArray(fieldOptions) ? (fieldOptions as FieldAssignCascaderOption[]) : []);
138
- }, [fieldOptions]);
228
+ loadedCascaderOptionsRef.current = new WeakSet();
229
+ setCascaderOptions(normalizeFieldOptions(fieldOptions));
230
+ }, [fieldOptions, normalizeFieldOptions, rootCollection, maxAssociationFieldDepth]);
139
231
 
140
232
  const getRuleKey = React.useCallback((item: FieldAssignRuleItem, index: number) => item?.key || String(index), []);
141
233
  const [titleFieldDraftMap, setTitleFieldDraftMap] = React.useState<Record<string, string | undefined>>({});
@@ -312,7 +404,7 @@ export const FieldAssignRulesEditor: React.FC<FieldAssignRulesEditorProps> = (pr
312
404
 
313
405
  const patchItem = (index: number, patch: Partial<FieldAssignRuleItem>) => {
314
406
  const next = value.map((it, i) => (i === index ? { ...it, ...patch } : it));
315
- onChange?.(next);
407
+ emitChange(next);
316
408
  };
317
409
 
318
410
  const removeItem = (index: number) => {
@@ -334,7 +426,7 @@ export const FieldAssignRulesEditor: React.FC<FieldAssignRulesEditorProps> = (pr
334
426
  setSyncingRuleKey(null);
335
427
  }
336
428
  const next = value.filter((_, i) => i !== index);
337
- onChange?.(next);
429
+ emitChange(next);
338
430
  };
339
431
 
340
432
  const moveItem = (index: number, direction: 'up' | 'down') => {
@@ -343,7 +435,7 @@ export const FieldAssignRulesEditor: React.FC<FieldAssignRulesEditorProps> = (pr
343
435
  if (targetIndex < 0 || targetIndex >= next.length) return;
344
436
  const [item] = next.splice(index, 1);
345
437
  next.splice(targetIndex, 0, item);
346
- onChange?.(next);
438
+ emitChange(next);
347
439
  };
348
440
 
349
441
  const addItem = () => {
@@ -352,29 +444,33 @@ export const FieldAssignRulesEditor: React.FC<FieldAssignRulesEditorProps> = (pr
352
444
  {
353
445
  key: uid(),
354
446
  enable: true,
355
- mode: fixedMode || defaultMode,
447
+ mode: getDefaultMode(),
356
448
  condition: { logic: '$and', items: [] },
357
449
  targetPath: undefined,
358
450
  value: undefined,
359
451
  },
360
452
  ];
361
- onChange?.(next);
453
+ emitChange(next);
362
454
  };
363
455
 
364
456
  const getEffectiveMode = (item: FieldAssignRuleItem): AssignMode => {
365
457
  if (fixedMode) return fixedMode;
366
- return item?.mode === 'default' ? 'default' : 'assign';
458
+ if (isAssignMode(item?.mode) && allowedModes.includes(item.mode)) return item.mode;
459
+ return getDefaultMode();
367
460
  };
368
461
 
369
462
  const renderAssignModeLabel = React.useCallback(
370
463
  (mode: AssignMode) => {
371
- const modeText = mode === 'default' ? t('Default value') : t('Fixed value');
464
+ const modeText =
465
+ mode === 'default' ? t('Default value') : mode === 'override' ? t('Override value') : t('Fixed value');
372
466
  const modeHelpText =
373
467
  mode === 'default'
374
468
  ? t(
375
469
  'A pre-filled value. Editable, for new entries only, and won’t affect existing data (including empty values).',
376
470
  )
377
- : t('A system-set value. Read-only.');
471
+ : mode === 'override'
472
+ ? t('Overrides existing values until the user edits it.')
473
+ : t('A system-set value. Read-only.');
378
474
 
379
475
  const preventModeToggle = (e: React.MouseEvent<HTMLElement>) => {
380
476
  e.preventDefault();
@@ -551,23 +647,26 @@ export const FieldAssignRulesEditor: React.FC<FieldAssignRulesEditorProps> = (pr
551
647
  const opts = selectedOptions || [];
552
648
  const target = opts[opts.length - 1];
553
649
  if (!target) return;
554
- if (target.children && Array.isArray(target.children) && target.children.length) return;
555
650
  if (target.isLeaf) return;
651
+ if (loadedCascaderOptionsRef.current.has(target)) return;
556
652
 
557
653
  const segments = opts.map((o) => String(o?.value)).filter(Boolean);
558
654
  const targetCollection = resolveTargetCollectionBySegments(segments);
559
655
  if (!targetCollection) {
560
- target.isLeaf = true;
656
+ target.isLeaf = !(target.children && target.children.length);
657
+ loadedCascaderOptionsRef.current.add(target);
561
658
  setCascaderOptions((prev) => [...prev]);
562
659
  return;
563
660
  }
564
661
 
565
662
  const children = buildChildrenFromCollection(targetCollection, segments.length);
566
663
  if (!children.length) {
567
- target.isLeaf = true;
664
+ target.isLeaf = !(target.children && target.children.length);
568
665
  } else {
569
- target.children = children;
666
+ target.children = mergeCascaderOptions(target.children || [], children);
667
+ target.isLeaf = false;
570
668
  }
669
+ loadedCascaderOptionsRef.current.add(target);
571
670
  setCascaderOptions((prev) => [...prev]);
572
671
  },
573
672
  [buildChildrenFromCollection, resolveTargetCollectionBySegments],
@@ -583,12 +682,14 @@ export const FieldAssignRulesEditor: React.FC<FieldAssignRulesEditorProps> = (pr
583
682
  const hit = options.find((o) => String(o?.value) === seg);
584
683
  if (!hit) return;
585
684
  selected.push(hit);
685
+ if (!hit.isLeaf && !loadedCascaderOptionsRef.current.has(hit)) {
686
+ await loadCascaderData(selected);
687
+ }
586
688
  if (hit.children?.length) {
587
689
  options = hit.children;
588
690
  continue;
589
691
  }
590
692
  if (hit.isLeaf) return;
591
- await loadCascaderData(selected);
592
693
  options = hit.children || [];
593
694
  }
594
695
  },
@@ -619,7 +720,9 @@ export const FieldAssignRulesEditor: React.FC<FieldAssignRulesEditorProps> = (pr
619
720
  await preloadCascaderPath(segs);
620
721
  }
621
722
  };
622
- void run();
723
+ run().catch((error) => {
724
+ console.warn('[FieldAssignRulesEditor] Failed to preload cascader path', error);
725
+ });
623
726
  return () => {
624
727
  cancelled = true;
625
728
  };
@@ -627,7 +730,8 @@ export const FieldAssignRulesEditor: React.FC<FieldAssignRulesEditorProps> = (pr
627
730
 
628
731
  const renderPanelHeader = (item: FieldAssignRuleItem, index: number) => {
629
732
  const mode = getEffectiveMode(item);
630
- const modeText = mode === 'default' ? t('Default value') : t('Fixed value');
733
+ const modeText =
734
+ mode === 'default' ? t('Default value') : mode === 'override' ? t('Override value') : t('Fixed value');
631
735
  const fieldLabel = getFieldLabel(item.targetPath);
632
736
  const title = fieldLabel ? String(fieldLabel) : t('Please select field');
633
737
 
@@ -935,8 +1039,11 @@ export const FieldAssignRulesEditor: React.FC<FieldAssignRulesEditorProps> = (pr
935
1039
  onChange={(event) => patchItem(index, { mode: event.target.value as AssignMode })}
936
1040
  >
937
1041
  <Space size={16}>
938
- <Radio value="default">{renderAssignModeLabel('default')}</Radio>
939
- <Radio value="assign">{renderAssignModeLabel('assign')}</Radio>
1042
+ {allowedModes.map((allowedMode) => (
1043
+ <Radio key={allowedMode} value={allowedMode}>
1044
+ {renderAssignModeLabel(allowedMode)}
1045
+ </Radio>
1046
+ ))}
940
1047
  </Space>
941
1048
  </Radio.Group>
942
1049
  </div>
@@ -42,6 +42,12 @@ import { normalizeFilterValueByOperator } from '../models/blocks/filter-form/val
42
42
  import { FieldAssignExactDatePicker, type ExactDatePickerMode } from './FieldAssignExactDatePicker';
43
43
  import { limitAssociationMetaTree } from './filter/metaTreeAssociationDepth';
44
44
 
45
+ type VariableInputConverters = {
46
+ renderInputComponent?: (metaTreeNode: MetaTreeNode | null) => React.ComponentType<any> | null;
47
+ resolvePathFromValue?: (value: any) => string[] | undefined;
48
+ resolveValueFromPath?: (metaTreeNode: MetaTreeNode) => any;
49
+ };
50
+
45
51
  const DATE_FIELD_INTERFACES = new Set(['date', 'datetime', 'datetimeNoTz', 'createdAt', 'updatedAt', 'unixTimestamp']);
46
52
 
47
53
  const TZ_AWARE_DATE_INTERFACES = new Set(['datetime', 'createdAt', 'updatedAt', 'unixTimestamp']);
@@ -341,7 +347,11 @@ interface Props {
341
347
  * 默认 false,保持历史行为。
342
348
  */
343
349
  enableDateVariableAsConstant?: boolean;
350
+ /** 是否允许在变量选择器中使用 RunJS。默认 true,保持历史行为。 */
351
+ allowRunJS?: boolean;
344
352
  maxAssociationFieldDepth?: number;
353
+ disabled?: boolean;
354
+ variableConverters?: VariableInputConverters;
345
355
  }
346
356
 
347
357
  type ResolvedFieldContext = {
@@ -712,7 +722,10 @@ export const FieldAssignValueInput: React.FC<Props> = ({
712
722
  preferFormItemFieldModel,
713
723
  associationFieldNamesOverride,
714
724
  enableDateVariableAsConstant = false,
725
+ allowRunJS = true,
715
726
  maxAssociationFieldDepth = 2,
727
+ disabled = false,
728
+ variableConverters,
716
729
  }) => {
717
730
  const flowCtx = useFlowContext<FlowModelContext>();
718
731
  const normalizeEventValue = React.useCallback((eventOrValue: unknown) => {
@@ -1028,18 +1041,22 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1028
1041
  collectionField: effectiveCollectionField,
1029
1042
  });
1030
1043
 
1031
- const created = engine?.createModel?.({
1032
- use: 'VariableFieldFormModel',
1033
- subModels: {
1034
- fields: [
1035
- {
1036
- use: effectiveFieldModelUse,
1037
- stepParams: tempFieldStepParams,
1038
- props: tempFieldProps,
1039
- },
1040
- ],
1044
+ const sourceContext = resolved?.itemModel?.context || flowCtx.model?.context;
1045
+ const created = engine?.createModel?.(
1046
+ {
1047
+ use: 'VariableFieldFormModel',
1048
+ subModels: {
1049
+ fields: [
1050
+ {
1051
+ use: effectiveFieldModelUse,
1052
+ stepParams: tempFieldStepParams,
1053
+ props: tempFieldProps,
1054
+ },
1055
+ ],
1056
+ },
1041
1057
  },
1042
- });
1058
+ sourceContext ? { delegate: sourceContext } : undefined,
1059
+ );
1043
1060
  if (!created) return;
1044
1061
 
1045
1062
  // 注入上下文(集合/数据源/字段/区块/资源)
@@ -1073,7 +1090,7 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1073
1090
  fm.setStepParams('selectSettings', 'fieldNames', { label: overrideLabel });
1074
1091
  }
1075
1092
  fm?.setProps?.({
1076
- disabled: false,
1093
+ disabled,
1077
1094
  readPretty: false,
1078
1095
  pattern: 'editable',
1079
1096
  updateAssociation: false,
@@ -1136,6 +1153,7 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1136
1153
  preferFormItemFieldModel,
1137
1154
  associationFieldNamesOverride?.label,
1138
1155
  associationFieldNamesOverride?.value,
1156
+ disabled,
1139
1157
  ]);
1140
1158
 
1141
1159
  // 当传入 operator / operatorMetaList 时,按 operator schema 适配临时字段的输入组件与 props。
@@ -1188,6 +1206,9 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1188
1206
  React.useEffect(() => {
1189
1207
  const coercedValue = coerceEmptyValueForRenderer(inputProps?.value);
1190
1208
  const handleChange = (ev: any) => {
1209
+ if (inputProps?.disabled) {
1210
+ return;
1211
+ }
1191
1212
  const nextRaw = normalizeEventValue(ev);
1192
1213
  const normalizedForStore = operator ? normalizeFilterValueByOperator(operator, nextRaw) : nextRaw;
1193
1214
  const nextValue = coerceEmptyValueForRenderer(normalizedForStore);
@@ -1219,6 +1240,7 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1219
1240
  value={inputProps?.value}
1220
1241
  onChange={(e) => inputProps?.onChange?.(normalizeEventValue(e))}
1221
1242
  placeholder={placeholder}
1243
+ disabled={inputProps?.disabled}
1222
1244
  style={withFullWidthStyle(wrapperStyle)}
1223
1245
  />
1224
1246
  );
@@ -1237,6 +1259,7 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1237
1259
  const C: React.FC<any> = (inputProps) => {
1238
1260
  const wrapperStyle = pickStyle(inputProps?.style);
1239
1261
  const raw = inputProps?.value;
1262
+ const isDisabled = Boolean(inputProps?.disabled);
1240
1263
  const parsed = isCtxDateExpression(raw) ? parseCtxDateExpression(raw) : raw;
1241
1264
  const parsedValue = typeof parsed === 'undefined' ? undefined : parsed;
1242
1265
  const { token } = theme.useToken();
@@ -1261,6 +1284,9 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1261
1284
  });
1262
1285
 
1263
1286
  const handleSelect = (val: string) => {
1287
+ if (isDisabled) {
1288
+ return;
1289
+ }
1264
1290
  setOpen(false);
1265
1291
  if (val === 'exact') {
1266
1292
  inputProps?.onChange?.('');
@@ -1275,10 +1301,16 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1275
1301
  };
1276
1302
 
1277
1303
  const handleExactSingleChange = (nextValue: any) => {
1304
+ if (isDisabled) {
1305
+ return;
1306
+ }
1278
1307
  inputProps?.onChange?.(nextValue || '');
1279
1308
  };
1280
1309
 
1281
1310
  const handleExactRangeChange = (nextValue: any) => {
1311
+ if (isDisabled) {
1312
+ return;
1313
+ }
1282
1314
  inputProps?.onChange?.(nextValue || '');
1283
1315
  };
1284
1316
 
@@ -1323,7 +1355,11 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1323
1355
  <Select
1324
1356
  options={options}
1325
1357
  open={open}
1326
- onDropdownVisibleChange={setOpen}
1358
+ onDropdownVisibleChange={(nextOpen) => {
1359
+ if (!isDisabled) {
1360
+ setOpen(nextOpen);
1361
+ }
1362
+ }}
1327
1363
  allowClear={false}
1328
1364
  style={{
1329
1365
  width: '100%',
@@ -1333,13 +1369,18 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1333
1369
  value={selectedType}
1334
1370
  onChange={handleSelect}
1335
1371
  dropdownRender={dropdownRender}
1372
+ disabled={isDisabled}
1336
1373
  />
1337
1374
  {['past', 'next'].includes(selectedType) && [
1338
1375
  <InputNumber
1339
1376
  key="number"
1340
1377
  style={{ flex: 1 }}
1341
1378
  value={(parsedValue as any)?.number}
1379
+ disabled={isDisabled}
1342
1380
  onChange={(nextNumber) => {
1381
+ if (isDisabled) {
1382
+ return;
1383
+ }
1343
1384
  inputProps?.onChange?.({
1344
1385
  ...(parsedValue as any),
1345
1386
  type: selectedType,
@@ -1352,7 +1393,11 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1352
1393
  key="unit"
1353
1394
  value={(parsedValue as any)?.unit}
1354
1395
  style={{ minWidth: 130, maxWidth: 140 }}
1396
+ disabled={isDisabled}
1355
1397
  onChange={(nextUnit) => {
1398
+ if (isDisabled) {
1399
+ return;
1400
+ }
1356
1401
  inputProps?.onChange?.({
1357
1402
  ...(parsedValue as any),
1358
1403
  type: selectedType,
@@ -1375,6 +1420,7 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1375
1420
  isRange={isRange}
1376
1421
  value={isRange ? exactRangeValue : exactSingleValue}
1377
1422
  onChange={isRange ? handleExactRangeChange : handleExactSingleChange}
1423
+ disabled={isDisabled}
1378
1424
  style={{ flex: 1 }}
1379
1425
  />
1380
1426
  )}
@@ -1394,7 +1440,12 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1394
1440
 
1395
1441
  const RunJSComponent = React.useMemo(() => {
1396
1442
  const C: React.FC<any> = (inputProps) => (
1397
- <RunJSValueEditor t={flowCtx.t} value={inputProps?.value} onChange={inputProps?.onChange} />
1443
+ <RunJSValueEditor
1444
+ t={flowCtx.t}
1445
+ value={inputProps?.value}
1446
+ onChange={inputProps?.onChange}
1447
+ disabled={inputProps?.disabled}
1448
+ />
1398
1449
  );
1399
1450
  return C;
1400
1451
  }, [flowCtx]);
@@ -1417,11 +1468,13 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1417
1468
  render: ConstantEditor,
1418
1469
  },
1419
1470
  { title: tExpr('Null'), name: 'null', type: 'object', paths: ['null'], render: NullComponent },
1420
- { title: tExpr('RunJS'), name: 'runjs', type: 'object', paths: ['runjs'], render: RunJSComponent },
1471
+ ...(allowRunJS
1472
+ ? [{ title: tExpr('RunJS'), name: 'runjs', type: 'object', paths: ['runjs'], render: RunJSComponent }]
1473
+ : []),
1421
1474
  ...limitedBase,
1422
1475
  ];
1423
1476
  };
1424
- }, [flowCtx, ConstantEditor, NullComponent, RunJSComponent, maxAssociationFieldDepth]);
1477
+ }, [flowCtx, ConstantEditor, NullComponent, RunJSComponent, allowRunJS, maxAssociationFieldDepth]);
1425
1478
 
1426
1479
  const displayValue = React.useMemo(() => {
1427
1480
  if (!useDateVariableConstant) {
@@ -1438,6 +1491,10 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1438
1491
 
1439
1492
  const handleVariableInputChange = React.useCallback(
1440
1493
  (nextValue: any) => {
1494
+ if (disabled) {
1495
+ return;
1496
+ }
1497
+
1441
1498
  if (!useDateVariableConstant) {
1442
1499
  onChange(nextValue);
1443
1500
  return;
@@ -1445,7 +1502,7 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1445
1502
 
1446
1503
  onChange(normalizeDateVariableOutput(nextValue, dateVariableComponentProps));
1447
1504
  },
1448
- [dateVariableComponentProps, onChange, useDateVariableConstant],
1505
+ [dateVariableComponentProps, disabled, onChange, useDateVariableConstant],
1449
1506
  );
1450
1507
 
1451
1508
  if (!fieldPath) {
@@ -1460,26 +1517,40 @@ export const FieldAssignValueInput: React.FC<Props> = ({
1460
1517
  metaTree={metaTree}
1461
1518
  style={{ width: '100%' }}
1462
1519
  clearValue={''}
1520
+ disabled={disabled}
1463
1521
  converters={{
1522
+ ...variableConverters,
1464
1523
  renderInputComponent: (meta) => {
1524
+ const external = variableConverters?.renderInputComponent?.(meta ?? null);
1525
+ if (external) {
1526
+ return external;
1527
+ }
1465
1528
  const firstPath = meta?.paths?.[0];
1466
1529
  if (firstPath === 'constant') return ConstantEditor;
1467
1530
  if (firstPath === 'null') return NullComponent;
1468
- if (firstPath === 'runjs') return RunJSComponent;
1531
+ if (allowRunJS && firstPath === 'runjs') return RunJSComponent;
1469
1532
  return null;
1470
1533
  },
1471
1534
  resolveValueFromPath: (item) => {
1535
+ const external = variableConverters?.resolveValueFromPath?.(item);
1536
+ if (external !== undefined) {
1537
+ return external;
1538
+ }
1472
1539
  const firstPath = item?.paths?.[0];
1473
1540
  if (firstPath === 'constant') {
1474
1541
  return useDateVariableConstant ? { type: 'today' } : '';
1475
1542
  }
1476
1543
  if (firstPath === 'null') return null;
1477
- if (firstPath === 'runjs') return { code: '', version: 'v2' };
1544
+ if (allowRunJS && firstPath === 'runjs') return { code: '', version: 'v2' };
1478
1545
  return undefined;
1479
1546
  },
1480
1547
  resolvePathFromValue: (currentValue) => {
1548
+ const external = variableConverters?.resolvePathFromValue?.(currentValue);
1549
+ if (external !== undefined) {
1550
+ return external;
1551
+ }
1481
1552
  if (currentValue === null) return ['null'];
1482
- if (isRunJSValue(currentValue)) return ['runjs'];
1553
+ if (allowRunJS && isRunJSValue(currentValue)) return ['runjs'];
1483
1554
  if (useDateVariableConstant && isCtxDateExpression(currentValue)) {
1484
1555
  return ['constant'];
1485
1556
  }