From 5b63ca06ab3d90112ba80a0f5056f14d9b129ae7 Mon Sep 17 00:00:00 2001 From: ScarletRedMan Date: Fri, 17 Nov 2023 15:59:02 +0700 Subject: [PATCH] Added register bucket component --- .../web/component/RegisterBucket.java | 118 ++++++++++++++++++ .../web/page/NodeDetailsPage.java | 13 +- 2 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/component/RegisterBucket.java diff --git a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/component/RegisterBucket.java b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/component/RegisterBucket.java new file mode 100644 index 0000000..ee82053 --- /dev/null +++ b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/component/RegisterBucket.java @@ -0,0 +1,118 @@ +package ru.dragonestia.loadbalancer.web.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.details.Details; +import com.vaadin.flow.component.html.H2; +import com.vaadin.flow.component.notification.Notification; +import com.vaadin.flow.component.notification.NotificationVariant; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.component.textfield.Autocomplete; +import com.vaadin.flow.component.textfield.TextArea; +import com.vaadin.flow.component.textfield.TextField; +import org.springframework.lang.Nullable; +import ru.dragonestia.loadbalancer.web.model.Bucket; +import ru.dragonestia.loadbalancer.web.model.Node; +import ru.dragonestia.loadbalancer.web.model.type.SlotLimit; + +import java.util.function.Function; + +public class RegisterBucket extends Details { + + private final Node node; + private final Function onSubmit; + private final TextField identifierField; + private final TextArea payloadField; + + public RegisterBucket(Node node, Function onSubmit) { + super(new H2("Register bucket")); + this.node = node; + this.onSubmit = onSubmit; + + var layout = new VerticalLayout(); + layout.add(createNodeIdentifierField()); + layout.add(identifierField = createBucketIdentifierField()); + layout.add(payloadField = createPayloadField()); + layout.add(createSubmitButton()); + + add(layout); + } + + private TextField createNodeIdentifierField() { + var field = new TextField("Node identifier"); + field.setMinWidth(20, Unit.REM); + field.setValue(node.identifier()); + field.setReadOnly(true); + return field; + } + + private TextField createBucketIdentifierField() { + var field = new TextField("Identifier"); + field.setMinWidth(20, Unit.REM); + field.setPlaceholder("example-bucket-id"); + field.setHelperText("The field can contain only lowercase letters, numbers and a dash character"); + field.setRequired(true); + field.setPattern("^[a-z\\d-]+$"); + field.setAutocomplete(Autocomplete.OFF); + field.addValueChangeListener(event -> field.setValue(event.getValue().trim())); + return field; + } + + private TextArea createPayloadField() { + var field = new TextArea("Payload"); + field.setMinWidth(20, Unit.REM); + field.setPlaceholder("{\"value\": \"Hello world!\"}"); + field.setHelperText("Any useful data here"); + return field; + } + + private Button createSubmitButton() { + var button = new Button("Register"); + button.addThemeVariants(ButtonVariant.LUMO_PRIMARY); + button.addClickListener(event -> onClick()); + return button; + } + + public void clear() { + identifierField.clear(); + payloadField.clear(); + } + + private @Nullable String validateForm(String identifier) { + if (identifier.isEmpty()) { + return "Node identifier cannot be empty"; + } + + return null; + } + + private void onClick() { + var nodeIdentifier = identifierField.getValue(); + + String error = null; + if (identifierField.isInvalid() || (error = validateForm(nodeIdentifier)) != null) { + if (identifierField.isInvalid()) { + error = "Invalid bucket identifier format"; + } + + Notification.show(error, 3000, Notification.Position.TOP_END) + .addThemeVariants(NotificationVariant.LUMO_ERROR); + return; + } + + var bucket = Bucket.create(nodeIdentifier, node, SlotLimit.unlimited(), payloadField.getValue()); + var response = onSubmit.apply(bucket); + clear(); + if (response.error()) { + Notification.show(response.reason(), 3000, Notification.Position.TOP_END) + .addThemeVariants(NotificationVariant.LUMO_ERROR); + return; + } + + Notification.show("Bucket was successfully registered", 3000, Notification.Position.TOP_END) + .addThemeVariants(NotificationVariant.LUMO_SUCCESS); + } + + public record Response(boolean error, @Nullable String reason) {} +} diff --git a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/page/NodeDetailsPage.java b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/page/NodeDetailsPage.java index 7d39632..74f0271 100644 --- a/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/page/NodeDetailsPage.java +++ b/LoadBalancerWeb/src/main/java/ru/dragonestia/loadbalancer/web/page/NodeDetailsPage.java @@ -1,12 +1,8 @@ package ru.dragonestia.loadbalancer.web.page; import com.vaadin.flow.component.Html; -import com.vaadin.flow.component.HtmlComponent; -import com.vaadin.flow.component.HtmlContainer; -import com.vaadin.flow.component.Text; import com.vaadin.flow.component.html.H2; import com.vaadin.flow.component.html.Hr; -import com.vaadin.flow.component.html.Span; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.router.BeforeEnterEvent; import com.vaadin.flow.router.BeforeEnterObserver; @@ -15,6 +11,7 @@ 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.component.RegisterBucket; import ru.dragonestia.loadbalancer.web.model.Bucket; import ru.dragonestia.loadbalancer.web.model.Node; import ru.dragonestia.loadbalancer.web.model.type.LoadBalancingMethod; @@ -28,6 +25,7 @@ import java.util.List; public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserver { private Node node; + private RegisterBucket registerBucket; private BucketList bucketList; @Override @@ -53,6 +51,12 @@ public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserv new NavPath.Point(node.identifier(), "/nodes/" + node.identifier()))); printNodeDetails(node); + add(new Hr()); + add(registerBucket = new RegisterBucket(node, (bucket) -> { + // TODO: register bucket and getting all buckets + return new RegisterBucket.Response(false, ""); + })); + add(new Hr()); add(bucketList = new BucketList(buckets)); } @@ -64,6 +68,5 @@ public class NodeDetailsPage extends VerticalLayout implements BeforeEnterObserv layout.add(new Html("Mode: " + node.method().getName() + "")); add(layout); - add(new Hr()); } }