Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions hawkbit-ui/src/main/frontend/themes/hawkbit/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,14 @@ a.nocolor:link {

a.nocolor:visited {
color: inherit;
}

vaadin-split-layout.no-splitter::part(splitter) {
display: none;
}

vaadin-grid::part(selected-row) {
/* layer the tint over an opaque base so frozen (sticky) cells like Edit/Details stay opaque */
background-image: linear-gradient(var(--lumo-primary-color-10pct), var(--lumo-primary-color-10pct));
background-color: var(--lumo-base-color);
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ public boolean hasRolloutRead() {
return hasRead(() -> rolloutRestApi.getRollout(-1L));
}

public boolean hasRolloutApprove() {
return hasRead(() -> rolloutRestApi.approve(-1L, null));
}

public boolean hasDistributionSetRead() {
return hasRead(() -> distributionSetRestApi.getDistributionSet(-1L));
}
Expand All @@ -93,6 +97,10 @@ public boolean hasAutoAssignmentRead() {
return hasRead(() -> autoAssignmentRestApi.getAutoAssignment(-1L));
}

public boolean hasAutoAssignmentApprove() {
return hasRead(() -> autoAssignmentRestApi.approve(-1L, null));
}

private boolean hasRead(final Supplier<ResponseEntity<?>> doCall) {
try {
final int statusCode = doCall.get().getStatusCode().value();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,13 @@ private void addHeaderContent() {
}

private void addDrawerContent() {
final H1 appName = new H1("hawkBit UI");
final H2 appName = new H2("HawkBit");
final HorizontalLayout layout = new HorizontalLayout();
layout.setPadding(true);
layout.setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER);
layout.setJustifyContentMode(FlexComponent.JustifyContentMode.START);
final Image icon = new Image("images/hawkbit.png", "hawkBit icon");
icon.setMaxHeight(24, Unit.PIXELS);
icon.setMaxWidth(24, Unit.PIXELS);
icon.setMaxHeight(40, Unit.PIXELS);
icon.setMaxWidth(40, Unit.PIXELS);
appName.addClassNames(LumoUtility.AlignItems.BASELINE, LumoUtility.FontSize.LARGE, LumoUtility.Margin.NONE);
layout.add(icon, appName);
final Header header = new Header(layout);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ public List<SimpleGrantedAuthority> getGrantedAuthorities(Authentication authent
if (hawkbitClient.hasRolloutRead()) {
roles.add("ROLLOUT_READ");
}
if (hawkbitClient.hasRolloutApprove()) {
roles.add("ROLLOUT_APPROVE");
}
if (hawkbitClient.hasDistributionSetRead()) {
roles.add("DISTRIBUTION_SET_READ");
}
Expand All @@ -52,6 +55,9 @@ public List<SimpleGrantedAuthority> getGrantedAuthorities(Authentication authent
if (hawkbitClient.hasAutoAssignmentRead()) {
roles.add("AUTO_ASSIGNMENT_READ");
}
if (hawkbitClient.hasAutoAssignmentApprove()) {
roles.add("AUTO_ASSIGNMENT_APPROVE");
}
return roles.stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role)).toList();
}

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,40 @@ public interface Constants {
String LAST_POLL = "Last Poll";
String SECURITY_TOKEN = "Security Token";
String ATTRIBUTES = "Attributes";
String COMPLETE = "Complete";
String LOCKED = "Locked";
String DELETED = "Deleted";
String ENCRYPTED = "Encrypted";
String VALID = "Valid";
String REQUIRED_MIGRATION_STEP = "Required Migration Step";
String WEIGHT = "Weight";

// target
String UPDATE_STATUS = "Update Status";
String LAST_CONTROLLER_REQUEST_AT = "Last Controller Request At";
String INSTALLED_AT = "Installed At";
String IP_ADDRESS = "IP Address";
String TARGET_TYPE = "Target Type";
String REQUEST_ATTRIBUTES = "Request Attributes";
String AUTO_CONFIRM_ACTIVE = "Auto Confirm Active";
String NEXT_EXPECTED_POLL = "Next Expected Poll";
String OVERDUE = "Overdue";

// rollout
String GROUPS = "Groups";
String GROUP_COUNT = "Group Count";
String TARGET_COUNT = "Target Count";
String STATS = "Stats";
String STATUS = "Status";
String ACTIONS = "Actions";

String TOTAL_TARGETS = "Total Targets";
String TOTAL_GROUPS = "Total Groups";
String FORCE_TIME = "Force Time";
String APPROVAL_REMARK = "Approval Remark";
String APPROVAL_DECIDED_BY = "Approval Decided By";
String CONFIRMATION_REQUIRED = "Confirmation Required";

// create rollout
String TARGET_FILTER = "Target Filter";
String DISTRIBUTION_SET = "Distribution Set";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,28 @@
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.checkbox.CheckboxGroup;
import com.vaadin.flow.component.dependency.Uses;
import com.vaadin.flow.component.details.Details;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.GridSortOrder;
import com.vaadin.flow.component.html.Span;
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.select.Select;
import com.vaadin.flow.component.splitlayout.SplitLayout;
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.provider.SortDirection;
import com.vaadin.flow.data.renderer.ComponentRenderer;
import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPost;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPut;
import org.eclipse.hawkbit.mgmt.json.model.distributionsettype.MgmtDistributionSetType;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule;
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleAssignment;
Expand All @@ -74,8 +79,6 @@ public DistributionSetView(final HawkbitMgmtClient hawkbitClient) {
new DistributionSetRawFilter(),
new SelectionGrid.EntityRepresentation<>(MgmtDistributionSet.class, MgmtDistributionSet::getId) {

private final DistributionSetDetails details = new DistributionSetDetails(hawkbitClient);

@Override
protected void addColumns(Grid<MgmtDistributionSet> grid) {
var createdAtCol = grid.addColumn(Utils.localDateTimeRenderer(MgmtDistributionSet::getCreatedAt)).setHeader(
Expand All @@ -87,9 +90,6 @@ protected void addColumns(Grid<MgmtDistributionSet> grid) {
grid.addColumn(MgmtDistributionSet::getTypeName).setHeader(Constants.TYPE).setAutoWidth(true).setKey("typename")
.setSortable(true);
grid.sort(List.of(new GridSortOrder<>(createdAtCol, SortDirection.DESCENDING)));

grid.setItemDetailsRenderer(new ComponentRenderer<>(
() -> details, DistributionSetDetails::setItem));
}
},
(query, rsqlFilter) -> Optional.ofNullable(
Expand All @@ -104,7 +104,42 @@ protected void addColumns(Grid<MgmtDistributionSet> grid) {
distributionSet -> hawkbitClient.getDistributionSetRestApi()
.deleteDistributionSet(distributionSet.getId()));
return CompletableFuture.completedFuture(null);
}, null);
},
distributionSet -> {
final DistributionSetDetailedView detailedView = new DistributionSetDetailedView(hawkbitClient);
detailedView.setItem(distributionSet);
return detailedView;
},
SplitLayout.Orientation.VERTICAL,
distributionSet -> new EditDialog(distributionSet, hawkbitClient).result());
}

private static class DistributionSetDetailedView extends VerticalLayout {

@Serial
private static final long serialVersionUID = 1L;

private final Span distributionSetName;
private final DistributionSetDetails details;

private DistributionSetDetailedView(final HawkbitMgmtClient hawkbitClient) {
distributionSetName = new Span();
details = new DistributionSetDetails(hawkbitClient);
setWidthFull();
setHeightFull();
getStyle().set("overflow", "auto");

add(distributionSetName);
final TabSheet tabSheet = new TabSheet();
tabSheet.setWidthFull();
tabSheet.add("Details", details);
add(tabSheet);
}

private void setItem(final MgmtDistributionSet distributionSet) {
distributionSetName.setText(distributionSet.getName() + ":" + distributionSet.getVersion());
details.setItem(distributionSet);
}
}

private static SelectionGrid<MgmtSoftwareModule, Long> selectSoftwareModuleGrid() {
Expand Down Expand Up @@ -194,39 +229,63 @@ private static class DistributionSetDetails extends FormLayout {
private final transient HawkbitMgmtClient hawkbitClient;

private final TextArea description = new TextArea("Description");
private final TextField id = Utils.textField(Constants.ID);
private final TextField createdBy = Utils.textField("Created by");
private final TextField createdAt = Utils.textField("Created at");
private final TextField lastModifiedBy = Utils.textField("Last modified by");
private final TextField lastModifiedAt = Utils.textField("Last modified at");
private final Checkbox complete = new Checkbox(Constants.COMPLETE);
private final Checkbox valid = new Checkbox(Constants.VALID);
private final Checkbox locked = new Checkbox(Constants.LOCKED);
private final Checkbox requiredMigrationStep = new Checkbox(Constants.REQUIRED_MIGRATION_STEP);
private final Checkbox deleted = new Checkbox(Constants.DELETED);
private final TextArea metadata = new TextArea("Metadata");
private final SelectionGrid<MgmtSoftwareModule, Long> softwareModulesGrid = selectSoftwareModuleGrid();
private final Details softwareModulesSection;

private DistributionSetDetails(final HawkbitMgmtClient hawkbitClient) {
this.hawkbitClient = hawkbitClient;

description.setMinLength(2);
softwareModulesGrid.setAllRowsVisible(true);
softwareModulesGrid.setWidthFull();
softwareModulesSection = new Details("Software Modules", softwareModulesGrid);
softwareModulesSection.setOpened(false);
softwareModulesSection.setWidthFull();
Stream.of(
description,
createdBy, createdAt,
id,
createdBy,
lastModifiedBy, lastModifiedAt, metadata)
.forEach(field -> {
field.setReadOnly(true);
add(field);
});
add(softwareModulesGrid);
Stream.of(complete, valid, locked, requiredMigrationStep, deleted)
.forEach(checkbox -> {
checkbox.setReadOnly(true);
checkbox.setEnabled(false);
add(checkbox);
});
add(softwareModulesSection);

setResponsiveSteps(new ResponsiveStep("0", 2));
setColspan(description, 2);
setColspan(softwareModulesGrid, 2);
setColspan(metadata, 2);
setColspan(softwareModulesSection, 2);
}

private void setItem(final MgmtDistributionSet distributionSet) {
description.setValue(Objects.requireNonNullElse(distributionSet.getDescription(), ""));
id.setValue(distributionSet.getId() == null ? "" : String.valueOf(distributionSet.getId()));

createdBy.setValue(distributionSet.getCreatedBy());
createdAt.setValue(Utils.localDateTimeFromTs(distributionSet.getCreatedAt()));
lastModifiedBy.setValue(distributionSet.getLastModifiedBy());
lastModifiedAt.setValue(Utils.localDateTimeFromTs(distributionSet.getLastModifiedAt()));
complete.setValue(Boolean.TRUE.equals(distributionSet.getComplete()));
valid.setValue(distributionSet.isValid());
locked.setValue(distributionSet.isLocked());
requiredMigrationStep.setValue(distributionSet.isRequiredMigrationStep());
deleted.setValue(distributionSet.isDeleted());
metadata.setValue(Optional.ofNullable(
hawkbitClient.getDistributionSetRestApi().getMetadata(distributionSet.getId()).getBody())
.map(body -> body.getContent().stream()
Expand Down Expand Up @@ -255,6 +314,7 @@ private static class CreateDialog extends Utils.BaseDialog<Void> {
private final TextField version;
private final TextArea description;
private final Checkbox requiredMigrationStep;
private final Checkbox locked;
private final Button create;

private CreateDialog(final HawkbitMgmtClient hawkbitClient) {
Expand All @@ -280,7 +340,9 @@ private CreateDialog(final HawkbitMgmtClient hawkbitClient) {
description = new TextArea(Constants.DESCRIPTION);
description.setWidthFull();
description.setMinLength(2);
description.setValueChangeMode(ValueChangeMode.EAGER);
requiredMigrationStep = new Checkbox("Required Migration Step");
locked = new Checkbox("Locked");

create = Utils.tooltip(new Button("Create"), "Create (Enter)");
create.setEnabled(false);
Expand All @@ -297,7 +359,7 @@ private CreateDialog(final HawkbitMgmtClient hawkbitClient) {
layout.setSizeFull();
layout.setPadding(true);
layout.setSpacing(false);
layout.add(type, name, version, vendor, description, requiredMigrationStep);
layout.add(type, name, version, vendor, description, requiredMigrationStep, locked);
add(layout);
open();
}
Expand All @@ -320,7 +382,8 @@ private void addCreateClickListener() {
.setName(name.getValue())
.setVersion(version.getValue())
.setDescription(description.getValue())
.setRequiredMigrationStep(requiredMigrationStep.getValue())))
.setRequiredMigrationStep(requiredMigrationStep.getValue())
.setLocked(locked.getValue())))
.getBody())
.stream()
.flatMap(Collection::stream)
Expand All @@ -332,6 +395,73 @@ private void addCreateClickListener() {
}
}

private static class EditDialog extends Utils.BaseDialog<Void> {

@Serial
private static final long serialVersionUID = 1L;

private final TextField name;
private final TextField version;
private final TextArea description;
private final Checkbox requiredMigrationStep;
private final Button save;

private EditDialog(final MgmtDistributionSet distributionSet, final HawkbitMgmtClient hawkbitClient) {
super("Edit Distribution Set");

final TextField type = Utils.textField(Constants.TYPE);
type.setValue(Objects.requireNonNullElse(distributionSet.getTypeName(), ""));
type.setReadOnly(true);
type.setWidthFull();

name = Utils.textField(Constants.NAME, this::readyToSave);
version = Utils.textField(Constants.VERSION, this::readyToSave);
description = new TextArea(Constants.DESCRIPTION);
description.setWidthFull();
description.setMinLength(2);
description.setValueChangeMode(ValueChangeMode.EAGER);
requiredMigrationStep = new Checkbox("Required Migration Step");
requiredMigrationStep.setValue(distributionSet.isRequiredMigrationStep());

save = Utils.tooltip(new Button("Save"), "Save (Enter)");
name.setValue(Objects.requireNonNullElse(distributionSet.getName(), ""));
version.setValue(Objects.requireNonNullElse(distributionSet.getVersion(), ""));
description.setValue(Objects.requireNonNullElse(distributionSet.getDescription(), ""));
save.addClickListener(e -> {
hawkbitClient.getDistributionSetRestApi().updateDistributionSet(
distributionSet.getId(),
new MgmtDistributionSetRequestBodyPut()
.setName(name.getValue())
.setVersion(version.getValue())
.setDescription(description.getValue())
.setRequiredMigrationStep(requiredMigrationStep.getValue()));
close();
});
save.addClickShortcut(Key.ENTER);
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
final Button cancel = Utils.tooltip(new Button(CANCEL), CANCEL_ESC);
cancel.addClickListener(e -> close());
cancel.addClickShortcut(Key.ESCAPE);
getFooter().add(cancel);
getFooter().add(save);

final VerticalLayout layout = new VerticalLayout();
layout.setSizeFull();
layout.setPadding(true);
layout.setSpacing(false);
layout.add(type, name, version, description, requiredMigrationStep);
add(layout);
open();
}

private void readyToSave(final Object v) {
final boolean saveEnabled = !name.isEmpty() && !version.isEmpty();
if (save.isEnabled() != saveEnabled) {
save.setEnabled(saveEnabled);
}
}
}

@SuppressWarnings({ "java:S1171", "java:S3599" })
private static class AddSoftwareModulesDialog extends Utils.BaseDialog<Void> {

Expand Down
Loading
Loading