diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/main/java/com/vaadin/flow/component/dashboard/tests/DashboardDragReorderPage.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/main/java/com/vaadin/flow/component/dashboard/tests/DashboardDragReorderPage.java index 3228dae5a0d..ecdf680bbff 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/main/java/com/vaadin/flow/component/dashboard/tests/DashboardDragReorderPage.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/main/java/com/vaadin/flow/component/dashboard/tests/DashboardDragReorderPage.java @@ -63,10 +63,6 @@ public DashboardDragReorderPage() { }); toggleAttached.setId("toggle-attached"); - NativeButton toggleEditable = new NativeButton("Toggle editable", - e -> dashboard.setEditable(!dashboard.isEditable())); - toggleEditable.setId("toggle-editable"); - - add(toggleAttached, toggleEditable, dashboard); + add(toggleAttached, dashboard); } } diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/main/java/com/vaadin/flow/component/dashboard/tests/DashboardDragResizePage.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/main/java/com/vaadin/flow/component/dashboard/tests/DashboardDragResizePage.java index d8a54a95117..bb1ebaa9dd6 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/main/java/com/vaadin/flow/component/dashboard/tests/DashboardDragResizePage.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/main/java/com/vaadin/flow/component/dashboard/tests/DashboardDragResizePage.java @@ -12,7 +12,6 @@ import com.vaadin.flow.component.dashboard.DashboardSection; import com.vaadin.flow.component.dashboard.DashboardWidget; import com.vaadin.flow.component.html.Div; -import com.vaadin.flow.component.html.NativeButton; import com.vaadin.flow.router.Route; /** @@ -37,10 +36,6 @@ public DashboardDragResizePage() { DashboardSection section = dashboard.addSection("Section"); section.add(widgetInSection); - NativeButton toggleEditable = new NativeButton("Toggle editable", - e -> dashboard.setEditable(!dashboard.isEditable())); - toggleEditable.setId("toggle-editable"); - - add(toggleEditable, dashboard); + add(dashboard); } } diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/main/java/com/vaadin/flow/component/dashboard/tests/DashboardPage.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/main/java/com/vaadin/flow/component/dashboard/tests/DashboardPage.java index 433a6d0a843..2a300a4b420 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/main/java/com/vaadin/flow/component/dashboard/tests/DashboardPage.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/main/java/com/vaadin/flow/component/dashboard/tests/DashboardPage.java @@ -128,9 +128,14 @@ public DashboardPage() { click -> dashboard.setMaximumColumnCount(null)); setMaximumColumnCountNull.setId("set-maximum-column-count-null"); + NativeButton toggleEditable = new NativeButton("Toggle editable", + e -> dashboard.setEditable(!dashboard.isEditable())); + toggleEditable.setId("toggle-editable"); + add(addMultipleWidgets, removeFirstAndLastWidgets, removeAll, addSectionWithMultipleWidgets, removeFirstSection, - setMaximumColumnCount1, setMaximumColumnCountNull, dashboard); + setMaximumColumnCount1, setMaximumColumnCountNull, + toggleEditable, dashboard); } private static Optional getFirstSection( diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragReorderIT.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragReorderIT.java index 8b9c4eaf041..fb5cdc82a6b 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragReorderIT.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragReorderIT.java @@ -69,22 +69,6 @@ public void detachReattach_reorderWidgetOnClientSide_itemsAreReorderedCorrectly( reorderWidgetOnClientSide_itemsAreReorderedCorrectly(); } - @Test - public void setDashboardNotEditable_dragHandleNotVisible() { - var widget = dashboardElement.getWidgets().get(0); - Assert.assertTrue(isDragHandleVisible(widget)); - clickElementWithJs("toggle-editable"); - Assert.assertFalse(isDragHandleVisible(widget)); - } - - @Test - public void setDashboardEditable_dragHandleNotVisible() { - clickElementWithJs("toggle-editable"); - clickElementWithJs("toggle-editable"); - Assert.assertTrue( - isDragHandleVisible(dashboardElement.getWidgets().get(0))); - } - private void dragResizeElement(TestBenchElement draggedElement, TestBenchElement targetElement) { var dragHandle = getDragHandle(draggedElement); diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragResizeIT.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragResizeIT.java index 7e10446592c..371b641d566 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragResizeIT.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragResizeIT.java @@ -45,22 +45,6 @@ public void resizeWidgetInSectionBothHorizontallyAndVertically_widgetIsResizedCo assertWidgetResized(1); } - @Test - public void setDashboardNotEditable_resizeHandleNotVisible() { - var widget = dashboardElement.getWidgets().get(0); - Assert.assertTrue(isResizeHandleVisible(widget)); - clickElementWithJs("toggle-editable"); - Assert.assertFalse(isResizeHandleVisible(widget)); - } - - @Test - public void setDashboardEditable_resizeHandleNotVisible() { - clickElementWithJs("toggle-editable"); - clickElementWithJs("toggle-editable"); - Assert.assertTrue( - isResizeHandleVisible(dashboardElement.getWidgets().get(0))); - } - private void assertWidgetResized(int widgetIndexToResize) { var widgetToResize = dashboardElement.getWidgets() .get(widgetIndexToResize); diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardIT.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardIT.java index cbea894bb70..7c60e918e2a 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardIT.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardIT.java @@ -19,6 +19,7 @@ import com.vaadin.flow.component.dashboard.testbench.DashboardSectionElement; import com.vaadin.flow.component.dashboard.testbench.DashboardWidgetElement; import com.vaadin.flow.testutil.TestPath; +import com.vaadin.testbench.TestBenchElement; import com.vaadin.tests.AbstractComponentIT; /** @@ -57,6 +58,27 @@ public void removeFirstAndLastWidgetsFromDashboard_widgetsAreCorrectlyRemoved() "Widget 1 in Section 1", "Widget 2 in Section 1"); } + @Test + public void removeWidgetUsingButton_widgetIsRemoved() { + clickElementWithJs("toggle-editable"); + DashboardWidgetElement widgetToRemove = dashboardElement.getWidgets() + .get(0); + getRemoveButton(widgetToRemove).click(); + assertDashboardWidgetsByTitle("Widget 2", "Widget 3", + "Widget 1 in Section 1", "Widget 2 in Section 1", + "Widget 1 in Section 2"); + } + + @Test + public void removeWidgetInSectionUsingButton_widgetIsRemoved() { + clickElementWithJs("toggle-editable"); + DashboardSectionElement section = dashboardElement.getSections().get(0); + DashboardWidgetElement widgetToRemove = section.getWidgets().get(0); + getRemoveButton(widgetToRemove).click(); + assertDashboardWidgetsByTitle("Widget 1", "Widget 2", "Widget 3", + "Widget 2 in Section 1", "Widget 1 in Section 2"); + } + @Test public void removeAllFromDashboard_widgetsAnsSectionsAreCorrectlyRemoved() { clickElementWithJs("remove-all"); @@ -100,6 +122,20 @@ public void removeFirstSection_sectionIsRemoved() { assertSectionWidgetsByTitle(firstSection, "Widget 1 in Section 2"); } + @Test + public void removeFirstSectionUsingButton_sectionIsRemoved() { + clickElementWithJs("toggle-editable"); + DashboardSectionElement sectionToRemove = dashboardElement.getSections() + .get(0); + String sectionTitle = sectionToRemove.getTitle(); + getRemoveButton(sectionToRemove).click(); + assertDashboardWidgetsByTitle("Widget 1", "Widget 2", "Widget 3", + "Widget 1 in Section 2"); + List sectionTitles = dashboardElement.getSections().stream() + .map(DashboardSectionElement::getTitle).toList(); + Assert.assertFalse(sectionTitles.contains(sectionTitle)); + } + @Test public void changeMaximumColumnCountTo1_widgetsShouldBeOnTheSameColumn() { List widgets = dashboardElement.getWidgets(); @@ -144,4 +180,8 @@ private static void assertWidgetsByTitle( .map(DashboardWidgetElement::getTitle).toList(); Assert.assertEquals(Arrays.asList(expectedWidgetTitles), widgetTitles); } + + private static TestBenchElement getRemoveButton(TestBenchElement element) { + return element.$("button").withId("remove-button").first(); + } } diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/Dashboard.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/Dashboard.java index 4a337e8be42..5467af9a69d 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/Dashboard.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/Dashboard.java @@ -56,6 +56,7 @@ public Dashboard() { childDetachHandler = getChildDetachHandler(); addItemReorderEndListener(this::onItemReorderEnd); addItemResizeEndListener(this::onItemResizeEnd); + addItemRemovedListener(this::onItemRemoved); } /** @@ -350,6 +351,18 @@ public Registration addItemResizeEndListener( return addListener(DashboardItemResizeEndEvent.class, listener); } + /** + * Adds an item removed listener to this dashboard. + * + * @param listener + * the listener to add, not null + * @return a handle that can be used for removing the listener + */ + public Registration addItemRemovedListener( + ComponentEventListener listener) { + return addListener(DashboardItemRemovedEvent.class, listener); + } + @Override public Stream getChildren() { return childrenComponents.stream(); @@ -480,6 +493,11 @@ private void onItemResizeEnd( resizedWidget.setColspan(dashboardItemResizeEndEvent.getColspan()); } + private void onItemRemoved( + DashboardItemRemovedEvent dashboardItemRemovedEvent) { + dashboardItemRemovedEvent.getRemovedItem().removeFromParent(); + } + private void reorderItems(JsonArray orderedItemsFromClient) { // Keep references to the root level children before clearing them Map nodeIdToComponent = childrenComponents.stream() diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardItemRemovedEvent.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardItemRemovedEvent.java new file mode 100644 index 00000000000..8702a08ecfe --- /dev/null +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardItemRemovedEvent.java @@ -0,0 +1,68 @@ +/** + * Copyright 2000-2024 Vaadin Ltd. + * + * This program is available under Vaadin Commercial License and Service Terms. + * + * See {@literal } for the full + * license. + */ +package com.vaadin.flow.component.dashboard; + +import java.util.Objects; + +import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.ComponentEvent; +import com.vaadin.flow.component.ComponentEventListener; +import com.vaadin.flow.component.DomEvent; +import com.vaadin.flow.component.EventData; + +/** + * Widget or section removed event of {@link Dashboard}. + * + * @author Vaadin Ltd. + * @see Dashboard#addItemRemovedListener(ComponentEventListener) + */ +@DomEvent("dashboard-item-removed") +public class DashboardItemRemovedEvent extends ComponentEvent { + + private final Component removedItem; + + /** + * Creates a dashboard item removed event. + * + * @param source + * Dashboard that contains the item that was removed + * @param fromClient + * true if the event originated from the client + * side, false otherwise + */ + public DashboardItemRemovedEvent(Dashboard source, boolean fromClient, + @EventData("event.detail.item.nodeid") int nodeId) { + super(source, fromClient); + this.removedItem = getRemovedItem(source, nodeId); + } + + /** + * Returns the removed item + * + * @return the removed item + */ + public Component getRemovedItem() { + return removedItem; + } + + private static Component getRemovedItem(Dashboard dashboard, int nodeId) { + return dashboard.getChildren().map(item -> { + if (nodeId == item.getElement().getNode().getId()) { + return item; + } + if (item instanceof DashboardSection section) { + return section.getWidgets().stream() + .filter(sectionItem -> nodeId == sectionItem + .getElement().getNode().getId()) + .findAny().orElse(null); + } + return null; + }).filter(Objects::nonNull).findAny().orElse(null); + } +} diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragReorderTest.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragReorderTest.java index e61af6cee62..fd39b0d2fdb 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragReorderTest.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragReorderTest.java @@ -121,7 +121,6 @@ private void assertSectionWidgetReorder(int sectionIndex, int initialIndex, } private void assertRootLevelItemReorder(int initialIndex, int finalIndex) { - reorderRootLevelItem(initialIndex, finalIndex); List expectedRootLevelNodeIds = getExpectedRootLevelItemNodeIds( initialIndex, finalIndex);