Skip to content

Commit

Permalink
feat: grid empty state content (#6321)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomivirkki authored May 30, 2024
1 parent 0e8d7be commit 7b814e5
Show file tree
Hide file tree
Showing 5 changed files with 309 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.vaadin.flow.component.grid.it;

import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.data.bean.Person;
import com.vaadin.flow.router.Route;

@Route("vaadin-grid/empty-state")
public class GridEmptyStatePage extends Div {
public GridEmptyStatePage() {
var grid = new Grid<>(Person.class);
add(grid);

// Button to set the empty state content
var setEmptyStateContentButton = new Button("Set empty state content",
event -> grid.setEmptyStateText("Custom empty state content"));
setEmptyStateContentButton.setId("set-empty-state-content");

// Button to set the grid items
var setItemsButton = new Button("Set items", event -> grid
.setItems(new Person("John", 20), new Person("Jane", 30)));
setItemsButton.setId("set-items");

// Button to clear the grid items
var clearItemsButton = new Button("Clear items",
event -> grid.setItems());
clearItemsButton.setId("clear-items");

add(setEmptyStateContentButton, setItemsButton, clearItemsButton);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.vaadin.flow.component.grid.it;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.NoSuchElementException;

import com.vaadin.flow.component.button.testbench.ButtonElement;
import com.vaadin.flow.component.grid.testbench.GridElement;
import com.vaadin.flow.testutil.TestPath;
import com.vaadin.tests.AbstractComponentIT;

@TestPath("vaadin-grid/empty-state")
public class GridEmptyStateIT extends AbstractComponentIT {
private GridElement grid;
private ButtonElement setEmptyStateContentButton;
private ButtonElement clearItemsButton;
private ButtonElement setItemsButton;

@Before
public void init() {
open();
grid = $(GridElement.class).first();
setEmptyStateContentButton = $(ButtonElement.class)
.id("set-empty-state-content");
clearItemsButton = $(ButtonElement.class).id("clear-items");
setItemsButton = $(ButtonElement.class).id("set-items");
}

@Test
public void getEmptyStateContent_throws() {
Assert.assertThrows("No empty state content was found",
NoSuchElementException.class,
() -> grid.getEmptyStateContent());
}

@Test
public void setEmptyStateContent_emptyStateContentDisplayed() {
setEmptyStateContentButton.click();
var content = grid.getEmptyStateContent();
Assert.assertEquals("Custom empty state content", content.getText());
Assert.assertTrue(content.isDisplayed());
}

@Test
public void setEmptyStateContent_setItems_emptyStateContentNotDisplayed() {
setEmptyStateContentButton.click();
setItemsButton.click();
var content = grid.getEmptyStateContent();
Assert.assertFalse(content.isDisplayed());
}

@Test
public void setEmptyStateContent_setItems_clearItems_emptyStateContentDisplayed() {
setEmptyStateContentButton.click();
setItemsButton.click();
clearItemsButton.click();
var content = grid.getEmptyStateContent();
Assert.assertTrue(content.isDisplayed());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
import com.vaadin.flow.component.grid.editor.Editor;
import com.vaadin.flow.component.grid.editor.EditorImpl;
import com.vaadin.flow.component.grid.editor.EditorRenderer;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.page.PendingJavaScriptResult;
import com.vaadin.flow.component.shared.SelectionPreservationHandler;
import com.vaadin.flow.component.shared.SelectionPreservationMode;
Expand Down Expand Up @@ -1457,6 +1458,10 @@ public UpdateQueueData getUpdateQueueData() {

private PendingJavaScriptResult pendingSorterUpdate;

private static final String EMPTY_STATE_SLOT = "empty-state";
private Component emptyStateComponent;
private String emptyStateText;

/**
* Creates a new instance, with page size of 50.
*/
Expand Down Expand Up @@ -5056,4 +5061,62 @@ private String getUniqueKey(T item) {
.map(provider -> provider.apply(item))
.orElse(getDataCommunicator().getKeyMapper().key(item));
}

/**
* Sets the component to be displayed when the grid is empty.
* <p>
* Note: This will also override any empty state content set with
* {@link #setEmptyStateText(String)}.
*
* @param emptyStateComponent
* the component to be displayed when the grid is empty
*/
public void setEmptyStateComponent(Component emptyStateComponent) {
this.emptyStateText = null;
this.emptyStateComponent = emptyStateComponent;
updateEmptyStateContent();
}

/**
* Sets the text to be displayed when the grid is empty.
* <p>
* Note: This will also override any empty state content set with
* {@link #setEmptyStateComponent(Component)}.
*
* @param emptyStateText
* the text to be displayed when the grid is empty
*/
public void setEmptyStateText(String emptyStateText) {
this.emptyStateComponent = null;
this.emptyStateText = emptyStateText;
updateEmptyStateContent();
}

/**
* Returns the component that is displayed when the grid is empty.
*
* @return the component that is displayed when the grid is empty
*/
public Component getEmptyStateComponent() {
return emptyStateComponent;
}

/**
* Returns the text that is displayed when the grid is empty.
*
* @return the text that is displayed when the grid is empty
*/
public String getEmptyStateText() {
return emptyStateText;
}

private void updateEmptyStateContent() {
if (emptyStateComponent != null) {
SlotUtils.setSlot(this, EMPTY_STATE_SLOT, emptyStateComponent);
} else if (emptyStateText != null) {
SlotUtils.setSlot(this, EMPTY_STATE_SLOT, new Span(emptyStateText));
} else {
SlotUtils.clearSlot(this, EMPTY_STATE_SLOT);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* Copyright 2000-2024 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package com.vaadin.flow.component.grid;

import java.util.Optional;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.dom.Element;

public class GridEmptyStateTest {

private Grid<String> grid;

@Before
public void setup() {
grid = new Grid<>();
}

@Test
public void setEmptyStateComponent_hasEmptyStateComponent() {
var content = new Div();
grid.setEmptyStateComponent(content);
Assert.assertEquals(content.getElement(), getEmptyStateElement());
}

@Test
public void setEmptyStateText_hasEmptyStateText() {
var content = "empty";
grid.setEmptyStateText(content);
var emptyStateElement = getEmptyStateElement();
Assert.assertEquals(content, emptyStateElement.getText());
Assert.assertEquals("span", emptyStateElement.getTag());
}

@Test
public void setEmptyStateComponent_overridesEmptyStateText() {
grid.setEmptyStateText("empty");
var content = new Div();
grid.setEmptyStateComponent(content);
Assert.assertEquals(content.getElement(), getEmptyStateElement());
}

@Test
public void setEmptyStateText_overridesEmptyStateComponent() {
var content = "empty";
grid.setEmptyStateComponent(new Div());
grid.setEmptyStateText(content);
var emptyStateElement = getEmptyStateElement();
Assert.assertEquals(content, emptyStateElement.getText());
Assert.assertEquals("span", emptyStateElement.getTag());
}

@Test
public void setEmptyStateComponentNull_noEmptyStateComponent() {
grid.setEmptyStateText("empty");
grid.setEmptyStateComponent(null);
Assert.assertTrue(getEmptyStateElementOptional().isEmpty());
}

@Test
public void setEmptyStateTextNull_noEmptyStateComponent() {
grid.setEmptyStateText("empty");
grid.setEmptyStateText(null);
Assert.assertTrue(getEmptyStateElementOptional().isEmpty());
}

@Test
public void setEmptyStateComponent_getEmptyStateComponent() {
var content = new Div();
grid.setEmptyStateComponent(content);
Assert.assertEquals(content, grid.getEmptyStateComponent());
}

@Test
public void setEmptyStateText_getEmptyStateText() {
var content = "empty";
grid.setEmptyStateText(content);
Assert.assertEquals(content, grid.getEmptyStateText());
}

@Test
public void setEmptyStateComponent_setEmptyStateText_getEmptyStateComponent() {
grid.setEmptyStateComponent(new Div());
grid.setEmptyStateText("empty");
Assert.assertNull(grid.getEmptyStateComponent());
}

@Test
public void setEmptyStateText_setEmptyStateComponent_getEmptyStateText() {
grid.setEmptyStateText("empty");
grid.setEmptyStateComponent(new Div());
Assert.assertNull(grid.getEmptyStateText());
}

@Test
public void setEmptyStateComponent_setEmptyStateTextNull_getEmptyStateComponent() {
grid.setEmptyStateComponent(new Div());
grid.setEmptyStateText(null);
Assert.assertNull(grid.getEmptyStateComponent());
Assert.assertNull(grid.getEmptyStateText());
}

@Test
public void setEmptyStateText_setEmptyStateComponentNull_getEmptyStateText() {
grid.setEmptyStateText("empty");
grid.setEmptyStateComponent(null);
Assert.assertNull(grid.getEmptyStateComponent());
Assert.assertNull(grid.getEmptyStateText());
}

private Element getEmptyStateElement() {
return getEmptyStateElementOptional().orElse(null);
}

private Optional<Element> getEmptyStateElementOptional() {
return grid.getElement().getChildren().filter(
child -> child.getAttribute("slot").equals("empty-state"))
.findFirst();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -499,4 +499,19 @@ public List<GridTHTDElement> getCells(int rowIndex) {
getAllColumns().toArray(new GridColumnElement[0]));
}

/**
* Gets the empty state content.
*
* @return the empty state content
* @throws NoSuchElementException
* if no empty state content was found
*/
public TestBenchElement getEmptyStateContent() {
try {
return findElement(By.cssSelector("[slot='empty-state']"));
} catch (NoSuchElementException e) {
throw new NoSuchElementException(
"No empty state content was found");
}
}
}

0 comments on commit 7b814e5

Please sign in to comment.