diff --git a/packages/core/src/sheets/worksheet.ts b/packages/core/src/sheets/worksheet.ts index a3055e0bce..56576ffd0e 100644 --- a/packages/core/src/sheets/worksheet.ts +++ b/packages/core/src/sheets/worksheet.ts @@ -580,6 +580,23 @@ export class Worksheet { return this._viewModel.getRowFiltered(row); } + /** + * Get the filtered out rows in a given range. used for remove rows operation, etc. + * @param range - The range to get filtered rows from. + * @returns {number[]} An array of row indices that are filtered out within the specified range. + */ + getRangeFilterRows(range: IRange): number[] { + const rangeFilteredRows = []; + + for (let r = range.startRow; r <= range.endRow; r++) { + if (this.getRowFiltered(r)) { + rangeFilteredRows.push(r); + } + } + + return rangeFilteredRows; + } + /** * Get cell matrix from a given range and pick out non-first cells of merged cells. * diff --git a/packages/sheets-formula/src/controllers/utils/ref-range-formula.ts b/packages/sheets-formula/src/controllers/utils/ref-range-formula.ts index 83c2d8a087..2e2c476c98 100644 --- a/packages/sheets-formula/src/controllers/utils/ref-range-formula.ts +++ b/packages/sheets-formula/src/controllers/utils/ref-range-formula.ts @@ -48,8 +48,18 @@ export interface IFormulaReferenceMoveParam { from?: IRange; to?: IRange; sheetName?: string; - definedNameId?: string; // defined name id - definedName?: string; // new defined name + /** + * defined name id + */ + definedNameId?: string; + /** + * new defined name + */ + definedName?: string; + /** + * The filtered rows contained in the range, used for remove rows operation, etc. + */ + rangeFilteredRows?: number[]; } const formulaReferenceSheetList = [ @@ -208,7 +218,7 @@ export function refRangeFormula(oldFormulaData: IFormulaData, newFormulaData: IF const redoFormulaData: Record>>> = {}; const undoFormulaData: Record>>> = {}; - const { type, unitId: targetUnitId, sheetId, range, from, to } = formulaReferenceMoveParam; + const { unitId: targetUnitId, sheetId } = formulaReferenceMoveParam; // Iterate over all unitId in oldFormulaData const allUnitIds = new Set([...Object.keys(oldFormulaData), ...Object.keys(newFormulaData)]); @@ -237,7 +247,7 @@ export function refRangeFormula(oldFormulaData: IFormulaData, newFormulaData: IF if (unitId !== targetUnitId || currentSheetId !== sheetId) { rangeList = processFormulaRange(newFormulaMatrix); } else { - rangeList = processFormulaChanges(oldFormulaMatrix, type, from, to, range); + rangeList = processFormulaChanges(oldFormulaMatrix, formulaReferenceMoveParam); } const sheetRedoFormulaData = getRedoFormulaData(rangeList, oldFormulaMatrix, newFormulaMatrix); @@ -267,8 +277,9 @@ export function refRangeFormula(oldFormulaData: IFormulaData, newFormulaData: IF }; } -function processFormulaChanges(oldFormulaMatrix: ObjectMatrix>, type: FormulaReferenceMoveType, from: Nullable, to: Nullable, range: Nullable) { +function processFormulaChanges(oldFormulaMatrix: ObjectMatrix>, formulaReferenceMoveParam: IFormulaReferenceMoveParam) { // When undoing and redoing, the traversal order may be different. Record the range list of all single formula offsets, and then retrieve the traversal as needed. + const { type, from, to, range } = formulaReferenceMoveParam; const rangeList: IRangeChange[] = []; oldFormulaMatrix.forValue((row, column, cell) => { @@ -283,7 +294,7 @@ function processFormulaChanges(oldFormulaMatrix: ObjectMatrix, to: } } -function handleInsertDelete(type: FormulaReferenceMoveType, range: IRange, oldCell: IRange) { +function handleInsertDelete(oldCell: IRange, formulaReferenceMoveParam: IFormulaReferenceMoveParam) { + const { type, rangeFilteredRows } = formulaReferenceMoveParam; + const range = formulaReferenceMoveParam.range as IRange; + let newCell: IRange | null = null; let isReverse = false; @@ -346,7 +360,7 @@ function handleInsertDelete(type: FormulaReferenceMoveType, range: IRange, oldCe isReverse = true; break; case FormulaReferenceMoveType.RemoveRow: - newCell = handleRefRemoveRow(range, oldCell); + newCell = handleRefRemoveRow(range, oldCell, rangeFilteredRows); break; case FormulaReferenceMoveType.RemoveColumn: newCell = handleRefRemoveCol(range, oldCell); @@ -432,13 +446,14 @@ function handleRefInsertCol(range: IRange, oldCell: IRange) { return runRefRangeMutations(operators, oldCell); } -function handleRefRemoveRow(range: IRange, oldCell: IRange) { +function handleRefRemoveRow(range: IRange, oldCell: IRange, rangeFilteredRows?: number[]) { const operators = handleIRemoveRow( { id: EffectRefRangId.RemoveRowCommandId, params: { range }, }, - oldCell + oldCell, + rangeFilteredRows ); return runRefRangeMutations(operators, oldCell); diff --git a/packages/sheets-formula/src/controllers/utils/ref-range-move.ts b/packages/sheets-formula/src/controllers/utils/ref-range-move.ts index 4f2c9615a1..8185989730 100644 --- a/packages/sheets-formula/src/controllers/utils/ref-range-move.ts +++ b/packages/sheets-formula/src/controllers/utils/ref-range-move.ts @@ -66,7 +66,7 @@ export function getNewRangeByMoveParam( currentFormulaUnitId: string, currentFormulaSheetId: string ) { - const { type, unitId: userUnitId, sheetId: userSheetId, range, from, to } = formulaReferenceMoveParam; + const { type, unitId: userUnitId, sheetId: userSheetId, range, from, to, rangeFilteredRows } = formulaReferenceMoveParam; const { range: unitRange, @@ -241,7 +241,8 @@ export function getNewRangeByMoveParam( id: EffectRefRangId.RemoveRowCommandId, params: { range }, }, - sequenceRange + sequenceRange, + rangeFilteredRows ); const result = runRefRangeMutations(operators, sequenceRange); diff --git a/packages/sheets-formula/src/controllers/utils/ref-range-param.ts b/packages/sheets-formula/src/controllers/utils/ref-range-param.ts index 57667f9383..1506bd1043 100644 --- a/packages/sheets-formula/src/controllers/utils/ref-range-param.ts +++ b/packages/sheets-formula/src/controllers/utils/ref-range-param.ts @@ -287,6 +287,7 @@ function handleRefRemoveRow(command: ICommandInfo, w range, unitId, sheetId, + rangeFilteredRows: workbook.getSheetBySheetId(sheetId)?.getRangeFilterRows(range) ?? [], }; } diff --git a/packages/sheets/src/basics/utils.ts b/packages/sheets/src/basics/utils.ts index a4c19be135..3dff2ecf16 100644 --- a/packages/sheets/src/basics/utils.ts +++ b/packages/sheets/src/basics/utils.ts @@ -141,7 +141,7 @@ export function getActiveWorksheet(instanceService: UniverInstanceService): [Nul return [workbook, worksheet]; } -export function rangeToDiscreteRange(range: IRange, accessor: IAccessor, unitId?: string, subUnitId?: string, considerHide?: boolean): IDiscreteRange | null { +export function rangeToDiscreteRange(range: IRange, accessor: IAccessor, unitId?: string, subUnitId?: string): IDiscreteRange | null { const univerInstanceService = accessor.get(IUniverInstanceService); const workbook = unitId ? univerInstanceService.getUnit(unitId, UniverInstanceType.UNIVER_SHEET) @@ -156,23 +156,11 @@ export function rangeToDiscreteRange(range: IRange, accessor: IAccessor, unitId? const cols = []; for (let r = startRow; r <= endRow; r++) { if (!worksheet.getRowFiltered(r)) { - if (considerHide) { - if (worksheet.getRowRawVisible(r)) { - rows.push(r); - } - } else { - rows.push(r); - } + rows.push(r); } } for (let c = startColumn; c <= endColumn; c++) { - if (considerHide) { - if (worksheet.getColVisible(c)) { - cols.push(c); - } - } else { - cols.push(c); - } + cols.push(c); } return { rows, @@ -185,7 +173,7 @@ export function getVisibleRanges(ranges: IRange[], accessor: IAccessor, unitId?: const allCols: number[] = []; for (const range of ranges) { - const discreteRange = rangeToDiscreteRange(range, accessor, unitId, subUnitId, true); + const discreteRange = rangeToDiscreteRange(range, accessor, unitId, subUnitId); if (discreteRange) { allRows.push(...discreteRange.rows); diff --git a/packages/sheets/src/commands/commands/remove-row-col.command.ts b/packages/sheets/src/commands/commands/remove-row-col.command.ts index 1b2b211cfc..2b3ffac93c 100644 --- a/packages/sheets/src/commands/commands/remove-row-col.command.ts +++ b/packages/sheets/src/commands/commands/remove-row-col.command.ts @@ -106,33 +106,44 @@ export const RemoveRowByRangeCommand: ICommand = cellValue: removedRows.getMatrix(), }; - const intercepted = sheetInterceptorService.onCommandExecute({ - id: RemoveRowCommandId, - params: { range: visibleRange } as IRemoveRowColCommandParams, - }); - - redos.push(...(intercepted.preRedos ?? [])); redos.push({ id: RemoveRowMutation.id, params: removeRowsParams }); - redos.push(...(intercepted.redos ?? [])); - undos.push(...(intercepted.preUndos ?? [])); undos.push({ id: InsertRowMutation.id, params: undoRemoveRowsParams }); undos.push({ id: SetRangeValuesMutation.id, params: undoSetRangeValuesParams }); - undos.push(...(intercepted.undos ?? [])); redoMutations.push(...redos); undoMutations.unshift(...undos); }); - redoMutations.push(followSelectionOperation(range, workbook, worksheet)); + const intercepted = sheetInterceptorService.onCommandExecute({ + id: RemoveRowCommandId, + params: { range } as IRemoveRowColCommandParams, + }); const commandService = accessor.get(ICommandService); - const result = sequenceExecute(redoMutations, commandService); + const result = sequenceExecute( + [ + ...(intercepted.preRedos ?? []), + ...redoMutations, + ...intercepted.redos, + followSelectionOperation(range, workbook, worksheet), + ], + commandService + ); + if (result.result) { const undoRedoService = accessor.get(IUndoRedoService); undoRedoService.pushUndoRedo({ unitID: unitId, - undoMutations, - redoMutations, + undoMutations: [ + ...(intercepted.preUndos ?? []), + ...undoMutations, + ...intercepted.undos, + ], + redoMutations: [ + ...(intercepted.preRedos ?? []), + ...redoMutations, + ...intercepted.redos, + ], }); return true; } diff --git a/packages/sheets/src/services/ref-range/util.ts b/packages/sheets/src/services/ref-range/util.ts index 3145e06a1d..b60b17b671 100644 --- a/packages/sheets/src/services/ref-range/util.ts +++ b/packages/sheets/src/services/ref-range/util.ts @@ -516,23 +516,60 @@ export const handleIRemoveCol = (param: IRemoveRowColCommand, targetRange: IRang return operators; }; -export const handleIRemoveRow = (param: IRemoveRowColCommand, targetRange: IRange) => { +export const handleIRemoveRow = (param: IRemoveRowColCommand, targetRange: IRange, rangeFilteredRows?: number[]) => { const range = param.params?.range; if (!range) { return []; } + const operators: IOperator[] = []; - const result = handleBaseRemoveRange(rotateRange(range), rotateRange(targetRange)); - if (!result) { - operators.push({ type: OperatorType.Delete }); + + // check the remove range contains the filtered rows, if so, we need to skip the filtered rows + if (rangeFilteredRows && rangeFilteredRows.length > 0) { + let startRow = range.startRow; + + for (let r = range.startRow; r <= range.endRow; r++) { + if (rangeFilteredRows.includes(r)) { + if (r === startRow) { + startRow = r + 1; + continue; + } + + _handleBaseRemoveRange({ + ...range, + startRow, + endRow: r - 1, + }); + startRow = r + 1; + continue; + } + + if (r === range.endRow) { + _handleBaseRemoveRange({ + ...range, + startRow, + endRow: range.endRow, + }); + } + } } else { - const { step, length } = result; - operators.push({ - type: OperatorType.VerticalMove, - step, - length, - }); + _handleBaseRemoveRange(range); } + + function _handleBaseRemoveRange(removeRange: IRange) { + const result = handleBaseRemoveRange(rotateRange(removeRange), rotateRange(targetRange)); + if (!result) { + operators.push({ type: OperatorType.Delete }); + } else { + const { step, length } = result; + operators.push({ + type: OperatorType.VerticalMove, + step, + length, + }); + } + } + return operators; }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4092d6115b..a7745db5e3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3545,6 +3545,9 @@ importers: '@univerjs/sheets-data-validation': specifier: workspace:* version: link:../../packages/sheets-data-validation + '@univerjs/sheets-filter': + specifier: workspace:* + version: link:../../packages/sheets-filter '@univerjs/sheets-formula': specifier: workspace:* version: link:../../packages/sheets-formula diff --git a/tests/formula-integration/package.json b/tests/formula-integration/package.json index 0868fc2695..6a22ea85c2 100644 --- a/tests/formula-integration/package.json +++ b/tests/formula-integration/package.json @@ -19,6 +19,7 @@ "@univerjs/sheets": "workspace:*", "@univerjs/sheets-conditional-formatting": "workspace:*", "@univerjs/sheets-data-validation": "workspace:*", + "@univerjs/sheets-filter": "workspace:*", "@univerjs/sheets-formula": "workspace:*", "@univerjs/sheets-numfmt": "workspace:*", "univer-examples": "workspace:*" diff --git a/tests/formula-integration/src/__snapshots__/test-remove-rows---of-filter-rows-result.json b/tests/formula-integration/src/__snapshots__/test-remove-rows---of-filter-rows-result.json new file mode 100644 index 0000000000..109a49b242 --- /dev/null +++ b/tests/formula-integration/src/__snapshots__/test-remove-rows---of-filter-rows-result.json @@ -0,0 +1,327 @@ +{ + "id": "YoRIim", + "sheetOrder": [ + "_P52izs4-QQtg1AbFSjwH" + ], + "name": "", + "appVersion": "0.8.1", + "locale": "zhCN", + "styles": {}, + "sheets": { + "_P52izs4-QQtg1AbFSjwH": { + "id": "_P52izs4-QQtg1AbFSjwH", + "name": "Sheet1", + "tabColor": "", + "hidden": 0, + "rowCount": 998, + "columnCount": 20, + "zoomRatio": 1, + "freeze": { + "xSplit": 0, + "ySplit": 0, + "startRow": -1, + "startColumn": -1 + }, + "scrollTop": 0, + "scrollLeft": 0, + "defaultColumnWidth": 88, + "defaultRowHeight": 24, + "mergeData": [], + "cellData": { + "0": { + "0": { + "v": 1, + "t": 2 + }, + "1": { + "v": 2, + "t": 2 + }, + "2": { + "v": 3, + "t": 2 + }, + "3": { + "v": 4, + "t": 2 + }, + "4": { + "v": 5, + "t": 2 + }, + "5": { + "v": 6, + "t": 2 + }, + "6": { + "v": 7, + "t": 2 + } + }, + "1": { + "0": { + "v": 3, + "t": 2 + }, + "1": { + "v": 4, + "t": 2 + }, + "2": { + "v": 5, + "t": 2 + }, + "3": { + "v": 6, + "t": 2 + }, + "4": { + "v": 7, + "t": 2 + }, + "5": { + "v": 8, + "t": 2 + }, + "6": { + "v": 9, + "t": 2 + } + }, + "2": { + "0": { + "v": 4, + "t": 2 + }, + "1": { + "v": 5, + "t": 2 + }, + "2": { + "v": 6, + "t": 2 + }, + "3": { + "v": 7, + "t": 2 + }, + "4": { + "v": 8, + "t": 2 + }, + "5": { + "v": 9, + "t": 2 + }, + "6": { + "v": 10, + "t": 2 + } + }, + "3": { + "0": { + "v": 6, + "t": 2 + }, + "1": { + "v": 7, + "t": 2 + }, + "2": { + "v": 8, + "t": 2 + }, + "3": { + "v": 9, + "t": 2 + }, + "4": { + "v": 10, + "t": 2 + }, + "5": { + "v": 11, + "t": 2 + }, + "6": { + "v": 12, + "t": 2 + } + }, + "4": { + "0": { + "v": 7, + "t": 2 + }, + "1": { + "v": 8, + "t": 2 + }, + "2": { + "v": 9, + "t": 2 + }, + "3": { + "v": 10, + "t": 2 + }, + "4": { + "v": 11, + "t": 2 + }, + "5": { + "v": 12, + "t": 2 + }, + "6": { + "v": 13, + "t": 2 + } + }, + "5": { + "0": { + "v": 8, + "t": 2 + }, + "1": { + "v": 9, + "t": 2 + }, + "2": { + "v": 10, + "t": 2 + }, + "3": { + "v": 11, + "t": 2 + }, + "4": { + "v": 12, + "t": 2 + }, + "5": { + "v": 13, + "t": 2 + }, + "6": { + "v": 14, + "t": 2 + } + }, + "6": { + "0": { + "v": 9, + "t": 2 + }, + "1": { + "v": 10, + "t": 2 + }, + "2": { + "v": 11, + "t": 2 + }, + "3": { + "v": 12, + "t": 2 + }, + "4": { + "v": 13, + "t": 2 + }, + "5": { + "v": 14, + "t": 2 + }, + "6": { + "v": 15, + "t": 2 + } + }, + "7": { + "0": { + "v": 10, + "t": 2 + }, + "1": { + "v": 11, + "t": 2 + }, + "2": { + "v": 12, + "t": 2 + }, + "3": { + "v": 13, + "t": 2 + }, + "4": { + "v": 14, + "t": 2 + }, + "5": { + "v": 15, + "t": 2 + }, + "6": { + "v": 16, + "t": 2 + } + }, + "9": { + "1": { + "f": "=SUM(B8)", + "v": 11, + "t": 2 + } + } + }, + "rowData": {}, + "columnData": { + "5": { + "hd": 1 + } + }, + "showGridlines": 1, + "rowHeader": { + "width": 46, + "hidden": 0 + }, + "columnHeader": { + "height": 20, + "hidden": 0 + }, + "rightToLeft": 0 + } + }, + "resources": [ + { + "name": "SHEET_RANGE_PROTECTION_PLUGIN", + "data": "" + }, + { + "name": "SHEET_AuthzIoMockService_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_WORKSHEET_PROTECTION_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_WORKSHEET_PROTECTION_POINT_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_DEFINED_NAME_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_RANGE_THEME_MODEL_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_FILTER_PLUGIN", + "data": "{\"_P52izs4-QQtg1AbFSjwH\":{\"ref\":{\"startRow\":0,\"startColumn\":0,\"endRow\":3,\"endColumn\":6,\"rangeType\":0},\"filterColumns\":[{\"colId\":3,\"filters\":{\"filters\":[\"5\",\"8\",\"9\"]}}],\"cachedFilteredOut\":[1,2]}}" + } + ] +} diff --git a/tests/formula-integration/src/__snapshots__/test-remove-rows---of-filter-rows.json b/tests/formula-integration/src/__snapshots__/test-remove-rows---of-filter-rows.json new file mode 100644 index 0000000000..81d9a6aba1 --- /dev/null +++ b/tests/formula-integration/src/__snapshots__/test-remove-rows---of-filter-rows.json @@ -0,0 +1,387 @@ +{ + "id": "YoRIim", + "sheetOrder": [ + "_P52izs4-QQtg1AbFSjwH" + ], + "name": "", + "appVersion": "0.8.1", + "locale": "zhCN", + "styles": {}, + "sheets": { + "_P52izs4-QQtg1AbFSjwH": { + "id": "_P52izs4-QQtg1AbFSjwH", + "name": "Sheet1", + "tabColor": "", + "hidden": 0, + "rowCount": 1000, + "columnCount": 20, + "zoomRatio": 1, + "freeze": { + "xSplit": 0, + "ySplit": 0, + "startRow": -1, + "startColumn": -1 + }, + "scrollTop": 0, + "scrollLeft": 0, + "defaultColumnWidth": 88, + "defaultRowHeight": 24, + "mergeData": [], + "cellData": { + "0": { + "0": { + "v": 1, + "t": 2 + }, + "1": { + "v": 2, + "t": 2 + }, + "2": { + "v": 3, + "t": 2 + }, + "3": { + "v": 4, + "t": 2 + }, + "4": { + "v": 5, + "t": 2 + }, + "5": { + "v": 6, + "t": 2 + }, + "6": { + "v": 7, + "t": 2 + } + }, + "1": { + "0": { + "v": 2, + "t": 2 + }, + "1": { + "v": 3, + "t": 2 + }, + "2": { + "v": 4, + "t": 2 + }, + "3": { + "v": 5, + "t": 2 + }, + "4": { + "v": 6, + "t": 2 + }, + "5": { + "v": 7, + "t": 2 + }, + "6": { + "v": 8, + "t": 2 + } + }, + "2": { + "0": { + "v": 3, + "t": 2 + }, + "1": { + "v": 4, + "t": 2 + }, + "2": { + "v": 5, + "t": 2 + }, + "3": { + "v": 6, + "t": 2 + }, + "4": { + "v": 7, + "t": 2 + }, + "5": { + "v": 8, + "t": 2 + }, + "6": { + "v": 9, + "t": 2 + } + }, + "3": { + "0": { + "v": 4, + "t": 2 + }, + "1": { + "v": 5, + "t": 2 + }, + "2": { + "v": 6, + "t": 2 + }, + "3": { + "v": 7, + "t": 2 + }, + "4": { + "v": 8, + "t": 2 + }, + "5": { + "v": 9, + "t": 2 + }, + "6": { + "v": 10, + "t": 2 + } + }, + "4": { + "0": { + "v": 5, + "t": 2 + }, + "1": { + "v": 6, + "t": 2 + }, + "2": { + "v": 7, + "t": 2 + }, + "3": { + "v": 8, + "t": 2 + }, + "4": { + "v": 9, + "t": 2 + }, + "5": { + "v": 10, + "t": 2 + }, + "6": { + "v": 11, + "t": 2 + } + }, + "5": { + "0": { + "v": 6, + "t": 2 + }, + "1": { + "v": 7, + "t": 2 + }, + "2": { + "v": 8, + "t": 2 + }, + "3": { + "v": 9, + "t": 2 + }, + "4": { + "v": 10, + "t": 2 + }, + "5": { + "v": 11, + "t": 2 + }, + "6": { + "v": 12, + "t": 2 + } + }, + "6": { + "0": { + "v": 7, + "t": 2 + }, + "1": { + "v": 8, + "t": 2 + }, + "2": { + "v": 9, + "t": 2 + }, + "3": { + "v": 10, + "t": 2 + }, + "4": { + "v": 11, + "t": 2 + }, + "5": { + "v": 12, + "t": 2 + }, + "6": { + "v": 13, + "t": 2 + } + }, + "7": { + "0": { + "v": 8, + "t": 2 + }, + "1": { + "v": 9, + "t": 2 + }, + "2": { + "v": 10, + "t": 2 + }, + "3": { + "v": 11, + "t": 2 + }, + "4": { + "v": 12, + "t": 2 + }, + "5": { + "v": 13, + "t": 2 + }, + "6": { + "v": 14, + "t": 2 + } + }, + "8": { + "0": { + "v": 9, + "t": 2 + }, + "1": { + "v": 10, + "t": 2 + }, + "2": { + "v": 11, + "t": 2 + }, + "3": { + "v": 12, + "t": 2 + }, + "4": { + "v": 13, + "t": 2 + }, + "5": { + "v": 14, + "t": 2 + }, + "6": { + "v": 15, + "t": 2 + } + }, + "9": { + "0": { + "v": 10, + "t": 2 + }, + "1": { + "v": 11, + "t": 2 + }, + "2": { + "v": 12, + "t": 2 + }, + "3": { + "v": 13, + "t": 2 + }, + "4": { + "v": 14, + "t": 2 + }, + "5": { + "v": 15, + "t": 2 + }, + "6": { + "v": 16, + "t": 2 + } + }, + "11": { + "1": { + "f": "=SUM(B10)", + "v": 11, + "t": 2 + } + } + }, + "rowData": {}, + "columnData": { + "5": { + "hd": 1 + } + }, + "showGridlines": 1, + "rowHeader": { + "width": 46, + "hidden": 0 + }, + "columnHeader": { + "height": 20, + "hidden": 0 + }, + "rightToLeft": 0 + } + }, + "resources": [ + { + "name": "SHEET_RANGE_PROTECTION_PLUGIN", + "data": "" + }, + { + "name": "SHEET_AuthzIoMockService_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_WORKSHEET_PROTECTION_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_WORKSHEET_PROTECTION_POINT_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_DEFINED_NAME_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_RANGE_THEME_MODEL_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_FILTER_PLUGIN", + "data": "{\"_P52izs4-QQtg1AbFSjwH\":{\"ref\":{\"startRow\":0,\"startColumn\":0,\"endRow\":5,\"endColumn\":6,\"rangeType\":0},\"filterColumns\":[{\"colId\":3,\"filters\":{\"filters\":[\"5\",\"8\",\"9\"]}}],\"cachedFilteredOut\":[2,3]}}" + } + ] +} diff --git a/tests/formula-integration/src/__testing__/test-remove-rows-of-filter-rows.ts b/tests/formula-integration/src/__testing__/test-remove-rows-of-filter-rows.ts new file mode 100644 index 0000000000..53a4c8144d --- /dev/null +++ b/tests/formula-integration/src/__testing__/test-remove-rows-of-filter-rows.ts @@ -0,0 +1,98 @@ +/** + * Copyright 2023-present DreamNum Co., Ltd. + * + * 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 fs from 'node:fs'; +import path from 'node:path'; +import { IUniverInstanceService, type IWorkbookData, LocaleType, Univer } from '@univerjs/core'; +import { FUniver } from '@univerjs/core/facade'; +import { UniverFormulaEnginePlugin } from '@univerjs/engine-formula'; +import zhCN from '@univerjs/mockdata/locales/zh-CN'; +import { UniverSheetsPlugin } from '@univerjs/sheets'; +import { UniverSheetsFilterPlugin } from '@univerjs/sheets-filter'; +import { UniverSheetsFormulaPlugin } from '@univerjs/sheets-formula'; +import { expect } from 'vitest'; +import { getTestFilePath, getTestName } from './util'; + +function createTestBed() { + const univer = new Univer({ + locale: LocaleType.ZH_CN, + locales: { + [LocaleType.ZH_CN]: zhCN, + }, + }); + + univer.registerPlugin(UniverFormulaEnginePlugin); + univer.registerPlugin(UniverSheetsPlugin); + univer.registerPlugin(UniverSheetsFormulaPlugin); + univer.registerPlugin(UniverSheetsFilterPlugin); + + const injector = univer.__getInjector(); + + return { + univer, + get: injector.get.bind(injector), + api: FUniver.newAPI(univer), + }; +} + +export async function expectRemoveRowsOfFilterRowsResultMatchesSnapshot() { + const testBed = createTestBed(); + const snapshotRootDir = path.join(import.meta.dirname, '../__snapshots__'); + + const testSnapshotPath = path.resolve(snapshotRootDir, `${getTestFilePath()}.json`); + if (!fs.existsSync(testSnapshotPath)) { + throw new Error(`Cannot find snapshot file for test "${getTestName()}".`); + } + + const testSnapshotRaw = fs.readFileSync(testSnapshotPath, 'utf-8'); + const testSnapshot = JSON.parse(testSnapshotRaw) as IWorkbookData; + + const workbook = testBed.api.createWorkbook(testSnapshot); + const univerInstanceService = testBed.get(IUniverInstanceService); + univerInstanceService.focusUnit('YoRIim'); + const worksheet = workbook.getActiveSheet(); + + // remove rows 2 to 5, where the 3 to 4 rows are filtered rows + worksheet.deleteRows(1, 4); + + const resultSnapshot = workbook.save(); + const snapshotFilePath = path.resolve(snapshotRootDir, `${getTestFilePath()}-result.json`); + if (fs.existsSync(snapshotFilePath)) { + const resultSnapshotFileString = fs.readFileSync(snapshotFilePath, 'utf-8'); + expect(resultSnapshot).toMatchObject(JSON.parse(resultSnapshotFileString)); + } else { + fs.writeFileSync(snapshotFilePath, JSON.stringify(resultSnapshot, null, 4)); + + // eslint-disable-next-line no-console + console.log(`Snapshot file created at: ${snapshotFilePath}`); + } + + // perform undo operation + await testBed.api.undo(); + + // compare the result with the snapshot + const resultSnapshot_undo = workbook.save(); + const snapshotFilePath_undo = path.resolve(snapshotRootDir, `${getTestFilePath()}.json`); + if (fs.existsSync(snapshotFilePath_undo)) { + const resultSnapshotFileString = fs.readFileSync(snapshotFilePath_undo, 'utf-8'); + expect(resultSnapshot_undo).toMatchObject(JSON.parse(resultSnapshotFileString)); + } else { + fs.writeFileSync(snapshotFilePath_undo, JSON.stringify(resultSnapshot_undo, null, 4)); + + // eslint-disable-next-line no-console + console.log(`Snapshot file created at: ${snapshotFilePath_undo}`); + } +} diff --git a/tests/formula-integration/src/__testing__/util.ts b/tests/formula-integration/src/__testing__/util.ts index cd28529211..84cb27f940 100644 --- a/tests/formula-integration/src/__testing__/util.ts +++ b/tests/formula-integration/src/__testing__/util.ts @@ -20,7 +20,7 @@ import path from 'node:path'; import { expect } from 'vitest'; import { createFormulaTestBed } from './univer'; -function getTestName(): string { +export function getTestName(): string { const testName = expect.getState().currentTestName; if (!testName) { throw new Error('Cannot get test name. Maybe you call the method outside a test case?'); diff --git a/tests/formula-integration/src/__tests__/test-remove-rows-of-filter-rows.spec.ts b/tests/formula-integration/src/__tests__/test-remove-rows-of-filter-rows.spec.ts new file mode 100644 index 0000000000..b9e8059c91 --- /dev/null +++ b/tests/formula-integration/src/__tests__/test-remove-rows-of-filter-rows.spec.ts @@ -0,0 +1,24 @@ +/** + * Copyright 2023-present DreamNum Co., Ltd. + * + * 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 { describe, it } from 'vitest'; +import { expectRemoveRowsOfFilterRowsResultMatchesSnapshot } from '../__testing__/test-remove-rows-of-filter-rows'; + +describe('Test remove rows', () => { + it('of filter rows', () => { + expectRemoveRowsOfFilterRowsResultMatchesSnapshot(); + }); +});