feat: add target filter query view (#2892)
* feat: add target filter query view * fix: add missing file header, also add query column and details panel in TargetFilterQueryView --------- Co-authored-by: MICKAEL MAUGER <mickael.mauger@siemens.com>
This commit is contained in:
@@ -45,6 +45,7 @@ import org.eclipse.hawkbit.ui.view.ConfigView;
|
||||
import org.eclipse.hawkbit.ui.view.DistributionSetView;
|
||||
import org.eclipse.hawkbit.ui.view.RolloutView;
|
||||
import org.eclipse.hawkbit.ui.view.SoftwareModuleView;
|
||||
import org.eclipse.hawkbit.ui.view.TargetFilterQueryView;
|
||||
import org.eclipse.hawkbit.ui.view.TargetView;
|
||||
|
||||
/**
|
||||
@@ -117,6 +118,9 @@ public final class MainLayout extends AppLayout {
|
||||
if (accessChecker.hasAccess(TargetView.class)) {
|
||||
nav.addItem(new SideNavItem("Targets", TargetView.class, VaadinIcon.FILTER.create()));
|
||||
}
|
||||
if (accessChecker.hasAccess(TargetFilterQueryView.class)) {
|
||||
nav.addItem(new SideNavItem("Target Filter Queries", TargetFilterQueryView.class, VaadinIcon.FILTER.create()));
|
||||
}
|
||||
if (accessChecker.hasAccess(RolloutView.class)) {
|
||||
nav.addItem(new SideNavItem("Rollouts", RolloutView.class, VaadinIcon.COGS.create()));
|
||||
}
|
||||
|
||||
@@ -337,7 +337,7 @@ public final class RolloutView extends TableView<MgmtRolloutResponseBody, Long>
|
||||
description.setMinLength(2);
|
||||
description.setWidthFull();
|
||||
|
||||
actionType = Utils.actionTypeControls(forceTime);
|
||||
actionType = Utils.actionTypeControls(MgmtActionType.FORCED, forceTime);
|
||||
|
||||
startType = new Select<>();
|
||||
startType.setValue(StartType.MANUAL);
|
||||
|
||||
@@ -0,0 +1,405 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Contributors to the Eclipse Foundation
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.view;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.Key;
|
||||
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.combobox.ComboBox;
|
||||
import com.vaadin.flow.component.confirmdialog.ConfirmDialog;
|
||||
import com.vaadin.flow.component.dependency.Uses;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.grid.Grid;
|
||||
import com.vaadin.flow.component.html.Div;
|
||||
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.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.component.select.Select;
|
||||
import com.vaadin.flow.component.tabs.TabSheet;
|
||||
import com.vaadin.flow.component.textfield.TextArea;
|
||||
import com.vaadin.flow.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.renderer.ComponentRenderer;
|
||||
import com.vaadin.flow.dom.Style;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.theme.lumo.LumoUtility;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import lombok.Getter;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtDistributionSetAutoAssignment;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.ui.HawkbitMgmtClient;
|
||||
import org.eclipse.hawkbit.ui.MainLayout;
|
||||
import org.eclipse.hawkbit.ui.view.util.Filter;
|
||||
import org.eclipse.hawkbit.ui.view.util.SelectionGrid;
|
||||
import org.eclipse.hawkbit.ui.view.util.TableView;
|
||||
import org.eclipse.hawkbit.ui.view.util.Utils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@PageTitle("Target Filter Queries")
|
||||
@Route(value = "target_filter_queries", layout = MainLayout.class)
|
||||
@RolesAllowed({ "TARGET_READ" })
|
||||
@Uses(Icon.class)
|
||||
public class TargetFilterQueryView extends TableView<TargetFilterQueryView.TargetFilterQueryGridItem, Long> {
|
||||
public TargetFilterQueryView(final HawkbitMgmtClient hawkbitClient) {
|
||||
super(
|
||||
new TargetFilterQueryFilter(),
|
||||
null,
|
||||
new SelectionGrid.EntityRepresentation<>(TargetFilterQueryGridItem.class, TargetFilterQueryGridItem::getId) {
|
||||
|
||||
@Override
|
||||
protected void addColumns(final Grid<TargetFilterQueryGridItem> grid) {
|
||||
grid.addColumn(MgmtTargetFilterQuery::getId).setHeader(Constants.ID).setAutoWidth(true).setKey("id").setSortable(true);
|
||||
grid.addColumn(MgmtTargetFilterQuery::getName).setHeader(Constants.NAME).setAutoWidth(true).setKey("name").setSortable(true).setResizable(true);
|
||||
grid.addColumn(new ComponentRenderer<>(QueryCell::new)).setHeader("Query").setAutoWidth(true).setKey("query").setResizable(true);
|
||||
grid.addColumn(Utils.localDateTimeRenderer(MgmtTargetFilterQuery::getLastModifiedAt)).setHeader(Constants.LAST_MODIFIED_AT).setKey("lastModifiedAt")
|
||||
.setSortable(true).setAutoWidth(true).setResizable(true);
|
||||
grid.addColumn(new ComponentRenderer<>(DistributionSetCell::new)).setHeader(Constants.DISTRIBUTION_SET).setAutoWidth(true).setResizable(true);
|
||||
|
||||
grid.addComponentColumn(rollout -> new Actions(rollout, grid, hawkbitClient)).setHeader(
|
||||
Constants.ACTIONS).setAutoWidth(true);
|
||||
}
|
||||
},
|
||||
(query, filter) -> Optional.ofNullable(
|
||||
hawkbitClient.getTargetFilterQueryRestApi()
|
||||
.getFilters(filter, query.getOffset(), query.getPageSize(), Utils.getSortParam(query.getSortOrders(), Constants.NAME_ASC), "compact")
|
||||
.getBody())
|
||||
.stream()
|
||||
.map(PagedList::getContent)
|
||||
.flatMap(List::stream)
|
||||
.map(m -> TargetFilterQueryGridItem.from(hawkbitClient, m)),
|
||||
null,
|
||||
selectionGrid -> {
|
||||
selectionGrid.getSelectedItems()
|
||||
.forEach(toDelete -> hawkbitClient.getTargetFilterQueryRestApi().deleteFilter(toDelete.getId()));
|
||||
return CompletableFuture.completedFuture(null);
|
||||
},
|
||||
filterQuery -> {
|
||||
final TargetFilterQueryDetailedView detailedView = new TargetFilterQueryDetailedView();
|
||||
detailedView.setItem(filterQuery);
|
||||
return detailedView;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private static class TargetFilterQueryFilter implements Filter.Rsql {
|
||||
|
||||
private final TextField name = Utils.textField(Constants.NAME);
|
||||
|
||||
private TargetFilterQueryFilter() {
|
||||
name.setPlaceholder("<name filter>");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Component> components() {
|
||||
return List.of(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filter() {
|
||||
return Filter.filter(
|
||||
Map.of(
|
||||
"name", name.getOptionalValue().map(s -> "*" + s + "*")
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private static class QueryCell extends Div {
|
||||
|
||||
private QueryCell(final TargetFilterQueryGridItem filterQuery) {
|
||||
String query = filterQuery.getQuery();
|
||||
if (query != null) {
|
||||
setText(query);
|
||||
setTitle(query);
|
||||
}
|
||||
getStyle().setOverflow(Style.Overflow.HIDDEN);
|
||||
getStyle().set("text-overflow", "ellipsis");
|
||||
setWhiteSpace(WhiteSpace.NOWRAP);
|
||||
setMaxWidth(400, Unit.PIXELS);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DistributionSetCell extends HorizontalLayout {
|
||||
|
||||
private DistributionSetCell(final TargetFilterQueryGridItem filterQuery) {
|
||||
filterQuery.getDs().ifPresent(ds -> {
|
||||
Icon icon = getActionTypeIcon(filterQuery.getAutoAssignActionType());
|
||||
icon.getStyle().setFlexShrink("0");
|
||||
|
||||
Span dsName = new Span(ds.getName() + ":" + ds.getVersion());
|
||||
dsName.getStyle().setOverflow(Style.Overflow.HIDDEN);
|
||||
dsName.getStyle().set("text-overflow", "ellipsis");
|
||||
dsName.getStyle().setWhiteSpace(Style.WhiteSpace.NOWRAP);
|
||||
|
||||
add(icon, dsName);
|
||||
});
|
||||
setAlignItems(Alignment.CENTER);
|
||||
setSpacing(true);
|
||||
getStyle().setFlexWrap(Style.FlexWrap.NOWRAP);
|
||||
}
|
||||
|
||||
private Icon getActionTypeIcon(MgmtActionType actionType) {
|
||||
Icon icon = switch (actionType) {
|
||||
case FORCED -> VaadinIcon.BOLT.create();
|
||||
case SOFT -> VaadinIcon.USER_CHECK.create();
|
||||
case DOWNLOAD_ONLY -> VaadinIcon.DOWNLOAD.create();
|
||||
default -> VaadinIcon.QUESTION_CIRCLE.create();
|
||||
};
|
||||
icon.addClassNames(LumoUtility.IconSize.SMALL);
|
||||
return Utils.tooltip(icon, actionType.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static class Actions extends HorizontalLayout {
|
||||
|
||||
private final Grid<TargetFilterQueryGridItem> grid;
|
||||
private final transient HawkbitMgmtClient hawkbitClient;
|
||||
|
||||
private Actions(final MgmtTargetFilterQuery filter, final Grid<TargetFilterQueryGridItem> grid,
|
||||
final HawkbitMgmtClient hawkbitClient) {
|
||||
this.grid = grid;
|
||||
this.hawkbitClient = hawkbitClient;
|
||||
init(filter);
|
||||
}
|
||||
|
||||
private void init(final MgmtTargetFilterQuery filter) {
|
||||
if (filter.getAutoAssignDistributionSet() == null) {
|
||||
Button autoAssignButton = new Button(VaadinIcon.LINK.create());
|
||||
autoAssignButton.addClickListener(e ->
|
||||
new AutoAssignDialog(filter.getId(), hawkbitClient, () -> refresh(filter.getId())).open()
|
||||
);
|
||||
add(Utils.tooltip(autoAssignButton, "Auto assign"));
|
||||
} else {
|
||||
Button unassignButton = new Button(VaadinIcon.UNLINK.create());
|
||||
unassignButton.addClickListener(e -> {
|
||||
ConfirmDialog dialog = Utils.confirmDialog("Unassign Distribution Set",
|
||||
"Are you sure you want to unassign the distribution set of target filter query '" + filter.getName() + "'?",
|
||||
"Unassign",
|
||||
() -> {
|
||||
hawkbitClient.getTargetFilterQueryRestApi().deleteAssignedDistributionSet(filter.getId());
|
||||
refresh(filter.getId());
|
||||
});
|
||||
dialog.open();
|
||||
});
|
||||
add(Utils.tooltip(unassignButton, "Unassign"));
|
||||
}
|
||||
Button deleteButton = new Button(VaadinIcon.TRASH.create());
|
||||
deleteButton.addClickListener(e -> {
|
||||
ConfirmDialog dialog = Utils.confirmDialog("Delete Target Filter Query",
|
||||
"Are you sure you want to delete the target filter query '" + filter.getName() + "'?",
|
||||
"Delete",
|
||||
() -> {
|
||||
hawkbitClient.getTargetFilterQueryRestApi().deleteFilter(filter.getId());
|
||||
grid.getDataProvider().refreshAll();
|
||||
});
|
||||
dialog.open();
|
||||
});
|
||||
add(Utils.tooltip(deleteButton, "Delete"));
|
||||
}
|
||||
|
||||
private void refresh(Long filterId) {
|
||||
removeAll();
|
||||
final MgmtTargetFilterQuery body = hawkbitClient.getTargetFilterQueryRestApi().getFilter(filterId).getBody();
|
||||
if (body != null) {
|
||||
grid.getDataProvider().refreshItem(TargetFilterQueryGridItem.from(hawkbitClient, body));
|
||||
init(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class AutoAssignDialog extends Utils.BaseDialog<Void> {
|
||||
|
||||
private final Long filterId;
|
||||
private final Select<MgmtActionType> actionType;
|
||||
private final ComboBox<MgmtDistributionSet> distributionSet;
|
||||
private final Button assign = new Button("Assign");
|
||||
|
||||
private AutoAssignDialog(final Long filterId, final HawkbitMgmtClient hawkbitClient, Runnable onSuccess) {
|
||||
super("Select auto assignment distribution set");
|
||||
|
||||
this.filterId = filterId;
|
||||
|
||||
Paragraph description = new Paragraph("When an auto assign distribution set is selected, " +
|
||||
"it will be automatically assigned to all targets that match the target filter.");
|
||||
|
||||
actionType = Utils.actionTypeControls(new MgmtActionType[]{MgmtActionType.SOFT, MgmtActionType.FORCED, MgmtActionType.DOWNLOAD_ONLY}, MgmtActionType.FORCED, null);
|
||||
|
||||
distributionSet = Utils.nameComboBox("Distribution Set", this::readyToAssign, query -> Optional.ofNullable(
|
||||
hawkbitClient.getDistributionSetRestApi()
|
||||
.getDistributionSets(
|
||||
query.getFilter().orElse(null),
|
||||
query.getOffset(),
|
||||
query.getLimit(),
|
||||
Constants.NAME_ASC)
|
||||
.getBody()).stream().flatMap(body -> body.getContent().stream()));
|
||||
distributionSet.setItemLabelGenerator(ds -> ds.getName() + ":" + ds.getVersion());
|
||||
distributionSet.focus();
|
||||
distributionSet.setRequiredIndicatorVisible(true);
|
||||
distributionSet.setWidthFull();
|
||||
|
||||
assign.setEnabled(false);
|
||||
assign.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||
addAssignClickListener(hawkbitClient, onSuccess);
|
||||
final Button cancel = Utils.tooltip(new Button(CANCEL), CANCEL_ESC);
|
||||
cancel.addClickListener(e -> close());
|
||||
cancel.addClickShortcut(Key.ESCAPE);
|
||||
getFooter().add(cancel);
|
||||
getFooter().add(assign);
|
||||
|
||||
final VerticalLayout layout = new VerticalLayout();
|
||||
layout.setSizeFull();
|
||||
layout.setSpacing(false);
|
||||
layout.add(description, actionType, distributionSet);
|
||||
add(layout);
|
||||
open();
|
||||
}
|
||||
|
||||
private void readyToAssign(final Object v) {
|
||||
final boolean createEnabled = !distributionSet.isEmpty();
|
||||
if (assign.isEnabled() != createEnabled) {
|
||||
assign.setEnabled(createEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
private void addAssignClickListener(final HawkbitMgmtClient hawkbitClient, Runnable onSuccess) {
|
||||
assign.addClickListener(e -> {
|
||||
MgmtDistributionSetAutoAssignment newAssignment = new MgmtDistributionSetAutoAssignment();
|
||||
newAssignment.setId(distributionSet.getValue().getId());
|
||||
newAssignment.setType(actionType.getValue());
|
||||
hawkbitClient.getTargetFilterQueryRestApi().postAssignedDistributionSet(filterId, newAssignment);
|
||||
onSuccess.run();
|
||||
close();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static class TargetFilterQueryDetailedView extends VerticalLayout {
|
||||
|
||||
private final Span filterName;
|
||||
private final TargetFilterQueryDetails details;
|
||||
|
||||
private TargetFilterQueryDetailedView() {
|
||||
filterName = new Span();
|
||||
details = new TargetFilterQueryDetails();
|
||||
setWidthFull();
|
||||
|
||||
add(filterName);
|
||||
final TabSheet tabSheet = new TabSheet();
|
||||
tabSheet.setWidthFull();
|
||||
tabSheet.add("Details", details);
|
||||
add(tabSheet);
|
||||
}
|
||||
|
||||
private void setItem(final TargetFilterQueryGridItem filterQuery) {
|
||||
this.filterName.setText(filterQuery.getName());
|
||||
this.details.setItem(filterQuery);
|
||||
}
|
||||
}
|
||||
|
||||
private static class TargetFilterQueryDetails extends FormLayout {
|
||||
|
||||
private final TextField name = Utils.textField(Constants.NAME);
|
||||
private final TextArea query = new TextArea("Query");
|
||||
private final TextField createdBy = Utils.textField(Constants.CREATED_BY);
|
||||
private final TextField createdAt = Utils.textField(Constants.CREATED_AT);
|
||||
private final TextField lastModifiedBy = Utils.textField(Constants.LAST_MODIFIED_BY);
|
||||
private final TextField lastModifiedAt = Utils.textField(Constants.LAST_MODIFIED_AT);
|
||||
private final TextField autoAssignDistributionSet = Utils.textField("Auto Assign Distribution Set");
|
||||
private final TextField autoAssignActionType = Utils.textField("Auto Assign Action Type");
|
||||
private final TextField autoAssignWeight = Utils.textField("Auto Assign Weight");
|
||||
private final TextField confirmationRequired = Utils.textField("Confirmation Required");
|
||||
|
||||
private TargetFilterQueryDetails() {
|
||||
query.setMinLength(2);
|
||||
Stream.of(
|
||||
name, query,
|
||||
createdBy, createdAt,
|
||||
lastModifiedBy, lastModifiedAt,
|
||||
autoAssignDistributionSet, autoAssignActionType,
|
||||
autoAssignWeight, confirmationRequired
|
||||
)
|
||||
.forEach(field -> {
|
||||
field.setReadOnly(true);
|
||||
add(field);
|
||||
});
|
||||
|
||||
setResponsiveSteps(new FormLayout.ResponsiveStep("0", 2));
|
||||
setColspan(query, 2);
|
||||
}
|
||||
|
||||
private void setItem(final TargetFilterQueryGridItem filterQuery) {
|
||||
name.setValue(filterQuery.getName() != null ? filterQuery.getName() : "");
|
||||
query.setValue(filterQuery.getQuery() != null ? filterQuery.getQuery() : "");
|
||||
createdBy.setValue(filterQuery.getCreatedBy() != null ? filterQuery.getCreatedBy() : "");
|
||||
createdAt.setValue(Utils.localDateTimeFromTs(filterQuery.getCreatedAt()));
|
||||
lastModifiedBy.setValue(filterQuery.getLastModifiedBy() != null ? filterQuery.getLastModifiedBy() : "");
|
||||
lastModifiedAt.setValue(Utils.localDateTimeFromTs(filterQuery.getLastModifiedAt()));
|
||||
|
||||
filterQuery.getDs().ifPresentOrElse(
|
||||
ds -> autoAssignDistributionSet.setValue(ds.getName() + ":" + ds.getVersion()),
|
||||
() -> autoAssignDistributionSet.setValue("")
|
||||
);
|
||||
autoAssignActionType.setValue(filterQuery.getAutoAssignActionType() != null ?
|
||||
filterQuery.getAutoAssignActionType().getName() : "");
|
||||
autoAssignWeight.setValue(filterQuery.getAutoAssignWeight() != null ?
|
||||
filterQuery.getAutoAssignWeight().toString() : "");
|
||||
confirmationRequired.setValue(filterQuery.getConfirmationRequired() != null ?
|
||||
filterQuery.getConfirmationRequired().toString() : "");
|
||||
}
|
||||
}
|
||||
|
||||
// todo change /targetfilters api to reduce api calls ?
|
||||
@Getter
|
||||
public static class TargetFilterQueryGridItem extends MgmtTargetFilterQuery {
|
||||
|
||||
TargetFilterQueryGridItem() {
|
||||
super();
|
||||
}
|
||||
|
||||
private Optional<MgmtDistributionSet> ds;
|
||||
static ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
public static TargetFilterQueryGridItem from(final HawkbitMgmtClient hawkbitClient, MgmtTargetFilterQuery filter) {
|
||||
TargetFilterQueryGridItem filterGridItem = objectMapper.convertValue(filter, TargetFilterQueryGridItem.class);
|
||||
|
||||
if (filterGridItem.getAutoAssignDistributionSet() != null) {
|
||||
filterGridItem.ds = Optional.ofNullable(
|
||||
hawkbitClient.getTargetFilterQueryRestApi().getAssignedDistributionSet(filterGridItem.getId()).getBody()
|
||||
);
|
||||
} else {
|
||||
filterGridItem.ds = Optional.empty();
|
||||
}
|
||||
return filterGridItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof TargetFilterQueryGridItem other)) return false;
|
||||
return Objects.equals(getId(), other.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -638,11 +638,10 @@ public final class TargetView extends TableView<TargetView.TargetWithDs, String>
|
||||
metadataArea.setEmptyStateText("No metadata found");
|
||||
metadataArea.addColumn(MgmtMetadata::getKey).setHeader(KEY).setAutoWidth(true);
|
||||
metadataArea.addColumn(MgmtMetadata::getValue).setHeader(VALUE).setAutoWidth(true);
|
||||
metadataArea.addComponentColumn(metadata -> {
|
||||
final Button deleteBtn = Utils.tooltip(new Button(VaadinIcon.TRASH.create()), "Delete Metadata");
|
||||
deleteBtn.addClickListener(e -> confirmDeleteDialog(metadata.getKey()));
|
||||
return deleteBtn;
|
||||
}).setHeader("Actions").setAutoWidth(true).setFlexGrow(0);
|
||||
metadataArea.addComponentColumn(metadata -> Utils.deleteButton("Delete metadata", () -> {
|
||||
hawkbitClient.getTargetRestApi().deleteMetadata(target.getControllerId(), metadata.getKey());
|
||||
refreshMetadatas();
|
||||
})).setHeader("Actions").setAutoWidth(true).setFlexGrow(0);
|
||||
metadataArea.setWidthFull();
|
||||
add(metadataArea);
|
||||
|
||||
@@ -671,24 +670,6 @@ public final class TargetView extends TableView<TargetView.TargetWithDs, String>
|
||||
.map(PagedList::getContent)
|
||||
.orElse(Collections.emptyList()));
|
||||
}
|
||||
|
||||
private void confirmDeleteDialog(String key) {
|
||||
final ConfirmDialog dialog = new ConfirmDialog();
|
||||
dialog.setHeader("Confirm Deletion");
|
||||
dialog.setText("Are you sure you want to delete metadata " + key + "?");
|
||||
|
||||
dialog.setCancelable(true);
|
||||
dialog.addCancelListener(event -> dialog.close());
|
||||
|
||||
dialog.setConfirmButtonTheme(ButtonVariant.LUMO_ERROR.getVariantName());
|
||||
dialog.setConfirmText("Delete");
|
||||
dialog.addConfirmListener(event -> {
|
||||
hawkbitClient.getTargetRestApi().deleteMetadata(target.getControllerId(), key);
|
||||
refreshMetadatas();
|
||||
dialog.close();
|
||||
});
|
||||
dialog.open();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class TargetActionsHistoryLayout extends VerticalLayout {
|
||||
@@ -899,7 +880,7 @@ public final class TargetView extends TableView<TargetView.TargetWithDs, String>
|
||||
distributionSet.setItemLabelGenerator(distributionSetO -> distributionSetO.getName() + ":" + distributionSetO.getVersion());
|
||||
distributionSet.setWidthFull();
|
||||
|
||||
actionType = Utils.actionTypeControls(forceTime);
|
||||
actionType = Utils.actionTypeControls(MgmtActionType.FORCED, forceTime);
|
||||
|
||||
assign.setEnabled(false);
|
||||
assign.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||
|
||||
@@ -112,6 +112,15 @@ public class Utils {
|
||||
return combo;
|
||||
}
|
||||
|
||||
public static Button deleteButton(String tooltipText, Runnable deleteAction) {
|
||||
final Button button = Utils.tooltip(new Button(VaadinIcon.TRASH.create()), tooltipText);
|
||||
button.addClickListener(e -> {
|
||||
ConfirmDialog dialog = Utils.deleteConfirmDialog(deleteAction);
|
||||
dialog.open();
|
||||
});
|
||||
return button;
|
||||
}
|
||||
|
||||
@SuppressWarnings("java:S119") // better readability
|
||||
public static <T, ID> HorizontalLayout addRemoveControls(
|
||||
final Function<SelectionGrid<T, ID>, CompletionStage<Void>> addHandler,
|
||||
@@ -137,7 +146,10 @@ public class Utils {
|
||||
layout.add(addBtn);
|
||||
}
|
||||
if (removeHandler != null) {
|
||||
final ConfirmDialog dialog = promptForDeleteConfirmation(removeHandler, selectionGrid);
|
||||
final ConfirmDialog dialog = deleteConfirmDialog(
|
||||
() -> removeHandler
|
||||
.apply(selectionGrid)
|
||||
.thenAccept(v -> selectionGrid.refreshGrid(false)));
|
||||
final Button removeBtn = tooltip(new Button(VaadinIcon.MINUS.create()), "Remove");
|
||||
removeBtn.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_CONTRAST);
|
||||
removeBtn.addClickListener(e -> dialog.open());
|
||||
@@ -147,19 +159,29 @@ public class Utils {
|
||||
return layout;
|
||||
}
|
||||
|
||||
private static <T, ID> ConfirmDialog promptForDeleteConfirmation(
|
||||
final Function<SelectionGrid<T, ID>, CompletionStage<Void>> removeHandler, final SelectionGrid<T, ID> selectionGrid) {
|
||||
private static ConfirmDialog deleteConfirmDialog(final Runnable removeHandler) {
|
||||
return confirmDialog("Confirm Deletion",
|
||||
"Are you sure you want to delete the selected items? This action cannot be undone.",
|
||||
"Delete",
|
||||
removeHandler);
|
||||
}
|
||||
|
||||
public static ConfirmDialog confirmDialog(
|
||||
final String header,
|
||||
final String text,
|
||||
final String confirmText,
|
||||
final Runnable onConfirm) {
|
||||
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.setHeader(header);
|
||||
dialog.setText(text);
|
||||
|
||||
dialog.setCancelable(true);
|
||||
dialog.addCancelListener(event -> dialog.close());
|
||||
|
||||
dialog.setConfirmButtonTheme(ButtonVariant.LUMO_ERROR.getVariantName());
|
||||
dialog.setConfirmText("Delete");
|
||||
dialog.setConfirmText(confirmText);
|
||||
dialog.addConfirmListener(event -> {
|
||||
removeHandler.apply(selectionGrid).thenAccept(v -> selectionGrid.refreshGrid(false));
|
||||
onConfirm.run();
|
||||
dialog.close();
|
||||
});
|
||||
return dialog;
|
||||
@@ -210,12 +232,15 @@ public class Utils {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public static Select<MgmtActionType> actionTypeControls(DateTimePicker forceTime) {
|
||||
public static Select<MgmtActionType> actionTypeControls(MgmtActionType defaultValue, DateTimePicker forceTime) {
|
||||
return actionTypeControls(MgmtActionType.values(), defaultValue, forceTime);
|
||||
}
|
||||
|
||||
public static Select<MgmtActionType> actionTypeControls(MgmtActionType[] displayedValues, MgmtActionType defaultValue, DateTimePicker forceTime) {
|
||||
Select<MgmtActionType> actionType = new Select<>();
|
||||
actionType.setLabel(Constants.ACTION_TYPE);
|
||||
actionType.setItems(MgmtActionType.values());
|
||||
actionType.setValue(MgmtActionType.FORCED);
|
||||
actionType.setItems(displayedValues);
|
||||
actionType.setValue(defaultValue);
|
||||
final ComponentRenderer<Component, MgmtActionType> actionTypeRenderer = new ComponentRenderer<>(actionTypeO -> switch (actionTypeO) {
|
||||
case SOFT -> new Text(Constants.SOFT);
|
||||
case FORCED -> new Text(Constants.FORCED);
|
||||
|
||||
Reference in New Issue
Block a user