Skip to content

Commit b0c2d66

Browse files
committed
[FIX] clickable cells: prevent overlap with grid icons
If a cell has both a clickable cell and a clickable grid icon (eg. a link in a cell with a filter icon), clicking the icon would click the clickable cell. With this commit, we reduce the clickable cell size based on the position of the icons on the cell to prevent any overlap. closes #7569 Task: 4930803 X-original-commit: 645e850 Signed-off-by: Pierre Rousseau (pro) <pro@odoo.com>
1 parent 45725c9 commit b0c2d66

File tree

2 files changed

+106
-4
lines changed

2 files changed

+106
-4
lines changed

src/components/dashboard/clickable_cell_store.ts

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,18 @@ export class ClickableCellsStore extends SpreadsheetStore {
6666
get clickableCells(): ClickableCell[] {
6767
const cells: ClickableCell[] = [];
6868
const getters = this.getters;
69-
const sheetId = getters.getActiveSheetId();
7069
for (const position of this.getters.getVisibleCellPositions()) {
7170
const item = this.getClickableItem(position);
7271
if (!item) {
7372
continue;
7473
}
7574
const title = typeof item.title === "function" ? item.title(position, getters) : item.title;
76-
const zone = getters.expandZone(sheetId, positionToZone(position));
75+
const rect = this.getClickableCellRect(position);
76+
if (!rect) {
77+
continue;
78+
}
7779
cells.push({
78-
coordinates: getters.getVisibleRect(zone),
80+
coordinates: rect,
7981
position,
8082
action: item.execute,
8183
title: title || "",
@@ -85,4 +87,32 @@ export class ClickableCellsStore extends SpreadsheetStore {
8587
}
8688
return cells;
8789
}
90+
91+
private getClickableCellRect(position: CellPosition): Rect | undefined {
92+
const zone = this.getters.expandZone(position.sheetId, positionToZone(position));
93+
const clickableRect = this.getters.getVisibleRect(zone);
94+
95+
const icons = this.getters.getCellIcons(position);
96+
const iconsAtPosition = {
97+
center: icons.find((icon) => icon.horizontalAlign === "center"),
98+
left: icons.find((icon) => icon.horizontalAlign === "left"),
99+
right: icons.find((icon) => icon.horizontalAlign === "right"),
100+
};
101+
if (iconsAtPosition.center?.onClick) {
102+
return undefined;
103+
}
104+
if (iconsAtPosition.right?.onClick) {
105+
const cellRect = this.getters.getRect(zone);
106+
const iconRect = this.getters.getCellIconRect(iconsAtPosition.right, cellRect);
107+
clickableRect.width -= iconRect.width + iconsAtPosition.right.margin;
108+
}
109+
if (iconsAtPosition.left?.onClick) {
110+
const cellRect = this.getters.getRect(zone);
111+
const iconRect = this.getters.getCellIconRect(iconsAtPosition.left, cellRect);
112+
clickableRect.x += iconRect.width + iconsAtPosition.left.margin;
113+
clickableRect.width -= iconRect.width + iconsAtPosition.left.margin;
114+
}
115+
116+
return clickableRect;
117+
}
88118
}

tests/grid/dashboard_grid_component.test.ts

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Spreadsheet } from "../../src";
1+
import { Align, Spreadsheet } from "../../src";
2+
import { CHECKBOX_CHECKED } from "../../src/components/icons/icons";
23
import {
34
DEFAULT_CELL_HEIGHT,
45
DEFAULT_CELL_WIDTH,
@@ -9,6 +10,7 @@ import {
910
import { toZone } from "../../src/helpers";
1011
import { Model } from "../../src/model";
1112
import { clickableCellRegistry } from "../../src/registries/cell_clickable_registry";
13+
import { GridIcon, iconsOnCellRegistry } from "../../src/registries/icons_on_cell_registry";
1214
import {
1315
createTableWithFilter,
1416
selectCell,
@@ -221,4 +223,74 @@ describe("Grid component in dashboard mode", () => {
221223
"hello Magical Françoise"
222224
);
223225
});
226+
227+
const TEST_GRID_ICON: GridIcon = {
228+
horizontalAlign: "left",
229+
size: 20,
230+
margin: 2,
231+
type: "debug_icon",
232+
position: { sheetId: "s1", col: 0, row: 0 },
233+
priority: 1,
234+
svg: CHECKBOX_CHECKED,
235+
onClick: () => {},
236+
};
237+
238+
test("Clickable cell size is reduced based on the icon on the cell", async () => {
239+
let horizontalAlign: Exclude<Align, undefined> = "center";
240+
241+
addToRegistry(clickableCellRegistry, "fake", {
242+
condition: (position, getters) => position.row === 0 && position.col === 0,
243+
execute: () => () => {},
244+
sequence: 5,
245+
});
246+
addToRegistry(iconsOnCellRegistry, "test_icon", (getters, position) =>
247+
position.col === 0 && position.row === 0 ? { ...TEST_GRID_ICON, horizontalAlign } : undefined
248+
);
249+
250+
model.updateMode("dashboard");
251+
await nextTick();
252+
253+
expect("div.o-dashboard-clickable-cell").toHaveCount(0); // because center icon => no clickable cell
254+
255+
horizontalAlign = "right";
256+
model.dispatch("EVALUATE_CELLS");
257+
await nextTick();
258+
expect("div.o-dashboard-clickable-cell").toHaveStyle({
259+
left: "0px",
260+
width: DEFAULT_CELL_WIDTH - TEST_GRID_ICON.size - TEST_GRID_ICON.margin + "px",
261+
height: DEFAULT_CELL_HEIGHT + "px",
262+
});
263+
264+
horizontalAlign = "left";
265+
model.dispatch("EVALUATE_CELLS");
266+
await nextTick();
267+
expect("div.o-dashboard-clickable-cell").toHaveStyle({
268+
left: 20 + 2 + "px",
269+
width: DEFAULT_CELL_WIDTH - TEST_GRID_ICON.size - TEST_GRID_ICON.margin + "px",
270+
height: DEFAULT_CELL_HEIGHT + "px",
271+
});
272+
});
273+
274+
test("Clickable cell size is not reduced if the icon has no onClick action", async () => {
275+
addToRegistry(clickableCellRegistry, "fake", {
276+
condition: (position, getters) => position.row === 0 && position.col === 0,
277+
execute: () => () => {},
278+
sequence: 5,
279+
});
280+
addToRegistry(iconsOnCellRegistry, "test_icon", (getters, position) =>
281+
position.col === 0 && position.row === 0
282+
? { ...TEST_GRID_ICON, onClick: undefined }
283+
: undefined
284+
);
285+
286+
model.updateMode("dashboard");
287+
await nextTick();
288+
await nextTick(); // Need to wait one render to have correct grid position with the resize observers
289+
290+
expect("div.o-dashboard-clickable-cell").toHaveStyle({
291+
left: "0px",
292+
width: DEFAULT_CELL_WIDTH + "px",
293+
height: DEFAULT_CELL_HEIGHT + "px",
294+
});
295+
});
224296
});

0 commit comments

Comments
 (0)