Implemented buckets list component

This commit is contained in:
Andrey Terentev 2023-11-17 14:00:39 +07:00
parent f4c32dff24
commit 1058039e54
4 changed files with 190 additions and 3 deletions

View File

@ -0,0 +1,142 @@
package ru.dragonestia.loadbalancer.web.component;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
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.H2;
import com.vaadin.flow.component.html.Paragraph;
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.notification.Notification;
import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import ru.dragonestia.loadbalancer.web.model.Bucket;
import java.util.List;
public class BucketList extends VerticalLayout {
private final Grid<Bucket> bucketsGrid;
private final TextField searchField;
private List<Bucket> cachedBuckets;
public BucketList(List<Bucket> buckets) {
cachedBuckets = buckets;
add(new H2("Buckets"));
add(searchField = createSearchField());
add(bucketsGrid = createGrid());
update(buckets);
}
private TextField createSearchField() {
var field = new TextField("Search bucket");
field.setPrefixComponent(new Icon(VaadinIcon.SEARCH));
field.setClearButtonVisible(true);
field.setHelperText("Press Enter to search");
field.addValueChangeListener(event -> applySearch(event.getValue()));
return field;
}
private void applySearch(String input) {
var temp = input.trim();
bucketsGrid.setItems(cachedBuckets.stream()
.filter(bucket -> bucket.getIdentifier().startsWith(temp))
.toList());
}
private Grid<Bucket> createGrid() {
var grid = new Grid<>(Bucket.class, false);
grid.addColumn(Bucket::getIdentifier).setHeader("Identifier");
grid.addComponentColumn(bucket -> {
var result = new Span();
if (bucket.getSlots().isUnlimited()) {
result.setText("Unlimited");
result.getElement().getThemeList().add("badge contrast");
} else {
result.setText(Integer.toString(bucket.getSlots().getSlots()));
}
return result;
}).setHeader("Slots").setTextAlign(ColumnTextAlign.CENTER);
grid.addComponentColumn(this::createManageButtons).setHeader("Manage");
return grid;
}
private HorizontalLayout createManageButtons(Bucket bucket) {
var layout = new HorizontalLayout();
{
var button = new Button("Details");
button.addClickListener(event -> clickDetailsButton(bucket));
button.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
layout.add(button);
}
{
var button = new Button("Remove");
button.addClickListener(event -> clickRemoveButton(bucket));
button.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_ERROR);
layout.add(button);
}
return layout;
}
private void clickDetailsButton(Bucket bucket) {
getUI().ifPresent(ui -> {
ui.navigate("/nodes/" + bucket.getNodeIdentifier() +
"/" + bucket.getIdentifier());
});
}
private void clickRemoveButton(Bucket bucket) {
var dialog = new Dialog("Confirm bucket deletion");
dialog.add(new Paragraph("Confirm that you want to delete bucket. Enter '" + bucket.getIdentifier() + "' to field below and confirm."));
var inputField = new TextField();
dialog.add(inputField);
{ // confirm
var button = new Button("Confirm");
button.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_ERROR);
button.addClickListener(event -> {
if (!bucket.getIdentifier().equals(inputField.getValue())) {
Notification.show("Invalid input", 3000, Notification.Position.TOP_END)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
return;
}
removeBucket(bucket);
Notification.show("Bucket '" + bucket.getIdentifier() + "' was successfully removed!", 3000, Notification.Position.TOP_END)
.addThemeVariants(NotificationVariant.LUMO_SUCCESS);
dialog.close();
});
dialog.getFooter().add(button);
}
{ // cancel
var button = new Button("Cancel", event -> dialog.close());
button.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
dialog.getFooter().add(button);
}
dialog.open();
}
public void update(List<Bucket> buckets) {
cachedBuckets = buckets;
applySearch(searchField.getValue());
}
private void removeBucket(Bucket bucket) {
// TODO: send remove request and getting list
}
}

View File

@ -1,7 +1,6 @@
package ru.dragonestia.loadbalancer.web.component; package ru.dragonestia.loadbalancer.web.component;
import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant; import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.html.Span; import com.vaadin.flow.component.html.Span;

View File

@ -13,7 +13,6 @@ import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.component.textfield.TextFieldVariant;
import ru.dragonestia.loadbalancer.web.model.Node; import ru.dragonestia.loadbalancer.web.model.Node;
import java.util.List; import java.util.List;
@ -82,7 +81,7 @@ public class NodeList extends VerticalLayout {
} }
private void clickDetailsButton(Node node) { private void clickDetailsButton(Node node) {
// TODO getUI().ifPresent(ui -> ui.navigate("/nodes/" + node.identifier()));
} }
private void clickRemoveButton(Node node) { private void clickRemoveButton(Node node) {

View File

@ -0,0 +1,47 @@
package ru.dragonestia.loadbalancer.web.page;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
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 lombok.Getter;
import ru.dragonestia.loadbalancer.web.component.BucketList;
import ru.dragonestia.loadbalancer.web.component.NavPath;
import ru.dragonestia.loadbalancer.web.model.Bucket;
import ru.dragonestia.loadbalancer.web.model.Node;
import ru.dragonestia.loadbalancer.web.model.type.LoadBalancingMethod;
import ru.dragonestia.loadbalancer.web.model.type.SlotLimit;
import java.util.List;
@Getter
@PageTitle("Buckets")
@Route("/nodes/:nodeId")
public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserver {
private Node node;
private BucketList bucketList;
@Override
public void beforeEnter(BeforeEnterEvent event) {
var nodeIdOpt = event.getRouteParameters().get("nodeId");
if (nodeIdOpt.isEmpty()) {
getUI().ifPresent(ui -> ui.navigate("/nodes"));
return;
}
node = new Node(nodeIdOpt.get(), LoadBalancingMethod.ROUND_ROBIN); // TODO: getting node
add(new NavPath(new NavPath.Point("Nodes", "/nodes"),
new NavPath.Point(node.identifier(), "/nodes/" + node.identifier())));
// TODO: getting buckets
add(bucketList = new BucketList(List.of(
Bucket.create("test-1", node, SlotLimit.unlimited(), "Hello world!"),
Bucket.create("test-2", node, SlotLimit.of(12), "Hello world!"),
Bucket.create("test-3", node, SlotLimit.unlimited(), "Hello world!"),
Bucket.create("test-4", node, SlotLimit.of(32), "Hello world!"),
Bucket.create("test-5", node, SlotLimit.of(54), "Hello world!")
)));
}
}