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

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 (216) 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 +21 -0
  29. package/es/flow/models/blocks/form/value-runtime/types.d.ts +2 -2
  30. package/es/flow/models/blocks/table/TableActionsColumnModel.d.ts +1 -0
  31. package/es/flow/models/blocks/table/TableBlockModel.d.ts +1 -0
  32. package/es/flow/models/blocks/table/dragSort/dragSortHooks.d.ts +1 -1
  33. package/es/flow/models/blocks/table/dragSort/dragSortSettings.d.ts +2 -1
  34. package/es/flow/models/blocks/table/dragSort/dragSortUtils.d.ts +6 -4
  35. package/es/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.d.ts +2 -0
  36. package/es/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.d.ts +6 -0
  37. package/es/flow/resolveViewParamsToViewList.d.ts +1 -1
  38. package/es/flow/utils/dataScopeRowSnapshot.d.ts +59 -0
  39. package/es/flow/utils/dateTimeDisplayProps.d.ts +49 -0
  40. package/es/flow/utils/formValueDeps.d.ts +32 -0
  41. package/es/flow-compat/FieldValidation.d.ts +2 -1
  42. package/es/index.d.ts +2 -1
  43. package/es/index.mjs +233 -137
  44. package/lib/index.js +234 -138
  45. package/package.json +7 -7
  46. package/src/PluginSettingsManager.ts +53 -0
  47. package/src/RouteRepository.ts +126 -24
  48. package/src/__tests__/PluginSettingsManager.test.ts +13 -0
  49. package/src/__tests__/RouteRepository.test.ts +216 -0
  50. package/src/__tests__/browserChecker.test.ts +61 -0
  51. package/src/__tests__/exports.test.ts +16 -0
  52. package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +199 -0
  53. package/src/__tests__/plugin-manager.test.tsx +44 -2
  54. package/src/__tests__/settings-center.test.tsx +40 -1
  55. package/src/collection-manager/field-configure.ts +1 -1
  56. package/src/collection-manager/interfaces/id.ts +1 -1
  57. package/src/collection-manager/interfaces/m2m.tsx +2 -2
  58. package/src/collection-manager/interfaces/m2o.tsx +2 -2
  59. package/src/collection-manager/interfaces/nanoid.ts +1 -1
  60. package/src/collection-manager/interfaces/o2m.tsx +2 -2
  61. package/src/collection-manager/interfaces/obo.tsx +2 -2
  62. package/src/collection-manager/interfaces/oho.tsx +2 -2
  63. package/src/collection-manager/interfaces/properties/index.ts +2 -2
  64. package/src/collection-manager/interfaces/uuid.ts +1 -1
  65. package/src/components/AppComponents.tsx +19 -3
  66. package/src/components/README.md +7 -1
  67. package/src/components/README.zh-CN.md +6 -1
  68. package/src/components/category-tabs/SortableCategoryTabs.tsx +210 -0
  69. package/src/components/category-tabs/index.ts +10 -0
  70. package/src/components/form/JsonTextArea.tsx +21 -11
  71. package/src/components/form/TypedVariableInput.tsx +416 -93
  72. package/src/components/form/VariableJsonTextArea.tsx +175 -0
  73. package/src/components/form/__tests__/JsonTextArea.test.tsx +43 -0
  74. package/src/components/form/__tests__/TypedVariableInput.test.tsx +266 -9
  75. package/src/components/form/__tests__/VariableJsonTextArea.test.tsx +86 -0
  76. package/src/components/form/filter/CollectionFilterItem.tsx +32 -7
  77. package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +38 -0
  78. package/src/components/form/filter/index.ts +2 -0
  79. package/src/components/form/index.tsx +1 -0
  80. package/src/components/index.ts +2 -0
  81. package/src/flow/__tests__/FlowRoute.test.tsx +443 -5
  82. package/src/flow/__tests__/getKey.test.ts +7 -0
  83. package/src/flow/__tests__/resolveViewParamsToViewList.test.ts +34 -0
  84. package/src/flow/actions/__tests__/afterSuccess.test.ts +73 -0
  85. package/src/flow/actions/__tests__/dataScopeFilter.test.ts +58 -0
  86. package/src/flow/actions/__tests__/dataScopeFormValueClear.test.ts +1022 -0
  87. package/src/flow/actions/__tests__/fieldLinkageRules.scopeDepth.test.ts +150 -1
  88. package/src/flow/actions/__tests__/linkageAssignField.legacy.test.ts +135 -0
  89. package/src/flow/actions/__tests__/linkageRules.hiddenSync.restore.test.ts +19 -5
  90. package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +92 -0
  91. package/src/flow/actions/__tests__/openView.defineProps.route.test.tsx +104 -0
  92. package/src/flow/actions/__tests__/subFormFieldLinkageRules.inputArgs.test.ts +2 -2
  93. package/src/flow/actions/afterSuccess.tsx +142 -3
  94. package/src/flow/actions/customVariable.tsx +1 -2
  95. package/src/flow/actions/dataScopeFilter.ts +10 -0
  96. package/src/flow/actions/dateTimeFormat.tsx +42 -28
  97. package/src/flow/actions/index.ts +1 -1
  98. package/src/flow/actions/linkageRules.tsx +123 -35
  99. package/src/flow/actions/linkageRulesFormValueRefresh.ts +22 -130
  100. package/src/flow/actions/openView.tsx +38 -4
  101. package/src/flow/actions/runjs.tsx +2 -14
  102. package/src/flow/actions/validation.tsx +62 -30
  103. package/src/flow/admin-shell/BaseLayoutModel.tsx +25 -3
  104. package/src/flow/admin-shell/BaseLayoutRouteCoordinator.ts +5 -2
  105. package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +13 -0
  106. package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +34 -10
  107. package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.test.tsx +310 -0
  108. package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +44 -8
  109. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuFlowUtils.ts +5 -3
  110. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuModels.tsx +61 -9
  111. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.tsx +71 -8
  112. package/src/flow/admin-shell/admin-layout/AdminLayoutModel.tsx +1 -1
  113. package/src/flow/admin-shell/admin-layout/AdminLayoutSlotModels.tsx +23 -9
  114. package/src/flow/admin-shell/admin-layout/HelpLite.tsx +1 -3
  115. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutComponent.test.tsx +188 -0
  116. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +99 -0
  117. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutModel.test.tsx +82 -0
  118. package/src/flow/admin-shell/admin-layout/__tests__/TopbarActionsBar.test.tsx +166 -2
  119. package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.test.ts +20 -0
  120. package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.ts +33 -5
  121. package/src/flow/components/DefaultValue.tsx +1 -2
  122. package/src/flow/components/DynamicFlowsIcon.tsx +447 -126
  123. package/src/flow/components/FieldAssignRulesEditor.tsx +128 -21
  124. package/src/flow/components/FieldAssignValueInput.tsx +10 -5
  125. package/src/flow/components/FlowRoute.tsx +56 -11
  126. package/src/flow/components/__tests__/DynamicFlowsIcon.test.tsx +148 -2
  127. package/src/flow/components/__tests__/FieldAssignRulesEditor.test.tsx +508 -4
  128. package/src/flow/components/__tests__/fieldAssignOptions.test.ts +151 -3
  129. package/src/flow/components/code-editor/__tests__/useCodeRunner.test.tsx +2 -17
  130. package/src/flow/components/code-editor/hooks/useCodeRunner.ts +2 -14
  131. package/src/flow/components/code-editor/runjsDiagnostics.ts +8 -45
  132. package/src/flow/components/fieldAssignOptions.ts +155 -27
  133. package/src/flow/flows/editMarkdownFlow.tsx +1 -1
  134. package/src/flow/getViewDiffAndUpdateHidden.tsx +1 -0
  135. package/src/flow/index.ts +2 -1
  136. package/src/flow/internal/utils/operatorSchemaHelper.ts +15 -1
  137. package/src/flow/models/actions/JSActionModel.tsx +2 -7
  138. package/src/flow/models/actions/JSCollectionActionModel.tsx +2 -7
  139. package/src/flow/models/actions/JSItemActionModel.tsx +2 -7
  140. package/src/flow/models/actions/JSRecordActionModel.tsx +2 -7
  141. package/src/flow/models/base/ActionModel.tsx +12 -1
  142. package/src/flow/models/base/GridModel.tsx +38 -7
  143. package/src/flow/models/base/PageModel/PageModel.tsx +4 -1
  144. package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +28 -4
  145. package/src/flow/models/base/__tests__/ActionModel.test.ts +83 -0
  146. package/src/flow/models/base/__tests__/GridModel.dragSnapshotContainer.test.ts +239 -1
  147. package/src/flow/models/base/__tests__/transformRowsToSingleColumn.test.ts +48 -0
  148. package/src/flow/models/blocks/filter-form/FilterFormBlockModel.tsx +31 -3
  149. package/src/flow/models/blocks/filter-form/FilterFormJSActionModel.tsx +2 -7
  150. package/src/flow/models/blocks/filter-form/__tests__/defaultValues.wiring.test.ts +77 -0
  151. package/src/flow/models/blocks/filter-form/fields/FilterFormCustomFieldModel.tsx +1 -1
  152. package/src/flow/models/blocks/filter-manager/flow-actions/__tests__/customizeFilterRender.test.tsx +56 -1
  153. package/src/flow/models/blocks/form/EditFormModel.tsx +1 -0
  154. package/src/flow/models/blocks/form/FormActionModel.tsx +1 -1
  155. package/src/flow/models/blocks/form/FormBlockModel.tsx +7 -0
  156. package/src/flow/models/blocks/form/JSFormActionModel.tsx +2 -7
  157. package/src/flow/models/blocks/form/__tests__/FormBlockModel.test.tsx +17 -0
  158. package/src/flow/models/blocks/form/__tests__/submitHandler.test.ts +54 -1
  159. package/src/flow/models/blocks/form/submitHandler.ts +17 -3
  160. package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +880 -102
  161. package/src/flow/models/blocks/form/value-runtime/rules.ts +445 -13
  162. package/src/flow/models/blocks/form/value-runtime/runtime.ts +257 -13
  163. package/src/flow/models/blocks/form/value-runtime/types.ts +2 -2
  164. package/src/flow/models/blocks/js-block/JSBlock.tsx +2 -7
  165. package/src/flow/models/blocks/table/JSColumnModel.tsx +1 -9
  166. package/src/flow/models/blocks/table/TableActionsColumnModel.tsx +36 -13
  167. package/src/flow/models/blocks/table/TableBlockModel.tsx +38 -17
  168. package/src/flow/models/blocks/table/TableColumnModel.tsx +36 -3
  169. package/src/flow/models/blocks/table/__tests__/TableActionsColumnModel.test.tsx +111 -1
  170. package/src/flow/models/blocks/table/__tests__/TableBlockModel.dragSort.test.ts +127 -0
  171. package/src/flow/models/blocks/table/__tests__/TableBlockModel.mobileSettingsButtons.test.tsx +78 -0
  172. package/src/flow/models/blocks/table/__tests__/TableBlockModel.rowSelection.test.tsx +1 -0
  173. package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +159 -1
  174. package/src/flow/models/blocks/table/dragSort/dragSortHooks.tsx +28 -17
  175. package/src/flow/models/blocks/table/dragSort/dragSortSettings.ts +13 -6
  176. package/src/flow/models/blocks/table/dragSort/dragSortUtils.ts +15 -2
  177. package/src/flow/models/fields/AssociationFieldModel/AssociationFieldModel.tsx +1 -1
  178. package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/PopupSubTableFieldModel.tsx +29 -6
  179. package/src/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.tsx +16 -4
  180. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.tsx +141 -19
  181. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableField.tsx +13 -1
  182. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableColumnModel.rowRecord.test.ts +197 -0
  183. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableFieldModel.reset.test.ts +180 -0
  184. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.tsx +6 -4
  185. package/src/flow/models/fields/AssociationFieldModel/__tests__/AssociationFieldModel.updateAssociation.test.ts +72 -0
  186. package/src/flow/models/fields/AssociationFieldModel/__tests__/RecordPickerFieldModel.itemContext.test.ts +23 -0
  187. package/src/flow/models/fields/ClickableFieldModel.tsx +5 -0
  188. package/src/flow/models/fields/DisplayDateTimeFieldModel.tsx +29 -1
  189. package/src/flow/models/fields/InputFieldModel.tsx +40 -2
  190. package/src/flow/models/fields/JSEditableFieldModel.tsx +2 -11
  191. package/src/flow/models/fields/JSFieldModel.tsx +2 -7
  192. package/src/flow/models/fields/JSItemModel.tsx +2 -14
  193. package/src/flow/models/fields/SelectFieldModel.tsx +6 -4
  194. package/src/flow/models/fields/TextareaFieldModel.tsx +49 -3
  195. package/src/flow/models/fields/__tests__/DisplayDateTimeFieldModel.test.tsx +96 -0
  196. package/src/flow/models/fields/__tests__/InputFieldModel.test.tsx +117 -1
  197. package/src/flow/models/fields/__tests__/SelectFieldModel.test.tsx +43 -0
  198. package/src/flow/models/fields/__tests__/TextareaFieldModel.test.tsx +100 -0
  199. package/src/flow/models/topbar/TopbarActionModel.tsx +93 -10
  200. package/src/flow/resolveViewParamsToViewList.tsx +11 -3
  201. package/src/flow/utils/__tests__/dateTimeFormat.test.ts +258 -0
  202. package/src/flow/utils/dataScopeFormValueClear.ts +218 -81
  203. package/src/flow/utils/dataScopeRowSnapshot.ts +616 -0
  204. package/src/flow/utils/dateTimeDisplayProps.ts +135 -0
  205. package/src/flow/utils/formValueDeps.ts +170 -0
  206. package/src/flow-compat/FieldValidation.tsx +122 -60
  207. package/src/flow-compat/Popover.tsx +43 -4
  208. package/src/flow-compat/__tests__/Popover.test.tsx +34 -0
  209. package/src/index.ts +8 -1
  210. package/src/layout-manager/__tests__/LayoutRoute.test.tsx +41 -1
  211. package/src/nocobase-buildin-plugin/index.tsx +44 -14
  212. package/src/settings-center/AdminSettingsLayout.tsx +10 -2
  213. package/src/settings-center/SystemSettingsPage.tsx +1 -2
  214. package/src/settings-center/plugin-manager/PluginCard.tsx +2 -2
  215. package/src/settings-center/plugin-manager/index.tsx +3 -0
  216. package/src/settings-center/utils.tsx +0 -6
@@ -8,51 +8,187 @@
8
8
  */
9
9
 
10
10
  import type { FlowContext, FlowModel } from '@nocobase/flow-engine';
11
- import _ from 'lodash';
12
- import { namePathToPathKey, pathKeyToNamePath } from '../models/blocks/form/value-runtime/path';
11
+ import { namePathToPathKey } from '../models/blocks/form/value-runtime/path';
13
12
  import { collectStaticDepsFromTemplateValue, type DepCollector } from '../models/blocks/form/value-runtime/deps';
14
-
15
- type NamePath = Array<string | number>;
16
-
17
- type DataScopeClearDeps = {
18
- wildcard: boolean;
19
- valuePaths: NamePath[];
20
- };
13
+ import {
14
+ buildItemListRootPath,
15
+ buildItemRowPath,
16
+ findFormValueChangeSource,
17
+ getChangedPathsFromPayload,
18
+ isNamePathPrefix,
19
+ isSameNamePath,
20
+ parseFieldIndexEntries,
21
+ parsePathKey,
22
+ type NamePath,
23
+ } from './formValueDeps';
24
+ import {
25
+ applyDataScopeFieldIndexTargetKeys,
26
+ buildDepsSnapshot,
27
+ createDataScopeRowScope,
28
+ getDepsChangeStatus,
29
+ type DataScopeClearDeps,
30
+ type DataScopeClearSnapshot,
31
+ type DataScopeStructuralPath,
32
+ type DataScopeTriggerPath,
33
+ type DataScopeValuePath,
34
+ } from './dataScopeRowSnapshot';
21
35
 
22
36
  type DataScopeClearBinding = {
23
37
  signature: string;
38
+ snapshot: DataScopeClearSnapshot | null;
24
39
  dispose: () => void;
25
40
  };
26
41
 
27
42
  const FORM_VALUES_CHANGE_EVENT = 'formValuesChange';
28
43
  const DATA_SCOPE_CLEAR_BINDINGS_KEY = '__formValueDrivenDataScopeClearBindings';
29
44
 
30
- function dedupeNamePaths(paths: NamePath[]) {
31
- const byKey = new Map<string, NamePath>();
45
+ function dedupeValuePaths(paths: DataScopeValuePath[]) {
46
+ const byKey = new Map<string, DataScopeValuePath>();
32
47
  for (const path of paths) {
33
- if (!path?.length) continue;
34
- byKey.set(namePathToPathKey(path), path);
48
+ if (!path?.path?.length) continue;
49
+ byKey.set(namePathToPathKey(path.path), path);
35
50
  }
36
51
  return Array.from(byKey.values());
37
52
  }
38
53
 
39
- function isNamePathPrefix(prefix: NamePath, path: NamePath) {
40
- if (prefix.length > path.length) return false;
41
- return prefix.every((seg, index) => seg === path[index]);
42
- }
43
-
44
- function minimizeValueNamePaths(paths: NamePath[]) {
45
- const deduped = dedupeNamePaths(paths);
54
+ function minimizeValuePaths(paths: DataScopeValuePath[]) {
55
+ const deduped = dedupeValuePaths(paths);
46
56
  return deduped.filter((path, index) => {
47
- return !deduped.some((other, otherIndex) => otherIndex !== index && isNamePathPrefix(path, other));
57
+ return !deduped.some((other, otherIndex) => otherIndex !== index && isNamePathPrefix(path.path, other.path));
48
58
  });
49
59
  }
50
60
 
51
- function collectDataScopeClearDeps(params: any): DataScopeClearDeps {
61
+ function dedupeStructuralPaths(paths: DataScopeStructuralPath[]) {
62
+ const byKey = new Map<string, DataScopeStructuralPath>();
63
+ for (const path of paths) {
64
+ if (!path?.path?.length) continue;
65
+ byKey.set(`${path.kind}:${namePathToPathKey(path.path)}`, path);
66
+ }
67
+ return Array.from(byKey.values());
68
+ }
69
+
70
+ function dedupeTriggerPaths(paths: DataScopeTriggerPath[]) {
71
+ const byKey = new Map<string, DataScopeTriggerPath>();
72
+ for (const path of paths) {
73
+ if (!path?.path?.length) continue;
74
+ byKey.set(`${path.includeChildren ? 'children' : 'exact'}:${namePathToPathKey(path.path)}`, path);
75
+ }
76
+ return Array.from(byKey.values());
77
+ }
78
+
79
+ function emptyDeps(): DataScopeClearDeps {
80
+ return { wildcard: false, valuePaths: [], structuralPaths: [], triggerPaths: [] };
81
+ }
82
+
83
+ function wildcardDeps(): DataScopeClearDeps {
84
+ return { wildcard: true, valuePaths: [], structuralPaths: [], triggerPaths: [] };
85
+ }
86
+
87
+ function resolveRootItemDependencyPath(cursor: NamePath): DataScopeClearDeps {
88
+ const head = cursor[0];
89
+ if (head === 'value') {
90
+ const rootValuePath = cursor.slice(1);
91
+ return rootValuePath.length
92
+ ? { wildcard: false, valuePaths: [{ path: rootValuePath }], structuralPaths: [], triggerPaths: [] }
93
+ : wildcardDeps();
94
+ }
95
+
96
+ if (head === '__is_new__' || head === '__is_stored__') {
97
+ return { wildcard: false, valuePaths: [{ path: [head] }], structuralPaths: [], triggerPaths: [] };
98
+ }
99
+
100
+ return emptyDeps();
101
+ }
102
+
103
+ function resolveItemDependencyPath(ctx: FlowContext, depPath: NamePath): DataScopeClearDeps {
104
+ const entries = applyDataScopeFieldIndexTargetKeys(
105
+ ctx,
106
+ parseFieldIndexEntries((ctx.model as any)?.context?.fieldIndex ?? (ctx as any)?.fieldIndex),
107
+ );
108
+ if (!entries.length) {
109
+ return wildcardDeps();
110
+ }
111
+
112
+ let parentDepth = 0;
113
+ let cursor = [...depPath];
114
+ while (cursor[0] === 'parentItem') {
115
+ parentDepth += 1;
116
+ cursor = cursor.slice(1);
117
+ }
118
+
119
+ const head = cursor[0];
120
+ if (!head) {
121
+ return wildcardDeps();
122
+ }
123
+
124
+ if (parentDepth === entries.length) {
125
+ return resolveRootItemDependencyPath(cursor);
126
+ }
127
+
128
+ if (parentDepth > entries.length) {
129
+ return wildcardDeps();
130
+ }
131
+
132
+ if (head === 'value') {
133
+ const rowPath = buildItemRowPath(entries, parentDepth);
134
+ if (!rowPath) return wildcardDeps();
135
+ const listRootPath = buildItemListRootPath(entries, parentDepth);
136
+ const tailPath = cursor.slice(1);
137
+ return {
138
+ wildcard: false,
139
+ valuePaths: [
140
+ {
141
+ path: [...rowPath, ...tailPath],
142
+ rowScope: createDataScopeRowScope(entries, parentDepth, tailPath),
143
+ },
144
+ ],
145
+ structuralPaths: [],
146
+ triggerPaths: [
147
+ { path: rowPath, includeChildren: true },
148
+ ...(listRootPath ? [{ path: listRootPath, includeChildren: false }] : []),
149
+ ],
150
+ };
151
+ }
152
+
153
+ if (head === 'index' || head === 'length') {
154
+ const listRootPath = buildItemListRootPath(entries, parentDepth);
155
+ if (!listRootPath) return wildcardDeps();
156
+ return {
157
+ wildcard: false,
158
+ valuePaths: [],
159
+ structuralPaths: [
160
+ { path: listRootPath, kind: head, rowScope: createDataScopeRowScope(entries, parentDepth, []) },
161
+ ],
162
+ triggerPaths: [{ path: listRootPath, includeChildren: false }],
163
+ };
164
+ }
165
+
166
+ if (head === '__is_new__' || head === '__is_stored__') {
167
+ const rowPath = buildItemRowPath(entries, parentDepth);
168
+ if (!rowPath) return wildcardDeps();
169
+ return {
170
+ wildcard: false,
171
+ valuePaths: [
172
+ {
173
+ path: [...rowPath, head],
174
+ rowScope: createDataScopeRowScope(entries, parentDepth, [head]),
175
+ },
176
+ ],
177
+ structuralPaths: [],
178
+ triggerPaths: [{ path: rowPath, includeChildren: true }],
179
+ };
180
+ }
181
+
182
+ return wildcardDeps();
183
+ }
184
+
185
+ function collectDataScopeClearDeps(ctx: FlowContext, params: any): DataScopeClearDeps {
52
186
  const collector: DepCollector = { deps: new Set(), wildcard: false };
53
187
  collectStaticDepsFromTemplateValue(params, collector);
54
188
 
55
- const valuePaths: NamePath[] = [];
189
+ const valuePaths: DataScopeValuePath[] = [];
190
+ const structuralPaths: DataScopeStructuralPath[] = [];
191
+ const triggerPaths: DataScopeTriggerPath[] = [];
56
192
  let wildcard = collector.wildcard;
57
193
 
58
194
  for (const depKey of collector.deps) {
@@ -61,6 +197,15 @@ function collectDataScopeClearDeps(params: any): DataScopeClearDeps {
61
197
  continue;
62
198
  }
63
199
  if (!depKey.startsWith('fv:')) {
200
+ if (depKey === 'ctx:item' || depKey.startsWith('ctx:item:')) {
201
+ const subPath = depKey === 'ctx:item' ? '' : depKey.slice('ctx:item:'.length);
202
+ const depPath = subPath ? parsePathKey(subPath) : [];
203
+ const resolved = resolveItemDependencyPath(ctx, depPath);
204
+ wildcard ||= resolved.wildcard;
205
+ valuePaths.push(...resolved.valuePaths);
206
+ structuralPaths.push(...resolved.structuralPaths);
207
+ triggerPaths.push(...resolved.triggerPaths);
208
+ }
64
209
  continue;
65
210
  }
66
211
  const inner = depKey.slice('fv:'.length);
@@ -68,17 +213,19 @@ function collectDataScopeClearDeps(params: any): DataScopeClearDeps {
68
213
  wildcard = true;
69
214
  continue;
70
215
  }
71
- valuePaths.push(pathKeyToNamePath(inner));
216
+ valuePaths.push({ path: parsePathKey(inner) });
72
217
  }
73
218
 
74
219
  return {
75
220
  wildcard,
76
- valuePaths: minimizeValueNamePaths(valuePaths),
221
+ valuePaths: minimizeValuePaths(valuePaths),
222
+ structuralPaths: dedupeStructuralPaths(structuralPaths),
223
+ triggerPaths: dedupeTriggerPaths(triggerPaths),
77
224
  };
78
225
  }
79
226
 
80
227
  function hasDeps(deps: DataScopeClearDeps) {
81
- return deps.wildcard || deps.valuePaths.length > 0;
228
+ return deps.wildcard || deps.valuePaths.length > 0 || deps.structuralPaths.length > 0 || deps.triggerPaths.length > 0;
82
229
  }
83
230
 
84
231
  function hasModelValue(model: any) {
@@ -88,36 +235,6 @@ function hasModelValue(model: any) {
88
235
  return true;
89
236
  }
90
237
 
91
- function getChangedPathsFromPayload(payload: any): NamePath[] {
92
- const rawChangedPaths = Array.isArray(payload?.changedPaths) ? payload.changedPaths : [];
93
- const out: NamePath[] = [];
94
-
95
- for (const path of rawChangedPaths) {
96
- if (Array.isArray(path)) {
97
- const segs = path.filter((seg) => typeof seg === 'string' || typeof seg === 'number') as NamePath;
98
- if (segs.length) out.push(segs);
99
- continue;
100
- }
101
- if (typeof path === 'string' && path) {
102
- out.push(pathKeyToNamePath(path));
103
- }
104
- }
105
-
106
- if (out.length) {
107
- return out;
108
- }
109
-
110
- const changedValues = payload?.changedValues;
111
- if (changedValues && typeof changedValues === 'object' && !Array.isArray(changedValues)) {
112
- for (const key of Object.keys(changedValues)) {
113
- const namePath = pathKeyToNamePath(key);
114
- if (namePath.length) out.push(namePath);
115
- }
116
- }
117
-
118
- return out;
119
- }
120
-
121
238
  function depsMatchPayload(deps: DataScopeClearDeps, payload: any) {
122
239
  if (!hasDeps(deps)) return false;
123
240
  if (deps.wildcard) return true;
@@ -127,7 +244,28 @@ function depsMatchPayload(deps: DataScopeClearDeps, payload: any) {
127
244
 
128
245
  for (const changedPath of changedPaths) {
129
246
  for (const depPath of deps.valuePaths) {
130
- if (isNamePathPrefix(depPath, changedPath) || isNamePathPrefix(changedPath, depPath)) {
247
+ if (isNamePathPrefix(depPath.path, changedPath) || isNamePathPrefix(changedPath, depPath.path)) {
248
+ return true;
249
+ }
250
+ }
251
+
252
+ for (const depPath of deps.structuralPaths) {
253
+ if (isSameNamePath(depPath.path, changedPath)) {
254
+ return true;
255
+ }
256
+ if (isNamePathPrefix(changedPath, depPath.path)) {
257
+ return true;
258
+ }
259
+ }
260
+
261
+ for (const depPath of deps.triggerPaths) {
262
+ if (
263
+ depPath.includeChildren &&
264
+ (isNamePathPrefix(depPath.path, changedPath) || isNamePathPrefix(changedPath, depPath.path))
265
+ ) {
266
+ return true;
267
+ }
268
+ if (!depPath.includeChildren && isSameNamePath(depPath.path, changedPath)) {
131
269
  return true;
132
270
  }
133
271
  }
@@ -136,11 +274,17 @@ function depsMatchPayload(deps: DataScopeClearDeps, payload: any) {
136
274
  }
137
275
 
138
276
  function getDepsSignature(deps: DataScopeClearDeps, formBlock: any) {
139
- const toKeys = (paths: NamePath[]) => paths.map((path) => namePathToPathKey(path)).sort();
277
+ const toKeys = (paths: DataScopeValuePath[]) => paths.map((path) => namePathToPathKey(path.path)).sort();
278
+ const toStructuralKeys = (paths: DataScopeStructuralPath[]) =>
279
+ paths.map((path) => `${path.kind}:${namePathToPathKey(path.path)}`).sort();
140
280
  return JSON.stringify({
141
281
  formBlockUid: formBlock?.uid,
142
282
  wildcard: deps.wildcard,
143
283
  valuePaths: toKeys(deps.valuePaths),
284
+ structuralPaths: toStructuralKeys(deps.structuralPaths),
285
+ triggerPaths: deps.triggerPaths
286
+ .map((path) => `${path.includeChildren ? 'children' : 'exact'}:${namePathToPathKey(path.path)}`)
287
+ .sort(),
144
288
  });
145
289
  }
146
290
 
@@ -148,28 +292,8 @@ function getBindings(model: any): Map<string, DataScopeClearBinding> {
148
292
  return (model[DATA_SCOPE_CLEAR_BINDINGS_KEY] ||= new Map<string, DataScopeClearBinding>());
149
293
  }
150
294
 
151
- function isFormBlock(model: any) {
152
- if (!model || typeof model !== 'object') return false;
153
- if (!model.emitter || typeof model.emitter.on !== 'function' || typeof model.emitter.off !== 'function') return false;
154
- return !!model.formValueRuntime || !!model.context?.form || typeof model.context?.setFormValues === 'function';
155
- }
156
-
157
295
  function findFormBlock(ctx: FlowContext): any | null {
158
- const candidates: any[] = [];
159
- const push = (model: any) => {
160
- if (model && !candidates.includes(model)) candidates.push(model);
161
- };
162
-
163
- push((ctx.model as any)?.context?.blockModel);
164
- push(ctx.model);
165
-
166
- let cursor: any = (ctx.model as any)?.parent;
167
- while (cursor) {
168
- push(cursor);
169
- cursor = cursor?.parent;
170
- }
171
-
172
- return candidates.find(isFormBlock) || null;
296
+ return findFormValueChangeSource(ctx) as any;
173
297
  }
174
298
 
175
299
  function clearModelValue(model: any) {
@@ -207,7 +331,7 @@ export function ensureFormValueDrivenDataScopeClear(ctx: FlowContext, params: an
207
331
 
208
332
  const stepKey = 'dataScope';
209
333
  const bindingKey = `${flowKey}:${stepKey}`;
210
- const deps = collectDataScopeClearDeps(params);
334
+ const deps = collectDataScopeClearDeps(ctx, params);
211
335
  if (!hasDeps(deps)) {
212
336
  disposeBinding(model, bindingKey);
213
337
  return;
@@ -233,6 +357,7 @@ export function ensureFormValueDrivenDataScopeClear(ctx: FlowContext, params: an
233
357
 
234
358
  const binding: DataScopeClearBinding = {
235
359
  signature,
360
+ snapshot: buildDepsSnapshot(deps, formBlock),
236
361
  dispose: () => {},
237
362
  };
238
363
 
@@ -251,7 +376,19 @@ export function ensureFormValueDrivenDataScopeClear(ctx: FlowContext, params: an
251
376
  return;
252
377
  }
253
378
 
254
- if (!hasModelValue(model) || !depsMatchPayload(deps, payload)) {
379
+ if (!depsMatchPayload(deps, payload)) {
380
+ return;
381
+ }
382
+
383
+ const changeStatus = getDepsChangeStatus(deps, formBlock, payload, binding.snapshot);
384
+ if (changeStatus.snapshot?.complete) {
385
+ binding.snapshot = changeStatus.snapshot;
386
+ }
387
+ if (changeStatus.status === 'unchanged') {
388
+ return;
389
+ }
390
+
391
+ if (!hasModelValue(model)) {
255
392
  return;
256
393
  }
257
394