Skip to content

Commit 1d5199b

Browse files
committed
[IMP] carousel: allow duplicating charts in carousel
This commit adds a button in the cog wheel of the carousel panel to duplicate charts in the carousel. closes #7121 Task: 5081788 Signed-off-by: Lucas Lefèvre (lul) <lul@odoo.com>
1 parent b7a78da commit 1d5199b

File tree

5 files changed

+120
-2
lines changed

5 files changed

+120
-2
lines changed

packages/o-spreadsheet-engine/src/plugins/ui_stateful/carousel_ui.ts

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import { UuidGenerator } from "../../helpers";
22
import { CAROUSEL_DEFAULT_CHART_DEFINITION } from "../../helpers/carousel_helpers";
33
import { AbstractChart } from "../../helpers/figures/charts/abstract_chart";
4-
import { deepEquals } from "../../helpers/misc";
5-
import { Command, CommandResult, LocalCommand } from "../../types/commands";
4+
import { deepEquals, insertItemsAtIndex } from "../../helpers/misc";
5+
import {
6+
Command,
7+
CommandResult,
8+
DuplicateCarouselChartCommand,
9+
LocalCommand,
10+
} from "../../types/commands";
611
import { Carousel, CarouselItem } from "../../types/figure";
712
import { UID } from "../../types/misc";
813
import { UIPlugin } from "../ui_plugin";
@@ -28,6 +33,17 @@ export class CarouselUIPlugin extends UIPlugin {
2833
return CommandResult.InvalidFigureId;
2934
}
3035
return CommandResult.Success;
36+
case "DUPLICATE_CAROUSEL_CHART":
37+
if (
38+
!this.getters.doesCarouselExist(cmd.carouselId) ||
39+
!this.getters
40+
.getCarousel(cmd.carouselId)
41+
.items.some((item) => item.type === "chart" && item.chartId === cmd.chartId) ||
42+
this.getters.getChart(cmd.duplicatedChartId)
43+
) {
44+
return CommandResult.InvalidFigureId;
45+
}
46+
return CommandResult.Success;
3147
case "ADD_NEW_CHART_TO_CAROUSEL":
3248
if (!this.getters.doesCarouselExist(cmd.figureId)) {
3349
return CommandResult.InvalidFigureId;
@@ -55,6 +71,9 @@ export class CarouselUIPlugin extends UIPlugin {
5571
case "ADD_FIGURE_CHART_TO_CAROUSEL":
5672
this.addFigureChartToCarousel(cmd.carouselFigureId, cmd.chartFigureId, cmd.sheetId);
5773
break;
74+
case "DUPLICATE_CAROUSEL_CHART":
75+
this.duplicateCarouselChart(cmd);
76+
break;
5877
case "UPDATE_CAROUSEL_ACTIVE_ITEM":
5978
this.carouselStates[cmd.figureId] = this.getCarouselItemId(cmd.item);
6079
break;
@@ -212,6 +231,45 @@ export class CarouselUIPlugin extends UIPlugin {
212231
this.dispatch("DELETE_FIGURE", { sheetId, figureId: chartFigureId });
213232
}
214233

234+
private duplicateCarouselChart({
235+
carouselId,
236+
chartId,
237+
sheetId,
238+
duplicatedChartId,
239+
}: DuplicateCarouselChartCommand) {
240+
const chart = this.getters.getChart(chartId);
241+
if (!chart) {
242+
return;
243+
}
244+
const carousel = this.getters.getCarousel(carouselId);
245+
246+
const duplicatedItemIndex = carousel.items.findIndex(
247+
(item) => item.type === "chart" && item.chartId === chartId
248+
);
249+
if (duplicatedItemIndex === -1) {
250+
return;
251+
}
252+
253+
this.dispatch("CREATE_CHART", {
254+
chartId: duplicatedChartId,
255+
figureId: carouselId,
256+
sheetId,
257+
definition: chart.getDefinition(),
258+
});
259+
260+
const carouselItems = insertItemsAtIndex(
261+
carousel.items,
262+
[{ type: "chart", chartId: duplicatedChartId }],
263+
duplicatedItemIndex + 1
264+
);
265+
266+
this.dispatch("UPDATE_CAROUSEL", {
267+
sheetId,
268+
figureId: carouselId,
269+
definition: { ...carousel, items: carouselItems },
270+
});
271+
}
272+
215273
private getCarouselItemId(item: CarouselItem): UID {
216274
return item.type === "chart" ? item.chartId : "carouselDataView";
217275
}

packages/o-spreadsheet-engine/src/types/commands.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,13 @@ export interface AddFigureChartToCarouselCommand extends SheetDependentCommand {
602602
chartFigureId: UID;
603603
}
604604

605+
export interface DuplicateCarouselChartCommand extends SheetDependentCommand {
606+
type: "DUPLICATE_CAROUSEL_CHART";
607+
carouselId: UID;
608+
chartId: UID;
609+
duplicatedChartId: UID;
610+
}
611+
605612
export interface UpdateCarouselActiveItemCommand extends SheetDependentCommand {
606613
type: "UPDATE_CAROUSEL_ACTIVE_ITEM";
607614
figureId: UID;
@@ -1287,6 +1294,7 @@ export type LocalCommand =
12871294
| ToggleCheckboxCommand
12881295
| AddNewChartToCarouselCommand
12891296
| AddFigureChartToCarouselCommand
1297+
| DuplicateCarouselChartCommand
12901298
| UpdateCarouselActiveItemCommand
12911299
| PopOutChartFromCarouselCommand;
12921300

src/components/side_panel/carousel_panel/carousel_panel.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ export class CarouselPanel extends Component<Props, SpreadsheetChildEnv> {
126126
});
127127
}
128128

129+
duplicateCarouselChart(item: CarouselItem) {
130+
if (item.type !== "chart") return;
131+
this.env.model.dispatch("DUPLICATE_CAROUSEL_CHART", {
132+
sheetId: this.carouselSheetId,
133+
carouselId: this.props.figureId,
134+
chartId: item.chartId,
135+
duplicatedChartId: this.env.model.uuidGenerator.smallUuid(),
136+
});
137+
}
138+
129139
onDragHandleMouseDown(item: CarouselItem, event: MouseEvent) {
130140
if (event.button !== 0) return;
131141
const previewRects = Array.from(this.previewListRef.el!.children).map((previewEl) =>
@@ -222,6 +232,11 @@ export class CarouselPanel extends Component<Props, SpreadsheetChildEnv> {
222232
execute: () => this.popOutCarouselItem(item),
223233
icon: "o-spreadsheet-Icon.EXTERNAL",
224234
});
235+
actions.push({
236+
name: _t("Duplicate chart"),
237+
execute: () => this.duplicateCarouselChart(item),
238+
icon: "o-spreadsheet-Icon.COPY",
239+
});
225240
}
226241
actions.push({
227242
name: _t("Delete item"),

tests/figures/carousel/carousel_panel_component.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,22 @@ describe("Carousel panel component", () => {
105105
expect(model.getters.getChartIds(model.getters.getActiveSheetId())).toHaveLength(1);
106106
});
107107

108+
test("Can duplicate a carousel chart", async () => {
109+
createCarousel(model, { items: [] }, "carouselId");
110+
addNewChartToCarousel(model, "carouselId", { type: "radar" });
111+
112+
await mountCarouselPanel(model, "carouselId");
113+
await click(fixture, ".o-carousel-preview .os-cog-wheel-menu-icon");
114+
await click(fixture, '.o-menu-item[title="Duplicate chart"]');
115+
116+
const items = model.getters.getCarousel("carouselId").items;
117+
expect(items).toHaveLength(2);
118+
119+
expect(model.getters.getChartDefinition(items[0]["chartId"])).toMatchObject({ type: "radar" });
120+
expect(items[1]["chartId"]).not.toEqual(items[0]["chartId"]);
121+
expect(model.getters.getChartDefinition(items[1]["chartId"])).toMatchObject({ type: "radar" });
122+
});
123+
108124
test("Can drag & drop carousel items to re-order them", async () => {
109125
createCarousel(model, { items: [] }, "carouselId");
110126
const radarId = addNewChartToCarousel(model, "carouselId", { type: "radar" });

tests/figures/carousel/carousel_plugin.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,27 @@ describe("Carousel figure", () => {
9999
});
100100
expect(result).toBeSuccessfullyDispatched();
101101
});
102+
103+
test("Cannot duplicate wrong carousel item", () => {
104+
createCarousel(model, { items: [] }, "carouselId");
105+
const chartId = addNewChartToCarousel(model, "carouselId");
106+
107+
let result = model.dispatch("DUPLICATE_CAROUSEL_CHART", {
108+
carouselId: "wrongCarouselId",
109+
sheetId,
110+
chartId,
111+
duplicatedChartId: "anyId",
112+
});
113+
expect(result).toBeCancelledBecause(CommandResult.InvalidFigureId);
114+
115+
result = model.dispatch("DUPLICATE_CAROUSEL_CHART", {
116+
carouselId: "carouselId",
117+
sheetId,
118+
chartId: "invalidChartId",
119+
duplicatedChartId: "anyId",
120+
});
121+
expect(result).toBeCancelledBecause(CommandResult.InvalidFigureId);
122+
});
102123
});
103124

104125
test("Can create a carousel figure", () => {

0 commit comments

Comments
 (0)