update dockerfile
Signed-off-by: Peter Siegmund <developer@mars3142.org>
This commit is contained in:
35
Dockerfile
35
Dockerfile
@@ -1,4 +1,33 @@
|
||||
FROM eclipse-temurin:21-jre
|
||||
COPY target/*.jar app.jar
|
||||
FROM maven:3-eclipse-temurin-21-jammy as build
|
||||
|
||||
# Install nodejs
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y ca-certificates curl gnupg
|
||||
RUN mkdir -p /etc/apt/keyrings
|
||||
RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
||||
RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_18.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
|
||||
RUN apt-get update
|
||||
RUN apt-get install nodejs -y
|
||||
|
||||
# Stop running as root at this point
|
||||
RUN useradd -m vaadin
|
||||
WORKDIR /usr/src/app/
|
||||
RUN chown vaadin:vaadin /usr/src/app/
|
||||
USER vaadin
|
||||
|
||||
# Copy pom.xml and prefetch dependencies so a repeated build can continue from the next step with existing dependencies
|
||||
COPY --chown=vaadin pom.xml ./
|
||||
|
||||
# Copy all needed project files to a folder
|
||||
COPY --chown=vaadin:vaadin src src
|
||||
|
||||
# Build the production package, assuming that we validated the version before so no need for running tests again
|
||||
RUN mvn clean package -DskipTests -Pproduction --batch-mode
|
||||
|
||||
# Running stage: the part that is used for running the application
|
||||
FROM eclipse-temurin:21-jre-jammy
|
||||
COPY --from=build /usr/src/app/target/*.jar /usr/app/app.jar
|
||||
RUN useradd -m vaadin
|
||||
USER vaadin
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["java", "-jar", "/app.jar"]
|
||||
CMD java -jar /usr/app/app.jar
|
||||
|
23
src/main/frontend/index.html
Normal file
23
src/main/frontend/index.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
This file is auto-generated by Vaadin.
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<style>
|
||||
body, #outlet {
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
<!-- index.ts is included here automatically (either by the dev server or during the build) -->
|
||||
</head>
|
||||
<body>
|
||||
<!-- This outlet div is where the views are rendered -->
|
||||
<div id="outlet"></div>
|
||||
</body>
|
||||
</html>
|
@@ -27,7 +27,6 @@ import com.vaadin.flow.theme.lumo.LumoUtility.TextColor;
|
||||
import com.vaadin.flow.theme.lumo.LumoUtility.Whitespace;
|
||||
import com.vaadin.flow.theme.lumo.LumoUtility.Width;
|
||||
import dev.mars3142.fhq.views.checkoutform.CheckoutFormView;
|
||||
import dev.mars3142.fhq.views.dashboard.DashboardView;
|
||||
import dev.mars3142.fhq.views.myview.MyViewView;
|
||||
import org.vaadin.lineawesome.LineAwesomeIcon;
|
||||
|
||||
@@ -102,8 +101,6 @@ public class MainLayout extends AppLayout {
|
||||
|
||||
private MenuItemInfo[] createMenuItems() {
|
||||
return new MenuItemInfo[]{ //
|
||||
new MenuItemInfo("Dashboard", LineAwesomeIcon.CHART_AREA_SOLID.create(), DashboardView.class), //
|
||||
|
||||
new MenuItemInfo("Checkout Form", LineAwesomeIcon.CREDIT_CARD.create(), CheckoutFormView.class), //
|
||||
|
||||
new MenuItemInfo("My View", LineAwesomeIcon.PENCIL_RULER_SOLID.create(), MyViewView.class), //
|
||||
|
@@ -38,7 +38,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@PageTitle("Checkout Form")
|
||||
@Route(value = "checkout-form", layout = MainLayout.class)
|
||||
@Route(value = "", layout = MainLayout.class)
|
||||
public class CheckoutFormView extends Div {
|
||||
|
||||
private static final Set<String> states = new LinkedHashSet<>();
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -1,65 +0,0 @@
|
||||
package dev.mars3142.fhq.views.dashboard;
|
||||
|
||||
/**
|
||||
* Simple DTO class for the inbox list to demonstrate complex object data
|
||||
*/
|
||||
public class ServiceHealth {
|
||||
|
||||
private Status status;
|
||||
|
||||
private String city;
|
||||
|
||||
private int input;
|
||||
|
||||
private int output;
|
||||
|
||||
private String theme;
|
||||
|
||||
enum Status {
|
||||
EXCELLENT, OK, FAILING;
|
||||
}
|
||||
|
||||
public ServiceHealth() {
|
||||
|
||||
}
|
||||
|
||||
public ServiceHealth(Status status, String city, int input, int output) {
|
||||
this.status = status;
|
||||
this.city = city;
|
||||
this.input = input;
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Status status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public int getInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
public void setInput(int input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public int getOutput() {
|
||||
return output;
|
||||
}
|
||||
|
||||
public void setOutput(int output) {
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user