simple-ui: add support for side panel vs grid details (#2428)
This fixes a major issue with the jumpy UI when using the details view for each cell.
This commit is contained in:
@@ -106,9 +106,6 @@ public class TargetView extends TableView<MgmtTarget, String> {
|
|||||||
grid.addColumn(MgmtTarget::getControllerId).setHeader(CONTROLLER_ID).setAutoWidth(true);
|
grid.addColumn(MgmtTarget::getControllerId).setHeader(CONTROLLER_ID).setAutoWidth(true);
|
||||||
grid.addColumn(MgmtTarget::getName).setHeader(Constants.NAME).setAutoWidth(true);
|
grid.addColumn(MgmtTarget::getName).setHeader(Constants.NAME).setAutoWidth(true);
|
||||||
grid.addColumn(MgmtTarget::getTargetTypeName).setHeader(Constants.TYPE).setAutoWidth(true);
|
grid.addColumn(MgmtTarget::getTargetTypeName).setHeader(Constants.TYPE).setAutoWidth(true);
|
||||||
|
|
||||||
grid.setItemDetailsRenderer(new ComponentRenderer<>(
|
|
||||||
() -> new TargetDetailedView(hawkbitClient), TargetDetailedView::setItem));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(query, filter) -> hawkbitClient.getTargetRestApi()
|
(query, filter) -> hawkbitClient.getTargetRestApi()
|
||||||
@@ -124,6 +121,11 @@ public class TargetView extends TableView<MgmtTarget, String> {
|
|||||||
selectionGrid.getSelectedItems().forEach(toDelete ->
|
selectionGrid.getSelectedItems().forEach(toDelete ->
|
||||||
hawkbitClient.getTargetRestApi().deleteTarget(toDelete.getControllerId()));
|
hawkbitClient.getTargetRestApi().deleteTarget(toDelete.getControllerId()));
|
||||||
return CompletableFuture.completedFuture(null);
|
return CompletableFuture.completedFuture(null);
|
||||||
|
},
|
||||||
|
(target) -> {
|
||||||
|
var targetDetailedView = new TargetDetailedView(hawkbitClient);
|
||||||
|
targetDetailedView.setItem(target);
|
||||||
|
return targetDetailedView;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -317,7 +319,7 @@ public class TargetView extends TableView<MgmtTarget, String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TargetDetailedView extends TabSheet {
|
protected static class TargetDetailedView extends TabSheet {
|
||||||
|
|
||||||
private final TargetDetails targetDetails;
|
private final TargetDetails targetDetails;
|
||||||
private final TargetAssignedInstalled targetAssignedInstalled;
|
private final TargetAssignedInstalled targetAssignedInstalled;
|
||||||
@@ -483,7 +485,6 @@ public class TargetView extends TableView<MgmtTarget, String> {
|
|||||||
tagSelector.setWidthFull();
|
tagSelector.setWidthFull();
|
||||||
tagSelector.setItemLabelGenerator(MgmtTag::getName);
|
tagSelector.setItemLabelGenerator(MgmtTag::getName);
|
||||||
tagSelector.setClearButtonVisible(true);
|
tagSelector.setClearButtonVisible(true);
|
||||||
tagSelector.setItems(fetchAvailableTags());
|
|
||||||
|
|
||||||
final HorizontalLayout tagSelectorLayout = new HorizontalLayout(tagSelector, createTagButton);
|
final HorizontalLayout tagSelectorLayout = new HorizontalLayout(tagSelector, createTagButton);
|
||||||
tagSelectorLayout.setWidthFull();
|
tagSelectorLayout.setWidthFull();
|
||||||
@@ -499,6 +500,7 @@ public class TargetView extends TableView<MgmtTarget, String> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onAttach(AttachEvent attachEvent) {
|
protected void onAttach(AttachEvent attachEvent) {
|
||||||
|
tagSelector.setItems(fetchAvailableTags());
|
||||||
if (changeListener != null) {
|
if (changeListener != null) {
|
||||||
changeListener.remove();
|
changeListener.remove();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,11 +14,20 @@ import java.util.function.BiFunction;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import com.vaadin.flow.component.Component;
|
||||||
|
import com.vaadin.flow.component.button.Button;
|
||||||
|
import com.vaadin.flow.component.button.ButtonVariant;
|
||||||
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.VaadinIcon;
|
||||||
import com.vaadin.flow.component.orderedlayout.FlexComponent;
|
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.splitlayout.SplitLayout;
|
||||||
|
import com.vaadin.flow.component.splitlayout.SplitLayoutVariant;
|
||||||
import com.vaadin.flow.data.provider.Query;
|
import com.vaadin.flow.data.provider.Query;
|
||||||
|
import com.vaadin.flow.data.renderer.ComponentRenderer;
|
||||||
|
import com.vaadin.flow.function.SerializableFunction;
|
||||||
import com.vaadin.flow.theme.lumo.LumoUtility;
|
import com.vaadin.flow.theme.lumo.LumoUtility;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.ui.simple.view.Constants;
|
import org.eclipse.hawkbit.ui.simple.view.Constants;
|
||||||
@@ -30,6 +39,9 @@ public class TableView<T, ID> extends Div implements Constants {
|
|||||||
private final Filter filter;
|
private final Filter filter;
|
||||||
final VerticalLayout gridLayout;
|
final VerticalLayout gridLayout;
|
||||||
protected final HorizontalLayout controlsLayout;
|
protected final HorizontalLayout controlsLayout;
|
||||||
|
protected final SplitLayout splitLayout;
|
||||||
|
protected final Div detailsPanel = new Div();
|
||||||
|
protected Button currentSelectionButton;
|
||||||
|
|
||||||
public TableView(
|
public TableView(
|
||||||
final Filter.Rsql rsql,
|
final Filter.Rsql rsql,
|
||||||
@@ -43,7 +55,7 @@ public class TableView<T, ID> extends Div implements Constants {
|
|||||||
final Filter.Rsql alternativeRsql,
|
final Filter.Rsql alternativeRsql,
|
||||||
final SelectionGrid.EntityRepresentation<T, ID> entityRepresentation,
|
final SelectionGrid.EntityRepresentation<T, ID> entityRepresentation,
|
||||||
final BiFunction<Query<T, Void>, String, Stream<T>> queryFn) {
|
final BiFunction<Query<T, Void>, String, Stream<T>> queryFn) {
|
||||||
this(rsql, alternativeRsql, entityRepresentation, queryFn, null, null);
|
this(rsql, alternativeRsql, entityRepresentation, queryFn, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableView(
|
public TableView(
|
||||||
@@ -52,7 +64,7 @@ public class TableView<T, ID> extends Div implements Constants {
|
|||||||
final BiFunction<Query<T, Void>, String, Stream<T>> queryFn,
|
final BiFunction<Query<T, Void>, String, Stream<T>> queryFn,
|
||||||
final Function<SelectionGrid<T, ID>, CompletionStage<Void>> addHandler,
|
final Function<SelectionGrid<T, ID>, CompletionStage<Void>> addHandler,
|
||||||
final Function<SelectionGrid<T, ID>, CompletionStage<Void>> removeHandler) {
|
final Function<SelectionGrid<T, ID>, CompletionStage<Void>> removeHandler) {
|
||||||
this(rsql, null, entityRepresentation, queryFn, addHandler, removeHandler);
|
this(rsql, null, entityRepresentation, queryFn, addHandler, removeHandler, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableView(
|
public TableView(
|
||||||
@@ -60,13 +72,28 @@ public class TableView<T, ID> extends Div implements Constants {
|
|||||||
final SelectionGrid.EntityRepresentation<T, ID> entityRepresentation,
|
final SelectionGrid.EntityRepresentation<T, ID> entityRepresentation,
|
||||||
final BiFunction<Query<T, Void>, String, Stream<T>> queryFn,
|
final BiFunction<Query<T, Void>, String, Stream<T>> queryFn,
|
||||||
final Function<SelectionGrid<T, ID>, CompletionStage<Void>> addHandler,
|
final Function<SelectionGrid<T, ID>, CompletionStage<Void>> addHandler,
|
||||||
final Function<SelectionGrid<T, ID>, CompletionStage<Void>> removeHandler) {
|
final Function<SelectionGrid<T, ID>, CompletionStage<Void>> removeHandler,
|
||||||
|
final Function<T, Component> detailsButtonHandler
|
||||||
|
) {
|
||||||
selectionGrid = new SelectionGrid<>(entityRepresentation, queryFn);
|
selectionGrid = new SelectionGrid<>(entityRepresentation, queryFn);
|
||||||
|
selectionGrid.setSizeFull();
|
||||||
filter = new Filter(selectionGrid::setRsqlFilter, rsql, alternativeRsql);
|
filter = new Filter(selectionGrid::setRsqlFilter, rsql, alternativeRsql);
|
||||||
|
|
||||||
setSizeFull();
|
setSizeFull();
|
||||||
|
|
||||||
gridLayout = new VerticalLayout(filter, selectionGrid);
|
splitLayout = new SplitLayout();
|
||||||
|
splitLayout.setSizeFull();
|
||||||
|
splitLayout.setOrientation(SplitLayout.Orientation.HORIZONTAL);
|
||||||
|
splitLayout.addThemeVariants(SplitLayoutVariant.LUMO_SMALL);
|
||||||
|
splitLayout.setSplitterPosition(100);
|
||||||
|
splitLayout.addToPrimary(selectionGrid);
|
||||||
|
|
||||||
|
if (detailsButtonHandler != null) {
|
||||||
|
ComponentRenderer<Button, T> renderer = new ComponentRenderer<>(renderDetailsButton(detailsButtonHandler));
|
||||||
|
selectionGrid.addColumn(renderer).setHeader("Details").setAutoWidth(true).setFlexGrow(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
gridLayout = new VerticalLayout(filter, splitLayout);
|
||||||
gridLayout.setSizeFull();
|
gridLayout.setSizeFull();
|
||||||
gridLayout.setPadding(false);
|
gridLayout.setPadding(false);
|
||||||
gridLayout.setSpacing(false);
|
gridLayout.setSpacing(false);
|
||||||
@@ -81,4 +108,43 @@ public class TableView<T, ID> extends Div implements Constants {
|
|||||||
gridLayout.add(controlsLayout);
|
gridLayout.add(controlsLayout);
|
||||||
add(gridLayout);
|
add(gridLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SerializableFunction<T, Button> renderDetailsButton(final Function<T, Component> selectionHandler) {
|
||||||
|
return (selectedItem) -> {
|
||||||
|
int DEFAULT_OPEN_POSITION_SIZE = 50;
|
||||||
|
final Button button = new Button(VaadinIcon.EYE.create());
|
||||||
|
button.getStyle().set("color", "var(--lumo-secondary-text-color)");
|
||||||
|
|
||||||
|
button.addClickListener(event -> {
|
||||||
|
final Icon eyeIcon = VaadinIcon.EYE.create();
|
||||||
|
final Icon closeIcon = VaadinIcon.CLOSE_SMALL.create();
|
||||||
|
|
||||||
|
if (button == currentSelectionButton) {
|
||||||
|
button.setIcon(eyeIcon);
|
||||||
|
button.getStyle().set("color", "var(--lumo-secondary-text-color)");
|
||||||
|
detailsPanel.removeAll();
|
||||||
|
splitLayout.remove(detailsPanel);
|
||||||
|
splitLayout.setSplitterPosition(100);
|
||||||
|
currentSelectionButton = null;
|
||||||
|
} else {
|
||||||
|
button.setIcon(closeIcon);
|
||||||
|
button.getStyle().set("color", "var(--lumo-primary-color)");
|
||||||
|
if (currentSelectionButton == null) {
|
||||||
|
splitLayout.addToSecondary(detailsPanel);
|
||||||
|
} else {
|
||||||
|
currentSelectionButton.setIcon(eyeIcon);
|
||||||
|
currentSelectionButton.getStyle().set("color", "var(--lumo-secondary-text-color)");
|
||||||
|
}
|
||||||
|
detailsPanel.removeAll();
|
||||||
|
splitLayout.setSplitterPosition(DEFAULT_OPEN_POSITION_SIZE);
|
||||||
|
detailsPanel.add(selectionHandler.apply(selectedItem));
|
||||||
|
currentSelectionButton = button;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
button.setTooltipText("Show details");
|
||||||
|
button.addThemeVariants(ButtonVariant.LUMO_SMALL);
|
||||||
|
return button;
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user