Feature/customer list view #4

Merged
pitfriedrich merged 2 commits from feature/customer-list-view into main 2026-08-08 14:51:47 +00:00
6 changed files with 130 additions and 0 deletions
Showing only changes of commit de6c1f36e2 - Show all commits
@@ -0,0 +1,10 @@
package com.example.customer;
import java.time.LocalDate;
/**
* A customer record. This is a plain, immutable value type backed by
* {@link CustomerService}'s in-memory dummy data, not a JPA entity.
*/
public record Customer(String name, String email, String company, String status, LocalDate customerSince) {
}
@@ -0,0 +1,39 @@
package com.example.customer;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.List;
@Service
public class CustomerService {
// TODO Replace with a real data source (e.g. a JPA-backed CustomerRepository) once
// customers are no longer dummy data.
private static final List<Customer> DUMMY_CUSTOMERS = List.of(
new Customer("Alice Johnson", "alice.johnson@example.com", "Acme Corp", "Active",
LocalDate.of(2019, 3, 12)),
new Customer("Bob Smith", "bob.smith@example.com", "Globex Inc", "Active", LocalDate.of(2020, 7, 1)),
new Customer("Carla Diaz", "carla.diaz@example.com", "Initech", "Inactive", LocalDate.of(2018, 11, 23)),
new Customer("David Chen", "david.chen@example.com", "Umbrella Corp", "Prospect",
LocalDate.of(2024, 1, 15)),
new Customer("Elena Petrova", "elena.petrova@example.com", "Hooli", "Active", LocalDate.of(2021, 5, 30)),
new Customer("Frank Müller", "frank.mueller@example.com", "Soylent Corp", "Inactive",
LocalDate.of(2017, 9, 4)),
new Customer("Grace Kim", "grace.kim@example.com", "Stark Industries", "Active",
LocalDate.of(2022, 2, 18)),
new Customer("Hassan Ali", "hassan.ali@example.com", "Wayne Enterprises", "Prospect",
LocalDate.of(2025, 4, 9)),
new Customer("Ingrid Nilsson", "ingrid.nilsson@example.com", "Wonka Industries", "Active",
LocalDate.of(2016, 6, 21)),
new Customer("Julien Moreau", "julien.moreau@example.com", "Cyberdyne Systems", "Inactive",
LocalDate.of(2023, 10, 8)),
new Customer("Katrin Bauer", "katrin.bauer@example.com", "Massive Dynamic", "Active",
LocalDate.of(2020, 12, 3)),
new Customer("Liam O'Connor", "liam.oconnor@example.com", "Aperture Science", "Prospect",
LocalDate.of(2026, 1, 27)));
public List<Customer> list() {
return DUMMY_CUSTOMERS;
}
}
@@ -0,0 +1,4 @@
@NullMarked
package com.example.customer;
import org.jspecify.annotations.NullMarked;
@@ -0,0 +1,42 @@
package com.example.customer.ui;
import com.example.base.ui.ViewTitle;
import com.example.customer.Customer;
import com.example.customer.CustomerService;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Menu;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import jakarta.annotation.security.PermitAll;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
@Route(value = "customers")
@PageTitle("Customers")
@Menu(order = 1, icon = "vaadin:users", title = "Customers")
@PermitAll
class CustomerListView extends VerticalLayout {
final Grid<Customer> customerGrid;
CustomerListView(CustomerService customerService) {
var dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(getLocale());
customerGrid = new Grid<>();
customerGrid.setItems(customerService.list());
customerGrid.addColumn(Customer::name).setHeader("Name").setSortable(true);
customerGrid.addColumn(Customer::email).setHeader("Email").setSortable(true);
customerGrid.addColumn(Customer::company).setHeader("Company").setSortable(true);
customerGrid.addColumn(Customer::status).setHeader("Status").setSortable(true);
customerGrid.addColumn(customer -> dateFormatter.format(customer.customerSince()))
.setHeader("Customer Since")
.setSortable(true);
customerGrid.setEmptyStateText("No customers found");
customerGrid.setSizeFull();
setSizeFull();
add(new ViewTitle("Customers"), customerGrid);
}
}
@@ -0,0 +1,4 @@
@NullMarked
package com.example.customer.ui;
import org.jspecify.annotations.NullMarked;
@@ -0,0 +1,31 @@
package com.example.customer.ui;
import com.vaadin.browserless.SpringBrowserlessTest;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@WithMockUser(roles = "USER")
class CustomerListViewTest extends SpringBrowserlessTest {
@Test
void grid_shows_all_dummy_customers() {
var view = navigate(CustomerListView.class);
assertThat(test(view.customerGrid).size()).isEqualTo(12);
}
@Test
void grid_shows_customer_columns() {
var view = navigate(CustomerListView.class);
assertThat(test(view.customerGrid).getCellText(0, 0)).isEqualTo("Alice Johnson");
assertThat(test(view.customerGrid).getCellText(0, 1)).isEqualTo("alice.johnson@example.com");
assertThat(test(view.customerGrid).getCellText(0, 2)).isEqualTo("Acme Corp");
assertThat(test(view.customerGrid).getCellText(0, 3)).isEqualTo("Active");
assertThat(test(view.customerGrid).getCellText(0, 4)).isNotEmpty();
}
}