From cab820c2bfc20fa1ff587821c8d42adb103e0389 Mon Sep 17 00:00:00 2001 From: Stefan Haun Date: Fri, 2 Aug 2024 20:33:26 +0200 Subject: [PATCH 1/8] Move the ledger pages to the accounting page area --- .../settings => accounting}/ledgers/LedgerEditor.java | 2 +- .../settings => accounting}/ledgers/LedgersGrid.java | 2 +- .../ledgers/LedgersSettingsPage.java | 8 ++++---- .../ui/content/admin/settings/SettingsLayout.java | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) rename src/main/java/com/penguineering/gartenplus/ui/content/{admin/settings => accounting}/ledgers/LedgerEditor.java (98%) rename src/main/java/com/penguineering/gartenplus/ui/content/{admin/settings => accounting}/ledgers/LedgersGrid.java (96%) rename src/main/java/com/penguineering/gartenplus/ui/content/{admin/settings => accounting}/ledgers/LedgersSettingsPage.java (90%) diff --git a/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/ledgers/LedgerEditor.java b/src/main/java/com/penguineering/gartenplus/ui/content/accounting/ledgers/LedgerEditor.java similarity index 98% rename from src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/ledgers/LedgerEditor.java rename to src/main/java/com/penguineering/gartenplus/ui/content/accounting/ledgers/LedgerEditor.java index c08e0e5..15542af 100644 --- a/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/ledgers/LedgerEditor.java +++ b/src/main/java/com/penguineering/gartenplus/ui/content/accounting/ledgers/LedgerEditor.java @@ -1,4 +1,4 @@ -package com.penguineering.gartenplus.ui.content.admin.settings.ledgers; +package com.penguineering.gartenplus.ui.content.accounting.ledgers; import com.penguineering.gartenplus.accounting.model.ledger.LedgerDTO; import com.vaadin.flow.component.button.Button; diff --git a/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/ledgers/LedgersGrid.java b/src/main/java/com/penguineering/gartenplus/ui/content/accounting/ledgers/LedgersGrid.java similarity index 96% rename from src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/ledgers/LedgersGrid.java rename to src/main/java/com/penguineering/gartenplus/ui/content/accounting/ledgers/LedgersGrid.java index c292cac..71bdcb5 100644 --- a/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/ledgers/LedgersGrid.java +++ b/src/main/java/com/penguineering/gartenplus/ui/content/accounting/ledgers/LedgersGrid.java @@ -1,4 +1,4 @@ -package com.penguineering.gartenplus.ui.content.admin.settings.ledgers; +package com.penguineering.gartenplus.ui.content.accounting.ledgers; import com.penguineering.gartenplus.accounting.model.ledger.LedgerDTO; import com.vaadin.flow.component.button.Button; diff --git a/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/ledgers/LedgersSettingsPage.java b/src/main/java/com/penguineering/gartenplus/ui/content/accounting/ledgers/LedgersSettingsPage.java similarity index 90% rename from src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/ledgers/LedgersSettingsPage.java rename to src/main/java/com/penguineering/gartenplus/ui/content/accounting/ledgers/LedgersSettingsPage.java index 3e10b4e..8d8728d 100644 --- a/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/ledgers/LedgersSettingsPage.java +++ b/src/main/java/com/penguineering/gartenplus/ui/content/accounting/ledgers/LedgersSettingsPage.java @@ -1,9 +1,9 @@ -package com.penguineering.gartenplus.ui.content.admin.settings.ledgers; +package com.penguineering.gartenplus.ui.content.accounting.ledgers; import com.penguineering.gartenplus.accounting.model.ledger.LedgerDTO; import com.penguineering.gartenplus.accounting.model.ledger.LedgerEntityService; import com.penguineering.gartenplus.ui.appframe.GartenplusPage; -import com.penguineering.gartenplus.ui.content.admin.settings.SettingsLayout; +import com.penguineering.gartenplus.ui.content.accounting.AccountingLayout; import com.vaadin.flow.component.confirmdialog.ConfirmDialog; import com.vaadin.flow.component.html.H3; import com.vaadin.flow.router.PageTitle; @@ -13,9 +13,9 @@ import java.util.Optional; import java.util.UUID; -@Route(value = "ledgers", layout = SettingsLayout.class) +@Route(value = "ledgers", layout = AccountingLayout.class) @RolesAllowed({"ADMINISTRATOR", "TREASURER"}) -@PageTitle("GartenPlus | Einstellungen | Ledger") +@PageTitle("GartenPlus | Buchhaltung | Ledger") public class LedgersSettingsPage extends GartenplusPage { private final LedgerEntityService ledgerService; diff --git a/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/SettingsLayout.java b/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/SettingsLayout.java index f88bbf6..201b73b 100644 --- a/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/SettingsLayout.java +++ b/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/SettingsLayout.java @@ -3,7 +3,7 @@ import com.penguineering.gartenplus.auth.SecurityUtils; import com.penguineering.gartenplus.ui.content.admin.AdminLayout; import com.penguineering.gartenplus.ui.content.admin.settings.groups.GroupSettingsPage; -import com.penguineering.gartenplus.ui.content.admin.settings.ledgers.LedgersSettingsPage; +import com.penguineering.gartenplus.ui.content.accounting.ledgers.LedgersSettingsPage; import com.penguineering.gartenplus.ui.content.admin.settings.users.UsersSettingsPage; import com.vaadin.flow.component.Component; import com.vaadin.flow.component.HasElement; From 5120d36c3bad1a5cea938fa49aa0df6f3e5c5439 Mon Sep 17 00:00:00 2001 From: Stefan Haun Date: Fri, 2 Aug 2024 20:47:22 +0200 Subject: [PATCH 2/8] Add a base for tabbed sub-page layouts --- .../ui/appframe/TabbedLayoutBase.java | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/main/java/com/penguineering/gartenplus/ui/appframe/TabbedLayoutBase.java diff --git a/src/main/java/com/penguineering/gartenplus/ui/appframe/TabbedLayoutBase.java b/src/main/java/com/penguineering/gartenplus/ui/appframe/TabbedLayoutBase.java new file mode 100644 index 0000000..131b70e --- /dev/null +++ b/src/main/java/com/penguineering/gartenplus/ui/appframe/TabbedLayoutBase.java @@ -0,0 +1,80 @@ +package com.penguineering.gartenplus.ui.appframe; + +import com.penguineering.gartenplus.auth.SecurityUtils; +import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.HasElement; +import com.vaadin.flow.component.UI; +import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.component.tabs.Tab; +import com.vaadin.flow.component.tabs.Tabs; +import com.vaadin.flow.router.BeforeEnterEvent; +import com.vaadin.flow.router.BeforeEnterObserver; +import com.vaadin.flow.router.Route; +import com.vaadin.flow.router.RouterLayout; + +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +public abstract class TabbedLayoutBase extends VerticalLayout implements RouterLayout, BeforeEnterObserver { + private final Map> targets; + + private final Div content; + private final Tabs menu; + + public TabbedLayoutBase(Map> targets) { + super(); + this.targets = targets; + + Set userRoles = SecurityUtils.getCurrentUserRoles(); + + menu = new Tabs(); + targets.entrySet().stream() + .filter(e -> SecurityUtils.isUserAuthorizedForComponent(e.getValue(), userRoles)) + .map(Map.Entry::getKey) + .map(Tab::new) + .forEach(menu::add); + menu.addSelectedChangeListener(this::navigateToTab); + add(menu); + + content = new Div(); + content.setSizeFull(); + content.getStyle() + .set("margin", "0") + .set("padding", "0"); + add(content); + } + + private void navigateToTab(Tabs.SelectedChangeEvent event) { + Optional.of(event.getSelectedTab()) + .map(Tab::getLabel) + .map(targets::get) + .ifPresent(target -> UI.getCurrent().navigate(target)); + } + + @Override + public void beforeEnter(BeforeEnterEvent event) { + String currentPath = event.getLocation().getPath(); + targets.forEach((label, target) -> { + Route route = target.getAnnotation(Route.class); + if (route != null && currentPath.contains(route.value())) { + menu.setSelectedTab(menu.getChildren() + .filter(component -> component instanceof Tab) + .map(component -> (Tab) component) + .filter(tab -> tab.getLabel().equals(label)) + .findFirst() + .orElse(null)); + } + }); + } + + @Override + public void showRouterLayoutContent(HasElement newContent) { + // Previous content is automatically removed + + newContent.getElement() + .getComponent() + .ifPresent(content::add); + } +} From 1c65c94c39acf45c378e75aab8a294bd4327cc3a Mon Sep 17 00:00:00 2001 From: Stefan Haun Date: Fri, 2 Aug 2024 21:05:05 +0200 Subject: [PATCH 3/8] Refactor settings layout to the tabbed layout base --- .../admin/settings/SettingsLayout.java | 73 ++----------------- 1 file changed, 6 insertions(+), 67 deletions(-) diff --git a/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/SettingsLayout.java b/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/SettingsLayout.java index 201b73b..ff613aa 100644 --- a/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/SettingsLayout.java +++ b/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/SettingsLayout.java @@ -1,89 +1,28 @@ package com.penguineering.gartenplus.ui.content.admin.settings; -import com.penguineering.gartenplus.auth.SecurityUtils; +import com.penguineering.gartenplus.ui.appframe.TabbedLayoutBase; +import com.penguineering.gartenplus.ui.content.accounting.ledgers.LedgersSettingsPage; import com.penguineering.gartenplus.ui.content.admin.AdminLayout; import com.penguineering.gartenplus.ui.content.admin.settings.groups.GroupSettingsPage; -import com.penguineering.gartenplus.ui.content.accounting.ledgers.LedgersSettingsPage; import com.penguineering.gartenplus.ui.content.admin.settings.users.UsersSettingsPage; import com.vaadin.flow.component.Component; -import com.vaadin.flow.component.HasElement; -import com.vaadin.flow.component.UI; -import com.vaadin.flow.component.html.Div; -import com.vaadin.flow.component.orderedlayout.VerticalLayout; -import com.vaadin.flow.component.tabs.Tab; -import com.vaadin.flow.component.tabs.Tabs; -import com.vaadin.flow.router.*; +import com.vaadin.flow.router.ParentLayout; +import com.vaadin.flow.router.RoutePrefix; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Optional; -import java.util.Set; @ParentLayout(AdminLayout.class) @RoutePrefix(value = "settings") -public class SettingsLayout extends VerticalLayout implements RouterLayout, BeforeEnterObserver { +public class SettingsLayout extends TabbedLayoutBase { private static final Map> targets = new LinkedHashMap<>(); static { targets.put("Benutzer", UsersSettingsPage.class); targets.put("Gruppen", GroupSettingsPage.class); - targets.put("Hauptbücher", LedgersSettingsPage.class); } - private final Div content; - private final Tabs menu; - public SettingsLayout() { - super(); - - Set userRoles = SecurityUtils.getCurrentUserRoles(); - - menu = new Tabs(); - targets.entrySet().stream() - .filter(e -> SecurityUtils.isUserAuthorizedForComponent(e.getValue(), userRoles)) - .map(Map.Entry::getKey) - .map(Tab::new) - .forEach(menu::add); - menu.addSelectedChangeListener(this::navigateToTab); - add(menu); - - content = new Div(); - content.setSizeFull(); - content.getStyle() - .set("margin", "0") - .set("padding", "0"); - add(content); - } - - private void navigateToTab(Tabs.SelectedChangeEvent event) { - Optional.of(event.getSelectedTab()) - .map(Tab::getLabel) - .map(targets::get) - .ifPresent(target -> UI.getCurrent().navigate(target)); - } - - @Override - public void beforeEnter(BeforeEnterEvent event) { - String currentPath = event.getLocation().getPath(); - targets.forEach((label, target) -> { - Route route = target.getAnnotation(Route.class); - if (route != null && currentPath.contains(route.value())) { - menu.setSelectedTab(menu.getChildren() - .filter(component -> component instanceof Tab) - .map(component -> (Tab) component) - .filter(tab -> tab.getLabel().equals(label)) - .findFirst() - .orElse(null)); - } - }); - } - - @Override - public void showRouterLayoutContent(HasElement newContent) { - // Previous content is automatically removed - - newContent.getElement() - .getComponent() - .ifPresent(content::add); + super(targets); } } From 958cf637dbbf8b336c109127904b7e89c72371ba Mon Sep 17 00:00:00 2001 From: Stefan Haun Date: Fri, 2 Aug 2024 20:49:36 +0200 Subject: [PATCH 4/8] Navigate via router class on the settings page The URL-based navigation did not work in production --- .../gartenplus/ui/content/admin/settings/SettingsPage.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/SettingsPage.java b/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/SettingsPage.java index 5223848..3c1b84c 100644 --- a/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/SettingsPage.java +++ b/src/main/java/com/penguineering/gartenplus/ui/content/admin/settings/SettingsPage.java @@ -1,6 +1,7 @@ package com.penguineering.gartenplus.ui.content.admin.settings; import com.penguineering.gartenplus.ui.appframe.GartenplusPage; +import com.penguineering.gartenplus.ui.content.admin.settings.users.UsersSettingsPage; import com.vaadin.flow.router.BeforeEnterEvent; import com.vaadin.flow.router.BeforeEnterObserver; import com.vaadin.flow.router.PageTitle; @@ -13,6 +14,7 @@ public class SettingsPage extends GartenplusPage implements BeforeEnterObserver { @Override public void beforeEnter(BeforeEnterEvent event) { - event.getUI().navigate(event.getLocation().getPath() + "/users"); + + event.getUI().navigate(UsersSettingsPage.class); } } From 9dca352b029a58166ca0d07abc4c6339f1451882 Mon Sep 17 00:00:00 2001 From: Stefan Haun Date: Fri, 2 Aug 2024 21:01:50 +0200 Subject: [PATCH 5/8] Add an accounting root layout --- .../content/accounting/AccountingLayout.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/com/penguineering/gartenplus/ui/content/accounting/AccountingLayout.java diff --git a/src/main/java/com/penguineering/gartenplus/ui/content/accounting/AccountingLayout.java b/src/main/java/com/penguineering/gartenplus/ui/content/accounting/AccountingLayout.java new file mode 100644 index 0000000..00fdc51 --- /dev/null +++ b/src/main/java/com/penguineering/gartenplus/ui/content/accounting/AccountingLayout.java @@ -0,0 +1,28 @@ +package com.penguineering.gartenplus.ui.content.accounting; + + +import com.penguineering.gartenplus.ui.appframe.AppFrameLayout; +import com.penguineering.gartenplus.ui.appframe.TabbedLayoutBase; +import com.penguineering.gartenplus.ui.content.accounting.ledgers.LedgersSettingsPage; +import com.penguineering.gartenplus.ui.content.accounting.myfinances.MyFinancesPage; +import com.vaadin.flow.component.Component; +import com.vaadin.flow.router.ParentLayout; +import com.vaadin.flow.router.RoutePrefix; + +import java.util.LinkedHashMap; +import java.util.Map; + +@ParentLayout(AppFrameLayout.class) +@RoutePrefix(value = "accounting") +public class AccountingLayout extends TabbedLayoutBase { + private static final Map> targets = new LinkedHashMap<>(); + + static { + targets.put("Meine Finanzen", MyFinancesPage.class); + targets.put("Hauptbücher", LedgersSettingsPage.class); + } + + public AccountingLayout() { + super(targets); + } +} From 036a6196e58a5664f5b1c62240d1534228cb42fc Mon Sep 17 00:00:00 2001 From: Stefan Haun Date: Fri, 2 Aug 2024 20:52:30 +0200 Subject: [PATCH 6/8] Add a My Finances page --- .../accounting/myfinances/MyFinancesPage.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/main/java/com/penguineering/gartenplus/ui/content/accounting/myfinances/MyFinancesPage.java diff --git a/src/main/java/com/penguineering/gartenplus/ui/content/accounting/myfinances/MyFinancesPage.java b/src/main/java/com/penguineering/gartenplus/ui/content/accounting/myfinances/MyFinancesPage.java new file mode 100644 index 0000000..301e22a --- /dev/null +++ b/src/main/java/com/penguineering/gartenplus/ui/content/accounting/myfinances/MyFinancesPage.java @@ -0,0 +1,18 @@ +package com.penguineering.gartenplus.ui.content.accounting.myfinances; + +import com.penguineering.gartenplus.ui.appframe.GartenplusPage; +import com.penguineering.gartenplus.ui.content.accounting.AccountingLayout; +import com.vaadin.flow.component.html.Paragraph; +import com.vaadin.flow.router.PageTitle; +import com.vaadin.flow.router.Route; +import jakarta.annotation.security.PermitAll; +import jakarta.annotation.security.RolesAllowed; + +@Route(value = "myfinances", layout = AccountingLayout.class) +@PermitAll +@PageTitle("GartenPlus | Buchhaltung | Meine Finanzen") +public class MyFinancesPage extends GartenplusPage { + public MyFinancesPage() { + add(new Paragraph("Diese Seite wächst noch.")); + } +} From d2cf1cc98556a05f60d0b325cbb5476f4cd21d36 Mon Sep 17 00:00:00 2001 From: Stefan Haun Date: Fri, 2 Aug 2024 20:58:18 +0200 Subject: [PATCH 7/8] Add an accounting landing page --- .../ui/content/accounting/AccountingPage.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/java/com/penguineering/gartenplus/ui/content/accounting/AccountingPage.java diff --git a/src/main/java/com/penguineering/gartenplus/ui/content/accounting/AccountingPage.java b/src/main/java/com/penguineering/gartenplus/ui/content/accounting/AccountingPage.java new file mode 100644 index 0000000..873d72b --- /dev/null +++ b/src/main/java/com/penguineering/gartenplus/ui/content/accounting/AccountingPage.java @@ -0,0 +1,20 @@ +package com.penguineering.gartenplus.ui.content.accounting; + +import com.penguineering.gartenplus.ui.appframe.GartenplusPage; +import com.penguineering.gartenplus.ui.content.accounting.myfinances.MyFinancesPage; +import com.vaadin.flow.router.BeforeEnterEvent; +import com.vaadin.flow.router.BeforeEnterObserver; +import com.vaadin.flow.router.PageTitle; +import com.vaadin.flow.router.Route; +import jakarta.annotation.security.PermitAll; + +@Route(value = "", layout = AccountingLayout.class) +@PermitAll +@PageTitle("GartenPlus | Buchhaltung") +public class AccountingPage extends GartenplusPage implements BeforeEnterObserver { + @Override + public void beforeEnter(BeforeEnterEvent event) { + + event.getUI().navigate(MyFinancesPage.class); + } +} From da7a1dac4e71f3e3918c7495e05cae4785c3ca6f Mon Sep 17 00:00:00 2001 From: Stefan Haun Date: Fri, 2 Aug 2024 20:47:58 +0200 Subject: [PATCH 8/8] Link to accounting in the logged user view --- .../penguineering/gartenplus/ui/appframe/LoggedUserView.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/penguineering/gartenplus/ui/appframe/LoggedUserView.java b/src/main/java/com/penguineering/gartenplus/ui/appframe/LoggedUserView.java index 512a9d0..626d900 100644 --- a/src/main/java/com/penguineering/gartenplus/ui/appframe/LoggedUserView.java +++ b/src/main/java/com/penguineering/gartenplus/ui/appframe/LoggedUserView.java @@ -8,12 +8,10 @@ import com.vaadin.flow.component.contextmenu.MenuItem; import com.vaadin.flow.component.contextmenu.SubMenu; import com.vaadin.flow.component.html.Div; -import com.vaadin.flow.component.icon.Icon; import com.vaadin.flow.component.icon.IconFactory; import com.vaadin.flow.component.icon.VaadinIcon; import com.vaadin.flow.component.menubar.MenuBar; import com.vaadin.flow.component.menubar.MenuBarVariant; -import com.vaadin.flow.component.orderedlayout.FlexComponent; import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -71,6 +69,9 @@ public LoggedUserView(Supplier currentUser) { subMenu.addItem(createMenuItemWithIcon("Dashboard", VaadinIcon.HOME), e -> navigateTo("/")); + subMenu.addItem(createMenuItemWithIcon("Buchhaltung", VaadinIcon.PIGGY_BANK_COIN), + e -> navigateTo("/accounting")); + subMenu.addSeparator(); if (isAdmin) {