feat(data-validation): code optimize for data-validation (#2815)

This commit is contained in:
zhangw
2024-07-20 13:41:50 +08:00
committed by GitHub
parent ea92192833
commit ab242a32a1
15 changed files with 89 additions and 83 deletions
@@ -37,7 +37,7 @@ export interface IAddDataValidationCommandParams extends ISheetCommandSharedPara
export const AddDataValidationCommand: ICommand<IAddDataValidationCommandParams> = {
type: CommandType.COMMAND,
id: 'data-validation.command.addRule',
async handler(accessor, params) {
async handler(accessor, params) {
const logService = accessor.get(ILogService);
logService.warn('[Deprecated] AddDataValidationCommand is deprecated, please use AddSheetDataValidationCommand in @univerjs/sheets-data-validation instead!');
if (!params) {
@@ -83,7 +83,7 @@ export interface IRemoveDataValidationCommandParams extends ISheetCommandSharedP
export const removeDataValidationUndoFactory = (accessor: Injector, redoParams: IRemoveDataValidationMutationParams) => {
const dataValidationModel = accessor.get(DataValidationModel);
const { unitId, subUnitId, ruleId } = redoParams;
const { unitId, subUnitId, ruleId, source } = redoParams;
if (Array.isArray(ruleId)) {
const rules = ruleId.map((id) => dataValidationModel.getRuleById(unitId, subUnitId, id)).filter(Boolean) as ISheetDataValidationRule[];
return [{
@@ -92,6 +92,7 @@ export const removeDataValidationUndoFactory = (accessor: Injector, redoParams:
unitId,
subUnitId,
rule: rules,
source,
} as IAddDataValidationMutationParams,
}];
}
@@ -18,11 +18,13 @@ import { CommandType } from '@univerjs/core';
import type { ICommand, IDataValidationRule } from '@univerjs/core';
import type { ISheetCommandSharedParams } from '@univerjs/sheets';
import type { IUpdateRulePayload } from '../../types/interfaces/i-update-rule-payload';
import type { DataValidationChangeSource } from '../../models/data-validation-model';
import { DataValidationModel } from '../../models/data-validation-model';
export interface IAddDataValidationMutationParams extends ISheetCommandSharedParams {
rule: IDataValidationRule | IDataValidationRule[];
index?: number;
source?: DataValidationChangeSource;
}
export const AddDataValidationMutation: ICommand<IAddDataValidationMutationParams> = {
@@ -32,9 +34,9 @@ export const AddDataValidationMutation: ICommand<IAddDataValidationMutationParam
if (!params) {
return false;
}
const { unitId, subUnitId, rule, index } = params;
const { unitId, subUnitId, rule, index, source = 'command' } = params;
const dataValidationModel = accessor.get(DataValidationModel);
dataValidationModel.addRule(unitId, subUnitId, rule, index);
dataValidationModel.addRule(unitId, subUnitId, rule, source, index);
return true;
},
@@ -42,6 +44,7 @@ export const AddDataValidationMutation: ICommand<IAddDataValidationMutationParam
export interface IRemoveDataValidationMutationParams extends ISheetCommandSharedParams {
ruleId: string | string[];
source?: DataValidationChangeSource;
}
export const RemoveDataValidationMutation: ICommand<IRemoveDataValidationMutationParams> = {
@@ -52,14 +55,14 @@ export const RemoveDataValidationMutation: ICommand<IRemoveDataValidationMutatio
return false;
}
const { unitId, subUnitId, ruleId } = params;
const { unitId, subUnitId, ruleId, source = 'command' } = params;
const dataValidationModel = accessor.get(DataValidationModel);
if (Array.isArray(ruleId)) {
ruleId.forEach((item) => {
dataValidationModel.removeRule(unitId, subUnitId, item);
dataValidationModel.removeRule(unitId, subUnitId, item, source);
});
} else {
dataValidationModel.removeRule(unitId, subUnitId, ruleId);
dataValidationModel.removeRule(unitId, subUnitId, ruleId, source);
}
return true;
@@ -69,6 +72,7 @@ export const RemoveDataValidationMutation: ICommand<IRemoveDataValidationMutatio
export interface IUpdateDataValidationMutationParams extends ISheetCommandSharedParams {
payload: IUpdateRulePayload;
ruleId: string;
source?: DataValidationChangeSource;
}
export const UpdateDataValidationMutation: ICommand<IUpdateDataValidationMutationParams> = {
@@ -79,9 +83,9 @@ export const UpdateDataValidationMutation: ICommand<IUpdateDataValidationMutatio
return false;
}
const { unitId, subUnitId, ruleId, payload } = params;
const { unitId, subUnitId, ruleId, payload, source = 'command' } = params;
const dataValidationModel = accessor.get(DataValidationModel);
dataValidationModel.updateRule(unitId, subUnitId, ruleId, payload);
dataValidationModel.updateRule(unitId, subUnitId, ruleId, payload, source);
return true;
},
};
@@ -68,7 +68,7 @@ export class DataValidationResourceController extends Disposable {
Object.keys(value).forEach((subunitId) => {
const ruleList = value[subunitId];
ruleList.forEach((rule) => {
this._dataValidationModel.addRule(unitID, subunitId, rule);
this._dataValidationModel.addRule(unitID, subunitId, rule, 'patched');
});
});
},
@@ -61,11 +61,13 @@ export class DataValidationSheetController extends Disposable {
unitId,
subUnitId,
ruleId: ids,
source: 'patched',
};
const undoParams: IAddDataValidationMutationParams = {
unitId,
subUnitId,
rule: rules,
source: 'patched',
};
return {
+1 -1
View File
@@ -16,7 +16,7 @@
export { UniverDataValidationPlugin } from './plugin';
export { DataValidatorRegistryService, DataValidatorRegistryScope } from './services/data-validator-registry.service';
export { DataValidationModel } from './models/data-validation-model';
export { DataValidationModel, type DataValidationChangeSource } from './models/data-validation-model';
export {
createDefaultNewRule,
@@ -16,29 +16,24 @@
import type { CellValue, IDataValidationRule, Nullable } from '@univerjs/core';
import { DataValidationStatus, Disposable } from '@univerjs/core';
import { Subject } from 'rxjs';
import { BehaviorSubject } from 'rxjs';
import type { IUpdateRulePayload } from '../types/interfaces/i-update-rule-payload';
import { UpdateRuleType } from '../types/enum/update-rule-type';
import { getRuleOptions, getRuleSetting } from '../common/util';
export class DataValidationManager<T extends IDataValidationRule> extends Disposable {
private _dataValidations: T[];
private _dataValidations: T[] = [];
private _dataValidationMap = new Map<string, T>();
private _dataValidations$ = new Subject<T[]>();
private _dataValidations$ = new BehaviorSubject<T[]>(this._dataValidations);
readonly unitId: string;
readonly subUnitId: string;
readonly dataValidations$ = this._dataValidations$.asObservable();
constructor(unitId: string, subUnitId: string, dataValidations: T[] | undefined) {
constructor(unitId: string, subUnitId: string) {
super();
this.unitId = unitId;
this.subUnitId = subUnitId;
if (!dataValidations) {
return;
}
this._insertRules(dataValidations);
this._notice();
this.disposeWithMe({
@@ -52,13 +47,6 @@ export class DataValidationManager<T extends IDataValidationRule> extends Dispos
this._dataValidations$.next(this._dataValidations);
}
private _insertRules(dataValidations: T[]) {
this._dataValidations = dataValidations;
dataValidations.forEach((validation) => {
this._dataValidationMap.set(validation.uid, validation);
});
}
getRuleById(id: string) {
return this._dataValidationMap.get(id);
}
@@ -20,13 +20,15 @@ import type { IUpdateRulePayload } from '../types/interfaces/i-update-rule-paylo
import { DataValidationManager } from './data-validation-manager';
type ManagerCreator<T extends IDataValidationRule> = (unitId: string, subUnitId: string) => DataValidationManager<T>;
type RuleChangeType = 'update' | 'add' | 'remove';
type DataValidationChangeType = 'update' | 'add' | 'remove';
export type DataValidationChangeSource = 'command' | 'patched';
export interface IRuleChange<T extends IDataValidationRule> {
rule?: T;
type: RuleChangeType;
type: DataValidationChangeType;
unitId: string;
subUnitId: string;
source: DataValidationChangeSource;
}
export interface IValidStatusChange {
@@ -38,7 +40,7 @@ export interface IValidStatusChange {
export class DataValidationModel<T extends IDataValidationRule = IDataValidationRule> extends Disposable {
private readonly _model = new Map<string, Map<string, DataValidationManager<T>>>();
private _managerCreator: ManagerCreator<T> = (unitId: string, subUnitId: string) => new DataValidationManager<T>(unitId, subUnitId, []);
private _managerCreator: ManagerCreator<T> = (unitId: string, subUnitId: string) => new DataValidationManager<T>(unitId, subUnitId);
private readonly _ruleChange$ = new Subject<IRuleChange<T>>();
private readonly _validStatusChange$ = new Subject<IValidStatusChange>();
@@ -75,10 +77,11 @@ export class DataValidationModel<T extends IDataValidationRule = IDataValidation
const manager = this._managerCreator(unitId, subUnitId);
unitMap.set(subUnitId, manager);
this.disposeWithMe(manager);
return manager;
}
private _addRuleSideEffect(unitId: string, subUnitId: string, rule: T) {
private _addRuleSideEffect(unitId: string, subUnitId: string, rule: T, source: DataValidationChangeSource) {
const manager = this.ensureManager(unitId, subUnitId);
const oldRule = manager.getRuleById(rule.uid);
if (oldRule) {
@@ -89,15 +92,16 @@ export class DataValidationModel<T extends IDataValidationRule = IDataValidation
type: 'add',
unitId,
subUnitId,
source,
});
}
addRule(unitId: string, subUnitId: string, rule: T | T[], index?: number) {
addRule(unitId: string, subUnitId: string, rule: T | T[], source: DataValidationChangeSource, index?: number) {
try {
const manager = this.ensureManager(unitId, subUnitId);
const rules = Array.isArray(rule) ? rule : [rule];
rules.forEach((item) => {
this._addRuleSideEffect(unitId, subUnitId, item);
this._addRuleSideEffect(unitId, subUnitId, item, source);
});
manager.addRule(rule, index);
@@ -106,7 +110,7 @@ export class DataValidationModel<T extends IDataValidationRule = IDataValidation
}
}
updateRule(unitId: string, subUnitId: string, ruleId: string, payload: IUpdateRulePayload) {
updateRule(unitId: string, subUnitId: string, ruleId: string, payload: IUpdateRulePayload, source: DataValidationChangeSource) {
try {
const manager = this.ensureManager(unitId, subUnitId);
const rule = manager.updateRule(ruleId, payload);
@@ -116,13 +120,14 @@ export class DataValidationModel<T extends IDataValidationRule = IDataValidation
type: 'update',
unitId,
subUnitId,
source,
});
} catch (error) {
this._logService.error(error);
}
}
removeRule(unitId: string, subUnitId: string, ruleId: string) {
removeRule(unitId: string, subUnitId: string, ruleId: string, source: DataValidationChangeSource) {
try {
const manager = this.ensureManager(unitId, subUnitId);
const oldRule = manager.getRuleById(ruleId);
@@ -133,6 +138,7 @@ export class DataValidationModel<T extends IDataValidationRule = IDataValidation
type: 'remove',
unitId,
subUnitId,
source,
});
}
} catch (error) {
@@ -16,7 +16,7 @@
import { CommandType, DataValidationType, ICommandService, IUndoRedoService, IUniverInstanceService, ObjectMatrix, Range, sequenceExecute, sequenceExecuteAsync, Tools } from '@univerjs/core';
import type { CellValue, IAccessor, ICellData, ICommand, IDataValidationRuleBase, IDataValidationRuleOptions, IMutationInfo, IRange, ISheetDataValidationRule, Nullable } from '@univerjs/core';
import type { IAddDataValidationMutationParams, IUpdateDataValidationMutationParams } from '@univerjs/data-validation';
import type { DataValidationChangeSource, IAddDataValidationMutationParams, IUpdateDataValidationMutationParams } from '@univerjs/data-validation';
import { AddDataValidationMutation, createDefaultNewRule, DataValidationModel, DataValidatorRegistryService, getRuleOptions, getRuleSetting, RemoveDataValidationMutation, UpdateDataValidationMutation, UpdateRuleType } from '@univerjs/data-validation';
import type { ISetRangeValuesMutationParams, ISheetCommandSharedParams } from '@univerjs/sheets';
import { getSheetCommandTarget, SetRangeValuesMutation, SetRangeValuesUndoMutationFactory } from '@univerjs/sheets';
@@ -51,7 +51,8 @@ export function getDataValidationDiffMutations(
unitId: string,
subUnitId: string,
diffs: RangeMutation[],
accessor: IAccessor
accessor: IAccessor,
source: DataValidationChangeSource = 'command'
) {
const redoMutations: IMutationInfo[] = [];
const undoMutations: IMutationInfo[] = [];
@@ -93,6 +94,7 @@ export function getDataValidationDiffMutations(
unitId,
subUnitId,
ruleId: diff.rule.uid,
source,
},
});
undoMutations.unshift({
@@ -102,6 +104,7 @@ export function getDataValidationDiffMutations(
subUnitId,
rule: diff.rule,
index: diff.index,
source,
},
});
break;
@@ -116,6 +119,7 @@ export function getDataValidationDiffMutations(
type: UpdateRuleType.RANGE,
payload: diff.newRanges,
},
source,
} as IUpdateDataValidationMutationParams,
});
undoMutations.unshift({
@@ -128,6 +132,7 @@ export function getDataValidationDiffMutations(
type: UpdateRuleType.RANGE,
payload: diff.oldRanges,
},
source,
} as IUpdateDataValidationMutationParams,
});
const rule = manager.getRuleById(diff.ruleId);
@@ -145,6 +150,7 @@ export function getDataValidationDiffMutations(
unitId,
subUnitId,
rule: diff.rule,
source,
} as IAddDataValidationMutationParams,
});
undoMutations.unshift({
@@ -153,6 +159,7 @@ export function getDataValidationDiffMutations(
unitId,
subUnitId,
ruleId: diff.rule.uid,
source,
},
});
if (diff.rule.type === DataValidationType.CHECKBOX) {
@@ -95,7 +95,7 @@ export class DataValidationAutoFillController extends Disposable {
});
const diffs = ruleMatrixCopy.diff(manager.getDataValidations());
const { redoMutations, undoMutations } = getDataValidationDiffMutations(unitId, subUnitId, diffs, this._injector);
const { redoMutations, undoMutations } = getDataValidationDiffMutations(unitId, subUnitId, diffs, this._injector, 'patched');
return {
undos: undoMutations,
redos: redoMutations,
@@ -153,7 +153,8 @@ export class DataValidationCopyPasteController extends Disposable {
copyInfo.unitId,
copyInfo.subUnitId,
ruleMatrix.diffWithAddition(manager.getDataValidations(), additionRules.values()),
this._injector
this._injector,
'patched'
);
return {
@@ -188,7 +189,8 @@ export class DataValidationCopyPasteController extends Disposable {
unitId,
subUnitId,
ruleMatrix.diff(manager.getDataValidations()),
this._injector
this._injector,
'patched'
);
return {
@@ -34,7 +34,6 @@ export class DataValidationModelController extends Disposable {
return new SheetDataValidationManager(
unitId,
subUnitId,
[],
this._injector
);
}
@@ -162,6 +162,7 @@ export class DataValidationRefRangeController extends Disposable {
type: UpdateRuleType.RANGE,
payload: resultRanges,
},
source: 'patched',
};
// in ref-range case, there won't be any overlap about rule ranges
const redos = [{ id: UpdateDataValidationMutation.id, params: redoParams }];
@@ -175,6 +176,7 @@ export class DataValidationRefRangeController extends Disposable {
type: UpdateRuleType.RANGE,
payload: oldRanges,
},
source: 'patched',
},
}];
return { redos, undos };
@@ -23,7 +23,7 @@ import { AutoHeightController, IEditorBridgeService, SheetSkeletonManagerService
import type { Spreadsheet } from '@univerjs/engine-render';
import { IRenderManagerService } from '@univerjs/engine-render';
import { INTERCEPTOR_POINT, SheetInterceptorService } from '@univerjs/sheets';
import { bufferTime, debounceTime } from 'rxjs';
import { bufferTime, debounceTime, filter } from 'rxjs';
import { getCellValueOrigin } from '../utils/get-cell-data-origin';
import type { ListValidator } from '../validators';
import type { SheetDataValidationManager } from '../models/sheet-data-validation-manager';
@@ -311,19 +311,26 @@ export class SheetsDataValidationRenderController extends RxDisposable {
}
private _initAutoHeight() {
this._dataValidationModel.ruleChange$.pipe(bufferTime(16)).subscribe((infos) => {
const ranges: IRange[] = [];
infos.forEach((info) => {
if (info.rule?.ranges) {
ranges.push(...info.rule.ranges);
this._dataValidationModel.ruleChange$
.pipe(
// patched data-validation change don't need to re-calc row height
// re-calc of row height will be triggered precisely by the origin command
filter((change) => change.source === 'command'),
bufferTime(16)
)
.subscribe((infos) => {
const ranges: IRange[] = [];
infos.forEach((info) => {
if (info.rule?.ranges) {
ranges.push(...info.rule.ranges);
}
});
if (ranges.length) {
const mutations = this._autoHeightController.getUndoRedoParamsOfAutoHeight(ranges);
sequenceExecute(mutations.redos, this._commandService);
}
});
if (ranges.length) {
const mutations = this._autoHeightController.getUndoRedoParamsOfAutoHeight(ranges);
sequenceExecute(mutations.redos, this._commandService);
}
});
}
}
@@ -510,19 +517,23 @@ export class SheetsDataValidationMobileRenderController extends RxDisposable {
}
private _initAutoHeight() {
this._dataValidationModel.ruleChange$.pipe(bufferTime(16)).subscribe((infos) => {
const ranges: IRange[] = [];
infos.forEach((info) => {
if (info.rule?.ranges) {
ranges.push(...info.rule.ranges);
this._dataValidationModel.ruleChange$
.pipe(
filter((change) => change.source === 'command'),
bufferTime(16)
).subscribe((infos) => {
const ranges: IRange[] = [];
infos.forEach((info) => {
if (info.rule?.ranges) {
ranges.push(...info.rule.ranges);
}
});
if (ranges.length) {
const mutations = this._autoHeightController.getUndoRedoParamsOfAutoHeight(ranges);
sequenceExecute(mutations.redos, this._commandService);
}
});
if (ranges.length) {
const mutations = this._autoHeightController.getUndoRedoParamsOfAutoHeight(ranges);
sequenceExecute(mutations.redos, this._commandService);
}
});
}
}
@@ -128,7 +128,7 @@ export class DataValidationController extends RxDisposable {
selections && ruleMatrix.removeRange(selections);
const diffs = ruleMatrix.diff(manager.getDataValidations());
const { redoMutations, undoMutations } = getDataValidationDiffMutations(unitId, subUnitId, diffs, this._injector);
const { redoMutations, undoMutations } = getDataValidationDiffMutations(unitId, subUnitId, diffs, this._injector, 'patched');
return {
undos: undoMutations,
@@ -16,7 +16,7 @@
import type { CellValue, Injector, ISheetDataValidationRule, Nullable, Workbook } from '@univerjs/core';
import { DataValidationManager, DataValidatorRegistryService, UpdateRuleType } from '@univerjs/data-validation';
import { DataValidationStatus, DataValidationType, IUniverInstanceService, ObjectMatrix, Range, UniverInstanceType } from '@univerjs/core';
import { DataValidationStatus, DataValidationType, IUniverInstanceService, ObjectMatrix, UniverInstanceType } from '@univerjs/core';
import type { IUpdateRulePayload } from '@univerjs/data-validation';
import type { ISheetLocationBase } from '@univerjs/sheets';
import { isReferenceString } from '@univerjs/engine-formula';
@@ -24,7 +24,6 @@ import type { IDataValidationResCache } from '../services/dv-cache.service';
import { DataValidationCacheService } from '../services/dv-cache.service';
import { DataValidationFormulaService } from '../services/dv-formula.service';
import { DataValidationCustomFormulaService } from '../services/dv-custom-formula.service';
import { DataValidationRefRangeController } from '../controllers/dv-ref-range.controller';
import { RuleMatrix } from './rule-matrix';
export class SheetDataValidationManager extends DataValidationManager<ISheetDataValidationRule> {
@@ -37,36 +36,21 @@ export class SheetDataValidationManager extends DataValidationManager<ISheetData
private _dataValidationFormulaService: DataValidationFormulaService;
private _dataValidationCustomFormulaService: DataValidationCustomFormulaService;
private _cache: ObjectMatrix<Nullable<IDataValidationResCache>>;
private _dataValidationRefRangeController: DataValidationRefRangeController;
constructor(
unitId: string,
subUnitId: string,
rules: ISheetDataValidationRule[] | undefined,
private readonly _injector: Injector
) {
super(unitId, subUnitId, rules);
super(unitId, subUnitId);
this._dataValidatorRegistryService = this._injector.get(DataValidatorRegistryService);
this._dataValidationCacheService = this._injector.get(DataValidationCacheService);
this._dataValidationFormulaService = this._injector.get(DataValidationFormulaService);
this._dataValidationCustomFormulaService = this._injector.get(DataValidationCustomFormulaService);
this._dataValidationRefRangeController = this._injector.get(DataValidationRefRangeController);
this._cache = this._dataValidationCacheService.ensureCache(unitId, subUnitId);
const univerInstanceService = this._injector.get(IUniverInstanceService);
const worksheet = univerInstanceService.getUnit<Workbook>(unitId, UniverInstanceType.UNIVER_SHEET)!.getSheetBySheetId(subUnitId)!;
const matrix = new ObjectMatrix<string>();
rules?.forEach((rule) => {
const ruleId = rule.uid;
rule.ranges.forEach((range) => {
Range.foreach(range, (row, col) => {
matrix.setValue(row, col, ruleId);
});
});
});
rules?.forEach((rule) => {
this._dataValidationRefRangeController.register(unitId, subUnitId, rule);
});
this._ruleMatrix = new RuleMatrix(matrix, worksheet);
}