Add another chart + UI for charts

This commit is contained in:
2019-07-01 23:46:21 +02:00
parent 0669df181f
commit 1d5f23397f
19 changed files with 438 additions and 50 deletions

View File

@@ -0,0 +1,30 @@
package de.financer.chart;
import de.financer.config.FinancerConfig;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
public abstract class AbstractChartGenerator<P extends ChartParameter> implements ChartGenerator<P> {
private FinancerConfig financerConfig;
private MessageSource messageSource;
public String getMessage(String key) {
return this.getMessage(key, null);
}
public String getMessage(String key, Object[] args) {
return this.messageSource.getMessage(key, args, LocaleContextHolder.getLocale());
}
public FinancerConfig getFinancerConfig() {
return financerConfig;
}
public void setFinancerConfig(FinancerConfig financerConfig) {
this.financerConfig = financerConfig;
}
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}
}

View File

@@ -1,40 +0,0 @@
package de.financer.chart;
import de.financer.config.FinancerConfig;
import de.financer.dto.AccountGroupExpense;
import de.financer.template.GetAccountGroupExpensesTemplate;
import de.financer.util.ControllerUtils;
import org.apache.commons.collections4.IterableUtils;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import java.time.LocalDate;
public class AccountGroupExpensesChartGenerator {
public JFreeChart generateChart(FinancerConfig financerConfig, LocalDate periodStart, LocalDate periodEnd, MessageSource messageSource) {
final String start = ControllerUtils.formatDate(financerConfig, periodStart);
final String end = ControllerUtils.formatDate(financerConfig, periodEnd);
final Iterable<AccountGroupExpense> expenses = new GetAccountGroupExpensesTemplate()
.exchange(financerConfig, start, end).getBody();
final PieDataset dataSet = createDataSet(expenses);
return ChartFactory.createPieChart(messageSource
.getMessage("financer.chart.account-group-expenses-current-period.title", null, LocaleContextHolder
.getLocale()), dataSet);
}
private PieDataset createDataSet(Iterable<AccountGroupExpense> data) {
final DefaultPieDataset dataSet = new DefaultPieDataset();
IterableUtils.toList(data).stream()
.forEach((ex) -> dataSet.setValue(ex.getAccountGroup().getName(), ex.getExpense()));
return dataSet;
}
}

View File

@@ -0,0 +1,7 @@
package de.financer.chart;
import org.jfree.chart.JFreeChart;
public interface ChartGenerator<P extends ChartParameter> {
JFreeChart generateChart(P parameter);
}

View File

@@ -0,0 +1,4 @@
package de.financer.chart;
public interface ChartParameter {
}

View File

@@ -0,0 +1,18 @@
package de.financer.chart;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public enum ChartType {
ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD,
ACCOUNT_GROUP_EXPENSES_FOR_PERIOD;
public static List<String> valueList() {
return Arrays.stream(ChartType.values()).map(ChartType::name).collect(Collectors.toList());
}
public static ChartType getByValue(String value) {
return Arrays.asList(values()).stream().filter((ct) -> ct.name().equals(value)).findFirst().get();
}
}

View File

@@ -0,0 +1,38 @@
package de.financer.chart;
import de.financer.chart.impl.AccountGroupExpensesGenerator;
import de.financer.config.FinancerConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Component;
@Component
public class FinancerChartFactory {
@Autowired
private FinancerConfig financerConfig;
@Autowired
private MessageSource messageSource;
public <P extends ChartParameter> ChartGenerator<P> getGenerator(ChartType chartType) {
AbstractChartGenerator<P> generator;
switch (chartType) {
case ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD:
// TODO WHY IS THIS CAST NECESSARY???
generator = (AbstractChartGenerator<P>) new AccountGroupExpensesGenerator();
break;
default:
generator = null;
}
configureGenerator(generator);
return generator;
}
private void configureGenerator(AbstractChartGenerator<?> generator) {
generator.setFinancerConfig(this.financerConfig);
generator.setMessageSource(this.messageSource);
}
}

View File

@@ -0,0 +1,36 @@
package de.financer.chart.impl;
import de.financer.chart.AbstractChartGenerator;
import de.financer.dto.AccountGroupExpense;
import de.financer.template.GetAccountGroupExpensesTemplate;
import de.financer.util.ControllerUtils;
import org.apache.commons.collections4.IterableUtils;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
public class AccountGroupExpensesGenerator extends AbstractChartGenerator<AccountGroupExpensesParameter> {
@Override
public JFreeChart generateChart(AccountGroupExpensesParameter parameter) {
final String start = ControllerUtils.formatDate(this.getFinancerConfig(), parameter.getPeriodStart());
final String end = ControllerUtils.formatDate(this.getFinancerConfig(), parameter.getPeriodEnd());
final Iterable<AccountGroupExpense> expenses = new GetAccountGroupExpensesTemplate()
.exchange(this.getFinancerConfig(), start, end).getBody();
final PieDataset dataSet = createDataSet(expenses);
return ChartFactory
.createPieChart(this.getMessage(parameter.getTitle(), parameter.getArgsForTitle()), dataSet);
}
private PieDataset createDataSet(Iterable<AccountGroupExpense> data) {
final DefaultPieDataset dataSet = new DefaultPieDataset();
IterableUtils.toList(data).stream()
.forEach((ex) -> dataSet.setValue(ex.getAccountGroup().getName(), ex.getExpense()));
return dataSet;
}
}

View File

@@ -0,0 +1,44 @@
package de.financer.chart.impl;
import de.financer.chart.ChartParameter;
import java.time.LocalDate;
public class AccountGroupExpensesParameter implements ChartParameter {
private LocalDate periodStart;
private LocalDate periodEnd;
private String title;
private Object[] argsForTitle;
public LocalDate getPeriodStart() {
return periodStart;
}
public void setPeriodStart(LocalDate periodStart) {
this.periodStart = periodStart;
}
public LocalDate getPeriodEnd() {
return periodEnd;
}
public void setPeriodEnd(LocalDate periodEnd) {
this.periodEnd = periodEnd;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Object[] getArgsForTitle() {
return argsForTitle;
}
public void setArgsForTitle(Object[] argsForTitle) {
this.argsForTitle = argsForTitle;
}
}

View File

@@ -1,14 +1,20 @@
package de.financer.controller;
import de.financer.chart.AccountGroupExpensesChartGenerator;
import de.financer.chart.impl.AccountGroupExpensesParameter;
import de.financer.chart.ChartGenerator;
import de.financer.chart.ChartType;
import de.financer.chart.FinancerChartFactory;
import de.financer.config.FinancerConfig;
import de.financer.form.ConfigAccountGroupExpenseForPeriodForm;
import de.financer.util.ControllerUtils;
import de.financer.util.ExpensePeriod;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@@ -19,16 +25,47 @@ public class ChartController {
private FinancerConfig financerConfig;
@Autowired
private MessageSource messageSource;
private FinancerChartFactory financerChartFactory;
@GetMapping("/getAccountGroupExpensesCurrentPeriod")
public void getAccountGroupExpensesCurrentPeriod(HttpServletResponse response) {
final ExpensePeriod period = ExpensePeriod
.getCurrentExpensePeriod(this.financerConfig.getMonthPeriodStartDay());
final AccountGroupExpensesParameter parameter = new AccountGroupExpensesParameter();
JFreeChart chart = new AccountGroupExpensesChartGenerator()
.generateChart(this.financerConfig, period.getStart(), period.getEnd(), this.messageSource);
parameter.setPeriodStart(period.getStart());
parameter.setPeriodEnd(period.getEnd());
parameter.setTitle("financer.chart.account-group-expenses-current-period.title");
final ChartGenerator<AccountGroupExpensesParameter> generator =
this.financerChartFactory.getGenerator(ChartType.ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD);
final JFreeChart chart = generator.generateChart(parameter);
writeChart(response, chart);
}
@PostMapping("/getAccountGroupExpensesForPeriod")
public void getAccountGroupExpensesForPeriod(HttpServletResponse response, ConfigAccountGroupExpenseForPeriodForm form) {
final AccountGroupExpensesParameter parameter = new AccountGroupExpensesParameter();
parameter.setPeriodStart(ControllerUtils.parseDate(this.financerConfig, form.getFromDate()));
parameter.setPeriodEnd(ControllerUtils.parseDate(this.financerConfig, form.getToDate()));
parameter.setTitle("financer.chart.account-group-expenses-for-period.title");
parameter.setArgsForTitle(new Object[]{ControllerUtils.formatDate(this.financerConfig, form
.getFromDate(), LocaleContextHolder
.getLocale()), ControllerUtils.formatDate(this.financerConfig, form.getToDate(), LocaleContextHolder
.getLocale())});
final ChartGenerator<AccountGroupExpensesParameter> generator =
this.financerChartFactory.getGenerator(ChartType.ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD);
final JFreeChart chart = generator.generateChart(parameter);
writeChart(response, chart);
}
private void writeChart(HttpServletResponse response, JFreeChart chart) {
response.setContentType("image/png");
try {

View File

@@ -0,0 +1,64 @@
package de.financer.controller;
import de.financer.chart.ChartType;
import de.financer.config.FinancerConfig;
import de.financer.form.ConfigAccountGroupExpenseForPeriodForm;
import de.financer.form.SelectChartForm;
import de.financer.util.ControllerUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import java.util.NoSuchElementException;
@Controller
public class ReportController {
@Autowired
private FinancerConfig financerConfig;
@GetMapping("/selectChart")
public String selectChart(Model model) {
model.addAttribute("form", new SelectChartForm());
model.addAttribute("availableCharts", ChartType.valueList());
ControllerUtils.addVersionAttribute(model, this.financerConfig);
ControllerUtils.addCurrencySymbol(model, this.financerConfig);
return "report/selectChart";
}
@PostMapping("/configureChart")
public String configureChart(SelectChartForm form, Model model) {
final ChartType selectedChartType;
try {
selectedChartType = ChartType.getByValue(form.getChartType());
}
catch (NoSuchElementException nsee) {
model.addAttribute("form", new SelectChartForm());
model.addAttribute("errorMessage", "UNKNOWN_CHART_TYPE");
model.addAttribute("availableCharts", ChartType.valueList());
ControllerUtils.addVersionAttribute(model, this.financerConfig);
ControllerUtils.addCurrencySymbol(model, this.financerConfig);
return "report/selectChart";
}
switch(selectedChartType) {
case ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD:
// Special case: this chart does not require parameters, so we can
// directly redirect to the actual chart instead of the config page
return "redirect:/getAccountGroupExpensesCurrentPeriod";
case ACCOUNT_GROUP_EXPENSES_FOR_PERIOD:
model.addAttribute("form", new ConfigAccountGroupExpenseForPeriodForm());
ControllerUtils.addVersionAttribute(model, this.financerConfig);
ControllerUtils.addCurrencySymbol(model, this.financerConfig);
return "report/configureAccountGroupExpensesForPeriod";
default:
// Cannot happen
throw new IllegalStateException("Unexpected value: " + selectedChartType);
}
}
}

View File

@@ -0,0 +1,22 @@
package de.financer.form;
public class ConfigAccountGroupExpenseForPeriodForm {
private String fromDate;
private String toDate;
public String getFromDate() {
return fromDate;
}
public void setFromDate(String fromDate) {
this.fromDate = fromDate;
}
public String getToDate() {
return toDate;
}
public void setToDate(String toDate) {
this.toDate = toDate;
}
}

View File

@@ -0,0 +1,13 @@
package de.financer.form;
public class SelectChartForm {
private String chartType;
public String getChartType() {
return chartType;
}
public void setChartType(String chartType) {
this.chartType = chartType;
}
}

View File

@@ -11,10 +11,13 @@ import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.ui.Model;
import java.text.DateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
public class ControllerUtils {
@@ -55,6 +58,26 @@ public class ControllerUtils {
return formatted.format(DateTimeFormatter.ofPattern(financerConfig.getDateFormat()));
}
public static String formatDate(FinancerConfig financerConfig, String dateFromForm, Locale locale) {
if (StringUtils.isEmpty(dateFromForm)) {
return null;
}
// The format is always "yyyy-MM-dd", see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date
final LocalDate formatted = LocalDate.parse(dateFromForm, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
return formatted.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(locale));
}
public static LocalDate parseDate(FinancerConfig financerConfig, String dateFromForm) {
if (StringUtils.isEmpty(dateFromForm)) {
return null;
}
// The format is always "yyyy-MM-dd", see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date
return LocalDate.parse(dateFromForm, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
}
public static List<RecurringTransaction> filterEmptyEntries(Iterable<RecurringTransaction> recurringTransactions) {
return IterableUtils.toList(recurringTransactions).stream()
.filter((rt) -> rt.getFromAccount() != null && rt.getToAccount() != null)

View File

@@ -7,6 +7,7 @@ financer.account-overview.available-actions.create-transaction=Create new transa
financer.account-overview.available-actions.create-recurring-transaction=Create new recurring transaction
financer.account-overview.available-actions.recurring-transaction-all=Show all recurring transactions
financer.account-overview.available-actions.create-account-group=Create new account group
financer.account-overview.available-actions.select-chart=Generate a chart
financer.account-overview.status=Status\:
financer.account-overview.status.recurring-transaction-due-today=Recurring transactions due today\:
financer.account-overview.status.recurring-transaction-active=Active recurring transactions\:
@@ -18,7 +19,7 @@ financer.account-overview.table-header.group=Group
financer.account-overview.table-header.balance=Current Balance
financer.account-overview.table-header.type=Type
financer.account-overview.table-header.status=Status
financer.account-overview.tooltip.status.current-expenses=Period from {0} to {1}
financer.account-overview.tooltip.status.current-expenses=Period from {0} to {1}. Clicking the amount will open a graphical overview about the expenses grouped by account group
financer.account-overview.tooltip.status.current-assets=Assets available at short-notice
financer.account-new.title=financer\: create new account
@@ -103,6 +104,14 @@ financer.recurring-to-transaction-with-amount.title=financer\: create transactio
financer.recurring-to-transaction-with-amount.label.amount=Amount\:
financer.recurring-to-transaction-with-amount.submit=Create
financer.chart-select.title=Select a chart to generate
financer.chart-select.submit=Select
financer.chart-config-account-group-expenses-for-period.title=Configure account group expenses for period chart
financer.chart-config-account-group-expenses-for-period.label.from-date=From date\:
financer.chart-config-account-group-expenses-for-period.label.to-date=To date\:
financer.chart-config-account-group-expenses-for-period.submit=Generate
financer.interval-type.DAILY=Daily
financer.interval-type.WEEKLY=Weekly
financer.interval-type.MONTHLY=Monthly
@@ -133,10 +142,16 @@ financer.heading.recurring-transaction-list.dueToday=financer\: recurring transa
financer.heading.recurring-transaction-list.active=financer\: active recurring transactions
financer.heading.recurring-transaction-list.all=financer\: all recurring transaction
financer.heading.recurring-to-transaction-with-amount=financer\: create transaction from recurring with amount
financer.heading.chart-select=financer\: select a chart to generate
financer.heading.chart-config-account-group-expenses-for-period=financer\: configure account group expenses for period chart
financer.cancel-back-to-overview=Cancel and back to overview
financer.chart.account-group-expenses-current-period.title=Expenses of the current period grouped by account group
financer.chart.account-group-expenses-for-period.title=Expenses for period from {0} to {1} grouped by account group
financer.chart.name.ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD=Expenses of the current period grouped by account group
financer.chart.name.ACCOUNT_GROUP_EXPENSES_FOR_PERIOD=Expenses for a configurable period grouped by account group
financer.error-message.UNKNOWN_ERROR=An unknown error occurred!
financer.error-message.INVALID_ACCOUNT_TYPE=The selected account type is not valid!
@@ -164,4 +179,5 @@ financer.error-message.TRANSACTION_NOT_FOUND=The transaction could not be found!
financer.error-message.ACCOUNT_NOT_FOUND=The account could not be found!
financer.error-message.DUPLICATE_ACCOUNT_KEY=An account with the given key already exists!
financer.error-message.DUPLICATE_ACCOUNT_GROUP_NAME=An account group with the given key already exists!
financer.error-message.ACCOUNT_GROUP_NOT_FOUND=The account group could not be found!
financer.error-message.ACCOUNT_GROUP_NOT_FOUND=The account group could not be found!
financer.error-message.UNKNOWN_CHART_TYPE=The selected chart type is not known!

View File

@@ -7,6 +7,7 @@ financer.account-overview.available-actions.create-transaction=Neue Buchung erst
financer.account-overview.available-actions.create-recurring-transaction=Neue wiederkehrende Buchung erstellen
financer.account-overview.available-actions.recurring-transaction-all=Zeige alle wiederkehrende Buchungen
financer.account-overview.available-actions.create-account-group=Neue Konto-Gruppe erstellen
financer.account-overview.available-actions.select-chart=Ein Diagramm erzeugen
financer.account-overview.status=Status\:
financer.account-overview.status.recurring-transaction-due-today=Wiederkehrende Buchungen heute f\u00E4llig\:
financer.account-overview.status.recurring-transaction-active=Aktive wiederkehrende Buchungen\:
@@ -18,7 +19,7 @@ financer.account-overview.table-header.group=Gruppe
financer.account-overview.table-header.balance=Kontostand
financer.account-overview.table-header.type=Typ
financer.account-overview.table-header.status=Status
financer.account-overview.tooltip.status.current-expenses=Periode ab {0} bis {1}
financer.account-overview.tooltip.status.current-expenses=Periode ab {0} bis {1}. Durch Klicken des Betrags kann eine grafische \u00DCbersicht über die Ausgaben gruppiert nach Konto-Gruppe angezeigt werden
financer.account-overview.tooltip.status.current-assets=Kurzfristig verf\u00FCgbares Verm\u00F6gen
financer.account-new.title=financer\: Neues Konto erstellen
@@ -103,6 +104,14 @@ financer.recurring-to-transaction-with-amount.title=financer\: Buchung mit Betra
financer.recurring-to-transaction-with-amount.label.amount=Betrag\:
financer.recurring-to-transaction-with-amount.submit=Erstellen
financer.chart-select.title=Ein Diagramm zum Erzeugen ausw\u00E4hlen
financer.chart-select.submit=Ausw\u00E4hlen
financer.chart-config-account-group-expenses-for-period.title=Konfigurieren von Ausgaben f\u00FCr Periode gruppiert nach Konto-Gruppe Diagramm
financer.chart-config-account-group-expenses-for-period.label.from-date=Von Datum\:
financer.chart-config-account-group-expenses-for-period.label.to-date=Bis Datum\:
financer.chart-config-account-group-expenses-for-period.submit=Erzeugen
financer.interval-type.DAILY=T\u00E4glich
financer.interval-type.WEEKLY=W\u00F6chentlich
financer.interval-type.MONTHLY=Monatlich
@@ -133,7 +142,13 @@ financer.heading.recurring-transaction-list.dueToday=financer\: wiederkehrende B
financer.heading.recurring-transaction-list.active=financer\: aktive wiederkehrende Buchungen
financer.heading.recurring-transaction-list.all=financer\: alle wiederkehrende Buchungen
financer.heading.recurring-to-transaction-with-amount=financer\: Buchung mit Betrag aus wiederkehrender Buchung erstellen
financer.heading.chart-select=financer\: ein Diagramm zum Erzeugen ausw\u00E4hlen
financer.heading.chart-config-account-group-expenses-for-period=financer\: konfigurieren von Ausgaben f\u00FCr Periode gruppiert nach Konto-Gruppe Diagramm
financer.cancel-back-to-overview=Abbrechen und zur \u00DCbersicht
financer.chart.account-group-expenses-current-period.title=Ausgaben in der aktuellen Periode gruppiert nach Konto-Gruppe
financer.chart.account-group-expenses-current-period.title=Ausgaben in der aktuellen Periode gruppiert nach Konto-Gruppe
financer.chart.account-group-expenses-for-period.title=Ausgaben in der Periode vom {0} bis {1} gruppiert nach Konto-Gruppe
financer.chart.name.ACCOUNT_GROUP_EXPENSES_CURRENT_PERIOD=Ausgaben in der aktuellen Periode gruppiert nach Konto-Gruppe
financer.chart.name.ACCOUNT_GROUP_EXPENSES_FOR_PERIOD=Ausgaben f\u00FCr eine konfigurierbare Periode gruppiert nach Konto-Gruppe

View File

@@ -67,15 +67,24 @@ tr:hover {
#new-transaction-form *,
#new-recurring-transaction-form *,
#recurring-to-transaction-with-amount-form *,
#new-account-group-form * {
#new-account-group-form *,
#chart-config-account-group-expenses-for-period-form * {
display: block;
margin-top: 1em;
width: 20em;
box-sizing: border-box;
}
#chart-select-form div {
width: 20em;
margin-top: 1em;
display: block;
}
input[type=submit] {
margin-top: 1em;
margin-bottom: 1em;
width: 20em;
}
#footer-container {

View File

@@ -28,6 +28,7 @@
<span th:text="#{financer.account-overview.status.recurring-transaction-active}"/>
<a th:href="@{/recurringTransactionActive}" th:text="${rtAllActiveCount}"/>
</div>
</div>
<span th:text="#{financer.account-overview.available-actions}"/>
<div id="action-container">
@@ -48,6 +49,10 @@
<a th:href="@{/recurringTransactionAll}"
th:text="#{financer.account-overview.available-actions.recurring-transaction-all}"/>
</div>
<div id="action-container-sub-reports">
<a th:href="@{/selectChart}"
th:text="#{financer.account-overview.available-actions.select-chart}"/>
</div>
</div>
<table id="account-overview-table">
<tr>

View File

@@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="#{financer.chart-config-account-group-expenses-for-period.title}"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" th:href="@{/css/main.css}">
</head>
<body>
<h1 th:text="#{financer.heading.chart-config-account-group-expenses-for-period}"/>
<span class="errorMessage" th:if="${errorMessage != null}" th:text="#{'financer.error-message.' + ${errorMessage}}"/>
<a th:href="@{/accountOverview}" th:text="#{financer.cancel-back-to-overview}"/>
<form id="chart-config-account-group-expenses-for-period-form" action="#"
th:action="@{/getAccountGroupExpensesForPeriod}" th:object="${form}" method="post">
<label for="fromDate" th:text="#{financer.chart-config-account-group-expenses-for-period.label.from-date}"/>
<input type="date" id="fromDate" th:field="*{fromDate}"/>
<label for="toDate" th:text="#{financer.chart-config-account-group-expenses-for-period.label.to-date}"/>
<input type="date" id="toDate" th:field="*{toDate}"/>
<input type="submit" th:value="#{financer.chart-config-account-group-expenses-for-period.submit}"/>
</form>
<div th:replace="includes/footer :: footer"/>
</body>
</html>

View File

@@ -0,0 +1,24 @@
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="#{financer.chart-select.title}"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" th:href="@{/css/main.css}">
</head>
<body>
<h1 th:text="#{financer.heading.chart-select}"/>
<span class="errorMessage" th:if="${errorMessage != null}" th:text="#{'financer.error-message.' + ${errorMessage}}"/>
<a th:href="@{/accountOverview}" th:text="#{financer.cancel-back-to-overview}"/>
<form id="chart-select-form" action="#" th:action="@{/configureChart}" th:object="${form}" method="post">
<th:block th:each="chart, iterStat : ${availableCharts}">
<div>
<input type="radio" th:value="${chart}" th:field="*{chartType}" th:id="'chart' + ${iterStat.count}"/>
<label th:for="'chart' + ${iterStat.count}" th:text="#{${'financer.chart.name.' + chart}}"/>
</div>
</th:block>
<input type="submit" th:value="#{financer.chart-select.submit}"/>
</form>
<div th:replace="includes/footer :: footer"/>
</body>
</html>