Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support drag drop for dashboard #6633

Merged
merged 11 commits into from
Sep 12, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* Copyright 2000-2024 Vaadin Ltd.
*
* This program is available under Vaadin Commercial License and Service Terms.
*
* See {@literal <https://vaadin.com/commercial-license-and-service-terms>} for the full
* license.
*/
package com.vaadin.flow.component.dashboard.tests;

import com.vaadin.flow.component.dashboard.Dashboard;
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;

/**
* @author Vaadin Ltd
*/
@Route("vaadin-dashboard/drag-drop")
public class DashboardDragDropPage extends Div {

public DashboardDragDropPage() {
Dashboard dashboard = new Dashboard();
dashboard.setEditable(true);
dashboard.setMinimumRowHeight("100px");
dashboard.setMaximumColumnWidth("400px");

DashboardWidget widget1 = new DashboardWidget();
widget1.setTitle("Widget 1");

DashboardWidget widget2 = new DashboardWidget();
widget2.setTitle("Widget 2");

dashboard.add(widget1, widget2);

DashboardWidget widget1InSection1 = new DashboardWidget();
widget1InSection1.setTitle("Widget 1 in Section 1");

DashboardWidget widget2InSection1 = new DashboardWidget();
widget2InSection1.setTitle("Widget 2 in Section 1");

DashboardSection section1 = new DashboardSection("Section 1");
section1.add(widget1InSection1, widget2InSection1);

dashboard.addSection(section1);

DashboardWidget widgetInSection2 = new DashboardWidget();
widgetInSection2.setTitle("Widget in Section 2");

DashboardSection section2 = new DashboardSection("Section 2");
section2.add(widgetInSection2);

dashboard.addSection(section2);

NativeButton toggleAttached = new NativeButton("Toggle attached", e -> {
if (dashboard.getParent().isPresent()) {
dashboard.removeFromParent();
} else {
add(dashboard);
}
});
toggleAttached.setId("toggle-attached");

NativeButton toggleEditable = new NativeButton("Toggle editable",
e -> dashboard.setEditable(!dashboard.isEditable()));
toggleEditable.setId("toggle-editable");

add(toggleAttached, toggleEditable, dashboard);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
/**
* @author Vaadin Ltd
*/
@Route("vaadin-dashboard-section")
@Route("vaadin-dashboard/section")
public class DashboardSectionPage extends Div {

public DashboardSectionPage() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
/**
* @author Vaadin Ltd
*/
@Route("vaadin-dashboard-widget")
@Route("vaadin-dashboard/widget")
public class DashboardWidgetPage extends Div {

public DashboardWidgetPage() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* Copyright 2000-2024 Vaadin Ltd.
*
* This program is available under Vaadin Commercial License and Service Terms.
*
* See {@literal <https://vaadin.com/commercial-license-and-service-terms>} for the full
* license.
*/
package com.vaadin.flow.component.dashboard.tests;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.interactions.Actions;

import com.vaadin.flow.component.dashboard.testbench.DashboardElement;
import com.vaadin.flow.testutil.TestPath;
import com.vaadin.testbench.TestBenchElement;
import com.vaadin.tests.AbstractComponentIT;

/**
* @author Vaadin Ltd
*/
@TestPath("vaadin-dashboard/drag-drop")
public class DashboardDragDropIT extends AbstractComponentIT {

private DashboardElement dashboardElement;

@Before
public void init() {
open();
dashboardElement = $(DashboardElement.class).waitForFirst();
}

@Test
public void reorderWidgetOnClientSide_itemsAreReorderedCorrectly() {
var draggedWidget = dashboardElement.getWidgets().get(0);
var targetWidget = dashboardElement.getWidgets().get(1);
dragDropElement(draggedWidget, targetWidget);
Assert.assertEquals(draggedWidget.getTitle(),
dashboardElement.getWidgets().get(1).getTitle());
}

@Test
public void reorderSectionOnClientSide_itemsAreReorderedCorrectly() {
var draggedSection = dashboardElement.getSections().get(1);
var targetWidget = dashboardElement.getWidgets().get(0);
dragDropElement(draggedSection, targetWidget);
Assert.assertEquals(draggedSection.getTitle(),
dashboardElement.getSections().get(0).getTitle());
}

@Test
public void reorderWidgetInSectionOnClientSide_itemsAreReorderedCorrectly() {
var firstSection = dashboardElement.getSections().get(0);
var draggedWidget = firstSection.getWidgets().get(0);
var targetWidget = firstSection.getWidgets().get(1);
dragDropElement(draggedWidget, targetWidget);
firstSection = dashboardElement.getSections().get(0);
Assert.assertEquals(draggedWidget.getTitle(),
firstSection.getWidgets().get(1).getTitle());
}

@Test
public void detachReattach_reorderWidgetOnClientSide_itemsAreReorderedCorrectly() {
clickElementWithJs("toggle-attached");
clickElementWithJs("toggle-attached");
dashboardElement = $(DashboardElement.class).waitForFirst();
reorderWidgetOnClientSide_itemsAreReorderedCorrectly();
}

@Test
public void setDashboardNotEditable_widgetCannotBeDragged() {
var widget = dashboardElement.getWidgets().get(0);
Assert.assertTrue(isHeaderActionsVisible(widget));
clickElementWithJs("toggle-editable");
Assert.assertFalse(isHeaderActionsVisible(widget));
}

@Test
public void setDashboardEditable_widgetCanBeDragged() {
clickElementWithJs("toggle-editable");
clickElementWithJs("toggle-editable");
Assert.assertTrue(
isHeaderActionsVisible(dashboardElement.getWidgets().get(0)));
}

private void dragDropElement(TestBenchElement draggedElement,
TestBenchElement targetElement) {
var dragHandle = getDragHandle(draggedElement);

var yOffset = draggedElement.getLocation().getY() < targetElement
.getLocation().getY() ? 10 : -10;
var xOffset = draggedElement.getLocation().getX() < targetElement
.getLocation().getX() ? 10 : -10;

new Actions(driver).clickAndHold(dragHandle)
.moveToElement(targetElement, xOffset, yOffset)
.release(targetElement).build().perform();
}

private static boolean isHeaderActionsVisible(TestBenchElement element) {
TestBenchElement headerActions = element.$("*").withId("header-actions")
.first();
return !"none".equals(headerActions.getCssValue("display"));
}

private static TestBenchElement getDragHandle(TestBenchElement element) {
return element.$("*").withClassName("drag-handle").first();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
/**
* @author Vaadin Ltd
*/
@TestPath("vaadin-dashboard-section")
@TestPath("vaadin-dashboard/section")
public class DashboardSectionIT extends AbstractComponentIT {

private DashboardElement dashboardElement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
/**
* @author Vaadin Ltd
*/
@TestPath("vaadin-dashboard-widget")
@TestPath("vaadin-dashboard/widget")
public class DashboardWidgetIT extends AbstractComponentIT {

private DashboardElement dashboardElement;
Expand Down
Loading