From bb499673c506dbc6acc87ab4c2f7173afbf6f414 Mon Sep 17 00:00:00 2001 From: Ugur Saglam <106508695+ugur-vaadin@users.noreply.github.com> Date: Tue, 10 Sep 2024 12:31:40 +0300 Subject: [PATCH] feat: add header support to dashboard widget (#6617) * feat: add content related api to dashboard widget * feat: add header support to dashboard widget * test: fix merge problems * test: add missing buttons to test page --- .../dashboard/tests/DashboardWidgetPage.java | 22 +++++ .../dashboard/tests/DashboardWidgetIT.java | 30 +++++++ .../component/dashboard/DashboardWidget.java | 23 ++++++ .../dashboard/tests/DashboardWidgetTest.java | 80 +++++++++++++++++++ .../testbench/DashboardWidgetElement.java | 12 +++ 5 files changed, 167 insertions(+) diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/main/java/com/vaadin/flow/component/dashboard/tests/DashboardWidgetPage.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/main/java/com/vaadin/flow/component/dashboard/tests/DashboardWidgetPage.java index 0b53909b610..27eb5c834e5 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/main/java/com/vaadin/flow/component/dashboard/tests/DashboardWidgetPage.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/main/java/com/vaadin/flow/component/dashboard/tests/DashboardWidgetPage.java @@ -29,6 +29,7 @@ public DashboardWidgetPage() { DashboardWidget widget1 = new DashboardWidget(); widget1.setTitle("Widget 1"); widget1.setContent(new Div("Some content")); + widget1.setHeader(new Span("Some header")); widget1.setId("widget-1"); DashboardWidget widget2 = new DashboardWidget(); @@ -83,7 +84,28 @@ public DashboardWidgetPage() { removeContentOfTheFirstWidget .setId("remove-content-of-the-first-widget"); + NativeButton updateHeaderOfTheFirstWidget = new NativeButton( + "Update header of the first widget"); + updateHeaderOfTheFirstWidget.addClickListener(click -> { + List widgets = dashboard.getWidgets(); + if (!widgets.isEmpty()) { + widgets.get(0).setHeader(new Span("Updated header")); + } + }); + updateHeaderOfTheFirstWidget.setId("update-header-of-the-first-widget"); + + NativeButton removeHeaderOfTheFirstWidget = new NativeButton( + "Remove header of the first widget"); + removeHeaderOfTheFirstWidget.addClickListener(click -> { + List widgets = dashboard.getWidgets(); + if (!widgets.isEmpty()) { + widgets.get(0).setHeader(null); + } + }); + removeHeaderOfTheFirstWidget.setId("remove-header-of-the-first-widget"); + add(updateContentOfTheFirstWidget, removeContentOfTheFirstWidget, + updateHeaderOfTheFirstWidget, removeHeaderOfTheFirstWidget, increaseAllColspansBy1, decreaseAllColspansBy1, increaseAllRowspansBy1, decreaseAllRowspansBy1, dashboard); } diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardWidgetIT.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardWidgetIT.java index ae4d7b27f13..02d31dee991 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardWidgetIT.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow-integration-tests/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardWidgetIT.java @@ -104,4 +104,34 @@ public void removeWidgetContent_contentIsCorrectlyRemoved() { Assert.assertFalse(firstWidget.getText().contains("Some content")); Assert.assertNull(firstWidget.getContent()); } + + @Test + public void widgetWithInitialHeader_headerIsCorrectlySet() { + DashboardWidgetElement firstWidget = dashboardElement.getWidgets() + .get(0); + Assert.assertNotNull(firstWidget.getHeader()); + Assert.assertTrue( + firstWidget.getHeader().getText().contains("Some header")); + } + + @Test + public void updateWidgetHeader_headerIsCorrectlyUpdated() { + clickElementWithJs("update-header-of-the-first-widget"); + DashboardWidgetElement firstWidget = dashboardElement.getWidgets() + .get(0); + Assert.assertNotNull(firstWidget.getHeader()); + Assert.assertFalse( + firstWidget.getHeader().getText().contains("Some header")); + Assert.assertTrue( + firstWidget.getHeader().getText().contains("Updated header")); + } + + @Test + public void removeWidgetHeader_headerIsCorrectlyRemoved() { + clickElementWithJs("remove-header-of-the-first-widget"); + DashboardWidgetElement firstWidget = dashboardElement.getWidgets() + .get(0); + Assert.assertFalse(firstWidget.getText().contains("Some header")); + Assert.assertNull(firstWidget.getHeader()); + } } diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardWidget.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardWidget.java index c32c62aa56d..478bc7ceb37 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardWidget.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardWidget.java @@ -12,6 +12,7 @@ import com.vaadin.flow.component.Tag; import com.vaadin.flow.component.dependency.JsModule; import com.vaadin.flow.component.dependency.NpmPackage; +import com.vaadin.flow.component.shared.SlotUtils; /** * @author Vaadin Ltd @@ -132,6 +133,28 @@ public void setContent(Component content) { } } + /** + * Gets the component in the header slot of this widget. + * + * @return the header component of this widget, or {@code null} if no header + * component has been set + */ + public Component getHeader() { + return SlotUtils.getChildInSlot(this, "header"); + } + + /** + * Sets the component in the header slot of this widget, replacing any + * existing header component. + * + * @param header + * the component to set, can be {@code null} to remove existing + * header component + */ + public void setHeader(Component header) { + SlotUtils.setSlot(this, "header", header); + } + private void notifyParentDashboardOrSection() { getParent().ifPresent(parent -> { if (parent instanceof Dashboard dashboard) { diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardWidgetTest.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardWidgetTest.java index bdfba15f735..d5be4ef5180 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardWidgetTest.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardWidgetTest.java @@ -168,6 +168,86 @@ public void setNullContentToNonEmptyWidget_contentIsRemoved() { Assert.assertNull(widget.getContent()); } + @Test + public void defaultHeaderIsNull() { + DashboardWidget widget = new DashboardWidget(); + Assert.assertNull(widget.getHeader()); + } + + @Test + public void setHeaderToEmptyWidget_correctHeaderIsSet() { + Div header = new Div(); + DashboardWidget widget = new DashboardWidget(); + widget.setHeader(header); + Assert.assertEquals(header, widget.getHeader()); + } + + @Test + public void setAnotherHeaderToNonEmptyWidget_correctHeaderIsSet() { + DashboardWidget widget = new DashboardWidget(); + widget.setHeader(new Div()); + Span newHeader = new Span(); + widget.setHeader(newHeader); + Assert.assertEquals(newHeader, widget.getHeader()); + } + + @Test + public void setTheSameHeaderToNonEmptyWidget_correctHeaderIsSet() { + Div header = new Div(); + DashboardWidget widget = new DashboardWidget(); + widget.setHeader(header); + widget.setHeader(header); + Assert.assertEquals(header, widget.getHeader()); + } + + @Test + public void setNullHeaderToNonEmptyWidget_headerIsRemoved() { + DashboardWidget widget = new DashboardWidget(); + widget.setHeader(new Div()); + widget.setHeader(null); + Assert.assertNull(widget.getHeader()); + } + + @Test + public void setNullHeaderToWidgetWithContent_contentIsNotRemoved() { + Div content = new Div(); + DashboardWidget widget = new DashboardWidget(); + widget.setContent(content); + widget.setHeader(null); + Assert.assertEquals(content, widget.getContent()); + } + + @Test + public void setNullContentToWidgetWithHeader_headerIsNotRemoved() { + Div header = new Div(); + DashboardWidget widget = new DashboardWidget(); + widget.setHeader(header); + widget.setContent(null); + Assert.assertEquals(header, widget.getHeader()); + } + + @Test + public void setHeaderToWidgetWithContent_contentAndHeaderCorrectlyRetrieved() { + Div content = new Div(); + Span header = new Span(); + DashboardWidget widget = new DashboardWidget(); + widget.setContent(content); + widget.setHeader(header); + Assert.assertEquals(content, widget.getContent()); + Assert.assertEquals(header, widget.getHeader()); + } + + @Test + public void setContentToWidgetWithHeader_contentAndHeaderCorrectlyRetrieved() { + Div content = new Div(); + Span header = new Span(); + DashboardWidget widget = new DashboardWidget(); + widget.setHeader(header); + widget.setContent(content); + Assert.assertEquals(content, widget.getContent()); + Assert.assertEquals(header, widget.getHeader()); + } + private void fakeClientCommunication() { ui.getInternals().getStateTree().runExecutionsBeforeClientResponse(); ui.getInternals().getStateTree().collectChanges(ignore -> { diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-testbench/src/main/java/com/vaadin/flow/component/dashboard/testbench/DashboardWidgetElement.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-testbench/src/main/java/com/vaadin/flow/component/dashboard/testbench/DashboardWidgetElement.java index 3f9d335c850..15b5a2f1385 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-testbench/src/main/java/com/vaadin/flow/component/dashboard/testbench/DashboardWidgetElement.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-testbench/src/main/java/com/vaadin/flow/component/dashboard/testbench/DashboardWidgetElement.java @@ -60,6 +60,18 @@ public TestBenchElement getContent() { return content == null ? null : (TestBenchElement) content; } + /** + * Returns the header of the widget. + * + * @return the header element set to the widget + */ + public TestBenchElement getHeader() { + Object header = executeScript( + "return Array.from(arguments[0].children).filter(child => child.slot === 'header')[0]", + this); + return header == null ? null : (TestBenchElement) header; + } + private String getComputedCssValue(String propertyName) { return (String) executeScript( "return getComputedStyle(arguments[0]).getPropertyValue(arguments[1]);",