@nocobase/client-v2 2.2.0-beta.1 → 2.2.0-beta.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 (247) hide show
  1. package/es/BaseApplication.d.ts +3 -0
  2. package/es/PluginSettingsManager.d.ts +33 -0
  3. package/es/RouteRepository.d.ts +29 -6
  4. package/es/RouterManager.d.ts +15 -0
  5. package/es/authRedirect.d.ts +1 -0
  6. package/es/collection-field-interface/CollectionFieldInterface.d.ts +1 -0
  7. package/es/collection-field-interface/CollectionFieldInterfaceManager.d.ts +1 -0
  8. package/es/components/form/JsonTextArea.d.ts +2 -1
  9. package/es/components/form/VariableJsonTextArea.d.ts +19 -0
  10. package/es/components/form/index.d.ts +1 -0
  11. package/es/components/index.d.ts +1 -0
  12. package/es/entry-actions/EntryActionManager.d.ts +24 -0
  13. package/es/entry-actions/index.d.ts +9 -0
  14. package/es/flow/actions/afterSuccess.d.ts +8 -1
  15. package/es/flow/actions/index.d.ts +1 -1
  16. package/es/flow/admin-shell/BaseLayoutModel.d.ts +6 -0
  17. package/es/flow/admin-shell/BaseLayoutRouteCoordinator.d.ts +7 -0
  18. package/es/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.d.ts +2 -0
  19. package/es/flow/admin-shell/admin-layout/AdminLayoutMenuFlowUtils.d.ts +2 -1
  20. package/es/flow/admin-shell/admin-layout/AdminLayoutMenuModels.d.ts +2 -0
  21. package/es/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.d.ts +3 -2
  22. package/es/flow/admin-shell/admin-layout/AdminLayoutSlotModels.d.ts +5 -0
  23. package/es/flow/admin-shell/admin-layout/AppListRender.d.ts +2 -1
  24. package/es/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.d.ts +24 -0
  25. package/es/flow/admin-shell/admin-layout/index.d.ts +1 -0
  26. package/es/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.d.ts +6 -0
  27. package/es/flow/admin-shell/admin-layout/useApplications.d.ts +7 -2
  28. package/es/flow/components/FieldAssignRulesEditor.d.ts +3 -1
  29. package/es/flow/models/base/ActionModelCore.d.ts +2 -0
  30. package/es/flow/models/base/GridModel.d.ts +1 -1
  31. package/es/flow/models/blocks/filter-form/FilterFormBlockModel.d.ts +5 -0
  32. package/es/flow/models/blocks/form/FormBlockModel.d.ts +4 -0
  33. package/es/flow/models/blocks/form/QuickEditFormModel.d.ts +17 -2
  34. package/es/flow/models/blocks/form/submitHandler.d.ts +1 -1
  35. package/es/flow/models/blocks/form/value-runtime/rules.d.ts +21 -0
  36. package/es/flow/models/blocks/form/value-runtime/runtime.d.ts +30 -0
  37. package/es/flow/models/blocks/form/value-runtime/types.d.ts +2 -2
  38. package/es/flow/models/blocks/js-block/JSBlock.d.ts +1 -0
  39. package/es/flow/models/blocks/table/TableActionsColumnModel.d.ts +1 -0
  40. package/es/flow/models/blocks/table/TableBlockModel.d.ts +1 -0
  41. package/es/flow/models/blocks/table/dragSort/dragSortHooks.d.ts +1 -1
  42. package/es/flow/models/blocks/table/dragSort/dragSortSettings.d.ts +2 -1
  43. package/es/flow/models/blocks/table/dragSort/dragSortUtils.d.ts +6 -4
  44. package/es/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.d.ts +2 -0
  45. package/es/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.d.ts +6 -0
  46. package/es/flow/resolveViewParamsToViewList.d.ts +1 -1
  47. package/es/flow/routeTransientInputArgs.d.ts +14 -0
  48. package/es/flow/utils/dataScopeRowSnapshot.d.ts +59 -0
  49. package/es/flow/utils/dateTimeDisplayProps.d.ts +49 -0
  50. package/es/flow/utils/formValueDeps.d.ts +32 -0
  51. package/es/flow-compat/FieldValidation.d.ts +2 -1
  52. package/es/index.d.ts +4 -1
  53. package/es/index.mjs +305 -157
  54. package/es/utils/markdownSanitize.d.ts +11 -0
  55. package/lib/index.js +305 -157
  56. package/package.json +7 -7
  57. package/src/BaseApplication.tsx +6 -0
  58. package/src/PluginSettingsManager.ts +53 -0
  59. package/src/RouteRepository.ts +151 -24
  60. package/src/RouterManager.tsx +142 -1
  61. package/src/__tests__/PluginSettingsManager.test.ts +13 -0
  62. package/src/__tests__/RouteRepository.test.ts +239 -0
  63. package/src/__tests__/RouterManager.test.ts +125 -0
  64. package/src/__tests__/authRedirect.test.ts +17 -0
  65. package/src/__tests__/exports.test.ts +16 -0
  66. package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +199 -0
  67. package/src/__tests__/plugin-manager.test.tsx +44 -2
  68. package/src/__tests__/settings-center.test.tsx +40 -1
  69. package/src/authRedirect.ts +38 -0
  70. package/src/collection-field-interface/CollectionFieldInterface.ts +1 -0
  71. package/src/collection-field-interface/CollectionFieldInterfaceManager.ts +1 -0
  72. package/src/collection-manager/field-configure.ts +1 -1
  73. package/src/collection-manager/interfaces/id.ts +1 -1
  74. package/src/collection-manager/interfaces/m2m.tsx +2 -2
  75. package/src/collection-manager/interfaces/m2o.tsx +2 -2
  76. package/src/collection-manager/interfaces/nanoid.ts +1 -1
  77. package/src/collection-manager/interfaces/o2m.tsx +2 -2
  78. package/src/collection-manager/interfaces/obo.tsx +2 -2
  79. package/src/collection-manager/interfaces/oho.tsx +2 -2
  80. package/src/collection-manager/interfaces/properties/index.ts +2 -2
  81. package/src/collection-manager/interfaces/uuid.ts +1 -1
  82. package/src/components/AppComponents.tsx +19 -3
  83. package/src/components/form/JsonTextArea.tsx +21 -11
  84. package/src/components/form/VariableJsonTextArea.tsx +175 -0
  85. package/src/components/form/__tests__/JsonTextArea.test.tsx +43 -0
  86. package/src/components/form/__tests__/VariableJsonTextArea.test.tsx +86 -0
  87. package/src/components/form/index.tsx +1 -0
  88. package/src/components/index.ts +1 -0
  89. package/src/entry-actions/EntryActionManager.ts +76 -0
  90. package/src/entry-actions/index.ts +10 -0
  91. package/src/flow/FlowPage.tsx +38 -3
  92. package/src/flow/__tests__/FlowPage.test.tsx +201 -27
  93. package/src/flow/__tests__/FlowRoute.test.tsx +1088 -105
  94. package/src/flow/__tests__/getKey.test.ts +7 -0
  95. package/src/flow/__tests__/resolveViewParamsToViewList.test.ts +34 -0
  96. package/src/flow/actions/__tests__/afterSuccess.test.ts +73 -0
  97. package/src/flow/actions/__tests__/dataScopeFilter.test.ts +120 -0
  98. package/src/flow/actions/__tests__/dataScopeFormValueClear.test.ts +1022 -0
  99. package/src/flow/actions/__tests__/fieldLinkageRules.scopeDepth.test.ts +150 -1
  100. package/src/flow/actions/__tests__/linkageAssignField.legacy.test.ts +135 -0
  101. package/src/flow/actions/__tests__/linkageRules.hiddenSync.restore.test.ts +19 -5
  102. package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +92 -0
  103. package/src/flow/actions/__tests__/openView.defineProps.route.test.tsx +164 -0
  104. package/src/flow/actions/__tests__/subFormFieldLinkageRules.inputArgs.test.ts +2 -2
  105. package/src/flow/actions/afterSuccess.tsx +142 -3
  106. package/src/flow/actions/customVariable.tsx +1 -2
  107. package/src/flow/actions/dataScopeFilter.ts +20 -1
  108. package/src/flow/actions/dateTimeFormat.tsx +42 -28
  109. package/src/flow/actions/index.ts +1 -1
  110. package/src/flow/actions/linkageRules.tsx +123 -35
  111. package/src/flow/actions/linkageRulesFormValueRefresh.ts +22 -130
  112. package/src/flow/actions/openView.tsx +59 -5
  113. package/src/flow/actions/runjs.tsx +2 -14
  114. package/src/flow/actions/validation.tsx +62 -30
  115. package/src/flow/admin-shell/BaseLayoutModel.tsx +149 -3
  116. package/src/flow/admin-shell/BaseLayoutRouteCoordinator.ts +187 -42
  117. package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +1020 -110
  118. package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +74 -13
  119. package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.test.tsx +486 -0
  120. package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +64 -8
  121. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuFlowUtils.ts +5 -3
  122. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuModels.tsx +61 -9
  123. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.tsx +71 -8
  124. package/src/flow/admin-shell/admin-layout/AdminLayoutModel.tsx +1 -1
  125. package/src/flow/admin-shell/admin-layout/AdminLayoutSlotModels.tsx +23 -9
  126. package/src/flow/admin-shell/admin-layout/AppListRender.tsx +13 -2
  127. package/src/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.tsx +289 -0
  128. package/src/flow/admin-shell/admin-layout/HelpLite.tsx +1 -3
  129. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutComponent.test.tsx +188 -0
  130. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +99 -0
  131. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutModel.test.tsx +518 -2
  132. package/src/flow/admin-shell/admin-layout/__tests__/TopbarActionsBar.test.tsx +214 -2
  133. package/src/flow/admin-shell/admin-layout/index.ts +1 -0
  134. package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.test.ts +20 -0
  135. package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.ts +33 -5
  136. package/src/flow/admin-shell/admin-layout/useApplications.tsx +81 -12
  137. package/src/flow/common/Markdown/Display.tsx +14 -3
  138. package/src/flow/common/Markdown/Edit.tsx +19 -7
  139. package/src/flow/components/DefaultValue.tsx +1 -2
  140. package/src/flow/components/DynamicFlowsIcon.tsx +447 -126
  141. package/src/flow/components/FieldAssignRulesEditor.tsx +128 -21
  142. package/src/flow/components/FieldAssignValueInput.tsx +15 -11
  143. package/src/flow/components/FlowRoute.tsx +186 -25
  144. package/src/flow/components/__tests__/DynamicFlowsIcon.test.tsx +148 -2
  145. package/src/flow/components/__tests__/FieldAssignRulesEditor.test.tsx +508 -4
  146. package/src/flow/components/__tests__/FieldAssignValueInput.context.test.tsx +134 -0
  147. package/src/flow/components/__tests__/fieldAssignOptions.test.ts +151 -3
  148. package/src/flow/components/code-editor/__tests__/useCodeRunner.test.tsx +2 -17
  149. package/src/flow/components/code-editor/hooks/useCodeRunner.ts +2 -14
  150. package/src/flow/components/code-editor/runjsDiagnostics.ts +8 -45
  151. package/src/flow/components/fieldAssignOptions.ts +155 -27
  152. package/src/flow/flows/editMarkdownFlow.tsx +1 -1
  153. package/src/flow/getViewDiffAndUpdateHidden.tsx +1 -0
  154. package/src/flow/index.ts +1 -1
  155. package/src/flow/internal/components/Markdown/util.ts +2 -1
  156. package/src/flow/internal/utils/operatorSchemaHelper.ts +15 -1
  157. package/src/flow/models/actions/JSActionModel.tsx +2 -7
  158. package/src/flow/models/actions/JSCollectionActionModel.tsx +2 -7
  159. package/src/flow/models/actions/JSItemActionModel.tsx +2 -7
  160. package/src/flow/models/actions/JSRecordActionModel.tsx +2 -7
  161. package/src/flow/models/base/ActionModel.tsx +21 -8
  162. package/src/flow/models/base/ActionModelCore.tsx +11 -4
  163. package/src/flow/models/base/GridModel.tsx +38 -7
  164. package/src/flow/models/base/PageModel/PageModel.tsx +4 -1
  165. package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +28 -4
  166. package/src/flow/models/base/__tests__/ActionModel.test.ts +83 -0
  167. package/src/flow/models/base/__tests__/ActionModelCore.render.test.tsx +37 -0
  168. package/src/flow/models/base/__tests__/GridModel.dragSnapshotContainer.test.ts +239 -1
  169. package/src/flow/models/base/__tests__/transformRowsToSingleColumn.test.ts +48 -0
  170. package/src/flow/models/blocks/filter-form/FilterFormBlockModel.tsx +32 -3
  171. package/src/flow/models/blocks/filter-form/FilterFormItemModel.tsx +27 -12
  172. package/src/flow/models/blocks/filter-form/FilterFormJSActionModel.tsx +2 -7
  173. package/src/flow/models/blocks/filter-form/__tests__/FilterFormItemModel.defineChildren.test.ts +36 -0
  174. package/src/flow/models/blocks/filter-form/__tests__/defaultValues.wiring.test.ts +111 -0
  175. package/src/flow/models/blocks/filter-form/fields/FilterFormCustomFieldModel.tsx +1 -1
  176. package/src/flow/models/blocks/filter-manager/flow-actions/__tests__/customizeFilterRender.test.tsx +56 -1
  177. package/src/flow/models/blocks/form/EditFormModel.tsx +1 -0
  178. package/src/flow/models/blocks/form/FormActionModel.tsx +1 -1
  179. package/src/flow/models/blocks/form/FormBlockModel.tsx +7 -0
  180. package/src/flow/models/blocks/form/JSFormActionModel.tsx +2 -7
  181. package/src/flow/models/blocks/form/QuickEditFormModel.tsx +189 -36
  182. package/src/flow/models/blocks/form/__tests__/FormBlockModel.test.tsx +17 -0
  183. package/src/flow/models/blocks/form/__tests__/QuickEditFormModel.quickEdit.test.ts +350 -2
  184. package/src/flow/models/blocks/form/__tests__/submitHandler.test.ts +54 -1
  185. package/src/flow/models/blocks/form/submitHandler.ts +17 -3
  186. package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +940 -75
  187. package/src/flow/models/blocks/form/value-runtime/rules.ts +445 -13
  188. package/src/flow/models/blocks/form/value-runtime/runtime.ts +348 -13
  189. package/src/flow/models/blocks/form/value-runtime/types.ts +2 -2
  190. package/src/flow/models/blocks/js-block/JSBlock.tsx +225 -9
  191. package/src/flow/models/blocks/js-block/__tests__/JSBlockModel.test.tsx +150 -0
  192. package/src/flow/models/blocks/table/JSColumnModel.tsx +1 -9
  193. package/src/flow/models/blocks/table/TableActionsColumnModel.tsx +36 -13
  194. package/src/flow/models/blocks/table/TableBlockModel.tsx +38 -17
  195. package/src/flow/models/blocks/table/TableColumnModel.tsx +42 -5
  196. package/src/flow/models/blocks/table/__tests__/TableActionsColumnModel.test.tsx +111 -1
  197. package/src/flow/models/blocks/table/__tests__/TableBlockModel.dragSort.test.ts +127 -0
  198. package/src/flow/models/blocks/table/__tests__/TableBlockModel.mobileSettingsButtons.test.tsx +78 -0
  199. package/src/flow/models/blocks/table/__tests__/TableBlockModel.rowSelection.test.tsx +1 -0
  200. package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +210 -1
  201. package/src/flow/models/blocks/table/dragSort/dragSortHooks.tsx +28 -17
  202. package/src/flow/models/blocks/table/dragSort/dragSortSettings.ts +13 -6
  203. package/src/flow/models/blocks/table/dragSort/dragSortUtils.ts +15 -2
  204. package/src/flow/models/fields/AssociationFieldModel/AssociationFieldModel.tsx +1 -1
  205. package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/PopupSubTableFieldModel.tsx +30 -6
  206. package/src/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.tsx +61 -17
  207. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.tsx +141 -19
  208. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableField.tsx +13 -1
  209. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableColumnModel.rowRecord.test.ts +197 -0
  210. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableFieldModel.reset.test.ts +180 -0
  211. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.tsx +6 -4
  212. package/src/flow/models/fields/AssociationFieldModel/__tests__/AssociationFieldModel.updateAssociation.test.ts +72 -0
  213. package/src/flow/models/fields/AssociationFieldModel/__tests__/RecordPickerFieldModel.itemContext.test.ts +23 -0
  214. package/src/flow/models/fields/ClickableFieldModel.tsx +5 -0
  215. package/src/flow/models/fields/DisplayDateTimeFieldModel.tsx +29 -1
  216. package/src/flow/models/fields/InputFieldModel.tsx +40 -2
  217. package/src/flow/models/fields/JSEditableFieldModel.tsx +2 -11
  218. package/src/flow/models/fields/JSFieldModel.tsx +2 -7
  219. package/src/flow/models/fields/JSItemModel.tsx +2 -14
  220. package/src/flow/models/fields/SelectFieldModel.tsx +6 -4
  221. package/src/flow/models/fields/TextareaFieldModel.tsx +72 -3
  222. package/src/flow/models/fields/__tests__/DisplayDateTimeFieldModel.test.tsx +96 -0
  223. package/src/flow/models/fields/__tests__/InputFieldModel.test.tsx +117 -1
  224. package/src/flow/models/fields/__tests__/SelectFieldModel.test.tsx +43 -0
  225. package/src/flow/models/fields/__tests__/TextareaFieldModel.test.tsx +131 -0
  226. package/src/flow/models/fields/mobile-components/MobileLazySelect.tsx +20 -10
  227. package/src/flow/models/fields/mobile-components/MobileSelect.tsx +24 -12
  228. package/src/flow/models/topbar/TopbarActionModel.tsx +168 -10
  229. package/src/flow/resolveViewParamsToViewList.tsx +11 -3
  230. package/src/flow/routeTransientInputArgs.ts +27 -0
  231. package/src/flow/utils/__tests__/dateTimeFormat.test.ts +300 -0
  232. package/src/flow/utils/dataScopeFormValueClear.ts +218 -81
  233. package/src/flow/utils/dataScopeRowSnapshot.ts +616 -0
  234. package/src/flow/utils/dateTimeDisplayProps.ts +135 -0
  235. package/src/flow/utils/formValueDeps.ts +170 -0
  236. package/src/flow-compat/FieldValidation.tsx +122 -60
  237. package/src/flow-compat/Popover.tsx +43 -4
  238. package/src/flow-compat/__tests__/Popover.test.tsx +34 -0
  239. package/src/index.ts +10 -1
  240. package/src/layout-manager/__tests__/LayoutRoute.test.tsx +41 -1
  241. package/src/nocobase-buildin-plugin/index.tsx +51 -15
  242. package/src/settings-center/AdminSettingsLayout.tsx +10 -2
  243. package/src/settings-center/SystemSettingsPage.tsx +1 -2
  244. package/src/settings-center/plugin-manager/PluginCard.tsx +2 -2
  245. package/src/settings-center/plugin-manager/index.tsx +3 -0
  246. package/src/settings-center/utils.tsx +0 -6
  247. package/src/utils/markdownSanitize.ts +88 -0
@@ -15,17 +15,29 @@ import {
15
15
  isRunJSValue,
16
16
  } from '@nocobase/flow-engine';
17
17
  import _ from 'lodash';
18
- import { namePathToPathKey, parsePathString, pathKeyToNamePath } from '../models/blocks/form/value-runtime/path';
18
+ import { namePathToPathKey } from '../models/blocks/form/value-runtime/path';
19
19
  import {
20
20
  collectStaticDepsFromRunJSValue,
21
21
  collectStaticDepsFromTemplateValue,
22
22
  recordDep,
23
23
  type DepCollector,
24
24
  } from '../models/blocks/form/value-runtime/deps';
25
+ import {
26
+ buildItemListRootPath,
27
+ buildItemRowPath,
28
+ dedupeNamePaths,
29
+ findFormValueChangeSource,
30
+ getChangedPathsFromPayload,
31
+ getFieldIndexEntriesFromContext,
32
+ isNamePathPrefix,
33
+ isSameNamePath,
34
+ minimizeNamePaths,
35
+ parseDependencyPath,
36
+ parsePathKey,
37
+ type NamePath,
38
+ } from '../utils/formValueDeps';
25
39
  import { linkageRulesRefresh } from './linkageRulesRefresh';
26
40
 
27
- type NamePath = Array<string | number>;
28
-
29
41
  type LinkageRefreshDeps = {
30
42
  wildcard: boolean;
31
43
  valuePaths: NamePath[];
@@ -40,75 +52,11 @@ type LinkageRefreshBinding = {
40
52
  dispose: () => void;
41
53
  };
42
54
 
43
- type FieldIndexEntry = {
44
- name: string;
45
- index: number;
46
- };
47
-
48
55
  const FORM_VALUES_CHANGE_EVENT = 'formValuesChange';
49
56
  const LINKAGE_REFRESH_BINDINGS_KEY = '__formValueDrivenLinkageRefreshBindings';
50
57
 
51
- function isSameNamePath(a: NamePath, b: NamePath) {
52
- return a.length === b.length && a.every((seg, index) => seg === b[index]);
53
- }
54
-
55
- function isNamePathPrefix(prefix: NamePath, path: NamePath) {
56
- if (prefix.length > path.length) return false;
57
- return prefix.every((seg, index) => seg === path[index]);
58
- }
59
-
60
- function dedupeNamePaths(paths: NamePath[]) {
61
- const byKey = new Map<string, NamePath>();
62
- for (const path of paths) {
63
- if (!path?.length) continue;
64
- byKey.set(namePathToPathKey(path), path);
65
- }
66
- return Array.from(byKey.values());
67
- }
68
-
69
- function minimizeValueNamePaths(paths: NamePath[]) {
70
- const deduped = dedupeNamePaths(paths);
71
- return deduped.filter((path, index) => {
72
- return !deduped.some((other, otherIndex) => otherIndex !== index && isNamePathPrefix(path, other));
73
- });
74
- }
75
-
76
- function parseFieldIndexEntries(fieldIndex: unknown): FieldIndexEntry[] {
77
- const arr = Array.isArray(fieldIndex) ? fieldIndex : [];
78
- const entries: FieldIndexEntry[] = [];
79
- for (const it of arr) {
80
- if (typeof it !== 'string') continue;
81
- const [name, indexStr] = it.split(':');
82
- const index = Number(indexStr);
83
- if (!name || Number.isNaN(index)) continue;
84
- entries.push({ name, index });
85
- }
86
- return entries;
87
- }
88
-
89
- function getFieldIndexEntriesFromContext(ctx: any): FieldIndexEntry[] {
90
- return parseFieldIndexEntries(ctx?.model?.context?.fieldIndex ?? ctx?.fieldIndex);
91
- }
92
-
93
- function buildItemRowPath(entries: FieldIndexEntry[], parentDepth: number): NamePath | null {
94
- const targetIndex = entries.length - 1 - parentDepth;
95
- if (targetIndex < 0) return null;
96
-
97
- const out: NamePath = [];
98
- for (let i = 0; i <= targetIndex; i++) {
99
- out.push(entries[i].name, entries[i].index);
100
- }
101
- return out;
102
- }
103
-
104
- function buildItemListRootPath(entries: FieldIndexEntry[], parentDepth: number): NamePath | null {
105
- const rowPath = buildItemRowPath(entries, parentDepth);
106
- if (!rowPath?.length) return null;
107
- return rowPath.slice(0, -1);
108
- }
109
-
110
58
  function resolveItemDependencyPath(ctx: FlowContext, depPath: NamePath): LinkageRefreshDeps {
111
- const entries = getFieldIndexEntriesFromContext(ctx as any);
59
+ const entries = getFieldIndexEntriesFromContext(ctx);
112
60
  if (!entries.length) {
113
61
  return { wildcard: true, valuePaths: [], structuralPaths: [] };
114
62
  }
@@ -171,8 +119,7 @@ function addRunjsUsageToCollector(script: string, collector: DepCollector) {
171
119
  collector.wildcard = true;
172
120
  continue;
173
121
  }
174
- const segs = parsePathString(String(subPath)).filter((seg) => typeof seg !== 'object') as NamePath;
175
- recordDep(segs, collector);
122
+ recordDep(parseDependencyPath(String(subPath)), collector);
176
123
  continue;
177
124
  }
178
125
  if (varName === 'item') {
@@ -233,13 +180,13 @@ function collectLinkageRefreshDeps(ctx: FlowContext, params: any): LinkageRefres
233
180
  wildcard = true;
234
181
  continue;
235
182
  }
236
- valuePaths.push(pathKeyToNamePath(inner));
183
+ valuePaths.push(parsePathKey(inner));
237
184
  continue;
238
185
  }
239
186
 
240
187
  if (depKey === 'ctx:item' || depKey.startsWith('ctx:item:')) {
241
188
  const subPath = depKey === 'ctx:item' ? '' : depKey.slice('ctx:item:'.length);
242
- const depPath = subPath ? (parsePathString(subPath).filter((seg) => typeof seg !== 'object') as NamePath) : [];
189
+ const depPath = subPath ? parseDependencyPath(subPath) : [];
243
190
  const resolved = resolveItemDependencyPath(ctx, depPath);
244
191
  wildcard ||= resolved.wildcard;
245
192
  valuePaths.push(...resolved.valuePaths);
@@ -249,7 +196,7 @@ function collectLinkageRefreshDeps(ctx: FlowContext, params: any): LinkageRefres
249
196
 
250
197
  return {
251
198
  wildcard,
252
- valuePaths: minimizeValueNamePaths(valuePaths),
199
+ valuePaths: minimizeNamePaths(valuePaths),
253
200
  structuralPaths: dedupeNamePaths(structuralPaths),
254
201
  };
255
202
  }
@@ -258,44 +205,9 @@ function hasLinkageRefreshDeps(deps: LinkageRefreshDeps) {
258
205
  return deps.wildcard || deps.valuePaths.length > 0 || deps.structuralPaths.length > 0;
259
206
  }
260
207
 
261
- function getChangedPathsFromPayload(payload: any): NamePath[] {
262
- const rawChangedPaths = Array.isArray(payload?.changedPaths) ? payload.changedPaths : [];
263
- const out: NamePath[] = [];
264
-
265
- for (const path of rawChangedPaths) {
266
- if (Array.isArray(path)) {
267
- if (path.length === 1 && typeof path[0] === 'string') {
268
- const namePath = pathKeyToNamePath(path[0]);
269
- if (namePath.length) out.push(namePath);
270
- continue;
271
- }
272
- const segs = path.filter((seg) => typeof seg === 'string' || typeof seg === 'number') as NamePath;
273
- if (segs.length) out.push(segs);
274
- continue;
275
- }
276
- if (typeof path === 'string' && path) {
277
- out.push(pathKeyToNamePath(path));
278
- }
279
- }
280
-
281
- if (out.length) {
282
- return out;
283
- }
284
-
285
- const changedValues = payload?.changedValues;
286
- if (changedValues && typeof changedValues === 'object') {
287
- for (const key of Object.keys(changedValues)) {
288
- const namePath = pathKeyToNamePath(key);
289
- if (namePath.length) out.push(namePath);
290
- }
291
- }
292
-
293
- return out;
294
- }
295
-
296
208
  function linkageRefreshDepsMatchPayload(deps: LinkageRefreshDeps, payload: any) {
297
209
  if (!hasLinkageRefreshDeps(deps)) return false;
298
- const changedPaths = getChangedPathsFromPayload(payload);
210
+ const changedPaths = getChangedPathsFromPayload(payload, { includeArrayChangedValues: true });
299
211
  if (deps.wildcard) return true;
300
212
  if (!changedPaths.length) return true;
301
213
 
@@ -330,28 +242,8 @@ function getLinkageRefreshBindings(model: any): Map<string, LinkageRefreshBindin
330
242
  return (model[LINKAGE_REFRESH_BINDINGS_KEY] ||= new Map<string, LinkageRefreshBinding>());
331
243
  }
332
244
 
333
- function isFormBlockForLinkageRefresh(model: any) {
334
- if (!model || typeof model !== 'object') return false;
335
- if (!model.emitter || typeof model.emitter.on !== 'function' || typeof model.emitter.off !== 'function') return false;
336
- return !!model.formValueRuntime || !!model.context?.form || typeof model.context?.setFormValues === 'function';
337
- }
338
-
339
245
  function findFormBlockForLinkageRefresh(ctx: FlowContext): any | null {
340
- const candidates: any[] = [];
341
- const push = (model: any) => {
342
- if (model && !candidates.includes(model)) candidates.push(model);
343
- };
344
-
345
- push((ctx.model as any)?.context?.blockModel);
346
- push(ctx.model);
347
-
348
- let cursor: any = (ctx.model as any)?.parent;
349
- while (cursor) {
350
- push(cursor);
351
- cursor = cursor?.parent;
352
- }
353
-
354
- return candidates.find(isFormBlockForLinkageRefresh) || null;
246
+ return findFormValueChangeSource(ctx) as any;
355
247
  }
356
248
 
357
249
  function disposeLinkageRefreshBinding(model: any, key: string) {
@@ -7,11 +7,20 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
 
10
- import { defineAction, tExpr, FlowModelContext, FlowModel, FlowExitAllException } from '@nocobase/flow-engine';
10
+ import {
11
+ defineAction,
12
+ tExpr,
13
+ FlowModelContext,
14
+ FlowModel,
15
+ FlowExitAllException,
16
+ createOpenViewRouteState,
17
+ RUNJS_OPEN_VIEW_ROUTE_STATE,
18
+ } from '@nocobase/flow-engine';
11
19
  import React from 'react';
12
20
  import { FlowPage } from '../FlowPage';
13
21
  import { PageModel, RootPageModel } from '../models';
14
22
  import _ from 'lodash';
23
+ import { ROUTE_TRANSIENT_INPUT_ARGS_KEY } from '../routeTransientInputArgs';
15
24
 
16
25
  type DirtyAwareFlowModel = FlowModel & {
17
26
  getUserModifiedFields?: () => Set<string> | undefined;
@@ -23,6 +32,15 @@ type BeforeCloseDirtyState = {
23
32
  formModelUids: string[];
24
33
  };
25
34
 
35
+ const pickRouteTransientInputArgs = (inputArgs: Record<string, unknown>) => {
36
+ return _.pickBy(
37
+ {
38
+ formData: inputArgs.formData,
39
+ },
40
+ (value) => typeof value !== 'undefined',
41
+ );
42
+ };
43
+
26
44
  function collectDirtyFormModelUids(model?: FlowModel | null, ignoredDirtyFormModelUids: string[] = []): string[] {
27
45
  if (!model) {
28
46
  return [];
@@ -291,8 +309,32 @@ export const openView = defineAction({
291
309
  ? (inputArgs as any).associationName
292
310
  : (params as any)?.associationName;
293
311
  const mergedTabUid = typeof inputArgs.tabUid !== 'undefined' ? inputArgs.tabUid : params.tabUid;
294
- // 移动端中只需要显示子页面
295
- const openMode = ctx.inputArgs?.isMobileLayout ? 'embed' : ctx.inputArgs?.mode || params.mode || 'drawer';
312
+ const hasRunJSOpenViewRouteState = Object.prototype.hasOwnProperty.call(inputArgs, RUNJS_OPEN_VIEW_ROUTE_STATE);
313
+ const runJSOpenViewRouteStateInput = (inputArgs as Record<PropertyKey, unknown>)[RUNJS_OPEN_VIEW_ROUTE_STATE];
314
+ const runJSOpenViewRouteState = hasRunJSOpenViewRouteState
315
+ ? createOpenViewRouteState(
316
+ runJSOpenViewRouteStateInput && typeof runJSOpenViewRouteStateInput === 'object'
317
+ ? (runJSOpenViewRouteStateInput as { mode?: unknown; size?: unknown })
318
+ : {
319
+ mode: inputArgs.mode,
320
+ size: inputArgs.size,
321
+ },
322
+ )
323
+ : undefined;
324
+ const replayOpenViewRouteStateInput = (inputArgs as { openViewRouteState?: unknown }).openViewRouteState;
325
+ const replayOpenViewRouteState =
326
+ replayOpenViewRouteStateInput && typeof replayOpenViewRouteStateInput === 'object'
327
+ ? createOpenViewRouteState(replayOpenViewRouteStateInput as { mode?: unknown; size?: unknown })
328
+ : undefined;
329
+ const runtimeOpenViewRouteState = runJSOpenViewRouteState || replayOpenViewRouteState;
330
+ // 移动端中只需要显示子页面。本次 dispatch 参数优先于持久化默认值。
331
+ const openMode = ctx.inputArgs?.isMobileLayout
332
+ ? 'embed'
333
+ : runtimeOpenViewRouteState?.mode || ctx.inputArgs?.mode || params.mode || 'drawer';
334
+ const effectiveRunJSOpenViewRouteState =
335
+ runJSOpenViewRouteState && ctx.inputArgs?.isMobileLayout
336
+ ? createOpenViewRouteState({ ...runJSOpenViewRouteState, mode: openMode })
337
+ : runJSOpenViewRouteState;
296
338
  let navigation = typeof inputArgs.navigation !== 'undefined' ? inputArgs.navigation : params.navigation;
297
339
 
298
340
  // 传递了上下文就必须禁用路由,否则下次路由打开会缺少上下文
@@ -313,6 +355,7 @@ export const openView = defineAction({
313
355
  sourceId: mergedSourceId,
314
356
  tabUid: mergedTabUid,
315
357
  viewUid: ctx.model.context?.inputArgs?.viewUid || ctx.model.uid,
358
+ ...(effectiveRunJSOpenViewRouteState ? { openViewRouteState: effectiveRunJSOpenViewRouteState } : {}),
316
359
  } as Record<string, unknown>;
317
360
  const pendingView = {
318
361
  type: pendingType,
@@ -328,8 +371,19 @@ export const openView = defineAction({
328
371
  filterByTk: mergedFilterByTk,
329
372
  sourceId: mergedSourceId,
330
373
  tabUid: mergedTabUid,
374
+ ...(effectiveRunJSOpenViewRouteState ? { openViewRouteState: effectiveRunJSOpenViewRouteState } : {}),
331
375
  };
332
- ctx.view.navigation.navigateTo(nextView);
376
+ const transientInputArgs = pickRouteTransientInputArgs(inputArgs);
377
+ const navigationOptions = Object.keys(transientInputArgs).length
378
+ ? {
379
+ state: {
380
+ [ROUTE_TRANSIENT_INPUT_ARGS_KEY]: {
381
+ [nextView.viewUid]: transientInputArgs,
382
+ },
383
+ },
384
+ }
385
+ : undefined;
386
+ ctx.view.navigation.navigateTo(nextView, navigationOptions);
333
387
  return;
334
388
  }
335
389
  }
@@ -373,7 +427,7 @@ export const openView = defineAction({
373
427
 
374
428
  const pageModelClass =
375
429
  ctx.inputArgs.pageModelClass || params.pageModelClass || ctx.layout?.childPageModelClass || 'ChildPageModel';
376
- const size = ctx.inputArgs.size || params.size || 'medium';
430
+ const size = runtimeOpenViewRouteState?.size || ctx.inputArgs.size || params.size || 'medium';
377
431
  let pageModelUid: string | null = null;
378
432
  let pageModelRef: FlowModel | null = null;
379
433
 
@@ -7,14 +7,7 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
 
10
- import {
11
- ActionScene,
12
- defineAction,
13
- tExpr,
14
- createSafeWindow,
15
- createSafeDocument,
16
- createSafeNavigator,
17
- } from '@nocobase/flow-engine';
10
+ import { ActionScene, defineAction, tExpr } from '@nocobase/flow-engine';
18
11
  import { CodeEditor } from '../components/code-editor';
19
12
 
20
13
  export const runjs = defineAction({
@@ -38,11 +31,6 @@ export const runjs = defineAction({
38
31
  // 如果是 URL 触发的,则不执行代码
39
32
  if (ctx.inputArgs?.navigation) return;
40
33
 
41
- const navigator = createSafeNavigator();
42
- return ctx.runjs(params.code, {
43
- window: createSafeWindow({ navigator }),
44
- document: createSafeDocument(),
45
- navigator,
46
- });
34
+ return ctx.runjs(params.code);
47
35
  },
48
36
  });
@@ -10,6 +10,56 @@
10
10
  import { defineAction, jioToJoiSchema, tExpr } from '@nocobase/flow-engine';
11
11
  import { FieldValidation } from '../../flow-compat';
12
12
 
13
+ type ValidationType = 'string' | 'number' | 'array' | 'boolean' | 'any';
14
+
15
+ interface ValidationRule {
16
+ name: string;
17
+ args?: any;
18
+ }
19
+
20
+ interface ValidationData {
21
+ type: ValidationType;
22
+ rules?: ValidationRule[];
23
+ }
24
+
25
+ interface ValidationContext {
26
+ model: {
27
+ props: {
28
+ label?: string;
29
+ };
30
+ };
31
+ t: (key: string, options?: Record<string, unknown>) => string;
32
+ }
33
+
34
+ function buildValidationRules(ctx: ValidationContext, validation: ValidationData) {
35
+ const rules = [];
36
+ const schema = jioToJoiSchema(validation);
37
+ const label = ctx.model.props.label;
38
+ rules.push({
39
+ validator: (_: unknown, value: unknown) => {
40
+ const { error } = schema.validate(value, {
41
+ abortEarly: false,
42
+ });
43
+
44
+ if (error) {
45
+ const messages = error.details.map((d: { type: string; context?: Record<string, unknown> }) => {
46
+ return ctx.t(`${d.type}`, {
47
+ ...d.context,
48
+ ns: 'data-source-main',
49
+ label,
50
+ });
51
+ });
52
+ const div = document.createElement('div');
53
+ div.innerHTML = messages.join('; ');
54
+ return Promise.reject(div.textContent);
55
+ }
56
+
57
+ return Promise.resolve();
58
+ },
59
+ });
60
+ return rules;
61
+ }
62
+
13
63
  export const validation = defineAction({
14
64
  title: tExpr('Validation'),
15
65
  name: 'validation',
@@ -29,6 +79,7 @@ export const validation = defineAction({
29
79
  type: targetInterface.validationType,
30
80
  availableValidationOptions: [...new Set(targetInterface.availableValidationOptions)],
31
81
  excludeValidationOptions: [...new Set(targetInterface.excludeValidationOptions)],
82
+ inheritedValue: ctx.model.collectionField.validation,
32
83
  isAssociation: targetInterface.isAssociation,
33
84
  },
34
85
  },
@@ -36,40 +87,21 @@ export const validation = defineAction({
36
87
  },
37
88
  handler(ctx, params) {
38
89
  if (params.validation) {
39
- const rules = [];
40
- const schema = jioToJoiSchema(params.validation);
41
- const label = ctx.model.props.label;
42
- rules.push({
43
- validator: (_, value) => {
44
- const { error } = schema.validate(value, {
45
- abortEarly: false,
46
- });
47
-
48
- if (error) {
49
- const messages = error.details.map((d) => {
50
- return ctx.t(`${d.type}`, {
51
- ...d.context,
52
- ns: 'data-source-main',
53
- label,
54
- });
55
- });
56
- const div = document.createElement('div');
57
- div.innerHTML = messages.join('; ');
58
- return Promise.reject(div.textContent);
59
- }
60
-
61
- return Promise.resolve();
62
- },
63
- });
64
- const hasRequiredInCollection = params.validation.rules.some((rule) => rule.name === 'required');
65
- if (hasRequiredInCollection) {
90
+ const collectionValidation = ctx.model.collectionField?.validation;
91
+ const collectionRules = ctx.model.collectionField?.getComponentProps?.().rules || [];
92
+ const uiRules = params.validation.rules?.length
93
+ ? buildValidationRules(ctx as unknown as ValidationContext, params.validation)
94
+ : [];
95
+ const hasRequiredInValidation = [collectionValidation, params.validation].some(
96
+ (validation) => validation?.rules?.some((rule) => rule.name === 'required'),
97
+ );
98
+ if (hasRequiredInValidation) {
66
99
  ctx.model.setProps({
67
- required: hasRequiredInCollection,
100
+ required: hasRequiredInValidation,
68
101
  });
69
102
  }
70
- console.log(rules);
71
103
  ctx.model.setProps({
72
- rules,
104
+ rules: [...collectionRules, ...uiRules],
73
105
  validation: params.validation,
74
106
  });
75
107
  }