Added Accounts page
This commit is contained in:
parent
11ef2b51c9
commit
bbd55ed8b3
@ -0,0 +1,190 @@
|
|||||||
|
package ru.dragonestia.picker.cp.component;
|
||||||
|
|
||||||
|
import com.vaadin.flow.component.Unit;
|
||||||
|
import com.vaadin.flow.component.button.Button;
|
||||||
|
import com.vaadin.flow.component.button.ButtonVariant;
|
||||||
|
import com.vaadin.flow.component.checkbox.Checkbox;
|
||||||
|
import com.vaadin.flow.component.dialog.Dialog;
|
||||||
|
import com.vaadin.flow.component.grid.ColumnTextAlign;
|
||||||
|
import com.vaadin.flow.component.grid.Grid;
|
||||||
|
import com.vaadin.flow.component.html.H3;
|
||||||
|
import com.vaadin.flow.component.icon.Icon;
|
||||||
|
import com.vaadin.flow.component.icon.VaadinIcon;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||||
|
import com.vaadin.flow.component.textfield.PasswordField;
|
||||||
|
import com.vaadin.flow.component.textfield.TextField;
|
||||||
|
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||||
|
import com.vaadin.flow.theme.lumo.LumoIcon;
|
||||||
|
import ru.dragonestia.picker.api.model.account.ResponseAccount;
|
||||||
|
import ru.dragonestia.picker.api.repository.AccountRepository;
|
||||||
|
import ru.dragonestia.picker.cp.model.Permission;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class AccountList extends VerticalLayout implements RefreshableTable {
|
||||||
|
|
||||||
|
private final AccountRepository accountRepository;
|
||||||
|
private final TextField searchField;
|
||||||
|
private final Grid<ResponseAccount> grid;
|
||||||
|
|
||||||
|
private List<ResponseAccount> cachedAccounts = new ArrayList<>();
|
||||||
|
|
||||||
|
public AccountList(AccountRepository accountRepository) {
|
||||||
|
this.accountRepository = accountRepository;
|
||||||
|
|
||||||
|
add(searchField = createSearchField());
|
||||||
|
add(grid = createGridAccounts());
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private TextField createSearchField() {
|
||||||
|
var field = new TextField("Search by account username");
|
||||||
|
field.setPrefixComponent(new Icon(VaadinIcon.SEARCH));
|
||||||
|
field.setClearButtonVisible(true);
|
||||||
|
field.setHelperText("Press Enter to search");
|
||||||
|
field.addValueChangeListener(event -> applySearch(event.getValue()));
|
||||||
|
field.setValueChangeMode(ValueChangeMode.EAGER);
|
||||||
|
field.setMinWidth(30, Unit.PERCENTAGE);
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Grid<ResponseAccount> createGridAccounts() {
|
||||||
|
var grid = new Grid<>(ResponseAccount.class, false);
|
||||||
|
|
||||||
|
grid.addColumn(ResponseAccount::getUsername).setHeader("Username")
|
||||||
|
.setComparator(Comparator.comparing(ResponseAccount::getUsername)).setSortable(true);
|
||||||
|
|
||||||
|
grid.addComponentColumn(this::createAccountManagementButtons).setFrozenToEnd(true)
|
||||||
|
.setTextAlign(ColumnTextAlign.END).setHeader(createToolItems());
|
||||||
|
|
||||||
|
grid.setMultiSort(true, Grid.MultiSortPriority.APPEND);
|
||||||
|
|
||||||
|
return grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HorizontalLayout createAccountManagementButtons(ResponseAccount account) {
|
||||||
|
var layout = new HorizontalLayout(JustifyContentMode.END);
|
||||||
|
|
||||||
|
{
|
||||||
|
var button = new Button("Manage", VaadinIcon.COG_O.create());
|
||||||
|
button.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||||
|
button.addClickListener(event -> {
|
||||||
|
|
||||||
|
});
|
||||||
|
layout.add(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HorizontalLayout createToolItems() {
|
||||||
|
var layout = new HorizontalLayout(JustifyContentMode.END);
|
||||||
|
|
||||||
|
layout.add(createRegisterAccountButton());
|
||||||
|
layout.add(createRefreshButton());
|
||||||
|
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Button createRegisterAccountButton() {
|
||||||
|
var button = new Button("Register account", VaadinIcon.PLUS.create());
|
||||||
|
button.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_SUCCESS);
|
||||||
|
button.addClickListener(event -> openAccountRegistrationDialog());
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh() {
|
||||||
|
var list = new ArrayList<ResponseAccount>();
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
var acc = new ResponseAccount("test" + i, "", Set.of(), false);
|
||||||
|
list.add(acc);
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedAccounts = list; // TODO: accountRepository.getAllAccounts();
|
||||||
|
applySearch(searchField.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applySearch(String input) {
|
||||||
|
var temp = input.trim();
|
||||||
|
|
||||||
|
grid.setItems(cachedAccounts.stream()
|
||||||
|
.filter(account -> account.getUsername().startsWith(temp))
|
||||||
|
.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openAccountRegistrationDialog() {
|
||||||
|
var dialog = new Dialog();
|
||||||
|
dialog.setHeaderTitle("Register new account");
|
||||||
|
|
||||||
|
var closeButton = new Button(LumoIcon.CROSS.create(), e -> dialog.close());
|
||||||
|
closeButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
|
||||||
|
dialog.getHeader().add(closeButton);
|
||||||
|
|
||||||
|
var layout = new VerticalLayout();
|
||||||
|
|
||||||
|
var fieldUsername = new TextField("Account username");
|
||||||
|
fieldUsername.setWidth(70, Unit.PERCENTAGE);
|
||||||
|
layout.add(fieldUsername);
|
||||||
|
|
||||||
|
var fieldPassword = new PasswordField("Password");
|
||||||
|
fieldPassword.setWidth(70, Unit.PERCENTAGE);
|
||||||
|
layout.add(fieldPassword);
|
||||||
|
|
||||||
|
var fieldConfirmPassword = new PasswordField("Confirm password");
|
||||||
|
fieldConfirmPassword.setWidth(70, Unit.PERCENTAGE);
|
||||||
|
layout.add(fieldConfirmPassword);
|
||||||
|
|
||||||
|
layout.add(new H3("Permissions"));
|
||||||
|
|
||||||
|
var permissionsList = new ArrayList<PermissionCheckBox>();
|
||||||
|
for (var permission: Permission.Enum.values()) {
|
||||||
|
var comp = new PermissionCheckBox(permission);
|
||||||
|
permissionsList.add(comp);
|
||||||
|
layout.add(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var button = new Button("Register");
|
||||||
|
button.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||||
|
button.setWidth(100, Unit.PERCENTAGE);
|
||||||
|
button.addClickListener(event -> {
|
||||||
|
validateAndRegister(dialog, fieldUsername, fieldPassword, fieldConfirmPassword, permissionsList);
|
||||||
|
});
|
||||||
|
dialog.getFooter().add(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.add(layout);
|
||||||
|
dialog.setMinWidth(50, Unit.PERCENTAGE);
|
||||||
|
dialog.setCloseOnEsc(true);
|
||||||
|
dialog.setCloseOnOutsideClick(true);
|
||||||
|
|
||||||
|
dialog.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateAndRegister(Dialog dialog, TextField username, PasswordField passwordField, PasswordField confirm, List<PermissionCheckBox> permissionCheckBoxes) {
|
||||||
|
// TODO: validate and send request
|
||||||
|
|
||||||
|
dialog.close();
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PermissionCheckBox extends Checkbox {
|
||||||
|
|
||||||
|
private final Permission.Enum option;
|
||||||
|
|
||||||
|
public PermissionCheckBox(Permission.Enum option) {
|
||||||
|
super(option.getDescription());
|
||||||
|
this.option = option;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Permission.Enum getOption() {
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package ru.dragonestia.picker.cp.model;
|
package ru.dragonestia.picker.cp.model;
|
||||||
|
|
||||||
import com.github.javaparser.quality.NotNull;
|
import com.github.javaparser.quality.NotNull;
|
||||||
|
import lombok.Getter;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
|
||||||
public class Permission implements GrantedAuthority {
|
public class Permission implements GrantedAuthority {
|
||||||
@ -15,4 +16,19 @@ public class Permission implements GrantedAuthority {
|
|||||||
public String getAuthority() {
|
public String getAuthority() {
|
||||||
return authority;
|
return authority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public enum Enum {
|
||||||
|
// All from ru.dragonestia.picker.model.Permission (server)
|
||||||
|
// Except for USER and ADMIN
|
||||||
|
|
||||||
|
NODE_MANAGEMENT("Create and remove nodes"),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final String description;
|
||||||
|
|
||||||
|
Enum(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
package ru.dragonestia.picker.cp.page;
|
||||||
|
|
||||||
|
import com.vaadin.flow.component.html.H2;
|
||||||
|
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||||
|
import com.vaadin.flow.router.PageTitle;
|
||||||
|
import com.vaadin.flow.router.Route;
|
||||||
|
import jakarta.annotation.security.RolesAllowed;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import ru.dragonestia.picker.api.repository.AccountRepository;
|
||||||
|
import ru.dragonestia.picker.cp.component.AccountList;
|
||||||
|
import ru.dragonestia.picker.cp.service.SecurityService;
|
||||||
|
|
||||||
|
@RolesAllowed("ADMIN")
|
||||||
|
@PageTitle("Accounts")
|
||||||
|
@Route(value = "/admin/accounts", layout = MainLayout.class)
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AccountsPage extends VerticalLayout {
|
||||||
|
|
||||||
|
private final AccountRepository accountRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public AccountsPage(SecurityService securityService) {
|
||||||
|
accountRepository = securityService.getAuthenticatedAccount().getClient().getAccountRepository();
|
||||||
|
|
||||||
|
add(new H2("Account management"));
|
||||||
|
add(new AccountList(accountRepository));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -74,6 +74,9 @@ public class MainLayout extends AppLayout {
|
|||||||
var nav = new SideNav();
|
var nav = new SideNav();
|
||||||
nav.addItem(new SideNavItem("Nodes list", NodesPage.class, VaadinIcon.FOLDER_O.create()));
|
nav.addItem(new SideNavItem("Nodes list", NodesPage.class, VaadinIcon.FOLDER_O.create()));
|
||||||
nav.addItem(new SideNavItem("Search users", UserSearchPage.class, VaadinIcon.SEARCH.create()));
|
nav.addItem(new SideNavItem("Search users", UserSearchPage.class, VaadinIcon.SEARCH.create()));
|
||||||
|
if (isAdmin) {
|
||||||
|
nav.addItem(new SideNavItem("Accounts", AccountsPage.class, VaadinIcon.USERS.create()));
|
||||||
|
}
|
||||||
nav.addItem(new SideNavItem("Documentation", "https://github.com/ScarletRedMan/RoomPicker", VaadinIcon.BOOK.create()));
|
nav.addItem(new SideNavItem("Documentation", "https://github.com/ScarletRedMan/RoomPicker", VaadinIcon.BOOK.create()));
|
||||||
nav.addItem(new SideNavItem("Swagger UI", serverUrl + "/api-docs-ui", VaadinIcon.CURLY_BRACKETS.create()));
|
nav.addItem(new SideNavItem("Swagger UI", serverUrl + "/api-docs-ui", VaadinIcon.CURLY_BRACKETS.create()));
|
||||||
return nav;
|
return nav;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user