@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.
- package/es/PluginSettingsManager.d.ts +33 -0
- package/es/RouteRepository.d.ts +21 -6
- package/es/components/category-tabs/SortableCategoryTabs.d.ts +55 -0
- package/es/components/category-tabs/index.d.ts +9 -0
- package/es/components/form/JsonTextArea.d.ts +2 -1
- package/es/components/form/TypedVariableInput.d.ts +22 -4
- package/es/components/form/VariableJsonTextArea.d.ts +19 -0
- package/es/components/form/filter/CollectionFilterItem.d.ts +11 -1
- package/es/components/form/filter/index.d.ts +2 -0
- package/es/components/form/index.d.ts +1 -0
- package/es/components/index.d.ts +2 -0
- package/es/flow/actions/afterSuccess.d.ts +8 -1
- package/es/flow/actions/index.d.ts +1 -1
- package/es/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.d.ts +2 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuFlowUtils.d.ts +2 -1
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuModels.d.ts +2 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.d.ts +3 -2
- package/es/flow/admin-shell/admin-layout/AdminLayoutSlotModels.d.ts +5 -0
- package/es/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.d.ts +6 -0
- package/es/flow/components/FieldAssignRulesEditor.d.ts +3 -1
- package/es/flow/components/FieldAssignValueInput.d.ts +2 -0
- package/es/flow/index.d.ts +1 -0
- package/es/flow/models/base/GridModel.d.ts +1 -1
- package/es/flow/models/blocks/filter-form/FilterFormBlockModel.d.ts +5 -0
- package/es/flow/models/blocks/form/FormBlockModel.d.ts +4 -0
- package/es/flow/models/blocks/form/submitHandler.d.ts +1 -1
- package/es/flow/models/blocks/form/value-runtime/rules.d.ts +21 -0
- package/es/flow/models/blocks/form/value-runtime/runtime.d.ts +30 -0
- package/es/flow/models/blocks/form/value-runtime/types.d.ts +2 -2
- package/es/flow/models/blocks/js-block/JSBlock.d.ts +1 -0
- package/es/flow/models/blocks/table/TableActionsColumnModel.d.ts +1 -0
- package/es/flow/models/blocks/table/TableBlockModel.d.ts +1 -0
- package/es/flow/models/blocks/table/dragSort/dragSortHooks.d.ts +1 -1
- package/es/flow/models/blocks/table/dragSort/dragSortSettings.d.ts +2 -1
- package/es/flow/models/blocks/table/dragSort/dragSortUtils.d.ts +6 -4
- package/es/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.d.ts +2 -0
- package/es/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.d.ts +6 -0
- package/es/flow/resolveViewParamsToViewList.d.ts +1 -1
- package/es/flow/utils/dataScopeRowSnapshot.d.ts +59 -0
- package/es/flow/utils/dateTimeDisplayProps.d.ts +49 -0
- package/es/flow/utils/formValueDeps.d.ts +32 -0
- package/es/flow-compat/FieldValidation.d.ts +2 -1
- package/es/index.d.ts +2 -1
- package/es/index.mjs +233 -137
- package/lib/index.js +234 -138
- package/package.json +7 -7
- package/src/PluginSettingsManager.ts +53 -0
- package/src/RouteRepository.ts +126 -24
- package/src/__tests__/PluginSettingsManager.test.ts +13 -0
- package/src/__tests__/RouteRepository.test.ts +216 -0
- package/src/__tests__/browserChecker.test.ts +61 -0
- package/src/__tests__/exports.test.ts +16 -0
- package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +199 -0
- package/src/__tests__/plugin-manager.test.tsx +44 -2
- package/src/__tests__/settings-center.test.tsx +40 -1
- package/src/collection-manager/field-configure.ts +1 -1
- package/src/collection-manager/interfaces/id.ts +1 -1
- package/src/collection-manager/interfaces/m2m.tsx +2 -2
- package/src/collection-manager/interfaces/m2o.tsx +2 -2
- package/src/collection-manager/interfaces/nanoid.ts +1 -1
- package/src/collection-manager/interfaces/o2m.tsx +2 -2
- package/src/collection-manager/interfaces/obo.tsx +2 -2
- package/src/collection-manager/interfaces/oho.tsx +2 -2
- package/src/collection-manager/interfaces/properties/index.ts +2 -2
- package/src/collection-manager/interfaces/uuid.ts +1 -1
- package/src/components/AppComponents.tsx +19 -3
- package/src/components/README.md +7 -1
- package/src/components/README.zh-CN.md +6 -1
- package/src/components/category-tabs/SortableCategoryTabs.tsx +210 -0
- package/src/components/category-tabs/index.ts +10 -0
- package/src/components/form/JsonTextArea.tsx +21 -11
- package/src/components/form/TypedVariableInput.tsx +416 -93
- package/src/components/form/VariableJsonTextArea.tsx +175 -0
- package/src/components/form/__tests__/JsonTextArea.test.tsx +43 -0
- package/src/components/form/__tests__/TypedVariableInput.test.tsx +268 -9
- package/src/components/form/__tests__/VariableJsonTextArea.test.tsx +86 -0
- package/src/components/form/filter/CollectionFilterItem.tsx +32 -7
- package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +38 -0
- package/src/components/form/filter/index.ts +2 -0
- package/src/components/form/index.tsx +1 -0
- package/src/components/index.ts +2 -0
- package/src/flow/__tests__/FlowRoute.test.tsx +443 -5
- package/src/flow/__tests__/getKey.test.ts +7 -0
- package/src/flow/__tests__/resolveViewParamsToViewList.test.ts +34 -0
- package/src/flow/actions/__tests__/afterSuccess.test.ts +73 -0
- package/src/flow/actions/__tests__/dataScopeFilter.test.ts +58 -0
- package/src/flow/actions/__tests__/dataScopeFormValueClear.test.ts +1022 -0
- package/src/flow/actions/__tests__/fieldLinkageRules.scopeDepth.test.ts +150 -1
- package/src/flow/actions/__tests__/linkageAssignField.legacy.test.ts +135 -0
- package/src/flow/actions/__tests__/linkageRules.hiddenSync.restore.test.ts +19 -5
- package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +92 -0
- package/src/flow/actions/__tests__/openView.defineProps.route.test.tsx +104 -0
- package/src/flow/actions/__tests__/subFormFieldLinkageRules.inputArgs.test.ts +2 -2
- package/src/flow/actions/afterSuccess.tsx +142 -3
- package/src/flow/actions/customVariable.tsx +1 -2
- package/src/flow/actions/dataScopeFilter.ts +10 -0
- package/src/flow/actions/dateTimeFormat.tsx +42 -28
- package/src/flow/actions/index.ts +1 -1
- package/src/flow/actions/linkageRules.tsx +123 -35
- package/src/flow/actions/linkageRulesFormValueRefresh.ts +22 -130
- package/src/flow/actions/openView.tsx +38 -4
- package/src/flow/actions/runjs.tsx +2 -14
- package/src/flow/actions/validation.tsx +62 -30
- package/src/flow/admin-shell/BaseLayoutModel.tsx +25 -3
- package/src/flow/admin-shell/BaseLayoutRouteCoordinator.ts +5 -2
- package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +13 -0
- package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +34 -10
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.test.tsx +310 -0
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +44 -8
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuFlowUtils.ts +5 -3
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuModels.tsx +61 -9
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.tsx +71 -8
- package/src/flow/admin-shell/admin-layout/AdminLayoutModel.tsx +1 -1
- package/src/flow/admin-shell/admin-layout/AdminLayoutSlotModels.tsx +23 -9
- package/src/flow/admin-shell/admin-layout/HelpLite.tsx +1 -3
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutComponent.test.tsx +188 -0
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +99 -0
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutModel.test.tsx +82 -0
- package/src/flow/admin-shell/admin-layout/__tests__/TopbarActionsBar.test.tsx +166 -2
- package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.test.ts +20 -0
- package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.ts +33 -5
- package/src/flow/components/DefaultValue.tsx +1 -2
- package/src/flow/components/DynamicFlowsIcon.tsx +447 -126
- package/src/flow/components/FieldAssignRulesEditor.tsx +128 -21
- package/src/flow/components/FieldAssignValueInput.tsx +10 -5
- package/src/flow/components/FlowRoute.tsx +56 -11
- package/src/flow/components/__tests__/DynamicFlowsIcon.test.tsx +148 -2
- package/src/flow/components/__tests__/FieldAssignRulesEditor.test.tsx +508 -4
- package/src/flow/components/__tests__/fieldAssignOptions.test.ts +151 -3
- package/src/flow/components/code-editor/__tests__/useCodeRunner.test.tsx +2 -17
- package/src/flow/components/code-editor/hooks/useCodeRunner.ts +2 -14
- package/src/flow/components/code-editor/runjsDiagnostics.ts +8 -45
- package/src/flow/components/fieldAssignOptions.ts +155 -27
- package/src/flow/flows/editMarkdownFlow.tsx +1 -1
- package/src/flow/getViewDiffAndUpdateHidden.tsx +1 -0
- package/src/flow/index.ts +2 -1
- package/src/flow/internal/utils/operatorSchemaHelper.ts +15 -1
- package/src/flow/models/actions/JSActionModel.tsx +2 -7
- package/src/flow/models/actions/JSCollectionActionModel.tsx +2 -7
- package/src/flow/models/actions/JSItemActionModel.tsx +2 -7
- package/src/flow/models/actions/JSRecordActionModel.tsx +2 -7
- package/src/flow/models/base/ActionModel.tsx +12 -1
- package/src/flow/models/base/ActionModelCore.tsx +6 -4
- package/src/flow/models/base/GridModel.tsx +38 -7
- package/src/flow/models/base/PageModel/PageModel.tsx +4 -1
- package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +28 -4
- package/src/flow/models/base/__tests__/ActionModel.test.ts +83 -0
- package/src/flow/models/base/__tests__/ActionModelCore.render.test.tsx +37 -0
- package/src/flow/models/base/__tests__/GridModel.dragSnapshotContainer.test.ts +239 -1
- package/src/flow/models/base/__tests__/transformRowsToSingleColumn.test.ts +48 -0
- package/src/flow/models/blocks/filter-form/FilterFormBlockModel.tsx +31 -3
- package/src/flow/models/blocks/filter-form/FilterFormJSActionModel.tsx +2 -7
- package/src/flow/models/blocks/filter-form/__tests__/defaultValues.wiring.test.ts +77 -0
- package/src/flow/models/blocks/filter-form/fields/FilterFormCustomFieldModel.tsx +1 -1
- package/src/flow/models/blocks/filter-manager/flow-actions/__tests__/customizeFilterRender.test.tsx +56 -1
- package/src/flow/models/blocks/form/EditFormModel.tsx +1 -0
- package/src/flow/models/blocks/form/FormActionModel.tsx +1 -1
- package/src/flow/models/blocks/form/FormBlockModel.tsx +7 -0
- package/src/flow/models/blocks/form/JSFormActionModel.tsx +2 -7
- package/src/flow/models/blocks/form/__tests__/FormBlockModel.test.tsx +17 -0
- package/src/flow/models/blocks/form/__tests__/submitHandler.test.ts +54 -1
- package/src/flow/models/blocks/form/submitHandler.ts +17 -3
- package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +940 -75
- package/src/flow/models/blocks/form/value-runtime/rules.ts +445 -13
- package/src/flow/models/blocks/form/value-runtime/runtime.ts +348 -13
- package/src/flow/models/blocks/form/value-runtime/types.ts +2 -2
- package/src/flow/models/blocks/js-block/JSBlock.tsx +225 -9
- package/src/flow/models/blocks/js-block/__tests__/JSBlockModel.test.tsx +150 -0
- package/src/flow/models/blocks/table/JSColumnModel.tsx +1 -9
- package/src/flow/models/blocks/table/TableActionsColumnModel.tsx +36 -13
- package/src/flow/models/blocks/table/TableBlockModel.tsx +38 -17
- package/src/flow/models/blocks/table/TableColumnModel.tsx +36 -3
- package/src/flow/models/blocks/table/__tests__/TableActionsColumnModel.test.tsx +111 -1
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.dragSort.test.ts +127 -0
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.mobileSettingsButtons.test.tsx +78 -0
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.rowSelection.test.tsx +1 -0
- package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +159 -1
- package/src/flow/models/blocks/table/dragSort/dragSortHooks.tsx +28 -17
- package/src/flow/models/blocks/table/dragSort/dragSortSettings.ts +13 -6
- package/src/flow/models/blocks/table/dragSort/dragSortUtils.ts +15 -2
- package/src/flow/models/fields/AssociationFieldModel/AssociationFieldModel.tsx +1 -1
- package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/PopupSubTableFieldModel.tsx +29 -6
- package/src/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.tsx +16 -4
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.tsx +141 -19
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableField.tsx +13 -1
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableColumnModel.rowRecord.test.ts +197 -0
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableFieldModel.reset.test.ts +180 -0
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.tsx +6 -4
- package/src/flow/models/fields/AssociationFieldModel/__tests__/AssociationFieldModel.updateAssociation.test.ts +72 -0
- package/src/flow/models/fields/AssociationFieldModel/__tests__/RecordPickerFieldModel.itemContext.test.ts +23 -0
- package/src/flow/models/fields/ClickableFieldModel.tsx +5 -0
- package/src/flow/models/fields/DisplayDateTimeFieldModel.tsx +29 -1
- package/src/flow/models/fields/InputFieldModel.tsx +40 -2
- package/src/flow/models/fields/JSEditableFieldModel.tsx +2 -11
- package/src/flow/models/fields/JSFieldModel.tsx +2 -7
- package/src/flow/models/fields/JSItemModel.tsx +2 -14
- package/src/flow/models/fields/SelectFieldModel.tsx +6 -4
- package/src/flow/models/fields/TextareaFieldModel.tsx +49 -3
- package/src/flow/models/fields/__tests__/DisplayDateTimeFieldModel.test.tsx +96 -0
- package/src/flow/models/fields/__tests__/InputFieldModel.test.tsx +117 -1
- package/src/flow/models/fields/__tests__/SelectFieldModel.test.tsx +43 -0
- package/src/flow/models/fields/__tests__/TextareaFieldModel.test.tsx +100 -0
- package/src/flow/models/topbar/TopbarActionModel.tsx +93 -10
- package/src/flow/resolveViewParamsToViewList.tsx +11 -3
- package/src/flow/utils/__tests__/dateTimeFormat.test.ts +258 -0
- package/src/flow/utils/dataScopeFormValueClear.ts +218 -81
- package/src/flow/utils/dataScopeRowSnapshot.ts +616 -0
- package/src/flow/utils/dateTimeDisplayProps.ts +135 -0
- package/src/flow/utils/formValueDeps.ts +170 -0
- package/src/flow-compat/FieldValidation.tsx +122 -60
- package/src/flow-compat/Popover.tsx +43 -4
- package/src/flow-compat/__tests__/Popover.test.tsx +34 -0
- package/src/index.ts +8 -1
- package/src/layout-manager/__tests__/LayoutRoute.test.tsx +41 -1
- package/src/nocobase-buildin-plugin/index.tsx +44 -14
- package/src/settings-center/AdminSettingsLayout.tsx +10 -2
- package/src/settings-center/SystemSettingsPage.tsx +1 -2
- package/src/settings-center/plugin-manager/PluginCard.tsx +2 -2
- package/src/settings-center/plugin-manager/index.tsx +3 -0
- package/src/settings-center/utils.tsx +0 -6
|
@@ -38,12 +38,18 @@ type FormBlockModel = FlowModel & {
|
|
|
38
38
|
getAclActionName?: () => string;
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
+
export type FormValuePatch = {
|
|
42
|
+
path: NamePath;
|
|
43
|
+
value: unknown;
|
|
44
|
+
};
|
|
45
|
+
|
|
41
46
|
export class FormValueRuntime {
|
|
42
47
|
private readonly model: FormBlockModel;
|
|
43
48
|
private readonly getForm: () => FormInstance;
|
|
44
49
|
|
|
45
50
|
private readonly valuesMirror = observable({});
|
|
46
51
|
private readonly explicitSet = new Set<string>();
|
|
52
|
+
private readonly userEditedSet = new Set<string>();
|
|
47
53
|
private readonly lastDefaultValueByPathKey = new Map<string, any>();
|
|
48
54
|
private readonly lastWriteMetaByPathKey = new Map<string, FormValueWriteMeta>();
|
|
49
55
|
private readonly observableBindings = new Map<string, ObservableBinding>();
|
|
@@ -59,6 +65,8 @@ export class FormValueRuntime {
|
|
|
59
65
|
private lastObservedToken = 0;
|
|
60
66
|
|
|
61
67
|
private readonly formValuesProxy: any;
|
|
68
|
+
private readonly mountedFieldModelsByPathKey = new Map<string, Set<FlowModel>>();
|
|
69
|
+
private readonly mountedFieldModelPathKeys = new WeakMap<FlowModel, Set<string>>();
|
|
62
70
|
|
|
63
71
|
private mountedListener?: (payload: { model: FlowModel }) => void;
|
|
64
72
|
private unmountedListener?: (payload: { model: FlowModel }) => void;
|
|
@@ -99,6 +107,7 @@ export class FormValueRuntime {
|
|
|
99
107
|
getFormValueAtPath: (namePath) => this.getFormValueAtPath(namePath),
|
|
100
108
|
setFormValues: (callerCtx, patch, ruleOptions) => this.setFormValues(callerCtx, patch, ruleOptions),
|
|
101
109
|
findExplicitHit: (pathKey) => this.findExplicitHit(pathKey),
|
|
110
|
+
findUserEditedHit: (pathKey) => this.findUserEditedHit(pathKey),
|
|
102
111
|
lastDefaultValueByPathKey: this.lastDefaultValueByPathKey,
|
|
103
112
|
lastWriteMetaByPathKey: this.lastWriteMetaByPathKey,
|
|
104
113
|
observableBindings: this.observableBindings,
|
|
@@ -117,6 +126,7 @@ export class FormValueRuntime {
|
|
|
117
126
|
*
|
|
118
127
|
* - mode=default → source=default(遵循 explicit/空值覆盖语义)
|
|
119
128
|
* - mode=assign → source=system(不受 explicit 影响,依赖变化时持续生效)
|
|
129
|
+
* - mode=override → source=override(首次覆盖已有值,用户修改后停止)
|
|
120
130
|
*/
|
|
121
131
|
syncAssignRules(items: FormAssignRuleItem[]) {
|
|
122
132
|
this.ruleEngine.syncAssignRules(items);
|
|
@@ -137,6 +147,58 @@ export class FormValueRuntime {
|
|
|
137
147
|
return this.getForm().getFieldsValue(true);
|
|
138
148
|
}
|
|
139
149
|
|
|
150
|
+
getUserEditedValuePatches(): FormValuePatch[] {
|
|
151
|
+
const snapshot = this.getFormValuesSnapshot();
|
|
152
|
+
if (!snapshot || typeof snapshot !== 'object') {
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const patches: FormValuePatch[] = [];
|
|
157
|
+
const pathKeys = Array.from(this.userEditedSet).sort(
|
|
158
|
+
(a, b) => pathKeyToNamePath(a).length - pathKeyToNamePath(b).length,
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
for (const pathKey of pathKeys) {
|
|
162
|
+
if (!this.isCurrentUserEditedPath(pathKey)) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const namePath = pathKeyToNamePath(pathKey);
|
|
167
|
+
if (!namePath.length || !_.has(snapshot, namePath as any)) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const value = _.get(snapshot, namePath as any);
|
|
172
|
+
if (typeof value === 'undefined') {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
patches.push({
|
|
177
|
+
path: namePath,
|
|
178
|
+
value: this.omitNonUserDescendantValues(pathKey, this.toMirrorSnapshot(value)),
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return patches;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
getUserEditedValuesSnapshot(): Record<string, unknown> {
|
|
186
|
+
const values: Record<string, unknown> = {};
|
|
187
|
+
for (const patch of this.getUserEditedValuePatches()) {
|
|
188
|
+
_.set(values, patch.path as any, patch.value);
|
|
189
|
+
}
|
|
190
|
+
return values;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
private toMirrorSnapshot(value: any) {
|
|
194
|
+
const raw = isObservable(value) ? toJS(value) : value;
|
|
195
|
+
return _.cloneDeepWith(raw, (item) => {
|
|
196
|
+
if (!item || typeof item !== 'object') return undefined;
|
|
197
|
+
if (Array.isArray(item) || _.isPlainObject(item)) return undefined;
|
|
198
|
+
return item;
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
140
202
|
canApplyDefaultValuePatch(namePath: NamePath, resolved: any) {
|
|
141
203
|
if (!namePath?.length) return false;
|
|
142
204
|
if (typeof resolved === 'undefined') return false;
|
|
@@ -153,19 +215,24 @@ export class FormValueRuntime {
|
|
|
153
215
|
|
|
154
216
|
const canOverwrite = isEmptyValue(current) || currentEqualsLastDefault;
|
|
155
217
|
if (!canOverwrite && _.isEqual(current, nextSnapshot)) {
|
|
156
|
-
this.lastDefaultValueByPathKey.set(pathKey, nextSnapshot);
|
|
218
|
+
this.lastDefaultValueByPathKey.set(pathKey, this.toMirrorSnapshot(nextSnapshot));
|
|
157
219
|
return false;
|
|
158
220
|
}
|
|
159
221
|
|
|
160
222
|
return canOverwrite;
|
|
161
223
|
}
|
|
162
224
|
|
|
225
|
+
canApplyOverrideValuePatch(namePath: NamePath) {
|
|
226
|
+
if (!namePath?.length) return false;
|
|
227
|
+
return !this.findUserEditedHit(namePathToPathKey(namePath));
|
|
228
|
+
}
|
|
229
|
+
|
|
163
230
|
recordDefaultValuePatch(namePath: NamePath, value?: any) {
|
|
164
231
|
if (!namePath?.length) return;
|
|
165
232
|
const pathKey = namePathToPathKey(namePath);
|
|
166
233
|
const snapshot =
|
|
167
234
|
arguments.length >= 2 ? (isObservable(value) ? toJS(value) : value) : this.getFormValueAtPath(namePath);
|
|
168
|
-
this.lastDefaultValueByPathKey.set(pathKey, snapshot);
|
|
235
|
+
this.lastDefaultValueByPathKey.set(pathKey, this.toMirrorSnapshot(snapshot));
|
|
169
236
|
const current = this.getFormValueAtPath(namePath);
|
|
170
237
|
const currentSnapshot = isObservable(current) ? toJS(current) : current;
|
|
171
238
|
if (_.isEqual(currentSnapshot, snapshot)) {
|
|
@@ -195,9 +262,11 @@ export class FormValueRuntime {
|
|
|
195
262
|
|
|
196
263
|
if (!this.mountedListener && !this.unmountedListener) {
|
|
197
264
|
this.mountedListener = ({ model }: { model: FlowModel }) => {
|
|
265
|
+
this.indexMountedFieldModelTree(model);
|
|
198
266
|
this.ruleEngine.onModelMounted(model);
|
|
199
267
|
};
|
|
200
268
|
this.unmountedListener = ({ model }: { model: FlowModel }) => {
|
|
269
|
+
this.unindexMountedFieldModelTree(model);
|
|
201
270
|
this.ruleEngine.onModelUnmounted(model);
|
|
202
271
|
};
|
|
203
272
|
|
|
@@ -205,10 +274,12 @@ export class FormValueRuntime {
|
|
|
205
274
|
engineEmitter.on('model:unmounted', this.unmountedListener);
|
|
206
275
|
}
|
|
207
276
|
|
|
277
|
+
this.rebuildMountedFieldModelIndex();
|
|
278
|
+
|
|
208
279
|
if (options?.sync) {
|
|
209
280
|
const snapshot = this.getFormValuesSnapshot();
|
|
210
281
|
if (snapshot && typeof snapshot === 'object') {
|
|
211
|
-
_.merge(this.valuesMirror, snapshot);
|
|
282
|
+
_.merge(this.valuesMirror, this.toMirrorSnapshot(snapshot));
|
|
212
283
|
this.bumpChangeTick();
|
|
213
284
|
}
|
|
214
285
|
this.ruleEngine.enable();
|
|
@@ -228,6 +299,7 @@ export class FormValueRuntime {
|
|
|
228
299
|
}
|
|
229
300
|
|
|
230
301
|
this.ruleEngine.dispose();
|
|
302
|
+
this.mountedFieldModelsByPathKey.clear();
|
|
231
303
|
|
|
232
304
|
for (const binding of this.observableBindings.values()) {
|
|
233
305
|
binding.dispose();
|
|
@@ -241,6 +313,7 @@ export class FormValueRuntime {
|
|
|
241
313
|
if (this.disposed) return;
|
|
242
314
|
|
|
243
315
|
this.explicitSet.clear();
|
|
316
|
+
this.userEditedSet.clear();
|
|
244
317
|
this.lastDefaultValueByPathKey.clear();
|
|
245
318
|
this.lastWriteMetaByPathKey.clear();
|
|
246
319
|
this.txWriteCounts.clear();
|
|
@@ -258,7 +331,7 @@ export class FormValueRuntime {
|
|
|
258
331
|
delete (this.valuesMirror as Record<string, any>)[key];
|
|
259
332
|
}
|
|
260
333
|
if (snapshot && typeof snapshot === 'object') {
|
|
261
|
-
_.merge(this.valuesMirror, snapshot);
|
|
334
|
+
_.merge(this.valuesMirror, this.toMirrorSnapshot(snapshot));
|
|
262
335
|
}
|
|
263
336
|
|
|
264
337
|
this.writeSeq += 1;
|
|
@@ -266,6 +339,13 @@ export class FormValueRuntime {
|
|
|
266
339
|
this.ruleEngine.rescheduleAllRules();
|
|
267
340
|
}
|
|
268
341
|
|
|
342
|
+
resetUserEditedState() {
|
|
343
|
+
if (this.disposed) return;
|
|
344
|
+
|
|
345
|
+
this.userEditedSet.clear();
|
|
346
|
+
this.ruleEngine.rescheduleAllRules();
|
|
347
|
+
}
|
|
348
|
+
|
|
269
349
|
isSuppressed() {
|
|
270
350
|
return this.suppressFormCallbackDepth > 0;
|
|
271
351
|
}
|
|
@@ -292,7 +372,7 @@ export class FormValueRuntime {
|
|
|
292
372
|
this.writeSeq += 1;
|
|
293
373
|
bumpedWriteSeq = true;
|
|
294
374
|
}
|
|
295
|
-
_.set(this.valuesMirror, namePath, nextValue);
|
|
375
|
+
_.set(this.valuesMirror, namePath, this.toMirrorSnapshot(nextValue));
|
|
296
376
|
changedPaths.push(namePath);
|
|
297
377
|
const isMeaningfulTouched =
|
|
298
378
|
field?.touched === true && !this.shouldIgnoreSyntheticTouchedInit(namePath, prevValue, nextValue);
|
|
@@ -311,6 +391,7 @@ export class FormValueRuntime {
|
|
|
311
391
|
if (!suppressed && touchedChangedPathKeys.size) {
|
|
312
392
|
for (const key of touchedChangedPathKeys) {
|
|
313
393
|
this.markExplicit(key);
|
|
394
|
+
this.markUserEdited(key);
|
|
314
395
|
}
|
|
315
396
|
}
|
|
316
397
|
|
|
@@ -374,6 +455,11 @@ export class FormValueRuntime {
|
|
|
374
455
|
this.explicitSet.delete(key);
|
|
375
456
|
}
|
|
376
457
|
|
|
458
|
+
for (const key of Array.from(this.userEditedSet)) {
|
|
459
|
+
if (!this.isDeletedArrayItemPath(key, snapshot)) continue;
|
|
460
|
+
this.userEditedSet.delete(key);
|
|
461
|
+
}
|
|
462
|
+
|
|
377
463
|
for (const key of Array.from(this.lastDefaultValueByPathKey.keys())) {
|
|
378
464
|
if (!this.isDeletedArrayItemPath(key, snapshot)) continue;
|
|
379
465
|
this.lastDefaultValueByPathKey.delete(key);
|
|
@@ -444,6 +530,7 @@ export class FormValueRuntime {
|
|
|
444
530
|
if (!nextIndexByIdentity.size) continue;
|
|
445
531
|
|
|
446
532
|
this.reconcileArrayItemSet(this.explicitSet, path, prevValue, nextIndexByIdentity);
|
|
533
|
+
this.reconcileArrayItemSet(this.userEditedSet, path, prevValue, nextIndexByIdentity);
|
|
447
534
|
this.reconcileArrayItemMap(this.lastDefaultValueByPathKey, path, prevValue, nextIndexByIdentity);
|
|
448
535
|
this.reconcileArrayItemMap(this.lastWriteMetaByPathKey, path, prevValue, nextIndexByIdentity);
|
|
449
536
|
this.reconcileObservableBindings(path, prevValue, nextIndexByIdentity);
|
|
@@ -647,7 +734,7 @@ export class FormValueRuntime {
|
|
|
647
734
|
this.writeSeq += 1;
|
|
648
735
|
bumpedWriteSeq = true;
|
|
649
736
|
}
|
|
650
|
-
_.set(this.valuesMirror, p, nextValue);
|
|
737
|
+
_.set(this.valuesMirror, p, this.toMirrorSnapshot(nextValue));
|
|
651
738
|
hasMirrorChange = true;
|
|
652
739
|
actuallyChangedPaths.push(p);
|
|
653
740
|
}
|
|
@@ -665,7 +752,11 @@ export class FormValueRuntime {
|
|
|
665
752
|
|
|
666
753
|
// 非 default 来源写入:需要使默认值永久失效(explicit)
|
|
667
754
|
for (const p of explicitPathsToMark) {
|
|
668
|
-
|
|
755
|
+
const pathKey = namePathToPathKey(p);
|
|
756
|
+
this.markExplicit(pathKey);
|
|
757
|
+
if (source === 'user') {
|
|
758
|
+
this.markUserEdited(pathKey);
|
|
759
|
+
}
|
|
669
760
|
}
|
|
670
761
|
|
|
671
762
|
if (hasMirrorChange) {
|
|
@@ -726,6 +817,9 @@ export class FormValueRuntime {
|
|
|
726
817
|
seen,
|
|
727
818
|
);
|
|
728
819
|
}
|
|
820
|
+
if (prevValue.length !== nextValue.length) {
|
|
821
|
+
return nestedCount + (this.pushExplicitPath(basePath, explicitPaths, seen) ? 1 : 0);
|
|
822
|
+
}
|
|
729
823
|
return nestedCount;
|
|
730
824
|
}
|
|
731
825
|
|
|
@@ -870,7 +964,8 @@ export class FormValueRuntime {
|
|
|
870
964
|
} else {
|
|
871
965
|
form.setFieldsValue?.({ [pathKey]: value });
|
|
872
966
|
}
|
|
873
|
-
_.set(this.valuesMirror, [pathKey], value);
|
|
967
|
+
_.set(this.valuesMirror, [pathKey], this.toMirrorSnapshot(value));
|
|
968
|
+
this.syncMountedFieldModelValue([pathKey], value);
|
|
874
969
|
}
|
|
875
970
|
this.bumpChangeTick();
|
|
876
971
|
} finally {
|
|
@@ -885,6 +980,9 @@ export class FormValueRuntime {
|
|
|
885
980
|
if (markExplicit) {
|
|
886
981
|
for (const k of patchKeys) {
|
|
887
982
|
this.markExplicit(k);
|
|
983
|
+
if (source === 'user') {
|
|
984
|
+
this.markUserEdited(k);
|
|
985
|
+
}
|
|
888
986
|
}
|
|
889
987
|
}
|
|
890
988
|
|
|
@@ -969,7 +1067,8 @@ export class FormValueRuntime {
|
|
|
969
1067
|
try {
|
|
970
1068
|
for (const { namePath, value } of filteredToWrite) {
|
|
971
1069
|
form.setFieldValue?.(namePath, value);
|
|
972
|
-
_.set(this.valuesMirror, namePath, value);
|
|
1070
|
+
_.set(this.valuesMirror, namePath, this.toMirrorSnapshot(value));
|
|
1071
|
+
this.syncMountedFieldModelValue(namePath, value);
|
|
973
1072
|
changedPaths.push(namePath);
|
|
974
1073
|
}
|
|
975
1074
|
this.bumpChangeTick();
|
|
@@ -984,13 +1083,16 @@ export class FormValueRuntime {
|
|
|
984
1083
|
if (markExplicit) {
|
|
985
1084
|
for (const { pathKey } of filteredToWrite) {
|
|
986
1085
|
this.markExplicit(pathKey);
|
|
1086
|
+
if (source === 'user') {
|
|
1087
|
+
this.markUserEdited(pathKey);
|
|
1088
|
+
}
|
|
987
1089
|
}
|
|
988
1090
|
}
|
|
989
1091
|
|
|
990
1092
|
if (source === 'default') {
|
|
991
1093
|
for (const { namePath, pathKey } of filteredToWrite) {
|
|
992
1094
|
const current = this.getFormValueAtPath(namePath);
|
|
993
|
-
this.lastDefaultValueByPathKey.set(pathKey, current);
|
|
1095
|
+
this.lastDefaultValueByPathKey.set(pathKey, this.toMirrorSnapshot(current));
|
|
994
1096
|
}
|
|
995
1097
|
}
|
|
996
1098
|
|
|
@@ -1052,6 +1154,7 @@ export class FormValueRuntime {
|
|
|
1052
1154
|
if (this.disposed) return;
|
|
1053
1155
|
const form = this.getForm?.();
|
|
1054
1156
|
if (!form) return;
|
|
1157
|
+
if (source === 'override' && this.findUserEditedHit(pathKey)) return;
|
|
1055
1158
|
|
|
1056
1159
|
const prevValue = _.get(this.valuesMirror, namePath);
|
|
1057
1160
|
if (_.isEqual(prevValue, nextValue)) return;
|
|
@@ -1062,7 +1165,8 @@ export class FormValueRuntime {
|
|
|
1062
1165
|
this.suppressFormCallbackDepth++;
|
|
1063
1166
|
try {
|
|
1064
1167
|
form.setFieldValue?.(namePath, nextValue);
|
|
1065
|
-
_.set(this.valuesMirror, namePath, nextValue);
|
|
1168
|
+
_.set(this.valuesMirror, namePath, this.toMirrorSnapshot(nextValue));
|
|
1169
|
+
this.syncMountedFieldModelValue(namePath, nextValue);
|
|
1066
1170
|
this.bumpChangeTick();
|
|
1067
1171
|
} finally {
|
|
1068
1172
|
this.suppressFormCallbackDepth--;
|
|
@@ -1098,7 +1202,10 @@ export class FormValueRuntime {
|
|
|
1098
1202
|
}
|
|
1099
1203
|
this.emitFormValuesChange(payload);
|
|
1100
1204
|
|
|
1101
|
-
if (
|
|
1205
|
+
if (
|
|
1206
|
+
(source === 'default' && this.isExplicit(pathKey)) ||
|
|
1207
|
+
(source === 'override' && this.findUserEditedHit(pathKey))
|
|
1208
|
+
) {
|
|
1102
1209
|
const existing = this.observableBindings.get(pathKey);
|
|
1103
1210
|
if (existing) {
|
|
1104
1211
|
existing.dispose();
|
|
@@ -1107,7 +1214,7 @@ export class FormValueRuntime {
|
|
|
1107
1214
|
}
|
|
1108
1215
|
|
|
1109
1216
|
if (source === 'default') {
|
|
1110
|
-
this.lastDefaultValueByPathKey.set(pathKey, this.getFormValueAtPath(namePath));
|
|
1217
|
+
this.lastDefaultValueByPathKey.set(pathKey, this.toMirrorSnapshot(this.getFormValueAtPath(namePath)));
|
|
1111
1218
|
}
|
|
1112
1219
|
}
|
|
1113
1220
|
|
|
@@ -1133,6 +1240,148 @@ export class FormValueRuntime {
|
|
|
1133
1240
|
this.model.emitter?.emit?.('formValuesChange', payload);
|
|
1134
1241
|
}
|
|
1135
1242
|
|
|
1243
|
+
private syncMountedFieldModelValue(namePath: NamePath, value: unknown) {
|
|
1244
|
+
const targetKey = namePathToPathKey(namePath);
|
|
1245
|
+
if (!targetKey) return;
|
|
1246
|
+
|
|
1247
|
+
const models = this.mountedFieldModelsByPathKey.get(targetKey);
|
|
1248
|
+
if (!models?.size) return;
|
|
1249
|
+
|
|
1250
|
+
const visited = new Set<FlowModel>();
|
|
1251
|
+
for (const model of Array.from(models)) {
|
|
1252
|
+
this.syncMountedFieldModelValueForModel(model, value, visited);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
private syncMountedFieldModelValueForModel(
|
|
1257
|
+
model: FlowModel | null | undefined,
|
|
1258
|
+
value: unknown,
|
|
1259
|
+
visited: Set<FlowModel>,
|
|
1260
|
+
) {
|
|
1261
|
+
if (!model || visited.has(model)) return;
|
|
1262
|
+
visited.add(model);
|
|
1263
|
+
if (!this.isMountedModelInThisForm(model)) return;
|
|
1264
|
+
|
|
1265
|
+
const nextProps = { value };
|
|
1266
|
+
model.setProps?.(nextProps);
|
|
1267
|
+
const fieldModel = (model as FlowModel & { subModels?: { field?: FlowModel } }).subModels?.field;
|
|
1268
|
+
fieldModel?.setProps?.(nextProps);
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
private rebuildMountedFieldModelIndex() {
|
|
1272
|
+
this.mountedFieldModelsByPathKey.clear();
|
|
1273
|
+
const engine = this.model?.context?.engine;
|
|
1274
|
+
if (!engine || typeof engine.forEachModel !== 'function') return;
|
|
1275
|
+
|
|
1276
|
+
engine.forEachModel((model: FlowModel) => {
|
|
1277
|
+
this.indexMountedFieldModelTree(model);
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
private indexMountedFieldModelTree(model: FlowModel | null | undefined) {
|
|
1282
|
+
this.visitModelAndForks(model, (item) => this.indexMountedFieldModel(item));
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
private unindexMountedFieldModelTree(model: FlowModel | null | undefined) {
|
|
1286
|
+
this.visitModelAndForks(model, (item) => this.unindexMountedFieldModel(item));
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
private visitModelAndForks(model: FlowModel | null | undefined, visit: (model: FlowModel) => void) {
|
|
1290
|
+
if (!model) return;
|
|
1291
|
+
const visited = new Set<FlowModel>();
|
|
1292
|
+
const walk = (item: FlowModel | null | undefined) => {
|
|
1293
|
+
if (!item || visited.has(item)) return;
|
|
1294
|
+
visited.add(item);
|
|
1295
|
+
visit(item);
|
|
1296
|
+
const forks = (item as FlowModel & { forks?: { forEach?: (cb: (fork: FlowModel) => void) => void } }).forks;
|
|
1297
|
+
forks?.forEach?.((fork) => walk(fork));
|
|
1298
|
+
};
|
|
1299
|
+
walk(model);
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
private indexMountedFieldModel(model: FlowModel) {
|
|
1303
|
+
if (!this.isMountedModelInThisForm(model)) return;
|
|
1304
|
+
|
|
1305
|
+
const pathKeys = new Set<string>();
|
|
1306
|
+
for (const path of this.getMountedModelNamePaths(model)) {
|
|
1307
|
+
const key = namePathToPathKey(path);
|
|
1308
|
+
if (key) pathKeys.add(key);
|
|
1309
|
+
}
|
|
1310
|
+
if (!pathKeys.size) return;
|
|
1311
|
+
|
|
1312
|
+
this.unindexMountedFieldModel(model);
|
|
1313
|
+
this.mountedFieldModelPathKeys.set(model, pathKeys);
|
|
1314
|
+
|
|
1315
|
+
for (const key of pathKeys) {
|
|
1316
|
+
const models = this.mountedFieldModelsByPathKey.get(key) || new Set<FlowModel>();
|
|
1317
|
+
models.add(model);
|
|
1318
|
+
this.mountedFieldModelsByPathKey.set(key, models);
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
private unindexMountedFieldModel(model: FlowModel) {
|
|
1323
|
+
const pathKeys = this.mountedFieldModelPathKeys.get(model);
|
|
1324
|
+
if (!pathKeys) return;
|
|
1325
|
+
|
|
1326
|
+
for (const key of pathKeys) {
|
|
1327
|
+
const models = this.mountedFieldModelsByPathKey.get(key);
|
|
1328
|
+
if (!models) continue;
|
|
1329
|
+
models.delete(model);
|
|
1330
|
+
if (!models.size) {
|
|
1331
|
+
this.mountedFieldModelsByPathKey.delete(key);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
this.mountedFieldModelPathKeys.delete(model);
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
private isMountedModelInThisForm(model: FlowModel) {
|
|
1339
|
+
const blockModel = (model.context as { blockModel?: FlowModel } | undefined)?.blockModel;
|
|
1340
|
+
return !!blockModel && String(blockModel.uid) === String(this.model.uid);
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
private getMountedModelNamePaths(model: FlowModel): NamePath[] {
|
|
1344
|
+
const paths: NamePath[] = [];
|
|
1345
|
+
const push = (value: unknown) => {
|
|
1346
|
+
const path = this.normalizeNamePathValue(value);
|
|
1347
|
+
if (path?.length) paths.push(path);
|
|
1348
|
+
};
|
|
1349
|
+
|
|
1350
|
+
push((model.context as { fieldPathArray?: unknown } | undefined)?.fieldPathArray);
|
|
1351
|
+
|
|
1352
|
+
const props = typeof model.getProps === 'function' ? model.getProps() : (model as { props?: unknown }).props;
|
|
1353
|
+
if (props && typeof props === 'object') {
|
|
1354
|
+
push((props as { name?: unknown }).name);
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
try {
|
|
1358
|
+
const init = model.getStepParams?.('fieldSettings', 'init');
|
|
1359
|
+
if (init && typeof init === 'object') {
|
|
1360
|
+
push((init as { fieldPath?: unknown }).fieldPath);
|
|
1361
|
+
}
|
|
1362
|
+
} catch {
|
|
1363
|
+
// ignore models without field settings
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
const seen = new Set<string>();
|
|
1367
|
+
return paths.filter((path) => {
|
|
1368
|
+
const key = namePathToPathKey(path);
|
|
1369
|
+
if (!key || seen.has(key)) return false;
|
|
1370
|
+
seen.add(key);
|
|
1371
|
+
return true;
|
|
1372
|
+
});
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
private normalizeNamePathValue(value: unknown): NamePath | null {
|
|
1376
|
+
if (Array.isArray(value)) {
|
|
1377
|
+
const path = value.filter((seg): seg is string | number => typeof seg === 'string' || typeof seg === 'number');
|
|
1378
|
+
return path.length === value.length ? path : null;
|
|
1379
|
+
}
|
|
1380
|
+
if (typeof value === 'number') return [value];
|
|
1381
|
+
if (typeof value === 'string' && value) return pathKeyToNamePath(value);
|
|
1382
|
+
return null;
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1136
1385
|
private markExplicit(pathKey: string) {
|
|
1137
1386
|
if (this.explicitSet.has(pathKey)) return;
|
|
1138
1387
|
this.explicitSet.add(pathKey);
|
|
@@ -1154,6 +1403,18 @@ export class FormValueRuntime {
|
|
|
1154
1403
|
}
|
|
1155
1404
|
}
|
|
1156
1405
|
|
|
1406
|
+
private markUserEdited(pathKey: string) {
|
|
1407
|
+
if (this.userEditedSet.has(pathKey)) return;
|
|
1408
|
+
this.userEditedSet.add(pathKey);
|
|
1409
|
+
|
|
1410
|
+
for (const [k, binding] of Array.from(this.observableBindings.entries())) {
|
|
1411
|
+
if (binding.source !== 'override') continue;
|
|
1412
|
+
if (!this.findUserEditedHit(k)) continue;
|
|
1413
|
+
binding.dispose();
|
|
1414
|
+
this.observableBindings.delete(k);
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1157
1418
|
private normalizeObservedNamePath(name: NamePath | string | number | undefined): NamePath | null {
|
|
1158
1419
|
if (Array.isArray(name)) return name as NamePath;
|
|
1159
1420
|
if (typeof name === 'number') return [name];
|
|
@@ -1216,4 +1477,78 @@ export class FormValueRuntime {
|
|
|
1216
1477
|
}
|
|
1217
1478
|
return null;
|
|
1218
1479
|
}
|
|
1480
|
+
|
|
1481
|
+
private findUserEditedHit(pathKey: string): string | null {
|
|
1482
|
+
if (this.userEditedSet.has(pathKey)) return pathKey;
|
|
1483
|
+
const namePath = pathKeyToNamePath(pathKey);
|
|
1484
|
+
const prefix: NamePath = [];
|
|
1485
|
+
|
|
1486
|
+
for (let i = 0; i < namePath.length; i++) {
|
|
1487
|
+
prefix.push(namePath[i]);
|
|
1488
|
+
const key = namePathToPathKey(prefix as any);
|
|
1489
|
+
if (!this.userEditedSet.has(key)) continue;
|
|
1490
|
+
|
|
1491
|
+
const nextSeg = namePath[i + 1];
|
|
1492
|
+
if (typeof nextSeg === 'number') {
|
|
1493
|
+
continue;
|
|
1494
|
+
}
|
|
1495
|
+
return key;
|
|
1496
|
+
}
|
|
1497
|
+
for (const key of this.userEditedSet) {
|
|
1498
|
+
if (!this.isDescendantPathKey(key, pathKey)) continue;
|
|
1499
|
+
return key;
|
|
1500
|
+
}
|
|
1501
|
+
return null;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
private findLatestWriteMeta(pathKey: string): FormValueWriteMeta | undefined {
|
|
1505
|
+
let latest: FormValueWriteMeta | undefined;
|
|
1506
|
+
const namePath = pathKeyToNamePath(pathKey);
|
|
1507
|
+
const prefix: NamePath = [];
|
|
1508
|
+
|
|
1509
|
+
for (let i = 0; i < namePath.length; i++) {
|
|
1510
|
+
prefix.push(namePath[i]);
|
|
1511
|
+
const meta = this.lastWriteMetaByPathKey.get(namePathToPathKey(prefix as any));
|
|
1512
|
+
if (!meta) {
|
|
1513
|
+
continue;
|
|
1514
|
+
}
|
|
1515
|
+
if (!latest || meta.writeSeq >= latest.writeSeq) {
|
|
1516
|
+
latest = meta;
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
return latest;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
private isCurrentUserEditedPath(pathKey: string) {
|
|
1524
|
+
const lastWrite = this.findLatestWriteMeta(pathKey);
|
|
1525
|
+
return !lastWrite || lastWrite.source === 'user';
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
private omitNonUserDescendantValues(pathKey: string, value: unknown) {
|
|
1529
|
+
if (!value || typeof value !== 'object') {
|
|
1530
|
+
return value;
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
const namePath = pathKeyToNamePath(pathKey);
|
|
1534
|
+
for (const childKey of this.lastWriteMetaByPathKey.keys()) {
|
|
1535
|
+
if (!this.isDescendantPathKey(childKey, pathKey)) {
|
|
1536
|
+
continue;
|
|
1537
|
+
}
|
|
1538
|
+
if (this.isCurrentUserEditedPath(childKey)) {
|
|
1539
|
+
continue;
|
|
1540
|
+
}
|
|
1541
|
+
_.unset(value as Record<string, unknown>, pathKeyToNamePath(childKey).slice(namePath.length) as any);
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
return value;
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
private isDescendantPathKey(candidateKey: string, parentKey: string) {
|
|
1548
|
+
if (!candidateKey || !parentKey || candidateKey === parentKey) return false;
|
|
1549
|
+
const candidatePath = pathKeyToNamePath(candidateKey);
|
|
1550
|
+
const parentPath = pathKeyToNamePath(parentKey);
|
|
1551
|
+
if (candidatePath.length <= parentPath.length) return false;
|
|
1552
|
+
return parentPath.every((seg, index) => candidatePath[index] === seg);
|
|
1553
|
+
}
|
|
1219
1554
|
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
export type NamePath = Array<string | number>;
|
|
11
11
|
|
|
12
|
-
export type ValueSource = 'default' | 'linkage' | 'user' | 'system';
|
|
12
|
+
export type ValueSource = 'default' | 'linkage' | 'user' | 'system' | 'override';
|
|
13
13
|
|
|
14
14
|
export type Patch =
|
|
15
15
|
| Record<string, any>
|
|
@@ -57,7 +57,7 @@ export interface FormValuesChangePayload {
|
|
|
57
57
|
allValuesSnapshot?: any;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
export type AssignMode = 'default' | 'assign';
|
|
60
|
+
export type AssignMode = 'default' | 'assign' | 'override';
|
|
61
61
|
|
|
62
62
|
export type FormAssignRuleItem = {
|
|
63
63
|
key?: string;
|