|
|
|
@@ -1,227 +0,0 @@
|
|
|
|
|
package dev.mars3142.fhq.views.dashboard;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import com.vaadin.flow.component.Component;
|
|
|
|
|
import com.vaadin.flow.component.board.Board;
|
|
|
|
|
import com.vaadin.flow.component.charts.Chart;
|
|
|
|
|
import com.vaadin.flow.component.charts.model.*;
|
|
|
|
|
import com.vaadin.flow.component.grid.ColumnTextAlign;
|
|
|
|
|
import com.vaadin.flow.component.grid.Grid;
|
|
|
|
|
import com.vaadin.flow.component.grid.GridVariant;
|
|
|
|
|
import com.vaadin.flow.component.html.H2;
|
|
|
|
|
import com.vaadin.flow.component.html.Main;
|
|
|
|
|
import com.vaadin.flow.component.html.Span;
|
|
|
|
|
import com.vaadin.flow.component.icon.Icon;
|
|
|
|
|
import com.vaadin.flow.component.icon.VaadinIcon;
|
|
|
|
|
import com.vaadin.flow.component.orderedlayout.FlexComponent;
|
|
|
|
|
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
|
|
|
|
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
|
|
|
|
import com.vaadin.flow.component.select.Select;
|
|
|
|
|
import com.vaadin.flow.data.renderer.ComponentRenderer;
|
|
|
|
|
import com.vaadin.flow.router.PageTitle;
|
|
|
|
|
import com.vaadin.flow.router.Route;
|
|
|
|
|
import com.vaadin.flow.router.RouteAlias;
|
|
|
|
|
import com.vaadin.flow.theme.lumo.LumoUtility.BoxSizing;
|
|
|
|
|
import com.vaadin.flow.theme.lumo.LumoUtility.FontSize;
|
|
|
|
|
import com.vaadin.flow.theme.lumo.LumoUtility.FontWeight;
|
|
|
|
|
import com.vaadin.flow.theme.lumo.LumoUtility.Margin;
|
|
|
|
|
import com.vaadin.flow.theme.lumo.LumoUtility.Padding;
|
|
|
|
|
import com.vaadin.flow.theme.lumo.LumoUtility.TextColor;
|
|
|
|
|
import dev.mars3142.fhq.views.MainLayout;
|
|
|
|
|
import dev.mars3142.fhq.views.dashboard.ServiceHealth.Status;
|
|
|
|
|
|
|
|
|
|
@PageTitle("Dashboard")
|
|
|
|
|
@Route(value = "", layout = MainLayout.class)
|
|
|
|
|
@RouteAlias(value = "", layout = MainLayout.class)
|
|
|
|
|
public class DashboardView extends Main {
|
|
|
|
|
|
|
|
|
|
public DashboardView() {
|
|
|
|
|
addClassName("dashboard-view");
|
|
|
|
|
|
|
|
|
|
Board board = new Board();
|
|
|
|
|
board.addRow(createHighlight("Current users", "745", 33.7), createHighlight("View events", "54.6k", -112.45),
|
|
|
|
|
createHighlight("Conversion rate", "18%", 3.9), createHighlight("Custom metric", "-123.45", 0.0));
|
|
|
|
|
board.addRow(createViewEvents());
|
|
|
|
|
board.addRow(createServiceHealth(), createResponseTimes());
|
|
|
|
|
add(board);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Component createHighlight(String title, String value, Double percentage) {
|
|
|
|
|
VaadinIcon icon = VaadinIcon.ARROW_UP;
|
|
|
|
|
String prefix = "";
|
|
|
|
|
String theme = "badge";
|
|
|
|
|
|
|
|
|
|
if (percentage == 0) {
|
|
|
|
|
prefix = "±";
|
|
|
|
|
} else if (percentage > 0) {
|
|
|
|
|
prefix = "+";
|
|
|
|
|
theme += " success";
|
|
|
|
|
} else if (percentage < 0) {
|
|
|
|
|
icon = VaadinIcon.ARROW_DOWN;
|
|
|
|
|
theme += " error";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
H2 h2 = new H2(title);
|
|
|
|
|
h2.addClassNames(FontWeight.NORMAL, Margin.NONE, TextColor.SECONDARY, FontSize.XSMALL);
|
|
|
|
|
|
|
|
|
|
Span span = new Span(value);
|
|
|
|
|
span.addClassNames(FontWeight.SEMIBOLD, FontSize.XXXLARGE);
|
|
|
|
|
|
|
|
|
|
Icon i = icon.create();
|
|
|
|
|
i.addClassNames(BoxSizing.BORDER, Padding.XSMALL);
|
|
|
|
|
|
|
|
|
|
Span badge = new Span(i, new Span(prefix + percentage.toString()));
|
|
|
|
|
badge.getElement().getThemeList().add(theme);
|
|
|
|
|
|
|
|
|
|
VerticalLayout layout = new VerticalLayout(h2, span, badge);
|
|
|
|
|
layout.addClassName(Padding.LARGE);
|
|
|
|
|
layout.setPadding(false);
|
|
|
|
|
layout.setSpacing(false);
|
|
|
|
|
return layout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Component createViewEvents() {
|
|
|
|
|
// Header
|
|
|
|
|
Select year = new Select();
|
|
|
|
|
year.setItems("2011", "2012", "2013", "2014", "2015", "2016", "2017", "2018", "2019", "2020", "2021");
|
|
|
|
|
year.setValue("2021");
|
|
|
|
|
year.setWidth("100px");
|
|
|
|
|
|
|
|
|
|
HorizontalLayout header = createHeader("View events", "City/month");
|
|
|
|
|
header.add(year);
|
|
|
|
|
|
|
|
|
|
// Chart
|
|
|
|
|
Chart chart = new Chart(ChartType.AREASPLINE);
|
|
|
|
|
Configuration conf = chart.getConfiguration();
|
|
|
|
|
conf.getChart().setStyledMode(true);
|
|
|
|
|
|
|
|
|
|
XAxis xAxis = new XAxis();
|
|
|
|
|
xAxis.setCategories("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
|
|
|
|
|
conf.addxAxis(xAxis);
|
|
|
|
|
|
|
|
|
|
conf.getyAxis().setTitle("Values");
|
|
|
|
|
|
|
|
|
|
PlotOptionsAreaspline plotOptions = new PlotOptionsAreaspline();
|
|
|
|
|
plotOptions.setPointPlacement(PointPlacement.ON);
|
|
|
|
|
plotOptions.setMarker(new Marker(false));
|
|
|
|
|
conf.addPlotOptions(plotOptions);
|
|
|
|
|
|
|
|
|
|
conf.addSeries(new ListSeries("Berlin", 189, 191, 291, 396, 501, 403, 609, 712, 729, 942, 1044, 1247));
|
|
|
|
|
conf.addSeries(new ListSeries("London", 138, 246, 248, 348, 352, 353, 463, 573, 778, 779, 885, 887));
|
|
|
|
|
conf.addSeries(new ListSeries("New York", 65, 65, 166, 171, 293, 302, 308, 317, 427, 429, 535, 636));
|
|
|
|
|
conf.addSeries(new ListSeries("Tokyo", 0, 11, 17, 123, 130, 142, 248, 349, 452, 454, 458, 462));
|
|
|
|
|
|
|
|
|
|
// Add it all together
|
|
|
|
|
VerticalLayout viewEvents = new VerticalLayout(header, chart);
|
|
|
|
|
viewEvents.addClassName(Padding.LARGE);
|
|
|
|
|
viewEvents.setPadding(false);
|
|
|
|
|
viewEvents.setSpacing(false);
|
|
|
|
|
viewEvents.getElement().getThemeList().add("spacing-l");
|
|
|
|
|
return viewEvents;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Component createServiceHealth() {
|
|
|
|
|
// Header
|
|
|
|
|
HorizontalLayout header = createHeader("Service health", "Input / output");
|
|
|
|
|
|
|
|
|
|
// Grid
|
|
|
|
|
Grid<ServiceHealth> grid = new Grid();
|
|
|
|
|
grid.addThemeVariants(GridVariant.LUMO_NO_BORDER);
|
|
|
|
|
grid.setAllRowsVisible(true);
|
|
|
|
|
|
|
|
|
|
grid.addColumn(new ComponentRenderer<>(serviceHealth -> {
|
|
|
|
|
Span status = new Span();
|
|
|
|
|
String statusText = getStatusDisplayName(serviceHealth);
|
|
|
|
|
status.getElement().setAttribute("aria-label", "Status: " + statusText);
|
|
|
|
|
status.getElement().setAttribute("title", "Status: " + statusText);
|
|
|
|
|
status.getElement().getThemeList().add(getStatusTheme(serviceHealth));
|
|
|
|
|
return status;
|
|
|
|
|
})).setHeader("").setFlexGrow(0).setAutoWidth(true);
|
|
|
|
|
grid.addColumn(ServiceHealth::getCity).setHeader("City").setFlexGrow(1);
|
|
|
|
|
grid.addColumn(ServiceHealth::getInput).setHeader("Input").setAutoWidth(true).setTextAlign(ColumnTextAlign.END);
|
|
|
|
|
grid.addColumn(ServiceHealth::getOutput).setHeader("Output").setAutoWidth(true)
|
|
|
|
|
.setTextAlign(ColumnTextAlign.END);
|
|
|
|
|
|
|
|
|
|
grid.setItems(new ServiceHealth(Status.EXCELLENT, "Münster", 324, 1540),
|
|
|
|
|
new ServiceHealth(Status.OK, "Cluj-Napoca", 311, 1320),
|
|
|
|
|
new ServiceHealth(Status.FAILING, "Ciudad Victoria", 300, 1219));
|
|
|
|
|
|
|
|
|
|
// Add it all together
|
|
|
|
|
VerticalLayout serviceHealth = new VerticalLayout(header, grid);
|
|
|
|
|
serviceHealth.addClassName(Padding.LARGE);
|
|
|
|
|
serviceHealth.setPadding(false);
|
|
|
|
|
serviceHealth.setSpacing(false);
|
|
|
|
|
serviceHealth.getElement().getThemeList().add("spacing-l");
|
|
|
|
|
return serviceHealth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Component createResponseTimes() {
|
|
|
|
|
HorizontalLayout header = createHeader("Response times", "Average across all systems");
|
|
|
|
|
|
|
|
|
|
// Chart
|
|
|
|
|
Chart chart = new Chart(ChartType.PIE);
|
|
|
|
|
Configuration conf = chart.getConfiguration();
|
|
|
|
|
conf.getChart().setStyledMode(true);
|
|
|
|
|
chart.setThemeName("gradient");
|
|
|
|
|
|
|
|
|
|
DataSeries series = new DataSeries();
|
|
|
|
|
series.add(new DataSeriesItem("System 1", 12.5));
|
|
|
|
|
series.add(new DataSeriesItem("System 2", 12.5));
|
|
|
|
|
series.add(new DataSeriesItem("System 3", 12.5));
|
|
|
|
|
series.add(new DataSeriesItem("System 4", 12.5));
|
|
|
|
|
series.add(new DataSeriesItem("System 5", 12.5));
|
|
|
|
|
series.add(new DataSeriesItem("System 6", 12.5));
|
|
|
|
|
conf.addSeries(series);
|
|
|
|
|
|
|
|
|
|
// Add it all together
|
|
|
|
|
VerticalLayout serviceHealth = new VerticalLayout(header, chart);
|
|
|
|
|
serviceHealth.addClassName(Padding.LARGE);
|
|
|
|
|
serviceHealth.setPadding(false);
|
|
|
|
|
serviceHealth.setSpacing(false);
|
|
|
|
|
serviceHealth.getElement().getThemeList().add("spacing-l");
|
|
|
|
|
return serviceHealth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private HorizontalLayout createHeader(String title, String subtitle) {
|
|
|
|
|
H2 h2 = new H2(title);
|
|
|
|
|
h2.addClassNames(FontSize.XLARGE, Margin.NONE);
|
|
|
|
|
|
|
|
|
|
Span span = new Span(subtitle);
|
|
|
|
|
span.addClassNames(TextColor.SECONDARY, FontSize.XSMALL);
|
|
|
|
|
|
|
|
|
|
VerticalLayout column = new VerticalLayout(h2, span);
|
|
|
|
|
column.setPadding(false);
|
|
|
|
|
column.setSpacing(false);
|
|
|
|
|
|
|
|
|
|
HorizontalLayout header = new HorizontalLayout(column);
|
|
|
|
|
header.setJustifyContentMode(FlexComponent.JustifyContentMode.BETWEEN);
|
|
|
|
|
header.setSpacing(false);
|
|
|
|
|
header.setWidthFull();
|
|
|
|
|
return header;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String getStatusDisplayName(ServiceHealth serviceHealth) {
|
|
|
|
|
Status status = serviceHealth.getStatus();
|
|
|
|
|
if (status == Status.OK) {
|
|
|
|
|
return "Ok";
|
|
|
|
|
} else if (status == Status.FAILING) {
|
|
|
|
|
return "Failing";
|
|
|
|
|
} else if (status == Status.EXCELLENT) {
|
|
|
|
|
return "Excellent";
|
|
|
|
|
} else {
|
|
|
|
|
return status.toString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String getStatusTheme(ServiceHealth serviceHealth) {
|
|
|
|
|
Status status = serviceHealth.getStatus();
|
|
|
|
|
String theme = "badge primary small";
|
|
|
|
|
if (status == Status.EXCELLENT) {
|
|
|
|
|
theme += " success";
|
|
|
|
|
} else if (status == Status.FAILING) {
|
|
|
|
|
theme += " error";
|
|
|
|
|
}
|
|
|
|
|
return theme;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|