diff --git a/src/components/figures/figure_container/figure_container.ts b/src/components/figures/figure_container/figure_container.ts index 630b9c0b64..a61416896d 100644 --- a/src/components/figures/figure_container/figure_container.ts +++ b/src/components/figures/figure_container/figure_container.ts @@ -1,4 +1,4 @@ -import { Component, onMounted, useState } from "@odoo/owl"; +import { Component, onMounted, onWillUpdateProps, useState } from "@odoo/owl"; import { ComponentsImportance, MIN_FIG_SIZE } from "../../../constants"; import { isDefined } from "../../../helpers"; import { rectIntersection, rectUnion } from "../../../helpers/rectangle"; @@ -43,6 +43,7 @@ interface DndState { draggedFigure?: Figure; horizontalSnap?: Snap; verticalSnap?: Snap; + cancelDnd: (() => void) | undefined; } css/*SCSS*/ ` @@ -135,6 +136,7 @@ export class FiguresContainer extends Component { draggedFigure: undefined, horizontalSnap: undefined, verticalSnap: undefined, + cancelDnd: undefined, }); setup() { @@ -148,6 +150,19 @@ export class FiguresContainer extends Component { // new rendering this.render(); }); + onWillUpdateProps(() => { + const sheetId = this.env.model.getters.getActiveSheetId(); + const draggedFigureId = this.dnd.draggedFigure?.id; + if (draggedFigureId && !this.env.model.getters.getFigure(sheetId, draggedFigureId)) { + if (this.dnd.cancelDnd) { + this.dnd.cancelDnd(); + } + this.dnd.draggedFigure = undefined; + this.dnd.horizontalSnap = undefined; + this.dnd.verticalSnap = undefined; + this.dnd.cancelDnd = undefined; + } + }); } private getVisibleFigures(): Figure[] { @@ -156,12 +171,13 @@ export class FiguresContainer extends Component { this.dnd.draggedFigure && !visibleFigures.some((figure) => figure.id === this.dnd.draggedFigure?.id) ) { - visibleFigures.push( - this.env.model.getters.getFigure( - this.env.model.getters.getActiveSheetId(), - this.dnd.draggedFigure?.id - )! + const draggedFigure = this.env.model.getters.getFigure( + this.env.model.getters.getActiveSheetId(), + this.dnd.draggedFigure?.id ); + if (draggedFigure) { + visibleFigures.push(draggedFigure); + } } return visibleFigures; } @@ -314,7 +330,7 @@ export class FiguresContainer extends Component { this.dnd.verticalSnap = undefined; this.env.model.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, x, y }); }; - startDnd(onMouseMove, onMouseUp); + this.dnd.cancelDnd = startDnd(onMouseMove, onMouseUp); } /** @@ -382,7 +398,7 @@ export class FiguresContainer extends Component { this.dnd.horizontalSnap = undefined; this.dnd.verticalSnap = undefined; }; - startDnd(onMouseMove, onMouseUp); + this.dnd.cancelDnd = startDnd(onMouseMove, onMouseUp); } private getOtherFigures(figId: UID): Figure[] { diff --git a/tests/figures/figure_component.test.ts b/tests/figures/figure_component.test.ts index 372835920e..67a8b815c2 100644 --- a/tests/figures/figure_component.test.ts +++ b/tests/figures/figure_component.test.ts @@ -416,6 +416,15 @@ describe("figures", () => { ); } ); + + test("Deleting a figure during drag and drop does not crash", async () => { + createFigure(model, { id: "someuuid", x: 200, y: 100 }); + await nextTick(); + await dragElement(".o-figure", { x: 150, y: 100 }, undefined, false); + model.dispatch("DELETE_FIGURE", { id: "someuuid", sheetId }); + await nextTick(); + expect(model.getters.getFigure(sheetId, "someuuid")).toEqual(undefined); + }); }); test("Cannot select/move figure in readonly mode", async () => {