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

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 (220) hide show
  1. package/es/PluginSettingsManager.d.ts +33 -0
  2. package/es/RouteRepository.d.ts +21 -6
  3. package/es/components/category-tabs/SortableCategoryTabs.d.ts +55 -0
  4. package/es/components/category-tabs/index.d.ts +9 -0
  5. package/es/components/form/JsonTextArea.d.ts +2 -1
  6. package/es/components/form/TypedVariableInput.d.ts +22 -4
  7. package/es/components/form/VariableJsonTextArea.d.ts +19 -0
  8. package/es/components/form/filter/CollectionFilterItem.d.ts +11 -1
  9. package/es/components/form/filter/index.d.ts +2 -0
  10. package/es/components/form/index.d.ts +1 -0
  11. package/es/components/index.d.ts +2 -0
  12. package/es/flow/actions/afterSuccess.d.ts +8 -1
  13. package/es/flow/actions/index.d.ts +1 -1
  14. package/es/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.d.ts +2 -0
  15. package/es/flow/admin-shell/admin-layout/AdminLayoutMenuFlowUtils.d.ts +2 -1
  16. package/es/flow/admin-shell/admin-layout/AdminLayoutMenuModels.d.ts +2 -0
  17. package/es/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.d.ts +3 -2
  18. package/es/flow/admin-shell/admin-layout/AdminLayoutSlotModels.d.ts +5 -0
  19. package/es/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.d.ts +6 -0
  20. package/es/flow/components/FieldAssignRulesEditor.d.ts +3 -1
  21. package/es/flow/components/FieldAssignValueInput.d.ts +2 -0
  22. package/es/flow/index.d.ts +1 -0
  23. package/es/flow/models/base/GridModel.d.ts +1 -1
  24. package/es/flow/models/blocks/filter-form/FilterFormBlockModel.d.ts +5 -0
  25. package/es/flow/models/blocks/form/FormBlockModel.d.ts +4 -0
  26. package/es/flow/models/blocks/form/submitHandler.d.ts +1 -1
  27. package/es/flow/models/blocks/form/value-runtime/rules.d.ts +21 -0
  28. package/es/flow/models/blocks/form/value-runtime/runtime.d.ts +30 -0
  29. package/es/flow/models/blocks/form/value-runtime/types.d.ts +2 -2
  30. package/es/flow/models/blocks/js-block/JSBlock.d.ts +1 -0
  31. package/es/flow/models/blocks/table/TableActionsColumnModel.d.ts +1 -0
  32. package/es/flow/models/blocks/table/TableBlockModel.d.ts +1 -0
  33. package/es/flow/models/blocks/table/dragSort/dragSortHooks.d.ts +1 -1
  34. package/es/flow/models/blocks/table/dragSort/dragSortSettings.d.ts +2 -1
  35. package/es/flow/models/blocks/table/dragSort/dragSortUtils.d.ts +6 -4
  36. package/es/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.d.ts +2 -0
  37. package/es/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.d.ts +6 -0
  38. package/es/flow/resolveViewParamsToViewList.d.ts +1 -1
  39. package/es/flow/utils/dataScopeRowSnapshot.d.ts +59 -0
  40. package/es/flow/utils/dateTimeDisplayProps.d.ts +49 -0
  41. package/es/flow/utils/formValueDeps.d.ts +32 -0
  42. package/es/flow-compat/FieldValidation.d.ts +2 -1
  43. package/es/index.d.ts +2 -1
  44. package/es/index.mjs +233 -137
  45. package/lib/index.js +234 -138
  46. package/package.json +7 -7
  47. package/src/PluginSettingsManager.ts +53 -0
  48. package/src/RouteRepository.ts +126 -24
  49. package/src/__tests__/PluginSettingsManager.test.ts +13 -0
  50. package/src/__tests__/RouteRepository.test.ts +216 -0
  51. package/src/__tests__/browserChecker.test.ts +61 -0
  52. package/src/__tests__/exports.test.ts +16 -0
  53. package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +199 -0
  54. package/src/__tests__/plugin-manager.test.tsx +44 -2
  55. package/src/__tests__/settings-center.test.tsx +40 -1
  56. package/src/collection-manager/field-configure.ts +1 -1
  57. package/src/collection-manager/interfaces/id.ts +1 -1
  58. package/src/collection-manager/interfaces/m2m.tsx +2 -2
  59. package/src/collection-manager/interfaces/m2o.tsx +2 -2
  60. package/src/collection-manager/interfaces/nanoid.ts +1 -1
  61. package/src/collection-manager/interfaces/o2m.tsx +2 -2
  62. package/src/collection-manager/interfaces/obo.tsx +2 -2
  63. package/src/collection-manager/interfaces/oho.tsx +2 -2
  64. package/src/collection-manager/interfaces/properties/index.ts +2 -2
  65. package/src/collection-manager/interfaces/uuid.ts +1 -1
  66. package/src/components/AppComponents.tsx +19 -3
  67. package/src/components/README.md +7 -1
  68. package/src/components/README.zh-CN.md +6 -1
  69. package/src/components/category-tabs/SortableCategoryTabs.tsx +210 -0
  70. package/src/components/category-tabs/index.ts +10 -0
  71. package/src/components/form/JsonTextArea.tsx +21 -11
  72. package/src/components/form/TypedVariableInput.tsx +416 -93
  73. package/src/components/form/VariableJsonTextArea.tsx +175 -0
  74. package/src/components/form/__tests__/JsonTextArea.test.tsx +43 -0
  75. package/src/components/form/__tests__/TypedVariableInput.test.tsx +268 -9
  76. package/src/components/form/__tests__/VariableJsonTextArea.test.tsx +86 -0
  77. package/src/components/form/filter/CollectionFilterItem.tsx +32 -7
  78. package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +38 -0
  79. package/src/components/form/filter/index.ts +2 -0
  80. package/src/components/form/index.tsx +1 -0
  81. package/src/components/index.ts +2 -0
  82. package/src/flow/__tests__/FlowRoute.test.tsx +443 -5
  83. package/src/flow/__tests__/getKey.test.ts +7 -0
  84. package/src/flow/__tests__/resolveViewParamsToViewList.test.ts +34 -0
  85. package/src/flow/actions/__tests__/afterSuccess.test.ts +73 -0
  86. package/src/flow/actions/__tests__/dataScopeFilter.test.ts +58 -0
  87. package/src/flow/actions/__tests__/dataScopeFormValueClear.test.ts +1022 -0
  88. package/src/flow/actions/__tests__/fieldLinkageRules.scopeDepth.test.ts +150 -1
  89. package/src/flow/actions/__tests__/linkageAssignField.legacy.test.ts +135 -0
  90. package/src/flow/actions/__tests__/linkageRules.hiddenSync.restore.test.ts +19 -5
  91. package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +92 -0
  92. package/src/flow/actions/__tests__/openView.defineProps.route.test.tsx +104 -0
  93. package/src/flow/actions/__tests__/subFormFieldLinkageRules.inputArgs.test.ts +2 -2
  94. package/src/flow/actions/afterSuccess.tsx +142 -3
  95. package/src/flow/actions/customVariable.tsx +1 -2
  96. package/src/flow/actions/dataScopeFilter.ts +10 -0
  97. package/src/flow/actions/dateTimeFormat.tsx +42 -28
  98. package/src/flow/actions/index.ts +1 -1
  99. package/src/flow/actions/linkageRules.tsx +123 -35
  100. package/src/flow/actions/linkageRulesFormValueRefresh.ts +22 -130
  101. package/src/flow/actions/openView.tsx +38 -4
  102. package/src/flow/actions/runjs.tsx +2 -14
  103. package/src/flow/actions/validation.tsx +62 -30
  104. package/src/flow/admin-shell/BaseLayoutModel.tsx +25 -3
  105. package/src/flow/admin-shell/BaseLayoutRouteCoordinator.ts +5 -2
  106. package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +13 -0
  107. package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +34 -10
  108. package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.test.tsx +310 -0
  109. package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +44 -8
  110. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuFlowUtils.ts +5 -3
  111. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuModels.tsx +61 -9
  112. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.tsx +71 -8
  113. package/src/flow/admin-shell/admin-layout/AdminLayoutModel.tsx +1 -1
  114. package/src/flow/admin-shell/admin-layout/AdminLayoutSlotModels.tsx +23 -9
  115. package/src/flow/admin-shell/admin-layout/HelpLite.tsx +1 -3
  116. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutComponent.test.tsx +188 -0
  117. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +99 -0
  118. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutModel.test.tsx +82 -0
  119. package/src/flow/admin-shell/admin-layout/__tests__/TopbarActionsBar.test.tsx +166 -2
  120. package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.test.ts +20 -0
  121. package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.ts +33 -5
  122. package/src/flow/components/DefaultValue.tsx +1 -2
  123. package/src/flow/components/DynamicFlowsIcon.tsx +447 -126
  124. package/src/flow/components/FieldAssignRulesEditor.tsx +128 -21
  125. package/src/flow/components/FieldAssignValueInput.tsx +10 -5
  126. package/src/flow/components/FlowRoute.tsx +56 -11
  127. package/src/flow/components/__tests__/DynamicFlowsIcon.test.tsx +148 -2
  128. package/src/flow/components/__tests__/FieldAssignRulesEditor.test.tsx +508 -4
  129. package/src/flow/components/__tests__/fieldAssignOptions.test.ts +151 -3
  130. package/src/flow/components/code-editor/__tests__/useCodeRunner.test.tsx +2 -17
  131. package/src/flow/components/code-editor/hooks/useCodeRunner.ts +2 -14
  132. package/src/flow/components/code-editor/runjsDiagnostics.ts +8 -45
  133. package/src/flow/components/fieldAssignOptions.ts +155 -27
  134. package/src/flow/flows/editMarkdownFlow.tsx +1 -1
  135. package/src/flow/getViewDiffAndUpdateHidden.tsx +1 -0
  136. package/src/flow/index.ts +2 -1
  137. package/src/flow/internal/utils/operatorSchemaHelper.ts +15 -1
  138. package/src/flow/models/actions/JSActionModel.tsx +2 -7
  139. package/src/flow/models/actions/JSCollectionActionModel.tsx +2 -7
  140. package/src/flow/models/actions/JSItemActionModel.tsx +2 -7
  141. package/src/flow/models/actions/JSRecordActionModel.tsx +2 -7
  142. package/src/flow/models/base/ActionModel.tsx +12 -1
  143. package/src/flow/models/base/ActionModelCore.tsx +6 -4
  144. package/src/flow/models/base/GridModel.tsx +38 -7
  145. package/src/flow/models/base/PageModel/PageModel.tsx +4 -1
  146. package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +28 -4
  147. package/src/flow/models/base/__tests__/ActionModel.test.ts +83 -0
  148. package/src/flow/models/base/__tests__/ActionModelCore.render.test.tsx +37 -0
  149. package/src/flow/models/base/__tests__/GridModel.dragSnapshotContainer.test.ts +239 -1
  150. package/src/flow/models/base/__tests__/transformRowsToSingleColumn.test.ts +48 -0
  151. package/src/flow/models/blocks/filter-form/FilterFormBlockModel.tsx +31 -3
  152. package/src/flow/models/blocks/filter-form/FilterFormJSActionModel.tsx +2 -7
  153. package/src/flow/models/blocks/filter-form/__tests__/defaultValues.wiring.test.ts +77 -0
  154. package/src/flow/models/blocks/filter-form/fields/FilterFormCustomFieldModel.tsx +1 -1
  155. package/src/flow/models/blocks/filter-manager/flow-actions/__tests__/customizeFilterRender.test.tsx +56 -1
  156. package/src/flow/models/blocks/form/EditFormModel.tsx +1 -0
  157. package/src/flow/models/blocks/form/FormActionModel.tsx +1 -1
  158. package/src/flow/models/blocks/form/FormBlockModel.tsx +7 -0
  159. package/src/flow/models/blocks/form/JSFormActionModel.tsx +2 -7
  160. package/src/flow/models/blocks/form/__tests__/FormBlockModel.test.tsx +17 -0
  161. package/src/flow/models/blocks/form/__tests__/submitHandler.test.ts +54 -1
  162. package/src/flow/models/blocks/form/submitHandler.ts +17 -3
  163. package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +940 -75
  164. package/src/flow/models/blocks/form/value-runtime/rules.ts +445 -13
  165. package/src/flow/models/blocks/form/value-runtime/runtime.ts +348 -13
  166. package/src/flow/models/blocks/form/value-runtime/types.ts +2 -2
  167. package/src/flow/models/blocks/js-block/JSBlock.tsx +225 -9
  168. package/src/flow/models/blocks/js-block/__tests__/JSBlockModel.test.tsx +150 -0
  169. package/src/flow/models/blocks/table/JSColumnModel.tsx +1 -9
  170. package/src/flow/models/blocks/table/TableActionsColumnModel.tsx +36 -13
  171. package/src/flow/models/blocks/table/TableBlockModel.tsx +38 -17
  172. package/src/flow/models/blocks/table/TableColumnModel.tsx +36 -3
  173. package/src/flow/models/blocks/table/__tests__/TableActionsColumnModel.test.tsx +111 -1
  174. package/src/flow/models/blocks/table/__tests__/TableBlockModel.dragSort.test.ts +127 -0
  175. package/src/flow/models/blocks/table/__tests__/TableBlockModel.mobileSettingsButtons.test.tsx +78 -0
  176. package/src/flow/models/blocks/table/__tests__/TableBlockModel.rowSelection.test.tsx +1 -0
  177. package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +159 -1
  178. package/src/flow/models/blocks/table/dragSort/dragSortHooks.tsx +28 -17
  179. package/src/flow/models/blocks/table/dragSort/dragSortSettings.ts +13 -6
  180. package/src/flow/models/blocks/table/dragSort/dragSortUtils.ts +15 -2
  181. package/src/flow/models/fields/AssociationFieldModel/AssociationFieldModel.tsx +1 -1
  182. package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/PopupSubTableFieldModel.tsx +29 -6
  183. package/src/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.tsx +16 -4
  184. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.tsx +141 -19
  185. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableField.tsx +13 -1
  186. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableColumnModel.rowRecord.test.ts +197 -0
  187. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableFieldModel.reset.test.ts +180 -0
  188. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.tsx +6 -4
  189. package/src/flow/models/fields/AssociationFieldModel/__tests__/AssociationFieldModel.updateAssociation.test.ts +72 -0
  190. package/src/flow/models/fields/AssociationFieldModel/__tests__/RecordPickerFieldModel.itemContext.test.ts +23 -0
  191. package/src/flow/models/fields/ClickableFieldModel.tsx +5 -0
  192. package/src/flow/models/fields/DisplayDateTimeFieldModel.tsx +29 -1
  193. package/src/flow/models/fields/InputFieldModel.tsx +40 -2
  194. package/src/flow/models/fields/JSEditableFieldModel.tsx +2 -11
  195. package/src/flow/models/fields/JSFieldModel.tsx +2 -7
  196. package/src/flow/models/fields/JSItemModel.tsx +2 -14
  197. package/src/flow/models/fields/SelectFieldModel.tsx +6 -4
  198. package/src/flow/models/fields/TextareaFieldModel.tsx +49 -3
  199. package/src/flow/models/fields/__tests__/DisplayDateTimeFieldModel.test.tsx +96 -0
  200. package/src/flow/models/fields/__tests__/InputFieldModel.test.tsx +117 -1
  201. package/src/flow/models/fields/__tests__/SelectFieldModel.test.tsx +43 -0
  202. package/src/flow/models/fields/__tests__/TextareaFieldModel.test.tsx +100 -0
  203. package/src/flow/models/topbar/TopbarActionModel.tsx +93 -10
  204. package/src/flow/resolveViewParamsToViewList.tsx +11 -3
  205. package/src/flow/utils/__tests__/dateTimeFormat.test.ts +258 -0
  206. package/src/flow/utils/dataScopeFormValueClear.ts +218 -81
  207. package/src/flow/utils/dataScopeRowSnapshot.ts +616 -0
  208. package/src/flow/utils/dateTimeDisplayProps.ts +135 -0
  209. package/src/flow/utils/formValueDeps.ts +170 -0
  210. package/src/flow-compat/FieldValidation.tsx +122 -60
  211. package/src/flow-compat/Popover.tsx +43 -4
  212. package/src/flow-compat/__tests__/Popover.test.tsx +34 -0
  213. package/src/index.ts +8 -1
  214. package/src/layout-manager/__tests__/LayoutRoute.test.tsx +41 -1
  215. package/src/nocobase-buildin-plugin/index.tsx +44 -14
  216. package/src/settings-center/AdminSettingsLayout.tsx +10 -2
  217. package/src/settings-center/SystemSettingsPage.tsx +1 -2
  218. package/src/settings-center/plugin-manager/PluginCard.tsx +2 -2
  219. package/src/settings-center/plugin-manager/index.tsx +3 -0
  220. package/src/settings-center/utils.tsx +0 -6
@@ -7,13 +7,152 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
 
10
- import { defineAction, tExpr } from '@nocobase/flow-engine';
10
+ import {
11
+ FlowContext,
12
+ createRecordMetaFactory,
13
+ createRecordResolveOnServerWithLocal,
14
+ defineAction,
15
+ tExpr,
16
+ useFlowSettingsContext,
17
+ type Collection,
18
+ type FlowRuntimeContext,
19
+ type MetaTreeNode,
20
+ type PropertyMetaFactory,
21
+ } from '@nocobase/flow-engine';
11
22
  import { isURL } from '@nocobase/utils/client';
12
- import { TextAreaWithContextSelector } from '../components/TextAreaWithContextSelector';
23
+ import React, { useMemo } from 'react';
24
+ import {
25
+ TextAreaWithContextSelector,
26
+ type TextAreaWithContextSelectorProps,
27
+ } from '../components/TextAreaWithContextSelector';
28
+
29
+ type ResponseRecordPlainStepContext = {
30
+ steps?: FlowRuntimeContext['steps'];
31
+ };
32
+
33
+ type ResponseRecordFlowDefinitionContext = {
34
+ flowKey?: string;
35
+ model?: {
36
+ getFlow?: (flowKey: string) => { steps?: Record<string, unknown> } | undefined;
37
+ };
38
+ };
39
+
40
+ type ResponseRecordContext = FlowContext &
41
+ ResponseRecordPlainStepContext & {
42
+ blockModel?: { collection?: Collection };
43
+ collection?: Collection;
44
+ model?: FlowRuntimeContext['model'] & { collection?: Collection };
45
+ };
46
+
47
+ function getResponseRecordSteps(ctx: FlowContext | ResponseRecordPlainStepContext): FlowRuntimeContext['steps'] {
48
+ return 'steps' in ctx ? ctx.steps || {} : {};
49
+ }
50
+
51
+ export function getAfterSuccessResponseRecord(ctx: FlowContext | ResponseRecordPlainStepContext) {
52
+ const steps = getResponseRecordSteps(ctx);
53
+ const preferredStepKeys = ['saveResource', 'submit', 'request', 'apply', 'save'];
54
+
55
+ for (const stepKey of preferredStepKeys) {
56
+ if (Object.prototype.hasOwnProperty.call(steps, stepKey) && steps[stepKey]?.result != null) {
57
+ return steps[stepKey].result;
58
+ }
59
+ }
60
+
61
+ const results = Object.entries(steps)
62
+ .filter(([stepKey, step]) => stepKey !== 'afterSuccess' && step?.result != null)
63
+ .map(([, step]) => step.result);
64
+ return results[results.length - 1];
65
+ }
66
+
67
+ function getResponseRecordMeta(ctx: ResponseRecordContext): PropertyMetaFactory | undefined {
68
+ if (!hasResponseRecordSource(ctx)) {
69
+ return;
70
+ }
71
+ const collectionAccessor = getResponseRecordCollectionAccessor(ctx);
72
+ if (!collectionAccessor()) {
73
+ return;
74
+ }
75
+ return createRecordMetaFactory(collectionAccessor, ctx.t('Response record'), () => {
76
+ const collection = collectionAccessor();
77
+ const record = getAfterSuccessResponseRecord(ctx);
78
+ if (!collection || !record) {
79
+ return;
80
+ }
81
+ try {
82
+ const filterByTk = collection.getFilterByTK(record);
83
+ if (filterByTk == null) {
84
+ return;
85
+ }
86
+ return {
87
+ collection: collection.name,
88
+ dataSourceKey: collection.dataSourceKey || 'main',
89
+ filterByTk,
90
+ };
91
+ } catch (error) {
92
+ return;
93
+ }
94
+ });
95
+ }
96
+
97
+ function hasResponseRecordSource(ctx: FlowContext | ResponseRecordPlainStepContext) {
98
+ if (Object.prototype.hasOwnProperty.call(getResponseRecordSteps(ctx), 'saveResource')) {
99
+ return true;
100
+ }
101
+
102
+ const { model, flowKey } = ctx as ResponseRecordFlowDefinitionContext;
103
+ if (!model || typeof model.getFlow !== 'function' || !flowKey) {
104
+ return false;
105
+ }
106
+
107
+ return Object.prototype.hasOwnProperty.call(model.getFlow(flowKey)?.steps || {}, 'saveResource');
108
+ }
109
+
110
+ function getResponseRecordCollectionAccessor(ctx: ResponseRecordContext) {
111
+ return () => ctx.blockModel?.collection || ctx.collection || ctx.model?.collection || null;
112
+ }
113
+
114
+ export function getMetaTreeWithResponseRecord(ctx: FlowRuntimeContext): MetaTreeNode[] {
115
+ const responseRecordMeta = getResponseRecordMeta(ctx);
116
+ if (!responseRecordMeta) {
117
+ return ctx.getPropertyMetaTree?.() || [];
118
+ }
119
+
120
+ const scoped = new FlowContext();
121
+ scoped.addDelegate(ctx);
122
+ scoped.defineProperty('responseRecord', {
123
+ get: () => getAfterSuccessResponseRecord(ctx),
124
+ cache: false,
125
+ resolveOnServer: createRecordResolveOnServerWithLocal(getResponseRecordCollectionAccessor(ctx), () =>
126
+ getAfterSuccessResponseRecord(ctx),
127
+ ),
128
+ meta: responseRecordMeta,
129
+ });
130
+ return scoped.getPropertyMetaTree();
131
+ }
132
+
133
+ function AfterSuccessRedirectTextArea(props: TextAreaWithContextSelectorProps) {
134
+ const flowCtx = useFlowSettingsContext();
135
+ const metaTree = useMemo(() => () => getMetaTreeWithResponseRecord(flowCtx), [flowCtx]);
136
+
137
+ return <TextAreaWithContextSelector {...props} metaTree={metaTree} />;
138
+ }
13
139
 
14
140
  export const afterSuccess = defineAction({
15
141
  name: 'afterSuccess',
16
142
  title: tExpr('After successful submission'),
143
+ defineProperties(ctx) {
144
+ const responseRecordMeta = getResponseRecordMeta(ctx);
145
+ return {
146
+ responseRecord: {
147
+ get: () => getAfterSuccessResponseRecord(ctx),
148
+ cache: false,
149
+ resolveOnServer: createRecordResolveOnServerWithLocal(getResponseRecordCollectionAccessor(ctx), () =>
150
+ getAfterSuccessResponseRecord(ctx),
151
+ ),
152
+ ...(responseRecordMeta ? { meta: responseRecordMeta } : {}),
153
+ },
154
+ };
155
+ },
17
156
  uiSchema: {
18
157
  successMessage: {
19
158
  type: 'string',
@@ -46,7 +185,7 @@ export const afterSuccess = defineAction({
46
185
  type: 'string',
47
186
  title: tExpr('Link'),
48
187
  'x-decorator': 'FormItem',
49
- 'x-component': TextAreaWithContextSelector,
188
+ 'x-component': AfterSuccessRedirectTextArea,
50
189
  'x-reactions': {
51
190
  dependencies: ['actionAfterSuccess'],
52
191
  fulfill: {
@@ -12,7 +12,6 @@ import {
12
12
  defineAction,
13
13
  isRunJSValue,
14
14
  normalizeRunJSValue,
15
- runjsWithSafeGlobals,
16
15
  tExpr,
17
16
  type RunJSValue,
18
17
  useFlowContext,
@@ -43,7 +42,7 @@ export const customVariable = defineAction({
43
42
  if (variable.type === 'runjs') {
44
43
  const getFunction = async () => {
45
44
  const { code, version } = normalizeRunJSValue(variable.runjs);
46
- return runjsWithSafeGlobals(ctx, code, { version });
45
+ return ctx.runjs(code, undefined, { version });
47
46
  };
48
47
  const metaFunction = () => ({
49
48
  title: variable.title,
@@ -12,6 +12,12 @@ import { transformFilter } from '@nocobase/utils/client';
12
12
  import _ from 'lodash';
13
13
 
14
14
  const PRESERVE_NULL = { __nocobaseDataScopeNull__: true };
15
+ const SERVER_CURRENT_ROLE_VARIABLE = '{{$nRole}}';
16
+ const CURRENT_ROLE_EXPRESSION_RE = /^\s*\{\{\s*ctx\.role\s*\}\}\s*$/;
17
+
18
+ function isCurrentRoleExpression(value: unknown) {
19
+ return typeof value === 'string' && CURRENT_ROLE_EXPRESSION_RE.test(value);
20
+ }
15
21
 
16
22
  function isPreserveNull(value: any) {
17
23
  return (
@@ -45,6 +51,10 @@ function markEmptyVariableValues(rawNode: any, resolvedNode: any) {
45
51
  }
46
52
 
47
53
  if ('path' in rawNode && 'operator' in rawNode) {
54
+ if (isCurrentRoleExpression(rawNode.value)) {
55
+ resolvedNode.value = SERVER_CURRENT_ROLE_VARIABLE;
56
+ return;
57
+ }
48
58
  if (
49
59
  isVariableExpression(rawNode.value) &&
50
60
  (resolvedNode.value === undefined || resolvedNode.value === null || resolvedNode.value === '')
@@ -11,13 +11,36 @@ import { css } from '@emotion/css';
11
11
  import { defineAction, tExpr } from '@nocobase/flow-engine';
12
12
  import { getPickerFormat } from '@nocobase/utils/client';
13
13
  import { DateFormatCom, ExpiresRadio } from '../components';
14
+ import {
15
+ getDateTimeFormatCollectionField,
16
+ isDateOnlyCollectionField,
17
+ isTimeCollectionField,
18
+ resolveDateTimeDisplayProps,
19
+ } from '../utils/dateTimeDisplayProps';
20
+
21
+ const isTableColumnFieldSubModel = (model) => {
22
+ const parent = model?.parent;
23
+ return (
24
+ parent?.subModels?.field === model &&
25
+ (parent?.use === 'TableColumnModel' || parent?.constructor?.name === 'TableColumnModel')
26
+ );
27
+ };
28
+
29
+ const syncTableColumnDateTimeFormatProps = (ctx, props) => {
30
+ const model = ctx.model;
31
+ if (!isTableColumnFieldSubModel(model) || !model?.parent?.collectionField?.isAssociationField?.()) {
32
+ return;
33
+ }
34
+
35
+ model.parent.setProps(props);
36
+ };
14
37
 
15
38
  export const dateTimeFormat = defineAction({
16
39
  title: tExpr('Date display format'),
17
40
  name: 'dateDisplayFormat',
18
41
  uiSchema: (ctx) => {
19
- const { collectionField } = ctx.model.context as any;
20
- const isTimeField = collectionField.type === 'time' || collectionField.interface === 'time';
42
+ const collectionField = getDateTimeFormatCollectionField({ model: ctx.model });
43
+ const isTimeField = isTimeCollectionField(collectionField);
21
44
  const timeFormatField = {
22
45
  type: 'string',
23
46
  title: '{{t("Time format")}}',
@@ -43,7 +66,7 @@ export const dateTimeFormat = defineAction({
43
66
  (field) => {
44
67
  if (!isTimeField) {
45
68
  const { showTime, picker } = field.form.values || {};
46
- field.hidden = !showTime || picker !== 'date';
69
+ field.hidden = isDateOnlyCollectionField(collectionField) || !showTime || picker !== 'date';
47
70
  }
48
71
  },
49
72
  ],
@@ -146,10 +169,11 @@ export const dateTimeFormat = defineAction({
146
169
  },
147
170
  },
148
171
  (field) => {
149
- const { collectionField } = ctx.model.context as any;
172
+ const collectionField = getDateTimeFormatCollectionField({ model: ctx.model });
150
173
  const { picker } = field.form.values || {};
151
- field.hidden = collectionField.type === 'dateOnly' || picker !== 'date';
152
- if (picker !== 'date') {
174
+ const isDateOnlyField = isDateOnlyCollectionField(collectionField);
175
+ field.hidden = isDateOnlyField || picker !== 'date';
176
+ if (isDateOnlyField || picker !== 'date') {
153
177
  field.value = false;
154
178
  }
155
179
  },
@@ -159,34 +183,24 @@ export const dateTimeFormat = defineAction({
159
183
  };
160
184
  },
161
185
  defaultParams: (ctx: any) => {
162
- const { showTime, dateFormat, format, timeFormat, picker }: any = {
163
- ...ctx.model.context.collectionField.getComponentProps(),
164
- ...ctx.model.props,
165
- };
166
- const collectionField = ctx.model.context.collectionField;
167
- const isTimeField = collectionField.type === 'time' || collectionField.interface === 'time';
186
+ const { showTime, dateFormat, timeFormat, picker } = resolveDateTimeDisplayProps({
187
+ model: ctx.model,
188
+ withDefaults: true,
189
+ });
168
190
  return {
169
191
  picker: picker || 'date',
170
192
  dateFormat: dateFormat || 'YYYY-MM-DD',
171
- timeFormat: timeFormat || (isTimeField ? format : undefined) || 'HH:mm:ss',
193
+ timeFormat: timeFormat || 'HH:mm:ss',
172
194
  showTime,
173
195
  };
174
196
  },
197
+ async beforeParamsSave(ctx: any, params) {
198
+ const props = resolveDateTimeDisplayProps({ model: ctx.model, params });
199
+ ctx.model.setProps(props);
200
+ syncTableColumnDateTimeFormatProps(ctx, props);
201
+ await ctx.model.save?.();
202
+ },
175
203
  handler(ctx: any, params) {
176
- const { collectionField } = ctx.model.context as any;
177
- const isTimeField = collectionField.type === 'time' || collectionField.interface === 'time';
178
- if (isTimeField) {
179
- const timeFormat = params?.timeFormat || params?.format || 'HH:mm:ss';
180
- ctx.model.setProps({
181
- ...params,
182
- timeFormat,
183
- format: timeFormat,
184
- });
185
- } else {
186
- ctx.model.setProps({
187
- ...params,
188
- format: params?.showTime ? `${params.dateFormat} ${params.timeFormat}` : params.dateFormat,
189
- });
190
- }
204
+ ctx.model.setProps(resolveDateTimeDisplayProps({ model: ctx.model, params }));
191
205
  },
192
206
  });
@@ -7,7 +7,7 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
 
10
- export * from './afterSuccess';
10
+ export { afterSuccess } from './afterSuccess';
11
11
  export * from './confirm';
12
12
  export * from './dataScope';
13
13
  export * from './openView';
@@ -16,13 +16,9 @@ import {
16
16
  FlowRuntimeContext,
17
17
  useFlowContext,
18
18
  useFlowEngine,
19
- createSafeWindow,
20
- createSafeDocument,
21
- createSafeNavigator,
22
19
  observer,
23
20
  isRunJSValue,
24
21
  normalizeRunJSValue,
25
- runjsWithSafeGlobals,
26
22
  } from '@nocobase/flow-engine';
27
23
  import { evaluateConditions, FilterGroupType, removeInvalidFilterItems } from '@nocobase/utils/client';
28
24
  import React from 'react';
@@ -40,7 +36,7 @@ import { FilterGroup } from '../components/filter/FilterGroup';
40
36
  import { LinkageFilterItem } from '../components/filter';
41
37
  import { CodeEditor } from '../components/code-editor';
42
38
  import { FieldAssignRulesEditor } from '../components/FieldAssignRulesEditor';
43
- import type { FieldAssignRuleItem } from '../components/FieldAssignRulesEditor';
39
+ import type { AssignMode, FieldAssignRuleItem } from '../components/FieldAssignRulesEditor';
44
40
  import { collectFieldAssignCascaderOptions } from '../components/fieldAssignOptions';
45
41
  import { useAssociationTitleFieldSync } from '../components/useAssociationTitleFieldSync';
46
42
  import _ from 'lodash';
@@ -492,7 +488,7 @@ async function resolveLinkageAssignRuntimeValue(ctx: FlowContext, rawValue: any)
492
488
 
493
489
  try {
494
490
  const { code, version } = normalizeRunJSValue(rawValue);
495
- const ret = await runjsWithSafeGlobals(ctx, code, { version });
491
+ const ret = await ctx.runjs(code, undefined, { version });
496
492
  if (!ret?.success) {
497
493
  return SKIP_RUNJS_ASSIGN_VALUE;
498
494
  }
@@ -888,6 +884,20 @@ type ArrayFieldComponentProps = {
888
884
 
889
885
  const LEGACY_ASSIGN_RULE = { mode: 'assign', valueKey: 'assignValue' } as const;
890
886
  const LEGACY_DEFAULT_RULE = { mode: 'default', valueKey: 'initialValue' } as const;
887
+ const LINKAGE_ASSIGN_MODE_PROP = '__linkageAssignMode';
888
+
889
+ function normalizeLinkageAssignMode(mode: unknown): AssignMode {
890
+ if (mode === 'default') return 'default';
891
+ if (mode === 'override') return 'override';
892
+ return 'assign';
893
+ }
894
+
895
+ type LinkageValuePatch = {
896
+ path: Array<string | number>;
897
+ value: unknown;
898
+ whenEmpty?: boolean;
899
+ mode?: AssignMode;
900
+ };
891
901
 
892
902
  const FieldAssignRulesActionComponent: React.FC<
893
903
  ArrayFieldComponentProps & {
@@ -1002,16 +1012,24 @@ export const linkageAssignField = defineAction({
1002
1012
  continue;
1003
1013
  }
1004
1014
 
1005
- const mode = it?.mode === 'default' ? 'default' : 'assign';
1015
+ const mode = normalizeLinkageAssignMode(it?.mode);
1006
1016
  if (fieldModel) {
1007
1017
  if (mode === 'default') {
1008
1018
  setProps(fieldModel as FlowModel, { initialValue: finalValue });
1009
1019
  } else {
1010
- setProps(fieldModel as FlowModel, { value: finalValue });
1020
+ setProps(fieldModel as FlowModel, {
1021
+ value: finalValue,
1022
+ ...(mode === 'override' ? { [LINKAGE_ASSIGN_MODE_PROP]: mode } : {}),
1023
+ });
1011
1024
  }
1012
1025
  } else if (typeof addFormValuePatch === 'function') {
1013
1026
  // 对关联字段子属性(如 user.name)等没有独立 FormItemModel 的目标,直接写入表单值
1014
- addFormValuePatch({ path: targetPath, value: finalValue, whenEmpty: mode === 'default' });
1027
+ addFormValuePatch({
1028
+ path: targetPath,
1029
+ value: finalValue,
1030
+ whenEmpty: mode === 'default',
1031
+ ...(mode === 'override' ? { mode } : {}),
1032
+ });
1015
1033
  }
1016
1034
  }
1017
1035
  } catch (error) {
@@ -1177,7 +1195,7 @@ export const subFormLinkageAssignField = defineAction({
1177
1195
  continue;
1178
1196
  }
1179
1197
 
1180
- const mode = it?.mode === 'default' ? 'default' : 'assign';
1198
+ const mode = normalizeLinkageAssignMode(it?.mode);
1181
1199
  const actionName = (ctx.model as any)?.getAclActionName?.() ?? (ctx.model as any)?.context?.actionName;
1182
1200
  const isEditForm = actionName === 'update';
1183
1201
  const isNewItem = (ctx as any)?.item?.__is_new__ === true;
@@ -1207,12 +1225,21 @@ export const subFormLinkageAssignField = defineAction({
1207
1225
  continue;
1208
1226
  }
1209
1227
 
1228
+ if (mode === 'override' && hasExplicitPathHit(targetPath)) {
1229
+ continue;
1230
+ }
1231
+
1210
1232
  if (!fieldUid) {
1211
1233
  if (mode === 'default' && hasExplicitPathHit(targetPath)) {
1212
1234
  continue;
1213
1235
  }
1214
1236
  if (typeof addFormValuePatch === 'function') {
1215
- addFormValuePatch({ path: targetPath, value: finalValue, whenEmpty: mode === 'default' });
1237
+ addFormValuePatch({
1238
+ path: targetPath,
1239
+ value: finalValue,
1240
+ whenEmpty: mode === 'default',
1241
+ ...(mode === 'override' ? { mode } : {}),
1242
+ });
1216
1243
  }
1217
1244
  continue;
1218
1245
  }
@@ -1223,7 +1250,10 @@ export const subFormLinkageAssignField = defineAction({
1223
1250
  if (mode === 'default') {
1224
1251
  setProps(model, { initialValue: finalValue });
1225
1252
  } else {
1226
- setProps(model, { value: finalValue });
1253
+ setProps(model, {
1254
+ value: finalValue,
1255
+ ...(mode === 'override' ? { [LINKAGE_ASSIGN_MODE_PROP]: mode } : {}),
1256
+ });
1227
1257
  }
1228
1258
  }
1229
1259
  } catch (error) {
@@ -1363,8 +1393,7 @@ export const linkageRunjs = defineAction({
1363
1393
  }
1364
1394
 
1365
1395
  try {
1366
- const navigator = createSafeNavigator();
1367
- await ctx.runjs(script, { window: createSafeWindow({ navigator }), document: createSafeDocument(), navigator });
1396
+ await ctx.runjs(script);
1368
1397
  } catch (error) {
1369
1398
  console.error('Script execution error:', error);
1370
1399
  // 可以选择显示错误信息给用户
@@ -1781,7 +1810,7 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
1781
1810
  const modelsToApply = new Set<FlowModel>(allModels);
1782
1811
  const patchPropsByModel = new Map<FlowModel, any>();
1783
1812
  const clearValueOnHiddenModelUids = new Set<string>();
1784
- const directValuePatches: Array<{ path: Array<string | number>; value: any; whenEmpty?: boolean }> = [];
1813
+ const directValuePatches: LinkageValuePatch[] = [];
1785
1814
  const rootCollection = getCollectionFromModel((ctx.model as any)?.context?.blockModel ?? ctx.model);
1786
1815
  const isSafeToWriteAssociationSubpath = (namePath: any): boolean => {
1787
1816
  if (!Array.isArray(namePath) || !namePath.length) return true;
@@ -1836,13 +1865,18 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
1836
1865
  }
1837
1866
 
1838
1867
  for (const patch of lastPatchByPathKey.values()) {
1839
- if (!patch.whenEmpty) continue;
1868
+ if (!patch.whenEmpty && patch.mode !== 'default') continue;
1840
1869
  runtime.recordDefaultValuePatch(patch.path, patch.value);
1841
1870
  }
1842
1871
  };
1843
- const addFormValuePatch = (patch: { path: any; value: any; whenEmpty?: boolean }) => {
1872
+ const getPatchMode = (patch: { mode?: unknown; whenEmpty?: boolean }): AssignMode => {
1873
+ if (patch?.mode === 'default') return 'default';
1874
+ if (patch?.mode === 'override') return 'override';
1875
+ return patch?.whenEmpty ? 'default' : 'assign';
1876
+ };
1877
+ const addFormValuePatch = (patch: { path: unknown; value: unknown; whenEmpty?: boolean; mode?: AssignMode }) => {
1844
1878
  if (!patch) return;
1845
- const path = (patch as any)?.path;
1879
+ const path = patch.path;
1846
1880
  if (!path) return;
1847
1881
  const resolvedPath = resolveNamePathForPatch(path);
1848
1882
  if (!resolvedPath) {
@@ -1862,8 +1896,9 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
1862
1896
  });
1863
1897
  return;
1864
1898
  }
1865
- const whenEmpty = !!(patch as any)?.whenEmpty;
1866
- const value = (patch as any)?.value;
1899
+ const mode = getPatchMode(patch);
1900
+ const whenEmpty = mode === 'default';
1901
+ const value = patch.value;
1867
1902
  try {
1868
1903
  const form = ctx.model?.context?.form;
1869
1904
  const current = form?.getFieldValue?.(resolvedPath);
@@ -1878,6 +1913,15 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
1878
1913
  return;
1879
1914
  }
1880
1915
  }
1916
+ if (mode === 'override') {
1917
+ const runtime = getDefaultPatchRuntime();
1918
+ if (
1919
+ typeof runtime?.canApplyOverrideValuePatch === 'function' &&
1920
+ !runtime.canApplyOverrideValuePatch(resolvedPath)
1921
+ ) {
1922
+ return;
1923
+ }
1924
+ }
1881
1925
  if (_.isEqual(current, value)) {
1882
1926
  return;
1883
1927
  }
@@ -1889,6 +1933,7 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
1889
1933
  path: resolvedPath,
1890
1934
  value,
1891
1935
  ...(whenEmpty ? { whenEmpty: true } : {}),
1936
+ ...(mode === 'override' ? { mode } : {}),
1892
1937
  });
1893
1938
  };
1894
1939
  const removePendingFormValuePatches = (path: any) => {
@@ -1948,6 +1993,21 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
1948
1993
  >;
1949
1994
  return normalized.length ? normalized : null;
1950
1995
  };
1996
+ const pathKeysEqual = (
1997
+ a: Array<string | number> | null | undefined,
1998
+ b: Array<string | number> | null | undefined,
1999
+ ) => {
2000
+ if (!a || !b) return false;
2001
+ return namePathToPathKey(a) === namePathToPathKey(b);
2002
+ };
2003
+ const namePathEndsWith = (
2004
+ namePath: Array<string | number> | null | undefined,
2005
+ suffix: Array<string | number> | null | undefined,
2006
+ ) => {
2007
+ if (!namePath || !suffix || suffix.length > namePath.length) return false;
2008
+ const offset = namePath.length - suffix.length;
2009
+ return suffix.every((seg, index) => namePath[offset + index] === seg);
2010
+ };
1951
2011
  const getFieldIndexEntries = (fieldIndex: any): Array<{ name: string; index: number }> => {
1952
2012
  if (!Array.isArray(fieldIndex)) return [];
1953
2013
  return fieldIndex
@@ -1996,17 +2056,35 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
1996
2056
 
1997
2057
  return out;
1998
2058
  };
2059
+ const getTrustedFieldPathArray = (
2060
+ fieldPathArray: Array<string | number> | null,
2061
+ targetPath: string | null,
2062
+ fieldIndex: unknown,
2063
+ ): Array<string | number> | null => {
2064
+ if (!fieldPathArray || !targetPath) return null;
2065
+
2066
+ const targetNamePath = normalizeNamePathForKey(
2067
+ parsePathString(targetPath).filter((seg) => typeof seg === 'string' || typeof seg === 'number'),
2068
+ );
2069
+ const resolvedTargetPath = normalizeNamePathForKey(resolveDynamicNamePath(targetPath, fieldIndex));
2070
+ const indexedRelativePath = resolveIndexedRelativePath(targetPath, fieldIndex);
2071
+
2072
+ if (
2073
+ pathKeysEqual(fieldPathArray, resolvedTargetPath) ||
2074
+ pathKeysEqual(fieldPathArray, indexedRelativePath) ||
2075
+ namePathEndsWith(fieldPathArray, targetNamePath)
2076
+ ) {
2077
+ return fieldPathArray;
2078
+ }
2079
+
2080
+ return null;
2081
+ };
1999
2082
  const getModelTargetPathForHiddenClear = (model: any): string | Array<string | number> | null => {
2000
2083
  const fieldPathArray = normalizeNamePathForKey(model?.context?.fieldPathArray);
2001
2084
  const targetPath = getModelTargetPathForPatch(model);
2002
- if (fieldPathArray) {
2003
- const targetPathLastString = targetPath
2004
- ? ([...parsePathString(targetPath)].reverse().find((seg) => typeof seg === 'string') as string | undefined)
2005
- : undefined;
2006
- const fieldPathArrayLastString = [...fieldPathArray].reverse().find((seg) => typeof seg === 'string');
2007
- if (!targetPathLastString || targetPathLastString === fieldPathArrayLastString) {
2008
- return fieldPathArray;
2009
- }
2085
+ const trustedFieldPathArray = getTrustedFieldPathArray(fieldPathArray, targetPath, model?.context?.fieldIndex);
2086
+ if (trustedFieldPathArray) {
2087
+ return trustedFieldPathArray;
2010
2088
  }
2011
2089
 
2012
2090
  if (!targetPath) return null;
@@ -2016,12 +2094,13 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
2016
2094
  const getModelTargetPathKeys = (model: any): Set<string> => {
2017
2095
  const keys = new Set<string>();
2018
2096
  const fieldPathArray = normalizeNamePathForKey(model?.context?.fieldPathArray);
2019
- if (fieldPathArray) {
2020
- keys.add(namePathToPathKey(fieldPathArray));
2097
+ const targetPath = getModelTargetPathForPatch(model);
2098
+ const trustedFieldPathArray = getTrustedFieldPathArray(fieldPathArray, targetPath, model?.context?.fieldIndex);
2099
+ if (trustedFieldPathArray) {
2100
+ keys.add(namePathToPathKey(trustedFieldPathArray));
2021
2101
  return keys;
2022
2102
  }
2023
2103
 
2024
- const targetPath = getModelTargetPathForPatch(model);
2025
2104
  if (targetPath) {
2026
2105
  const fieldIndexEntries = getFieldIndexEntries(model?.context?.fieldIndex);
2027
2106
  if (!fieldIndexEntries.length) {
@@ -2082,6 +2161,14 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
2082
2161
 
2083
2162
  for (const action of actions) {
2084
2163
  const setProps = (model: FlowModel & { __originalProps?: any; __shouldReset?: boolean }, props: any) => {
2164
+ const normalizedProps =
2165
+ props && typeof props === 'object' && Object.prototype.hasOwnProperty.call(props, 'value')
2166
+ ? {
2167
+ ...props,
2168
+ [LINKAGE_ASSIGN_MODE_PROP]: normalizeLinkageAssignMode(props?.[LINKAGE_ASSIGN_MODE_PROP]),
2169
+ }
2170
+ : props;
2171
+
2085
2172
  // 存储原始值,用于恢复
2086
2173
  if (!model.__originalProps) {
2087
2174
  model.__originalProps = {
@@ -2097,7 +2184,7 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
2097
2184
  // 临时存起来,遍历完所有规则后,再统一处理
2098
2185
  patchPropsByModel.set(model, {
2099
2186
  ...(patchPropsByModel.get(model) || {}),
2100
- ...props,
2187
+ ...normalizedProps,
2101
2188
  });
2102
2189
 
2103
2190
  if (
@@ -2151,7 +2238,7 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
2151
2238
  const prevHidden = !!model.hidden;
2152
2239
  const nextHidden = !!newProps.hiddenModel;
2153
2240
 
2154
- model.setProps(_.omit(newProps, ['hiddenModel', 'value', 'hiddenText']));
2241
+ model.setProps(_.omit(newProps, ['hiddenModel', 'value', 'hiddenText', LINKAGE_ASSIGN_MODE_PROP]));
2155
2242
  syncFieldOptionsToForks(model, patchProps);
2156
2243
  if (typeof model.setHidden === 'function') {
2157
2244
  model.setHidden(nextHidden);
@@ -2190,7 +2277,8 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
2190
2277
  targetUid: model?.uid,
2191
2278
  });
2192
2279
  } else {
2193
- addFormValuePatch({ path: targetPath, value: newProps.value });
2280
+ const mode = normalizeLinkageAssignMode(patchProps?.[LINKAGE_ASSIGN_MODE_PROP]);
2281
+ addFormValuePatch({ path: targetPath, value: newProps.value, ...(mode === 'override' ? { mode } : {}) });
2194
2282
  }
2195
2283
  }
2196
2284
 
@@ -2842,7 +2930,7 @@ export const subFormFieldLinkageRules = defineAction({
2842
2930
  }
2843
2931
  } else {
2844
2932
  await Promise.all(
2845
- (grid.forks || []).map(async (forkModel: FlowModel) => {
2933
+ Array.from(grid.forks || []).map(async (forkModel: FlowModel) => {
2846
2934
  if (forkModel.hidden) {
2847
2935
  return;
2848
2936
  }