Skip to content

Commit 4123c85

Browse files
committed
[FIX] OT: fix missing transformations
With the OT registry condition, there are some Specific range transformations that are bypassed, specifically for changing the content of a cell after the renaming of a sheet. This revision adds a check for specific range transformation to ensure that we correctly update the content of a cell after a transformation. More widely, this also allows to support the range conversion upon sheet renaming for charts, cf, data validations and pivot computed measures. While this is an improvement of behaviour, it is a necessary refactoring to fix the update of ranges inside the gauge charts. Task: 4868971 X-original-commit: f14a229 Part-of: #7030 Signed-off-by: Lucas Lefèvre (lul) <lul@odoo.com> Signed-off-by: Rémi Rahir (rar) <rar@odoo.com>
1 parent 331cc7d commit 4123c85

File tree

11 files changed

+281
-60
lines changed

11 files changed

+281
-60
lines changed

src/collaborative/ot/ot.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
isInside,
66
moveHeaderIndexesOnHeaderAddition,
77
moveHeaderIndexesOnHeaderDeletion,
8+
rangeAdapterRegistry,
89
} from "../../helpers/index";
910
import { otRegistry } from "../../registries/ot_registry";
1011
import { specificRangeTransformRegistry } from "../../registries/srt_registry";
@@ -102,7 +103,10 @@ export function transformAll(
102103
// If the executed command is not in the registry, we skip it
103104
// because we know there won't be any transformation impacting the
104105
// commands to transform.
105-
if (possibleTransformations.has(executedCommand.type)) {
106+
if (
107+
possibleTransformations.has(executedCommand.type) ||
108+
rangeAdapterRegistry.contains(executedCommand.type)
109+
) {
106110
transformedCommands = transformedCommands.reduce<CoreCommand[]>((acc, cmd) => {
107111
const transformed = transform(cmd, executedCommand);
108112
if (transformed) {

src/helpers/formulas.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export function adaptStringRange(
3939
const sheetName = splitReference(sheetXC).sheetName;
4040
if (
4141
sheetName
42-
? !isSheetNameEqual(sheetName, applyChange.sheetName)
42+
? !isSheetNameEqual(sheetName, applyChange.sheetName.old)
4343
: defaultSheetId !== applyChange.sheetId
4444
) {
4545
return sheetXC;
@@ -61,7 +61,7 @@ export function adaptStringRange(
6161

6262
function getSheetNameGetter(applyChange: RangeAdapter) {
6363
return (sheetId: UID): string => {
64-
return sheetId === applyChange.sheetId ? applyChange.sheetName : "";
64+
return sheetId === applyChange.sheetId ? applyChange.sheetName.current : "";
6565
};
6666
}
6767

src/helpers/range.ts

Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import { Registry } from "../registries/registry";
12
import {
23
AddColumnsRowsCommand,
34
ApplyRangeChange,
45
CellPosition,
56
ChangeType,
6-
Command,
7+
CoreCommand,
8+
CoreCommandTypes,
79
CoreGetters,
810
DeleteSheetCommand,
911
MoveRangeCommand,
@@ -284,42 +286,54 @@ export function orderRange(range: Range): Range {
284286
};
285287
}
286288

287-
export function getRangeAdapter(cmd: Command): RangeAdapter | undefined {
288-
switch (cmd.type) {
289-
case "REMOVE_COLUMNS_ROWS":
290-
return {
291-
applyChange: getApplyRangeChangeRemoveColRow(cmd),
292-
sheetId: cmd.sheetId,
293-
sheetName: cmd.sheetName,
294-
};
295-
case "ADD_COLUMNS_ROWS":
296-
return {
297-
applyChange: getApplyRangeChangeAddColRow(cmd),
298-
sheetId: cmd.sheetId,
299-
sheetName: cmd.sheetName,
300-
};
301-
case "DELETE_SHEET":
302-
return {
303-
applyChange: getApplyRangeChangeDeleteSheet(cmd),
304-
sheetId: cmd.sheetId,
305-
sheetName: cmd.sheetName,
306-
};
307-
case "RENAME_SHEET":
308-
return {
309-
applyChange: getApplyRangeChangeRenameSheet(cmd),
310-
sheetId: cmd.sheetId,
311-
sheetName: cmd.oldName,
312-
};
313-
case "MOVE_RANGES":
314-
return {
315-
applyChange: getApplyRangeChangeMoveRange(cmd),
316-
sheetId: cmd.sheetId,
317-
sheetName: cmd.sheetName,
318-
};
289+
export function getRangeAdapter(cmd: CoreCommand): RangeAdapter | undefined {
290+
return rangeAdapterRegistry.get(cmd.type)?.(cmd);
291+
}
292+
293+
type GetRangeAdapter<C extends CoreCommand> = (cmd: C) => RangeAdapter;
294+
295+
class RangeAdapterRegistry extends Registry<GetRangeAdapter<CoreCommand>> {
296+
add<C extends CoreCommandTypes>(
297+
cmdType: C,
298+
fn: GetRangeAdapter<Extract<CoreCommand, { type: C }>>
299+
): this {
300+
super.add(cmdType, fn);
301+
return this;
302+
}
303+
get<C extends CoreCommandTypes>(cmdType: C): GetRangeAdapter<Extract<CoreCommand, { type: C }>> {
304+
return this.content[cmdType];
319305
}
320-
return undefined;
321306
}
322307

308+
export const rangeAdapterRegistry = new RangeAdapterRegistry();
309+
310+
rangeAdapterRegistry
311+
.add("REMOVE_COLUMNS_ROWS", (cmd) => ({
312+
applyChange: getApplyRangeChangeRemoveColRow(cmd),
313+
sheetId: cmd.sheetId,
314+
sheetName: { old: cmd.sheetName, current: cmd.sheetName },
315+
}))
316+
.add("ADD_COLUMNS_ROWS", (cmd) => ({
317+
applyChange: getApplyRangeChangeAddColRow(cmd),
318+
sheetId: cmd.sheetId,
319+
sheetName: { old: cmd.sheetName, current: cmd.sheetName },
320+
}))
321+
.add("DELETE_SHEET", (cmd) => ({
322+
applyChange: getApplyRangeChangeDeleteSheet(cmd),
323+
sheetId: cmd.sheetId,
324+
sheetName: { old: cmd.sheetName, current: cmd.sheetName },
325+
}))
326+
.add("RENAME_SHEET", (cmd) => ({
327+
applyChange: getApplyRangeChangeRenameSheet(cmd),
328+
sheetId: cmd.sheetId,
329+
sheetName: { old: cmd.oldName, current: cmd.newName },
330+
}))
331+
.add("MOVE_RANGES", (cmd) => ({
332+
applyChange: getApplyRangeChangeMoveRange(cmd),
333+
sheetId: cmd.sheetId,
334+
sheetName: { old: cmd.sheetName, current: cmd.sheetName },
335+
}));
336+
323337
function getApplyRangeChangeRemoveColRow(cmd: RemoveColumnsRowsCommand): ApplyRangeChange {
324338
const start: "left" | "top" = cmd.dimension === "COL" ? "left" : "top";
325339
const end: "right" | "bottom" = cmd.dimension === "COL" ? "right" : "bottom";

src/plugins/core/cell.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
toXC,
2121
} from "../../helpers/index";
2222
import {
23+
AdaptSheetName,
2324
AddColumnsRowsCommand,
2425
ApplyRangeChange,
2526
Cell,
@@ -72,12 +73,12 @@ export class CellPlugin extends CorePlugin<CoreState> implements CoreState {
7273
readonly nextId = 1;
7374
public readonly cells: { [sheetId: string]: { [id: string]: Cell } } = {};
7475

75-
adaptRanges(applyChange: ApplyRangeChange, sheetId: UID, sheetName: string) {
76+
adaptRanges(applyChange: ApplyRangeChange, sheetId: UID, sheetName: AdaptSheetName) {
7677
for (const sheet of Object.keys(this.cells)) {
7778
for (const cell of Object.values(this.cells[sheet] || {})) {
7879
if (cell.isFormula) {
7980
for (const range of cell.compiledFormula.dependencies) {
80-
if (range.sheetId === sheetId || range.invalidSheetName === sheetName) {
81+
if (range.sheetId === sheetId || range.invalidSheetName === sheetName.old) {
8182
const change = applyChange(range);
8283
if (change.changeType !== "NONE") {
8384
this.history.update(

src/plugins/core/conditional_format.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ export class ConditionalFormatPlugin
180180
}
181181
}
182182

183-
adaptRanges(applyChange: ApplyRangeChange, sheetId?: UID, sheetName?: string) {
183+
adaptRanges(applyChange: ApplyRangeChange, sheetId: UID) {
184184
const sheetIds = sheetId ? [sheetId] : Object.keys(this.cfRules);
185185
for (const sheetId of sheetIds) {
186186
this.adaptCFRanges(sheetId, applyChange);

src/plugins/core/range.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
} from "../../helpers/index";
1818
import { CellErrorType } from "../../types/errors";
1919
import {
20+
AdaptSheetName,
2021
ApplyRangeChange,
2122
ApplyRangeChangeResult,
2223
Command,
@@ -62,15 +63,15 @@ export class RangeAdapter implements CommandHandler<CoreCommand> {
6263
// ---------------------------------------------------------------------------
6364
// Command Handling
6465
// ---------------------------------------------------------------------------
65-
allowDispatch(cmd: Command): CommandResult {
66+
allowDispatch(cmd: CoreCommand): CommandResult {
6667
if (cmd.type === "MOVE_RANGES") {
6768
return cmd.target.length === 1 ? CommandResult.Success : CommandResult.InvalidZones;
6869
}
6970
return CommandResult.Success;
7071
}
7172
beforeHandle(command: Command) {}
7273

73-
handle(cmd: Command) {
74+
handle(cmd: CoreCommand) {
7475
const rangeAdapter = getRangeAdapter(cmd);
7576
if (rangeAdapter?.applyChange) {
7677
this.executeOnAllRanges(
@@ -99,7 +100,11 @@ export class RangeAdapter implements CommandHandler<CoreCommand> {
99100
};
100101
}
101102

102-
private executeOnAllRanges(adaptRange: ApplyRangeChange, sheetId: UID, sheetName: string) {
103+
private executeOnAllRanges(
104+
adaptRange: ApplyRangeChange,
105+
sheetId: UID,
106+
sheetName: AdaptSheetName
107+
) {
103108
const func = this.verifyRangeRemoved(adaptRange);
104109
for (const provider of this.providers) {
105110
provider(func, sheetId, sheetName);

src/plugins/core_plugin.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ModelConfig } from "../model";
22
import { StateObserver } from "../state_observer";
33
import {
4+
AdaptSheetName,
45
ApplyRangeChange,
56
CoreCommand,
67
CoreCommandDispatcher,
@@ -64,9 +65,10 @@ export class CorePlugin<State = any>
6465
* the type of change that occurred.
6566
*
6667
* @param applyChange a function that, when called, will adapt the range according to the change on the grid
67-
* @param sheetId an optional sheetId to adapt either range of that sheet specifically, or ranges pointing to that sheet
68+
* @param sheetId an sheetId to adapt either range of that sheet specifically, or ranges pointing to that sheet
69+
* @param sheetName couple of old and new sheet names to adapt ranges pointing to that sheet
6870
*/
69-
adaptRanges(applyChange: ApplyRangeChange, sheetId: UID, sheetName: string): void {}
71+
adaptRanges(applyChange: ApplyRangeChange, sheetId: UID, sheetName: AdaptSheetName): void {}
7072

7173
/**
7274
* Implement this method to clean unused external resources, such as images

src/registries/inverse_command_registry.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
RemoveMergeCommand,
1717
RemovePivotCommand,
1818
RemoveTableStyleCommand,
19+
RenameSheetCommand,
1920
UnhideColumnsRowsCommand,
2021
coreTypes,
2122
} from "../types/commands";
@@ -37,7 +38,8 @@ export const inverseCommandRegistry = new Registry<InverseFunction>()
3738
.add("HIDE_COLUMNS_ROWS", inverseHideColumnsRows)
3839
.add("UNHIDE_COLUMNS_ROWS", inverseUnhideColumnsRows)
3940
.add("CREATE_TABLE_STYLE", inverseCreateTableStyle)
40-
.add("ADD_PIVOT", inverseAddPivot);
41+
.add("ADD_PIVOT", inverseAddPivot)
42+
.add("RENAME_SHEET", inverseRenameSheet);
4143

4244
for (const cmd of coreTypes.values()) {
4345
if (!inverseCommandRegistry.contains(cmd)) {
@@ -150,3 +152,14 @@ function inverseUnhideColumnsRows(cmd: UnhideColumnsRowsCommand): HideColumnsRow
150152
function inverseCreateTableStyle(cmd: CreateTableStyleCommand): RemoveTableStyleCommand[] {
151153
return [{ type: "REMOVE_TABLE_STYLE", tableStyleId: cmd.tableStyleId }];
152154
}
155+
156+
function inverseRenameSheet(cmd: RenameSheetCommand): RenameSheetCommand[] {
157+
return [
158+
{
159+
type: "RENAME_SHEET",
160+
sheetId: cmd.sheetId,
161+
oldName: cmd.newName,
162+
newName: cmd.oldName,
163+
},
164+
];
165+
}

src/registries/srt_registry.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,9 @@ import { Registry } from "./registry";
1111
*
1212
*/
1313

14-
export type CommandAdaptRangeFunction<C extends CoreCommand> = (
15-
cmd: C,
16-
applyChange: RangeAdapter
17-
) => C;
14+
type CommandAdaptRangeFunction<C extends CoreCommand> = (cmd: C, applyChange: RangeAdapter) => C;
1815

19-
export class SpecificRangeTransformRegistry extends Registry<
20-
CommandAdaptRangeFunction<CoreCommand>
21-
> {
16+
class SpecificRangeTransformRegistry extends Registry<CommandAdaptRangeFunction<CoreCommand>> {
2217
add<C extends CoreCommand>(cmdType: C["type"], fn: CommandAdaptRangeFunction<C>): this {
2318
super.add(cmdType, fn);
2419
return this;

src/types/misc.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,11 @@ export type ApplyRangeChangeResult =
293293
| { changeType: "NONE" };
294294
export type ApplyRangeChange = (range: Range) => ApplyRangeChangeResult;
295295

296+
export type AdaptSheetName = { old: string; current: string };
297+
296298
export type RangeAdapter = {
297299
sheetId: UID;
298-
sheetName: string;
300+
sheetName: AdaptSheetName;
299301
applyChange: ApplyRangeChange;
300302
};
301303

@@ -304,7 +306,7 @@ export type Dimension = "COL" | "ROW";
304306
export type ConsecutiveIndexes = HeaderIndex[];
305307

306308
export interface RangeProvider {
307-
adaptRanges: (applyChange: ApplyRangeChange, sheetId: UID, sheetName: string) => void;
309+
adaptRanges: (applyChange: ApplyRangeChange, sheetId: UID, sheetName: AdaptSheetName) => void;
308310
}
309311

310312
export type Validation<T> = (toValidate: T) => CommandResult | CommandResult[];

0 commit comments

Comments
 (0)