SimpleUI: improve dialogs and add delete confirmation dialog (#2401)

* simple-ui: add systematic prompt before deletion

Signed-off-by: Mohamed Zenadi <mohamed.zenadi@wattsense.com>

* simple-ui: fix the dialogs layouts

Signed-off-by: Mohamed Zenadi <mohamed.zenadi@wattsense.com>

---------

Signed-off-by: Mohamed Zenadi <mohamed.zenadi@wattsense.com>
This commit is contained in:
Mohamed Zenadi
2025-05-15 08:32:47 +02:00
committed by GitHub
parent 9c53858de6
commit c306ed2d4f
5 changed files with 62 additions and 45 deletions

View File

@@ -25,6 +25,7 @@ import jakarta.annotation.security.RolesAllowed;
import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Key; import com.vaadin.flow.component.Key;
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.checkbox.Checkbox; import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.checkbox.CheckboxGroup; import com.vaadin.flow.component.checkbox.CheckboxGroup;
import com.vaadin.flow.component.dependency.Uses; import com.vaadin.flow.component.dependency.Uses;
@@ -237,15 +238,15 @@ public class DistributionSetView extends TableView<MgmtDistributionSet, Long> {
final Button cancel = Utils.tooltip(new Button("Cancel"), "Cancel (Esc)"); final Button cancel = Utils.tooltip(new Button("Cancel"), "Cancel (Esc)");
cancel.addClickListener(e -> close()); cancel.addClickListener(e -> close());
create.addClickShortcut(Key.ESCAPE); create.addClickShortcut(Key.ESCAPE);
final HorizontalLayout actions = new HorizontalLayout(create, cancel); create.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
actions.setSizeFull(); getFooter().add(cancel);
actions.setJustifyContentMode(FlexComponent.JustifyContentMode.END); getFooter().add(create);
final VerticalLayout layout = new VerticalLayout(); final VerticalLayout layout = new VerticalLayout();
layout.setSizeFull(); layout.setSizeFull();
layout.setPadding(true); layout.setPadding(true);
layout.setSpacing(false); layout.setSpacing(false);
layout.add(type, name, version, vendor, description, requiredMigrationStep, actions); layout.add(type, name, version, vendor, description, requiredMigrationStep);
add(layout); add(layout);
open(); open();
} }
@@ -304,7 +305,8 @@ public class DistributionSetView extends TableView<MgmtDistributionSet, Long> {
softwareModulesGrid.refreshGrid(false); softwareModulesGrid.refreshGrid(false);
close(); close();
}); });
add(addBtn); addBtn.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
getFooter().add(addBtn);
open(); open();
}}.result(), }}.result(),
v -> { v -> {
@@ -324,9 +326,9 @@ public class DistributionSetView extends TableView<MgmtDistributionSet, Long> {
close(); close();
}); });
finishBtn.addClickShortcut(Key.ENTER); finishBtn.addClickShortcut(Key.ENTER);
final HorizontalLayout finish = new HorizontalLayout(finishBtn); finishBtn.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
finish.setJustifyContentMode(FlexComponent.JustifyContentMode.END); getFooter().add(finishBtn);
finish.setWidthFull();
final HorizontalLayout addRemove = new HorizontalLayout(addRemoveControls); final HorizontalLayout addRemove = new HorizontalLayout(addRemoveControls);
addRemove.setJustifyContentMode(FlexComponent.JustifyContentMode.END); addRemove.setJustifyContentMode(FlexComponent.JustifyContentMode.END);
addRemove.setWidthFull(); addRemove.setWidthFull();
@@ -334,7 +336,7 @@ public class DistributionSetView extends TableView<MgmtDistributionSet, Long> {
final VerticalLayout layout = new VerticalLayout(); final VerticalLayout layout = new VerticalLayout();
layout.setSizeFull(); layout.setSizeFull();
layout.setSpacing(false); layout.setSpacing(false);
layout.add(softwareModulesGrid, addRemove, finish); layout.add(softwareModulesGrid, addRemove);
add(layout); add(layout);
} }
} }

View File

@@ -23,6 +23,7 @@ import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Key; import com.vaadin.flow.component.Key;
import com.vaadin.flow.component.Text; import com.vaadin.flow.component.Text;
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.checkbox.Checkbox; import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.datetimepicker.DateTimePicker; import com.vaadin.flow.component.datetimepicker.DateTimePicker;
import com.vaadin.flow.component.dependency.Uses; import com.vaadin.flow.component.dependency.Uses;
@@ -31,7 +32,6 @@ import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.icon.Icon; import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon; import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
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.select.Select; import com.vaadin.flow.component.select.Select;
@@ -358,13 +358,13 @@ public class RolloutView extends TableView<MgmtRolloutResponseBody, Long> {
errorThreshold.setSuffixComponent(percentSuffix); errorThreshold.setSuffixComponent(percentSuffix);
create.setEnabled(false); create.setEnabled(false);
create.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
addCreateClickListener(hawkbitClient); addCreateClickListener(hawkbitClient);
final Button cancel = Utils.tooltip(new Button("Cancel"), "Cancel (Esc)"); final Button cancel = Utils.tooltip(new Button("Cancel"), "Cancel (Esc)");
cancel.addClickListener(e -> close()); cancel.addClickListener(e -> close());
cancel.addClickShortcut(Key.ESCAPE); cancel.addClickShortcut(Key.ESCAPE);
final HorizontalLayout actions = new HorizontalLayout(create, cancel); getFooter().add(cancel);
actions.setJustifyContentMode(FlexComponent.JustifyContentMode.END); getFooter().add(create);
actions.setSizeFull();
final VerticalLayout layout = new VerticalLayout(); final VerticalLayout layout = new VerticalLayout();
layout.setSizeFull(); layout.setSizeFull();
@@ -373,8 +373,7 @@ public class RolloutView extends TableView<MgmtRolloutResponseBody, Long> {
name, distributionSet, targetFilter, description, name, distributionSet, targetFilter, description,
actionType, startType, actionType, startType,
groupNumber, triggerThreshold, errorThreshold, groupNumber, triggerThreshold, errorThreshold,
dynamic, dynamic);
actions);
add(layout); add(layout);
open(); open();
} }

View File

@@ -28,14 +28,13 @@ import jakarta.annotation.security.RolesAllowed;
import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Key; import com.vaadin.flow.component.Key;
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.checkbox.Checkbox; import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.checkbox.CheckboxGroup; import com.vaadin.flow.component.checkbox.CheckboxGroup;
import com.vaadin.flow.component.dependency.Uses; import com.vaadin.flow.component.dependency.Uses;
import com.vaadin.flow.component.formlayout.FormLayout; import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.icon.Icon; import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
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.select.Select; import com.vaadin.flow.component.select.Select;
import com.vaadin.flow.component.textfield.TextArea; import com.vaadin.flow.component.textfield.TextArea;
@@ -269,20 +268,19 @@ public class SoftwareModuleView extends TableView<MgmtSoftwareModule, Long> {
create.setEnabled(false); create.setEnabled(false);
addCreateClickListener(hawkbitClient); addCreateClickListener(hawkbitClient);
create.addClickShortcut(Key.ENTER); create.addClickShortcut(Key.ENTER);
create.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
final Button cancel = Utils.tooltip(new Button("Cancel"), "Cancel (Esc)"); final Button cancel = Utils.tooltip(new Button("Cancel"), "Cancel (Esc)");
cancel.addClickListener(e -> close()); cancel.addClickListener(e -> close());
cancel.addClickShortcut(Key.ESCAPE); cancel.addClickShortcut(Key.ESCAPE);
final HorizontalLayout actions = new HorizontalLayout(create, cancel); getFooter().add(cancel);
actions.setSizeFull(); getFooter().add(create);
actions.setJustifyContentMode(FlexComponent.JustifyContentMode.END);
final VerticalLayout layout = new VerticalLayout(); final VerticalLayout layout = new VerticalLayout();
layout.setSizeFull(); layout.setSizeFull();
layout.setSpacing(false); layout.setSpacing(false);
layout.add( layout.add(
type, name, version, vendor, description, enableArtifactEncryption, type, name, version, vendor, description, enableArtifactEncryption,
createDistributionSet, distType, distRequiredMigrationStep, createDistributionSet, distType, distRequiredMigrationStep);
actions);
add(layout); add(layout);
open(); open();
} }
@@ -373,11 +371,10 @@ public class SoftwareModuleView extends TableView<MgmtSoftwareModule, Long> {
finishBtn.addClickListener(e -> close()); finishBtn.addClickListener(e -> close());
finishBtn.addClickShortcut(Key.ENTER); finishBtn.addClickShortcut(Key.ENTER);
finishBtn.setHeightFull(); finishBtn.setHeightFull();
final HorizontalLayout finish = new HorizontalLayout(finishBtn); finishBtn.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
finish.setJustifyContentMode(FlexComponent.JustifyContentMode.END); getFooter().add(finishBtn);
finish.setWidthFull();
final VerticalLayout layout = new VerticalLayout(artifactGrid, uploadBtn, finish); final VerticalLayout layout = new VerticalLayout(artifactGrid, uploadBtn);
layout.setSizeFull(); layout.setSizeFull();
layout.setSpacing(false); layout.setSpacing(false);
add(layout); add(layout);

View File

@@ -9,6 +9,7 @@
*/ */
package org.eclipse.hawkbit.ui.simple.view; package org.eclipse.hawkbit.ui.simple.view;
import java.time.ZoneOffset;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.LinkedList; import java.util.LinkedList;
@@ -17,10 +18,10 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.time.ZoneOffset;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage; import java.util.concurrent.CompletionStage;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import jakarta.annotation.security.RolesAllowed; import jakarta.annotation.security.RolesAllowed;
@@ -61,7 +62,6 @@ import org.eclipse.hawkbit.ui.simple.view.util.SelectionGrid;
import org.eclipse.hawkbit.ui.simple.view.util.TableView; import org.eclipse.hawkbit.ui.simple.view.util.TableView;
import org.eclipse.hawkbit.ui.simple.view.util.Utils; import org.eclipse.hawkbit.ui.simple.view.util.Utils;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import java.util.stream.Collectors;
@PageTitle("Targets") @PageTitle("Targets")
@Route(value = "targets", layout = MainLayout.class) @Route(value = "targets", layout = MainLayout.class)
@@ -187,7 +187,6 @@ public class TargetView extends TableView<MgmtTarget, String> {
final Button saveBtn = Utils.tooltip(new Button(VaadinIcon.ARCHIVE.create()), "Save (Enter)"); final Button saveBtn = Utils.tooltip(new Button(VaadinIcon.ARCHIVE.create()), "Save (Enter)");
saveBtn.addClickListener(e -> saveBtn.addClickListener(e ->
new Utils.BaseDialog<Void>("Save Filter") {{ new Utils.BaseDialog<Void>("Save Filter") {{
setHeight("40%");
final Button finishBtn = Utils.tooltip(new Button("Save"), "Save (Enter)"); final Button finishBtn = Utils.tooltip(new Button("Save"), "Save (Enter)");
final TextField name = Utils.textField( final TextField name = Utils.textField(
Constants.NAME, Constants.NAME,
@@ -205,7 +204,8 @@ public class TargetView extends TableView<MgmtTarget, String> {
.getFilters(0, 30, null, null, null).getBody().getContent()); .getFilters(0, 30, null, null, null).getBody().getContent());
close(); close();
}); });
add(name, finishBtn); getFooter().add(finishBtn);
add(name);
open(); open();
}}); }});
saveBtn.addClickShortcut(Key.ENTER); saveBtn.addClickShortcut(Key.ENTER);
@@ -307,19 +307,18 @@ public class TargetView extends TableView<MgmtTarget, String> {
addCreateClickListener(register, hawkbitClient); addCreateClickListener(register, hawkbitClient);
register.setEnabled(false); register.setEnabled(false);
register.addClickShortcut(Key.ENTER); register.addClickShortcut(Key.ENTER);
register.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
final Button cancel = Utils.tooltip(new Button("Cancel"), "Cancel (Esc)"); final Button cancel = Utils.tooltip(new Button("Cancel"), "Cancel (Esc)");
cancel.addClickListener(e -> close()); cancel.addClickListener(e -> close());
register.addClickShortcut(Key.ESCAPE); register.addClickShortcut(Key.ESCAPE);
final HorizontalLayout actions = new HorizontalLayout(register, cancel); getFooter().add(cancel);
actions.setSizeFull(); getFooter().add(register);
actions.setPadding(true);
actions.setSpacing(true);
final VerticalLayout layout = new VerticalLayout(); final VerticalLayout layout = new VerticalLayout();
layout.setSizeFull(); layout.setSizeFull();
layout.setPadding(true); layout.setPadding(true);
layout.setSpacing(false); layout.setSpacing(false);
layout.add(type, controllerId, name, description, actions); layout.add(type, controllerId, name, description);
add(layout); add(layout);
open(); open();
} }
@@ -372,19 +371,18 @@ public class TargetView extends TableView<MgmtTarget, String> {
actionType = Utils.actionTypeControls(forceTime); actionType = Utils.actionTypeControls(forceTime);
assign.setEnabled(false); assign.setEnabled(false);
assign.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
addAssignClickListener(hawkbitClient, selectedTargets); addAssignClickListener(hawkbitClient, selectedTargets);
final Button cancel = Utils.tooltip(new Button("Cancel"), "Cancel (Esc)"); final Button cancel = Utils.tooltip(new Button("Cancel"), "Cancel (Esc)");
cancel.addClickListener(e -> close()); cancel.addClickListener(e -> close());
cancel.addClickShortcut(Key.ESCAPE); cancel.addClickShortcut(Key.ESCAPE);
final HorizontalLayout actions = new HorizontalLayout(assign, cancel); getFooter().add(cancel);
actions.setJustifyContentMode(FlexComponent.JustifyContentMode.END); getFooter().add(assign);
actions.setSizeFull();
final VerticalLayout layout = new VerticalLayout(); final VerticalLayout layout = new VerticalLayout();
layout.setSizeFull(); layout.setSizeFull();
layout.setSpacing(false); layout.setSpacing(false);
layout.add( layout.add(distributionSet, actionType);
distributionSet, actionType, actions);
add(layout); add(layout);
open(); open();
} }

View File

@@ -17,15 +17,17 @@ import java.util.concurrent.CompletionStage;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import org.eclipse.hawkbit.ui.simple.view.Constants;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType; import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
import org.eclipse.hawkbit.ui.simple.view.Constants;
import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.HasValue; import com.vaadin.flow.component.HasValue;
import com.vaadin.flow.component.Text; import com.vaadin.flow.component.Text;
import com.vaadin.flow.component.UI; import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.Unit;
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.confirmdialog.ConfirmDialog;
import com.vaadin.flow.component.datetimepicker.DateTimePicker; import com.vaadin.flow.component.datetimepicker.DateTimePicker;
import com.vaadin.flow.component.dialog.Dialog; import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.html.Div;
@@ -105,16 +107,35 @@ public class Utils {
layout.add(addBtn); layout.add(addBtn);
} }
if (removeHandler != null) { if (removeHandler != null) {
final ConfirmDialog dialog = promptForDeleteConfirmation(removeHandler, selectionGrid);
final Button removeBtn = tooltip(new Button(VaadinIcon.MINUS.create()), "Remove"); final Button removeBtn = tooltip(new Button(VaadinIcon.MINUS.create()), "Remove");
removeBtn.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_CONTRAST); removeBtn.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_CONTRAST);
removeBtn.addClickListener(e -> removeHandler removeBtn.addClickListener(e -> dialog.open());
.apply(selectionGrid)
.thenAccept(v -> selectionGrid.refreshGrid(false)));
layout.add(removeBtn); layout.add(removeBtn);
} }
return layout; return layout;
} }
private static <T, ID> ConfirmDialog promptForDeleteConfirmation(Function<SelectionGrid<T, ID>, CompletionStage<Void>> removeHandler, SelectionGrid<T, ID> selectionGrid) {
final ConfirmDialog dialog = new ConfirmDialog();
dialog.setHeader("Confirm Deletion");
dialog.setText("Are you sure you want to delete the selected items? This action cannot be undone.");
dialog.setCancelable(true);
dialog.addCancelListener(event -> dialog.close());
dialog.setConfirmButtonTheme(ButtonVariant.LUMO_ERROR.getVariantName());
dialog.setConfirmText("Delete");
dialog.addConfirmListener(event -> {
removeHandler
.apply(selectionGrid)
.thenAccept(v -> selectionGrid.refreshGrid(false));
dialog.close();
});
return dialog;
}
public static <T> void remove(final Collection<T> remove, final Set<T> from, final Function<T, ?> idFn) { public static <T> void remove(final Collection<T> remove, final Set<T> from, final Function<T, ?> idFn) {
remove.forEach(toRemove -> { remove.forEach(toRemove -> {
final Object id = idFn.apply(toRemove); final Object id = idFn.apply(toRemove);
@@ -185,7 +206,7 @@ public class Utils {
protected BaseDialog(final String headerTitle) { protected BaseDialog(final String headerTitle) {
setHeaderTitle(headerTitle); setHeaderTitle(headerTitle);
setHeightFull(); setMinWidth(640, Unit.PIXELS);
setModal(true); setModal(true);
setDraggable(true); setDraggable(true);