mirror of
https://github.com/dream-num/univer.git
synced 2026-09-24 15:32:18 +08:00
fix(sheets-data-validation): data validation validator status render error (#3752)
This commit is contained in:
@@ -140,7 +140,7 @@ export { isBlackColor, isWhiteColor } from './shared/color/color-kit';
|
||||
export { cellToRange } from './shared/common';
|
||||
export { getIntersectRange } from './shared/range';
|
||||
export { nameCharacterCheck } from './shared/name';
|
||||
export { fromCallback, takeAfter } from './shared/rxjs';
|
||||
export { bufferDebounceTime, fromCallback, takeAfter } from './shared/rxjs';
|
||||
export { awaitTime } from './shared/timer';
|
||||
export { Range } from './sheets/range';
|
||||
export {
|
||||
|
||||
@@ -14,8 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import type { OperatorFunction } from 'rxjs';
|
||||
import type { IDisposable } from '../common/di';
|
||||
import { debounceTime, map, Observable, tap } from 'rxjs';
|
||||
|
||||
type CallbackFn<T extends readonly unknown[]> = (cb: (...args: T) => void) => IDisposable;
|
||||
|
||||
@@ -57,3 +58,15 @@ export function takeAfter<T>(callback: (value: T) => boolean) {
|
||||
};
|
||||
}
|
||||
|
||||
export function bufferDebounceTime<T>(time: number = 0): OperatorFunction<T, T[]> {
|
||||
return (source: Observable<T>) => {
|
||||
let bufferedValues: T[] = [];
|
||||
|
||||
return source.pipe(
|
||||
tap((value) => bufferedValues.push(value)),
|
||||
debounceTime(time),
|
||||
map(() => bufferedValues),
|
||||
tap(() => bufferedValues = [])
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export {
|
||||
} from './common/util';
|
||||
export { DataValidationResourceController } from './controllers/dv-resource.controller';
|
||||
|
||||
export { type DataValidationChangeSource, DataValidationModel, type IRuleChange, type IValidStatusChange } from './models/data-validation-model';
|
||||
export { type DataValidationChangeSource, DataValidationModel, type IRuleChange } from './models/data-validation-model';
|
||||
|
||||
export { UniverDataValidationPlugin } from './plugin';
|
||||
export { DataValidatorRegistryScope, DataValidatorRegistryService } from './services/data-validator-registry.service';
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { IDataValidationRule } from '@univerjs/core';
|
||||
import type { IUpdateRulePayload } from '../types/interfaces/i-update-rule-payload';
|
||||
import { Disposable, ILogService, Tools } from '@univerjs/core';
|
||||
import { debounceTime, Subject } from 'rxjs';
|
||||
import type { DataValidationStatus, IDataValidationRule } from '@univerjs/core';
|
||||
import { getRuleOptions, getRuleSetting } from '../common/util';
|
||||
import { UpdateRuleType } from '../types/enum/update-rule-type';
|
||||
import type { IUpdateRulePayload } from '../types/interfaces/i-update-rule-payload';
|
||||
|
||||
type DataValidationChangeType = 'update' | 'add' | 'remove';
|
||||
export type DataValidationChangeSource = 'command' | 'patched';
|
||||
@@ -34,13 +34,6 @@ export interface IRuleChange {
|
||||
oldRule?: IDataValidationRule;
|
||||
}
|
||||
|
||||
export interface IValidStatusChange {
|
||||
unitId: string;
|
||||
subUnitId: string;
|
||||
ruleId: string;
|
||||
status: DataValidationStatus;
|
||||
}
|
||||
|
||||
interface ISubUnitDataValidation {
|
||||
map: Map<string, IDataValidationRule>; list: IDataValidationRule[];
|
||||
}
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
|
||||
import type { CommandListener, ICommandInfo, IDisposable, IExecutionOptions, IRange, IWorkbookData, Nullable, ObjectMatrix, Workbook } from '@univerjs/core';
|
||||
import type { IRuleChange, IValidStatusChange } from '@univerjs/data-validation';
|
||||
import type { IRuleChange } from '@univerjs/data-validation';
|
||||
import type { IUpdateCommandParams } from '@univerjs/docs-ui';
|
||||
import type {
|
||||
ISetSelectionsOperationParams,
|
||||
ISheetCommandSharedParams,
|
||||
} from '@univerjs/sheets';
|
||||
import type { IAddSheetDataValidationCommandParams, IDataValidationResCache, IRemoveSheetAllDataValidationCommandParams, IRemoveSheetDataValidationCommandParams, IUpdateSheetDataValidationOptionsCommandParams, IUpdateSheetDataValidationRangeCommandParams, IUpdateSheetDataValidationSettingCommandParams } from '@univerjs/sheets-data-validation';
|
||||
import type { IAddSheetDataValidationCommandParams, IDataValidationResCache, IRemoveSheetAllDataValidationCommandParams, IRemoveSheetDataValidationCommandParams, IUpdateSheetDataValidationOptionsCommandParams, IUpdateSheetDataValidationRangeCommandParams, IUpdateSheetDataValidationSettingCommandParams, IValidStatusChange } from '@univerjs/sheets-data-validation';
|
||||
import type { ICanvasFloatDom } from '@univerjs/sheets-drawing-ui';
|
||||
import type { ISheetHyperLinkInfo } from '@univerjs/sheets-hyper-link-ui';
|
||||
import type { CommentUpdate, IAddCommentCommandParams, IDeleteCommentCommandParams } from '@univerjs/thread-comment';
|
||||
|
||||
@@ -21,9 +21,10 @@ import type { FilterModel } from '@univerjs/sheets-filter';
|
||||
|
||||
import type { FWorkbook, IFICanvasFloatDom } from './f-workbook';
|
||||
import { Direction, ICommandService, Inject, Injector, ObjectMatrix, RANGE_TYPE } from '@univerjs/core';
|
||||
import { DataValidationModel } from '@univerjs/data-validation';
|
||||
import { deserializeRangeWithSheet } from '@univerjs/engine-formula';
|
||||
import { copyRangeStyles, InsertColCommand, InsertRowCommand, MoveColsCommand, MoveRowsCommand, RemoveColCommand, RemoveRowCommand, SetColHiddenCommand, SetColWidthCommand, SetFrozenCommand, SetRangeValuesMutation, SetRowHeightCommand, SetRowHiddenCommand, SetSpecificColsVisibleCommand, SetSpecificRowsVisibleCommand, SetWorksheetRowIsAutoHeightCommand, SheetsSelectionsService } from '@univerjs/sheets';
|
||||
import { DataValidationModel, SheetsDataValidationValidatorService } from '@univerjs/sheets-data-validation';
|
||||
import { SheetsDataValidationValidatorService } from '@univerjs/sheets-data-validation';
|
||||
import { SheetCanvasFloatDomManagerService } from '@univerjs/sheets-drawing-ui';
|
||||
import { SheetsFilterService } from '@univerjs/sheets-filter';
|
||||
import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment';
|
||||
|
||||
@@ -19,7 +19,7 @@ import { DataValidationStatus, DataValidationType, ICommandService, Inject, Inte
|
||||
import { DataValidatorRegistryService } from '@univerjs/data-validation';
|
||||
import { IRenderManagerService } from '@univerjs/engine-render';
|
||||
import { InterceptCellContentPriority, INTERCEPTOR_POINT, SheetInterceptorService } from '@univerjs/sheets';
|
||||
import { getCellValueOrigin, SheetDataValidationModel } from '@univerjs/sheets-data-validation';
|
||||
import { DataValidationCacheService, getCellValueOrigin, SheetDataValidationModel } from '@univerjs/sheets-data-validation';
|
||||
import { AutoHeightController, IEditorBridgeService, SheetSkeletonManagerService } from '@univerjs/sheets-ui';
|
||||
import { IMenuManagerService } from '@univerjs/ui';
|
||||
import { bufferTime, filter } from 'rxjs';
|
||||
@@ -44,6 +44,7 @@ export class SheetsDataValidationRenderController extends RxDisposable {
|
||||
@Inject(SheetDataValidationModel) private readonly _sheetDataValidationModel: SheetDataValidationModel,
|
||||
@Inject(DataValidatorRegistryService) private readonly _dataValidatorRegistryService: DataValidatorRegistryService,
|
||||
@Inject(SheetInterceptorService) private readonly _sheetInterceptorService: SheetInterceptorService,
|
||||
@Inject(DataValidationCacheService) private readonly _dataValidationCacheService: DataValidationCacheService,
|
||||
@Optional(IEditorBridgeService) private readonly _editorBridgeService?: IEditorBridgeService
|
||||
) {
|
||||
super();
|
||||
@@ -145,7 +146,7 @@ export class SheetsDataValidationRenderController extends RxDisposable {
|
||||
if (!rule) {
|
||||
return next(cell);
|
||||
}
|
||||
const validStatus = this._sheetDataValidationModel.validator(cell, rule, pos);
|
||||
const validStatus = this._dataValidationCacheService.getValue(unitId, subUnitId, row, col)?.status ?? DataValidationStatus.VALID;
|
||||
const validator = this._dataValidatorRegistryService.getValidatorItem(rule.type);
|
||||
const cellOrigin = pos.rawData;
|
||||
let cache: Nullable<CellValue>;
|
||||
@@ -264,7 +265,8 @@ export class SheetsDataValidationMobileRenderController extends RxDisposable {
|
||||
@Inject(AutoHeightController) private readonly _autoHeightController: AutoHeightController,
|
||||
@Inject(DataValidatorRegistryService) private readonly _dataValidatorRegistryService: DataValidatorRegistryService,
|
||||
@Inject(SheetInterceptorService) private readonly _sheetInterceptorService: SheetInterceptorService,
|
||||
@Inject(SheetDataValidationModel) private readonly _sheetDataValidationModel: SheetDataValidationModel
|
||||
@Inject(SheetDataValidationModel) private readonly _sheetDataValidationModel: SheetDataValidationModel,
|
||||
@Inject(DataValidationCacheService) private readonly _dataValidationCacheService: DataValidationCacheService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -293,7 +295,7 @@ export class SheetsDataValidationMobileRenderController extends RxDisposable {
|
||||
if (!rule) {
|
||||
return next(cell);
|
||||
}
|
||||
const validStatus = this._sheetDataValidationModel.validator(cell, rule, pos);
|
||||
const validStatus = this._dataValidationCacheService.getValue(unitId, subUnitId, row, col)?.status ?? DataValidationStatus.VALID;
|
||||
const validator = this._dataValidatorRegistryService.getValidatorItem(rule.type);
|
||||
const cellOrigin = worksheet.getCellRaw(row, col);
|
||||
const cellValue = getCellValueOrigin(cellOrigin);
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright 2023-present DreamNum Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Workbook } from '@univerjs/core';
|
||||
import type { IRenderContext, IRenderModule } from '@univerjs/engine-render';
|
||||
import type { IValidStatusChange } from '@univerjs/sheets-data-validation';
|
||||
import { bufferDebounceTime, Disposable, Inject } from '@univerjs/core';
|
||||
import { SheetDataValidationModel } from '@univerjs/sheets-data-validation';
|
||||
import { SheetSkeletonManagerService } from '@univerjs/sheets-ui';
|
||||
|
||||
export class SheetsDataValidationReRenderController extends Disposable implements IRenderModule {
|
||||
constructor(
|
||||
private readonly _context: IRenderContext<Workbook>,
|
||||
@Inject(SheetDataValidationModel) private readonly _sheetDataValidationModel: SheetDataValidationModel,
|
||||
@Inject(SheetSkeletonManagerService) private readonly _sheetSkeletonManagerService: SheetSkeletonManagerService
|
||||
) {
|
||||
super();
|
||||
this._initSkeletonChange();
|
||||
}
|
||||
|
||||
private _initSkeletonChange() {
|
||||
const reRender = (values: IValidStatusChange[]) => {
|
||||
if (!values.length) {
|
||||
return;
|
||||
}
|
||||
const sheetIds = new Set<string>();
|
||||
values.forEach((value) => {
|
||||
sheetIds.add(value.subUnitId);
|
||||
});
|
||||
sheetIds.forEach((sheetId) => {
|
||||
this._sheetSkeletonManagerService.getWorksheetSkeleton(sheetId)?.skeleton.makeDirty(true);
|
||||
});
|
||||
this._context.mainComponent?.makeForceDirty();
|
||||
};
|
||||
|
||||
this.disposeWithMe(this._sheetDataValidationModel.validStatusChange$.pipe(bufferDebounceTime(16)).subscribe(reRender));
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Dependency } from '@univerjs/core';
|
||||
import type { Dependency, Workbook } from '@univerjs/core';
|
||||
import type { IUniverSheetsDataValidationUIConfig } from './controllers/config.schema';
|
||||
import { ICommandService, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core';
|
||||
import { IRenderManagerService } from '@univerjs/engine-render';
|
||||
import { AddSheetDataValidationAndOpenCommand } from './commands/commands/data-validation-ui.command';
|
||||
import {
|
||||
CloseValidationPanelOperation,
|
||||
@@ -31,6 +32,7 @@ import { DataValidationAutoFillController } from './controllers/dv-auto-fill.con
|
||||
import { DataValidationCopyPasteController } from './controllers/dv-copy-paste.controller';
|
||||
import { DataValidationPermissionController } from './controllers/dv-permission.controller';
|
||||
import { SheetsDataValidationRenderController } from './controllers/dv-render.controller';
|
||||
import { SheetsDataValidationReRenderController } from './controllers/dv-rerender.controller';
|
||||
import { SheetsDataValidationUIController } from './controllers/dv-ui.controller';
|
||||
import { DataValidationPanelService } from './services/data-validation-panel.service';
|
||||
import { DataValidationDropdownManagerService } from './services/dropdown-manager.service';
|
||||
@@ -86,6 +88,12 @@ export class UniverSheetsDataValidationMobileUIPlugin extends Plugin {
|
||||
override onReady(): void {
|
||||
this._injector.get(DataValidationCopyPasteController);
|
||||
this._injector.get(DataValidationPermissionController);
|
||||
|
||||
const renderManager = this._injector.get(IRenderManagerService);
|
||||
renderManager.registerRenderModule<Workbook>(
|
||||
UniverInstanceType.UNIVER_SHEET,
|
||||
[SheetsDataValidationReRenderController] as Dependency
|
||||
);
|
||||
}
|
||||
|
||||
override onRendered(): void {
|
||||
|
||||
@@ -14,9 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Dependency } from '@univerjs/core';
|
||||
import type { Dependency, Workbook } from '@univerjs/core';
|
||||
import type { IUniverSheetsDataValidationUIConfig } from './controllers/config.schema';
|
||||
import { ICommandService, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core';
|
||||
import { IRenderManagerService } from '@univerjs/engine-render';
|
||||
import { AddSheetDataValidationAndOpenCommand } from './commands/commands/data-validation-ui.command';
|
||||
import {
|
||||
CloseValidationPanelOperation,
|
||||
@@ -32,6 +33,7 @@ import { DataValidationCopyPasteController } from './controllers/dv-copy-paste.c
|
||||
import { DataValidationPermissionController } from './controllers/dv-permission.controller';
|
||||
import { DataValidationRejectInputController } from './controllers/dv-reject-input.controller';
|
||||
import { SheetsDataValidationRenderController } from './controllers/dv-render.controller';
|
||||
import { SheetsDataValidationReRenderController } from './controllers/dv-rerender.controller';
|
||||
import { SheetsDataValidationUIController } from './controllers/dv-ui.controller';
|
||||
import { DataValidationPanelService } from './services/data-validation-panel.service';
|
||||
import { DataValidationDropdownManagerService } from './services/dropdown-manager.service';
|
||||
@@ -90,6 +92,12 @@ export class UniverSheetsDataValidationUIPlugin extends Plugin {
|
||||
this._injector.get(DataValidationPermissionController);
|
||||
this._injector.get(DataValidationRejectInputController);
|
||||
this._injector.get(DataValidationAlertController);
|
||||
|
||||
const renderManager = this._injector.get(IRenderManagerService);
|
||||
renderManager.registerRenderModule<Workbook>(
|
||||
UniverInstanceType.UNIVER_SHEET,
|
||||
[SheetsDataValidationReRenderController] as Dependency
|
||||
);
|
||||
}
|
||||
|
||||
override onRendered(): void {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
export { DATA_VALIDATION_PLUGIN_NAME } from './common/const';
|
||||
export { SheetDataValidationModel } from './models/sheet-data-validation-model';
|
||||
export { type IValidStatusChange, SheetDataValidationModel } from './models/sheet-data-validation-model';
|
||||
export { UniverSheetsDataValidationPlugin } from './plugin';
|
||||
export { DataValidationCacheService } from './services/dv-cache.service';
|
||||
export type { IDataValidationResCache } from './services/dv-cache.service';
|
||||
@@ -32,9 +32,6 @@ export { CHECKBOX_FORMULA_1, CHECKBOX_FORMULA_2, CheckboxValidator, transformChe
|
||||
export { ListMultipleValidator } from './validators/list-multiple-validator';
|
||||
export { deserializeListOptions, getDataValidationCellValue, serializeListOptions } from './validators/util';
|
||||
|
||||
// TODO: @jikkai: I think this is a mistake, it should be exported from here. @weird94
|
||||
export { DataValidationModel } from '@univerjs/data-validation';
|
||||
|
||||
// #region - all commands
|
||||
|
||||
export {
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { DataValidationType, ICellDataForSheetInterceptor, ISheetDataValidationRule, Nullable } from '@univerjs/core';
|
||||
import type { IRuleChange, IUpdateRulePayload, IValidStatusChange } from '@univerjs/data-validation';
|
||||
import type { ISheetDataValidationRule } from '@univerjs/core';
|
||||
import type { IRuleChange, IUpdateRulePayload } from '@univerjs/data-validation';
|
||||
import type { IRemoveSheetMutationParams, ISheetLocation } from '@univerjs/sheets';
|
||||
import { DataValidationStatus, Disposable, ICommandService, Inject, IUniverInstanceService } from '@univerjs/core';
|
||||
import { DataValidationStatus, DataValidationType, Disposable, ICommandService, Inject, IUniverInstanceService } from '@univerjs/core';
|
||||
import { DataValidationModel, DataValidatorRegistryService, UpdateRuleType } from '@univerjs/data-validation';
|
||||
import { RemoveSheetMutation } from '@univerjs/sheets';
|
||||
import { Subject } from 'rxjs';
|
||||
@@ -27,6 +27,15 @@ import { DataValidationFormulaService } from '../services/dv-formula.service';
|
||||
import { getCellValueOrigin } from '../utils/get-cell-data-origin';
|
||||
import { RuleMatrix } from './rule-matrix';
|
||||
|
||||
export interface IValidStatusChange {
|
||||
unitId: string;
|
||||
subUnitId: string;
|
||||
row: number;
|
||||
col: number;
|
||||
ruleId: string;
|
||||
status: DataValidationStatus;
|
||||
}
|
||||
|
||||
export class SheetDataValidationModel extends Disposable {
|
||||
private readonly _ruleMatrixMap = new Map<string, Map<string, RuleMatrix>>();
|
||||
private readonly _validStatusChange$ = new Subject<IValidStatusChange>();
|
||||
@@ -132,7 +141,9 @@ export class SheetDataValidationModel extends Disposable {
|
||||
ruleMatrix.addRule(rule);
|
||||
this._dataValidationCacheService.addRule(unitId, subUnitId, rule);
|
||||
this._dataValidationFormulaService.addRule(unitId, subUnitId, rule.uid, rule.formula1, rule.formula2);
|
||||
this._dataValidationCustomFormulaService.addRule(unitId, subUnitId, rule);
|
||||
if (rule.type === DataValidationType.CUSTOM) {
|
||||
this._dataValidationCustomFormulaService.addRule(unitId, subUnitId, rule);
|
||||
}
|
||||
}
|
||||
|
||||
private _addRule(unitId: string, subUnitId: string, rule: ISheetDataValidationRule | ISheetDataValidationRule[]): void {
|
||||
@@ -148,11 +159,20 @@ export class SheetDataValidationModel extends Disposable {
|
||||
if (payload.type === UpdateRuleType.RANGE) {
|
||||
ruleMatrix.updateRange(ruleId, payload.payload);
|
||||
this._dataValidationCacheService.updateRuleRanges(unitId, subUnitId, ruleId, payload.payload, oldRule.ranges);
|
||||
this._dataValidationCustomFormulaService.updateRuleRanges(unitId, subUnitId, ruleId, oldRule.ranges, payload.payload);
|
||||
if (oldRule.type === DataValidationType.CUSTOM) {
|
||||
this._dataValidationCustomFormulaService.updateRuleRanges(unitId, subUnitId, ruleId, oldRule.ranges, payload.payload);
|
||||
}
|
||||
} else if (payload.type === UpdateRuleType.SETTING) {
|
||||
this._dataValidationCacheService.markRangeDirty(unitId, subUnitId, oldRule.ranges);
|
||||
this._dataValidationFormulaService.updateRuleFormulaText(unitId, subUnitId, ruleId, payload.payload.formula1, payload.payload.formula2);
|
||||
this._dataValidationCustomFormulaService.updateRuleFormula(unitId, subUnitId, ruleId, oldRule.ranges, payload.payload.formula1!);
|
||||
if (oldRule.type === DataValidationType.CUSTOM) {
|
||||
this._dataValidationCustomFormulaService.updateRuleFormula(unitId, subUnitId, ruleId, oldRule.ranges, payload.payload.formula1!);
|
||||
} else if (payload.payload.type === DataValidationType.CUSTOM) {
|
||||
this._dataValidationCustomFormulaService.addRule(unitId, subUnitId, {
|
||||
...oldRule,
|
||||
...payload.payload,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,6 +180,9 @@ export class SheetDataValidationModel extends Disposable {
|
||||
const ruleMatrix = this._ensureRuleMatrix(unitId, subUnitId);
|
||||
ruleMatrix.removeRule(oldRule);
|
||||
this._dataValidationCacheService.removeRule(unitId, subUnitId, oldRule);
|
||||
if (oldRule.type === DataValidationType.CUSTOM) {
|
||||
this._dataValidationCustomFormulaService.deleteByRuleId(unitId, subUnitId, oldRule.uid);
|
||||
}
|
||||
}
|
||||
|
||||
getValidator(type: DataValidationType) {
|
||||
@@ -180,9 +203,11 @@ export class SheetDataValidationModel extends Disposable {
|
||||
return this._dataValidationModel.getRuleById(unitId, subUnitId, ruleId);
|
||||
}
|
||||
|
||||
validator(cell: Nullable<ICellDataForSheetInterceptor>, rule: ISheetDataValidationRule, pos: ISheetLocation, _onCompete?: (status: DataValidationStatus, changed: boolean) => void): DataValidationStatus {
|
||||
validator(rule: ISheetDataValidationRule, pos: ISheetLocation, _onCompete?: (status: DataValidationStatus, changed: boolean) => void): DataValidationStatus {
|
||||
const { col, row, unitId, subUnitId, worksheet } = pos;
|
||||
const ruleId = rule.uid;
|
||||
const formula1 = rule.formula1;
|
||||
const formula2 = rule.formula2;
|
||||
const onCompete = (status: DataValidationStatus, changed: boolean) => {
|
||||
if (_onCompete) {
|
||||
_onCompete(status, changed);
|
||||
@@ -193,9 +218,13 @@ export class SheetDataValidationModel extends Disposable {
|
||||
subUnitId,
|
||||
ruleId: rule.uid,
|
||||
status,
|
||||
row,
|
||||
col,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const cell = worksheet.getCellValueOnly(row, col);
|
||||
const validator = this.getValidator(rule.type);
|
||||
const cellRaw = worksheet.getCellRaw(row, col);
|
||||
const cellValue = getCellValueOrigin(cellRaw);
|
||||
@@ -204,12 +233,14 @@ export class SheetDataValidationModel extends Disposable {
|
||||
if (validator) {
|
||||
const cache = this._dataValidationCacheService.ensureCache(unitId, subUnitId);
|
||||
const current = cache.getValue(row, col);
|
||||
if (!current || current.value !== cellValue || current.interceptValue !== interceptValue || current.ruleId !== ruleId) {
|
||||
if (!current || current.value !== cellValue || current.interceptValue !== interceptValue || current.ruleId !== ruleId || current.formula1 !== formula1 || current.formula2 !== formula2) {
|
||||
cache.setValue(row, col, {
|
||||
value: cellValue,
|
||||
interceptValue,
|
||||
status: DataValidationStatus.VALIDATING,
|
||||
ruleId,
|
||||
formula1: formula1 || '',
|
||||
formula2: formula2 || '',
|
||||
});
|
||||
validator.validator(
|
||||
{
|
||||
@@ -231,6 +262,8 @@ export class SheetDataValidationModel extends Disposable {
|
||||
status: realStatus,
|
||||
ruleId,
|
||||
interceptValue,
|
||||
formula1: formula1 || '',
|
||||
formula2: formula2 || '',
|
||||
});
|
||||
onCompete(realStatus, true);
|
||||
});
|
||||
|
||||
@@ -90,6 +90,8 @@ export class UniverSheetsDataValidationPlugin extends Plugin {
|
||||
this._commandService.registerCommand(command);
|
||||
});
|
||||
|
||||
this._injector.get(DataValidationCacheService);
|
||||
this._injector.get(SheetsDataValidationValidatorService);
|
||||
this._injector.get(DataValidationRefRangeController);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ObjectMatrix, Range } from '@univerjs/core';
|
||||
import type { CellValue, DataValidationStatus, IRange, ISheetDataValidationRule, Nullable } from '@univerjs/core';
|
||||
import { Disposable, ICommandService, Inject, ObjectMatrix, Range } from '@univerjs/core';
|
||||
import { type ISetRangeValuesMutationParams, SetRangeValuesMutation } from '@univerjs/sheets';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
export interface IDataValidationResCache {
|
||||
value: Nullable<CellValue>;
|
||||
@@ -23,10 +25,40 @@ export interface IDataValidationResCache {
|
||||
status: DataValidationStatus;
|
||||
ruleId: string;
|
||||
temp?: boolean;
|
||||
formula1: string;
|
||||
formula2: string;
|
||||
}
|
||||
|
||||
export class DataValidationCacheService {
|
||||
export class DataValidationCacheService extends Disposable {
|
||||
private _cacheMatrix: Map<string, Map<string, ObjectMatrix<Nullable<IDataValidationResCache>>>> = new Map();
|
||||
private _dirtyRanges$ = new Subject<{ unitId: string; subUnitId: string; ranges: IRange[] }>();
|
||||
|
||||
readonly dirtyRanges$ = this._dirtyRanges$.asObservable();
|
||||
|
||||
constructor(
|
||||
@Inject(ICommandService) private readonly _commandService: ICommandService
|
||||
) {
|
||||
super();
|
||||
this._initDirtyRanges();
|
||||
}
|
||||
|
||||
private _initDirtyRanges() {
|
||||
this.disposeWithMe(this._commandService.onCommandExecuted((commandInfo) => {
|
||||
if (commandInfo.id === SetRangeValuesMutation.id) {
|
||||
const { cellValue, unitId, subUnitId } = commandInfo.params as ISetRangeValuesMutationParams;
|
||||
if (cellValue) {
|
||||
const range = new ObjectMatrix(cellValue).getDataRange();
|
||||
if (range.endRow === -1) return;
|
||||
|
||||
this._dirtyRanges$.next({
|
||||
unitId,
|
||||
subUnitId,
|
||||
ranges: [range],
|
||||
});
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private _ensureCache(unitId: string, subUnitId: string) {
|
||||
let unitMap = this._cacheMatrix.get(unitId);
|
||||
@@ -86,6 +118,8 @@ export class DataValidationCacheService {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this._dirtyRanges$.next({ unitId, subUnitId, ranges: [...oldRanges, ...newRanges] });
|
||||
}
|
||||
|
||||
markRangeDirty(unitId: string, subUnitId: string, ranges: IRange[]) {
|
||||
@@ -95,11 +129,14 @@ export class DataValidationCacheService {
|
||||
cache.setValue(row, col, undefined);
|
||||
});
|
||||
});
|
||||
|
||||
this._dirtyRanges$.next({ unitId, subUnitId, ranges });
|
||||
}
|
||||
|
||||
markCellDirty(unitId: string, subUnitId: string, row: number, col: number) {
|
||||
const cache = this._ensureCache(unitId, subUnitId);
|
||||
cache.setValue(row, col, undefined);
|
||||
this._dirtyRanges$.next({ unitId, subUnitId, ranges: [{ startRow: row, startColumn: col, endRow: row, endColumn: col }] });
|
||||
}
|
||||
|
||||
private _deleteRange(unitId: string, subUnitId: string, ranges: IRange[]) {
|
||||
@@ -109,6 +146,7 @@ export class DataValidationCacheService {
|
||||
cache.realDeleteValue(row, col);
|
||||
});
|
||||
});
|
||||
this._dirtyRanges$.next({ unitId, subUnitId, ranges });
|
||||
}
|
||||
|
||||
getValue(unitId: string, subUnitId: string, row: number, col: number) {
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { DataValidationType, Disposable, ILogService, Inject, isFormulaString, IUniverInstanceService, ObjectMatrix, Range, UniverInstanceType } from '@univerjs/core';
|
||||
import type { IRange, ISheetDataValidationRule } from '@univerjs/core';
|
||||
import { DataValidationType, Disposable, Inject, Injector, isFormulaString, IUniverInstanceService, ObjectMatrix, Range, UniverInstanceType } from '@univerjs/core';
|
||||
import { DataValidationModel } from '@univerjs/data-validation';
|
||||
import { LexerTreeBuilder } from '@univerjs/engine-formula';
|
||||
import { RegisterOtherFormulaService } from '@univerjs/sheets-formula';
|
||||
import type { IRange, ISheetDataValidationRule } from '@univerjs/core';
|
||||
import { DataValidationCacheService } from './dv-cache.service';
|
||||
|
||||
interface IDataValidationFormula {
|
||||
@@ -68,7 +68,7 @@ export class DataValidationCustomFormulaService extends Disposable {
|
||||
@Inject(LexerTreeBuilder) private _lexerTreeBuilder: LexerTreeBuilder,
|
||||
@Inject(DataValidationModel) private readonly _dataValidationModel: DataValidationModel,
|
||||
@Inject(DataValidationCacheService) private readonly _dataValidationCacheService: DataValidationCacheService,
|
||||
@ILogService private readonly _logService: ILogService
|
||||
@Inject(Injector) private readonly _injector: Injector
|
||||
) {
|
||||
super();
|
||||
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Nullable } from '@univerjs/core';
|
||||
import type { IFormulaInfo, IOtherFormulaResult } from '@univerjs/sheets-formula';
|
||||
import { Disposable, Inject, isFormulaString, IUniverInstanceService, UniverInstanceType } from '@univerjs/core';
|
||||
import { DataValidationModel } from '@univerjs/data-validation';
|
||||
import { RegisterOtherFormulaService } from '@univerjs/sheets-formula';
|
||||
import type { Nullable } from '@univerjs/core';
|
||||
import type { IFormulaInfo, IOtherFormulaResult } from '@univerjs/sheets-formula';
|
||||
import { DataValidationCacheService } from './dv-cache.service';
|
||||
|
||||
type RuleId = string;
|
||||
|
||||
@@ -14,19 +14,65 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { DataValidationStatus, Inject, IUniverInstanceService, Range, Tools, UniverInstanceType } from '@univerjs/core';
|
||||
import type { IDataValidationRule, IRange, Nullable, ObjectMatrix, Workbook } from '@univerjs/core';
|
||||
import type { IDataValidationResCache } from './dv-cache.service';
|
||||
import { bufferDebounceTime, DataValidationStatus, Disposable, Inject, IUniverInstanceService, LifecycleService, LifecycleStages, Range, Tools, UniverInstanceType } from '@univerjs/core';
|
||||
import { bufferWhen, filter } from 'rxjs';
|
||||
import { SheetDataValidationModel } from '../models/sheet-data-validation-model';
|
||||
import { DataValidationCacheService } from './dv-cache.service';
|
||||
import type { IDataValidationResCache } from './dv-cache.service';
|
||||
|
||||
export class SheetsDataValidationValidatorService {
|
||||
export class SheetsDataValidationValidatorService extends Disposable {
|
||||
constructor(
|
||||
@IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService,
|
||||
@Inject(SheetDataValidationModel) private readonly _sheetDataValidationModel: SheetDataValidationModel,
|
||||
@Inject(DataValidationCacheService) private readonly _dataValidationCacheService: DataValidationCacheService
|
||||
@Inject(DataValidationCacheService) private readonly _dataValidationCacheService: DataValidationCacheService,
|
||||
@Inject(LifecycleService) private readonly _lifecycleService: LifecycleService
|
||||
) {
|
||||
super();
|
||||
this._initRecalculate();
|
||||
}
|
||||
|
||||
private _initRecalculate() {
|
||||
const handleDirtyRanges = (ranges: { unitId: string; subUnitId: string; ranges: IRange[] }[]) => {
|
||||
if (ranges.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const workbook = this._univerInstanceService.getCurrentUnitForType<Workbook>(UniverInstanceType.UNIVER_SHEET);
|
||||
const worksheet = workbook?.getActiveSheet();
|
||||
|
||||
const map: Record<string, Record<string, IRange[]>> = {};
|
||||
|
||||
ranges.flat().forEach((range) => {
|
||||
if (!map[range.unitId]) {
|
||||
map[range.unitId] = {};
|
||||
}
|
||||
if (!map[range.unitId][range.subUnitId]) {
|
||||
map[range.unitId][range.subUnitId] = [];
|
||||
}
|
||||
const workbook = this._univerInstanceService.getUnit<Workbook>(range.unitId, UniverInstanceType.UNIVER_SHEET);
|
||||
const worksheet = workbook?.getSheetBySheetId(range.subUnitId);
|
||||
if (!worksheet) {
|
||||
return;
|
||||
}
|
||||
map[range.unitId][range.subUnitId].push(...range.ranges.map((range) => Range.transformRange(range, worksheet)));
|
||||
});
|
||||
|
||||
Object.entries(map).forEach(([unitId, subUnitMap]) => {
|
||||
Object.entries(subUnitMap).forEach(([subUnitId, ranges]) => {
|
||||
if (workbook?.getUnitId() === unitId && worksheet?.getSheetId() === subUnitId) {
|
||||
this.validatorRanges(unitId, subUnitId, ranges);
|
||||
} else {
|
||||
requestIdleCallback(() => {
|
||||
this.validatorRanges(unitId, subUnitId, ranges);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
this.disposeWithMe(this._dataValidationCacheService.dirtyRanges$.pipe(bufferWhen(() => this._lifecycleService.lifecycle$.pipe(filter((stage) => stage === LifecycleStages.Rendered)))).subscribe(handleDirtyRanges));
|
||||
this.disposeWithMe(this._dataValidationCacheService.dirtyRanges$.pipe(filter(() => this._lifecycleService.stage >= LifecycleStages.Rendered), bufferDebounceTime(20)).subscribe(handleDirtyRanges));
|
||||
}
|
||||
|
||||
async validatorCell(unitId: string, subUnitId: string, row: number, col: number) {
|
||||
@@ -44,14 +90,15 @@ export class SheetsDataValidationValidatorService {
|
||||
throw new Error(`row or col is not defined, row: ${row}, col: ${col}`);
|
||||
}
|
||||
|
||||
const cell = worksheet.getCell(row, col);
|
||||
const rule = this._sheetDataValidationModel.getRuleByLocation(unitId, subUnitId, row, col);
|
||||
if (!rule) {
|
||||
return DataValidationStatus.VALID;
|
||||
}
|
||||
|
||||
return new Promise<DataValidationStatus>((resolve) => {
|
||||
this._sheetDataValidationModel.validator(cell, rule, { unitId, subUnitId, row, col, worksheet, workbook }, resolve);
|
||||
this._sheetDataValidationModel.validator(rule, { unitId, subUnitId, row, col, worksheet, workbook }, (status) => {
|
||||
resolve(status);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user