[FEATURE] PWA + Showcase Grid
CI / build-and-test (pull_request) Successful in 10m36s

This commit is contained in:
Pit Friedrich
2026-07-12 18:10:26 +02:00
parent 9df764d065
commit acb2f5964f
11 changed files with 4771 additions and 93 deletions
@@ -1,10 +1,9 @@
package com.example.views;
import com.example.components.BarChart;
import com.example.components.Card;
import com.example.components.LineChart;
import com.example.components.PieChart;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.html.H3;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.PageTitle;
@@ -51,20 +50,8 @@ public class DashboardView extends VerticalLayout {
Notification.show("Slice %d".formatted(e.getDataPointIndex()));
});
add(card("Umsatz-Entwicklung", lineChart),
card("Umsatz nach Monat", barChart),
card("Umsatz nach Region", pieChart));
}
private Component card(String title, Component chart) {
H3 heading = new H3(title);
heading.addClassName("dialect-card__title");
VerticalLayout card = new VerticalLayout(heading, chart);
card.addClassName("dialect-card");
card.setWidthFull();
card.setPadding(false);
card.setSpacing(false);
return card;
add(new Card("Umsatz-Entwicklung", lineChart),
new Card("Umsatz nach Monat", barChart),
new Card("Umsatz nach Region", pieChart));
}
}
+3 -20
View File
@@ -1,5 +1,6 @@
package com.example.views;
import com.example.components.Card;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
@@ -8,19 +9,13 @@ import com.vaadin.flow.component.checkbox.CheckboxGroup;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.html.H3;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.radiobutton.RadioButtonGroup;
import com.vaadin.flow.component.select.Select;
import com.vaadin.flow.component.textfield.BigDecimalField;
import com.vaadin.flow.component.textfield.EmailField;
import com.vaadin.flow.component.textfield.IntegerField;
import com.vaadin.flow.component.textfield.PasswordField;
import com.vaadin.flow.component.textfield.TextArea;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.component.textfield.*;
import com.vaadin.flow.component.timepicker.TimePicker;
import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.data.validator.EmailValidator;
@@ -45,7 +40,7 @@ public class FormView extends VerticalLayout {
public FormView() {
addClassName("dialect-content");
add(card("Registrierung", buildForm()));
add(new Card("Registrierung", buildForm()));
//<theme-editor-local-classname>
addClassName("form-view-vertical-layout-1");
}
@@ -171,16 +166,4 @@ vorname.setAutofocus(true);
wrapper.setSpacing(true);
return wrapper;
}
private Component card(String title, Component body) {
H3 heading = new H3(title);
heading.addClassName("dialect-card__title");
VerticalLayout card = new VerticalLayout(heading, body);
card.addClassName("dialect-card");
card.setWidthFull();
card.setPadding(false);
card.setSpacing(false);
return card;
}
}
@@ -39,6 +39,8 @@ public class MainLayout extends AppLayout {
VaadinIcon.DASHBOARD.create()));
nav.addItem(new SideNavItem("Formular", FormView.class,
VaadinIcon.FORM.create()));
nav.addItem(new SideNavItem("Tabelle", TableView.class,
VaadinIcon.TABLE.create()));
addToDrawer(nav);
}
@@ -0,0 +1,81 @@
package com.example.views;
import com.example.components.Card;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.dataview.GridListDataView;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import java.text.NumberFormat;
import java.util.List;
import java.util.Locale;
/**
* Example view demonstrating a {@link Grid} with dummy data and a
* live text filter across all columns.
*/
@Route("tabelle")
@PageTitle("Tabelle")
public class TableView extends VerticalLayout {
private record Mitarbeiter(String name, String abteilung, String stadt, double gehalt) {
}
private static final List<Mitarbeiter> MITARBEITER = List.of(
new Mitarbeiter("Anna Schmidt", "Entwicklung", "Berlin", 68000),
new Mitarbeiter("Jonas Becker", "Vertrieb", "Hamburg", 54000),
new Mitarbeiter("Lena Fischer", "Marketing", "München", 59000),
new Mitarbeiter("Paul Wagner", "Support", "Köln", 47000),
new Mitarbeiter("Mia Hoffmann", "Geschäftsführung", "Frankfurt", 95000),
new Mitarbeiter("Felix Bauer", "Entwicklung", "Stuttgart", 71000),
new Mitarbeiter("Sophie Richter", "Vertrieb", "Wien", 52000),
new Mitarbeiter("Tim Klein", "Marketing", "Zürich", 63000),
new Mitarbeiter("Laura Wolf", "Support", "Leipzig", 45000),
new Mitarbeiter("Max Neumann", "Entwicklung", "Dresden", 69000),
new Mitarbeiter("Nina Schröder", "Geschäftsführung", "Düsseldorf", 98000),
new Mitarbeiter("David Zimmermann", "Vertrieb", "Nürnberg", 55000));
private static final NumberFormat GEHALT_FORMAT = NumberFormat.getCurrencyInstance(Locale.GERMANY);
public TableView() {
addClassName("dialect-content");
TextField suche = new TextField();
suche.setPlaceholder("Suchen…");
suche.setPrefixComponent(VaadinIcon.SEARCH.create());
suche.setClearButtonVisible(true);
suche.setValueChangeMode(ValueChangeMode.EAGER);
suche.setWidthFull();
Grid<Mitarbeiter> grid = new Grid<>();
grid.setWidthFull();
grid.addColumn(Mitarbeiter::name).setHeader("Name").setSortable(true);
grid.addColumn(Mitarbeiter::abteilung).setHeader("Abteilung").setSortable(true);
grid.addColumn(Mitarbeiter::stadt).setHeader("Stadt").setSortable(true);
grid.addColumn(m -> GEHALT_FORMAT.format(m.gehalt())).setHeader("Gehalt (€)").setSortable(true);
GridListDataView<Mitarbeiter> dataView = grid.setItems(MITARBEITER);
suche.addValueChangeListener(e -> dataView.refreshAll());
dataView.addFilter(mitarbeiter -> matches(mitarbeiter, suche.getValue()));
VerticalLayout content = new VerticalLayout(suche, grid);
content.setPadding(false);
content.setSpacing(true);
add(new Card("Mitarbeiter", content));
}
private static boolean matches(Mitarbeiter mitarbeiter, String filter) {
if (filter == null || filter.isBlank()) {
return true;
}
String suchbegriff = filter.trim().toLowerCase(Locale.GERMANY);
return mitarbeiter.name().toLowerCase(Locale.GERMANY).contains(suchbegriff)
|| mitarbeiter.abteilung().toLowerCase(Locale.GERMANY).contains(suchbegriff)
|| mitarbeiter.stadt().toLowerCase(Locale.GERMANY).contains(suchbegriff);
}
}