diff --git a/pom.xml b/pom.xml index e4af5cb..d3de326 100644 --- a/pom.xml +++ b/pom.xml @@ -52,6 +52,12 @@ com.vaadin vaadin-spring-boot-starter + + + org.apache.commons + commons-csv + 1.11.0 + org.vaadin.klaudeta grid-pagination @@ -101,6 +107,11 @@ vaadin-testbench-junit5 test + + org.apache.commons + commons-csv + 1.10.0 + diff --git a/src/main/java/com/application/munera/views/expenses/ExpensesView.java b/src/main/java/com/application/munera/views/expenses/ExpensesView.java index 98f505d..544c2aa 100644 --- a/src/main/java/com/application/munera/views/expenses/ExpensesView.java +++ b/src/main/java/com/application/munera/views/expenses/ExpensesView.java @@ -1,7 +1,7 @@ package com.application.munera.views.expenses; -import com.application.munera.security.SecurityUtils; import com.application.munera.data.*; +import com.application.munera.security.SecurityUtils; import com.application.munera.services.*; import com.application.munera.views.MainLayout; import com.vaadin.flow.component.UI; @@ -13,6 +13,7 @@ import com.vaadin.flow.component.datepicker.DatePicker; import com.vaadin.flow.component.dependency.Uses; import com.vaadin.flow.component.formlayout.FormLayout; import com.vaadin.flow.component.grid.GridVariant; +import com.vaadin.flow.component.html.Anchor; import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.icon.Icon; import com.vaadin.flow.component.notification.Notification; @@ -27,13 +28,22 @@ import com.vaadin.flow.data.binder.ValidationException; import com.vaadin.flow.data.converter.StringToBigDecimalConverter; import com.vaadin.flow.data.renderer.ComponentRenderer; import com.vaadin.flow.router.*; +import com.vaadin.flow.server.StreamResource; import jakarta.annotation.security.PermitAll; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.orm.ObjectOptimisticLockingFailureException; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.apache.commons.csv.CSVPrinter; +import org.apache.commons.csv.CSVFormat; + import org.vaadin.klaudeta.PaginatedGrid; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.util.List; import java.util.Objects; import java.util.Optional; @@ -52,6 +62,7 @@ public class ExpensesView extends Div implements BeforeEnterObserver { private final Button cancel = new Button("Cancel"); private final Button save = new Button("Save"); private final Button delete = new Button("Delete"); + private final Button exportToCSVButton = new Button("Export to CSV"); private final BeanValidationBinder binder; private Expense expense; @@ -109,6 +120,15 @@ public class ExpensesView extends Div implements BeforeEnterObserver { grid.setPageSize(22); // setting page size grid.addThemeVariants(GridVariant.LUMO_NO_BORDER); + // Export to CSV button + exportToCSVButton.addClickListener(event -> { + StreamResource resource = createCSVResource(expenseService.findAll()); + Anchor downloadLink = new Anchor(resource, "Download CSV"); + downloadLink.getElement().setAttribute("download", true); + add(downloadLink); + }); + add(exportToCSVButton); + // when a row is selected or deselected, populate form grid.asSingleSelect().addValueChangeListener(event -> { if (event.getValue() != null) UI.getCurrent().navigate(String.format(EXPENSE_EDIT_ROUTE_TEMPLATE, event.getValue().getId())); @@ -329,4 +349,29 @@ public class ExpensesView extends Div implements BeforeEnterObserver { } } } + + private StreamResource createCSVResource(List expenses) { + return new StreamResource("expenses.csv", () -> { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + try (OutputStreamWriter writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8); + CSVPrinter csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT.withHeader("Name", "Cost", "Category", "Period Interval", "Period Unit", "Date", "Status"))) { + + for (Expense expense : expenses) { + csvPrinter.printRecord( + expense.getName(), + expense.getCost(), + expense.getCategory() != null ? expense.getCategory().getName() : "", + expense.getPeriodInterval(), + expense.getPeriodUnit(), + expense.getDate(), + expense.getIsPaid() ? "Paid" : "Unpaid" + ); + } + } catch (Exception e) { + e.printStackTrace(); + } + + return new ByteArrayInputStream(stream.toByteArray()); + }); + } } \ No newline at end of file