Support for Multi-Assignments (#833)

* First draft of new assignment logic

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Enhancements of System Configuration view

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Drag&drop enhancements for multiple distribution set assignments

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Misc fixes

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* test that previous assignments are not canceled

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* add description and expected events to test

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* extend TenantConfigurationManagement by NullPointerException proof
getConfigurationValue method

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* Hide "Required Migration Step" if Multi Assignments is enabled

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* Make fields transient

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* Add IDs for Required Migration Step elements

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* Save work in progress

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Added new DMF message DmfMultiActionRequest

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* DMF enhancements to send out MultiActionRequest messages

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Minor changes

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Multi Assignment support for cancellations

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* fix permission problems and immutable lists

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* add message dispatcher tests for outgoing multiassignment messages, fix
old tests

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* Implement Multi-Assignment support for rollout groups

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Minor changes

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Refactoring

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Register new deployment event with protobuff framework

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Allow same DS to be assigned multiple times

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix assignment with pending cancellations

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Reduce repository /DB calls

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Revert latest perf fix (causing a regression)

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* test if a rollout sends multiaction messages in multiassignment mode

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* Minor changes

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Do not close new action if DS is already assigned (if multi-assign on)

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* add test that starts and finishes multiple rollouts in multiassignt mode

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* add javadoc to test method

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* Prevent Multi-Assignments from being disabled via Repo Config UI

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Add link to Provisioning State Machine

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* test that Multiassignment can not be disabled via mgmt-api

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* refactor AmqpMessageHandlerService code

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* Prevent Multi-Assignments feature from being disabled via Mgmt REST API

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* add license header, remove unused instance variables

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* fix tenantConfigurationManagement mock in test

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* return empty list instead of null

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* add ddi test for multiassignment, fix old test

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* Prevent autoclose from being modified if Multi-Assignments is enabled

# WARNING: head commit changed in the meantime

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Add test for autoClose /multiAssign

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Javadoc improvements

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* change test method that waits for dmf messages to be dispatched

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* clean up code

Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com>

* Fix UI-related PR review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix PR review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix PR review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix PR review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix PR review findings, Sonar issues, and test failures

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix PR review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix PR review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix PR review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix Sonar findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix PR review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix PR review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>

* Fix PR review findings

Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>
This commit is contained in:
Stefan Behl
2019-05-16 10:30:40 +02:00
committed by Dominic Schabel
parent f16f986eed
commit 1ac40a7a95
65 changed files with 1906 additions and 588 deletions

View File

@@ -209,6 +209,8 @@ public class UiProperties implements Serializable {
*/
private String rolloutView = "";
private String provisioningStateMachine = "";
public String getDeploymentView() {
return deploymentView;
}
@@ -249,6 +251,10 @@ public class UiProperties implements Serializable {
return maintenanceWindowView;
}
public String getProvisioningStateMachine() {
return provisioningStateMachine;
}
public void setDeploymentView(final String deploymentView) {
this.deploymentView = deploymentView;
}
@@ -289,6 +295,10 @@ public class UiProperties implements Serializable {
this.maintenanceWindowView = maintenanceWindowView;
}
public void setProvisioningStateMachine(final String provisioningStateMachine) {
this.provisioningStateMachine = provisioningStateMachine;
}
}
private final Documentation documentation = new Documentation();

View File

@@ -12,7 +12,9 @@ import java.util.Optional;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.common.tagdetails.DistributionTagToken;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
@@ -56,6 +58,8 @@ public abstract class AbstractDistributionSetDetails
private final SoftwareModuleDetailsTable softwareModuleDetailsTable;
private final transient TenantConfigurationManagement tenantConfigurationManagement;
private VerticalLayout softwareModuleTab;
protected AbstractDistributionSetDetails(final VaadinMessageSource i18n, final UIEventBus eventBus,
@@ -64,7 +68,8 @@ public abstract class AbstractDistributionSetDetails
final DistributionSetManagement distributionSetManagement,
final DsMetadataPopupLayout dsMetadataPopupLayout, final UINotification uiNotification,
final DistributionSetTagManagement distributionSetTagManagement,
final SoftwareModuleDetailsTable softwareModuleDetailsTable) {
final SoftwareModuleDetailsTable softwareModuleDetailsTable,
final TenantConfigurationManagement tenantConfigurationManagement) {
super(i18n, eventBus, permissionChecker, managementUIState);
this.distributionAddUpdateWindowLayout = distributionAddUpdateWindowLayout;
this.uiNotification = uiNotification;
@@ -73,6 +78,7 @@ public abstract class AbstractDistributionSetDetails
this.distributionTagToken = new DistributionTagToken(permissionChecker, i18n, uiNotification, eventBus,
managementUIState, distributionSetTagManagement, distributionSetManagement);
this.softwareModuleDetailsTable = softwareModuleDetailsTable;
this.tenantConfigurationManagement = tenantConfigurationManagement;
dsMetadataTable = new DistributionSetMetadataDetailsLayout(i18n, distributionSetManagement,
dsMetadataPopupLayout);
@@ -175,9 +181,19 @@ public abstract class AbstractDistributionSetDetails
typeLabel.setId(UIComponentIdProvider.DETAILS_TYPE_LABEL_ID);
detailsTabLayout.addComponent(typeLabel);
detailsTabLayout.addComponent(
SPUIComponentProvider.createNameValueLabel(getI18n().getMessage("checkbox.dist.migration.required"),
getMigrationRequiredValue(isMigrationRequired)));
final Label requiredMigrationStepLabel = SPUIComponentProvider.createNameValueLabel(
getI18n().getMessage("checkbox.dist.migration.required"),
getMigrationRequiredValue(isMigrationRequired));
requiredMigrationStepLabel.setId(UIComponentIdProvider.DETAILS_REQUIRED_MIGRATION_STEP_LABEL_ID);
if (!isMultiAssignmentEnabled()) {
detailsTabLayout.addComponent(requiredMigrationStepLabel);
}
}
private boolean isMultiAssignmentEnabled() {
return tenantConfigurationManagement
.getConfigurationValue(TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED, Boolean.class).getValue();
}
private String getMigrationRequiredValue(final Boolean isMigrationRequired) {

View File

@@ -21,6 +21,7 @@ import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.ui.AbstractHawkbitUI;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent;
@@ -102,7 +103,8 @@ public class DistributionsView extends AbstractNotificationView implements Brows
final DistributionsViewClientCriterion distributionsViewClientCriterion,
final ArtifactUploadState artifactUploadState, final SystemManagement systemManagement,
final ArtifactManagement artifactManagement, final NotificationUnreadButton notificationUnreadButton,
final DistributionsViewMenuItem distributionsViewMenuItem) {
final DistributionsViewMenuItem distributionsViewMenuItem,
final TenantConfigurationManagement configManagement) {
super(eventBus, notificationUnreadButton);
this.permChecker = permChecker;
this.i18n = i18n;
@@ -117,7 +119,7 @@ public class DistributionsView extends AbstractNotificationView implements Brows
this.distributionTableLayout = new DistributionSetTableLayout(i18n, eventBus, permChecker, manageDistUIState,
softwareModuleManagement, distributionSetManagement, distributionSetTypeManagement, targetManagement,
entityFactory, uiNotification, distributionSetTagManagement, distributionsViewClientCriterion,
systemManagement);
systemManagement, configManagement);
this.softwareModuleTableLayout = new SwModuleTableLayout(i18n, uiNotification, eventBus,
softwareModuleManagement, softwareModuleTypeManagement, entityFactory, manageDistUIState, permChecker,
distributionsViewClientCriterion, artifactUploadState, artifactManagement);

View File

@@ -13,6 +13,7 @@ import java.util.Map;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent;
@@ -58,11 +59,12 @@ public class DistributionSetDetails extends AbstractDistributionSetDetails {
final DistributionAddUpdateWindowLayout distributionAddUpdateWindowLayout,
final DistributionSetManagement distributionSetManagement, final UINotification uiNotification,
final DistributionSetTagManagement distributionSetTagManagement,
final DsMetadataPopupLayout dsMetadataPopupLayout) {
final DsMetadataPopupLayout dsMetadataPopupLayout, final TenantConfigurationManagement configManagement) {
super(i18n, eventBus, permissionChecker, managementUIState, distributionAddUpdateWindowLayout,
distributionSetManagement, dsMetadataPopupLayout, uiNotification, distributionSetTagManagement,
createSoftwareModuleDetailsTable(i18n, permissionChecker, distributionSetManagement, eventBus,
manageDistUIState, uiNotification));
manageDistUIState, uiNotification),
configManagement);
this.manageDistUIState = manageDistUIState;
tfqDetailsTable = new TargetFilterQueryDetailsTable(i18n);

View File

@@ -15,6 +15,7 @@ import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.common.table.AbstractTableLayout;
import org.eclipse.hawkbit.ui.dd.criteria.DistributionsViewClientCriterion;
@@ -41,7 +42,7 @@ public class DistributionSetTableLayout extends AbstractTableLayout<Distribution
final EntityFactory entityFactory, final UINotification uiNotification,
final DistributionSetTagManagement distributionSetTagManagement,
final DistributionsViewClientCriterion distributionsViewClientCriterion,
final SystemManagement systemManagement) {
final SystemManagement systemManagement, final TenantConfigurationManagement configManagement) {
this.distributionSetTable = new DistributionSetTable(eventBus, i18n, uiNotification, permissionChecker,
manageDistUIState, distributionSetManagement, softwareManagement, distributionsViewClientCriterion,
@@ -49,7 +50,7 @@ public class DistributionSetTableLayout extends AbstractTableLayout<Distribution
final DistributionAddUpdateWindowLayout distributionAddUpdateWindowLayout = new DistributionAddUpdateWindowLayout(
i18n, uiNotification, eventBus, distributionSetManagement, distributionSetTypeManagement,
systemManagement, entityFactory, distributionSetTable);
systemManagement, entityFactory, distributionSetTable, configManagement);
final DsMetadataPopupLayout popupLayout = new DsMetadataPopupLayout(i18n, uiNotification, eventBus,
distributionSetManagement, entityFactory, permissionChecker);
@@ -60,7 +61,7 @@ public class DistributionSetTableLayout extends AbstractTableLayout<Distribution
distributionSetTable,
new DistributionSetDetails(i18n, eventBus, permissionChecker, manageDistUIState, null,
distributionAddUpdateWindowLayout, distributionSetManagement, uiNotification,
distributionSetTagManagement, popupLayout));
distributionSetTagManagement, popupLayout, configManagement));
}
public DistributionSetTable getDistributionSetTable() {

View File

@@ -22,6 +22,7 @@ import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TargetTagManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.ui.AbstractHawkbitUI;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.UiProperties;
@@ -127,6 +128,7 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
final TargetTagManagement targetTagManagement,
final DistributionSetTagManagement distributionSetTagManagement,
final TargetFilterQueryManagement targetFilterQueryManagement, final SystemManagement systemManagement,
final TenantConfigurationManagement configManagement,
final NotificationUnreadButton notificationUnreadButton,
final DeploymentViewMenuItem deploymentViewMenuItem, @Qualifier("uiExecutor") final Executor uiExecutor) {
super(eventBus, notificationUnreadButton);
@@ -147,7 +149,7 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
targetFilterQueryManagement, targetTagManagement);
final TargetTable targetTable = new TargetTable(eventBus, i18n, uiNotification, targetManagement,
managementUIState, permChecker, managementViewClientCriterion, distributionSetManagement,
targetTagManagement, deploymentManagement, uiProperties);
targetTagManagement, deploymentManagement, configManagement, uiProperties);
this.countMessageLabel = new CountMessageLabel(eventBus, targetManagement, i18n, managementUIState,
targetTable);
@@ -175,7 +177,7 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
this.distributionTableLayout = new DistributionTableLayout(i18n, eventBus, permChecker, managementUIState,
distributionSetManagement, distributionSetTypeManagement, managementViewClientCriterion,
entityFactory, uiNotification, distributionSetTagManagement, targetTagManagement, systemManagement,
targetManagement, deploymentManagement, uiProperties);
targetManagement, deploymentManagement, configManagement, uiProperties);
} else {
this.distributionTagLayout = null;
this.distributionTableLayout = null;

View File

@@ -8,9 +8,7 @@
*/
package org.eclipse.hawkbit.ui.management;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
@@ -20,17 +18,19 @@ import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.MaintenanceScheduleHelper;
import org.eclipse.hawkbit.repository.exception.InvalidMaintenanceScheduleException;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.RepositoryModelConstants;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetWithActionType;
import org.eclipse.hawkbit.ui.UiProperties;
import org.eclipse.hawkbit.ui.common.confirmwindow.layout.ConfirmationTab;
import org.eclipse.hawkbit.ui.common.entity.DistributionSetIdName;
import org.eclipse.hawkbit.ui.common.entity.TargetIdName;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.management.event.PinUnpinEvent;
import org.eclipse.hawkbit.ui.management.event.SaveActionWindowEvent;
import org.eclipse.hawkbit.ui.management.miscs.AbstractActionTypeOptionGroupLayout;
import org.eclipse.hawkbit.ui.management.miscs.AbstractActionTypeOptionGroupLayout.ActionTypeOption;
import org.eclipse.hawkbit.ui.management.miscs.ActionTypeOptionGroupAssignmentLayout;
import org.eclipse.hawkbit.ui.management.miscs.MaintenanceWindowLayout;
import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
@@ -41,7 +41,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vaadin.spring.events.EventBus.UIEventBus;
import com.google.common.collect.Maps;
import com.vaadin.data.Property;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.HorizontalLayout;
@@ -59,8 +58,12 @@ public final class TargetAssignmentOperations {
}
/**
* Save all target(s)-distributionSet assignments
* Save the given distribution set assignments
*
* @param targets
* to assign the given distribution sets to
* @param distributionSets
* to assign to the given targets
* @param managementUIState
* the management UI state
* @param actionTypeOptionGroupLayout
@@ -78,79 +81,64 @@ public final class TargetAssignmentOperations {
* @param eventSource
* the source object for sending potential events
*/
public static void saveAllAssignments(final ManagementUIState managementUIState,
public static void saveAllAssignments(final List<Target> targets, final List<DistributionSet> distributionSets,
final ManagementUIState managementUIState,
final ActionTypeOptionGroupAssignmentLayout actionTypeOptionGroupLayout,
final MaintenanceWindowLayout maintenanceWindowLayout, final DeploymentManagement deploymentManagement,
final UINotification notification, final UIEventBus eventBus, final VaadinMessageSource i18n,
final Object eventSource) {
final Set<TargetIdName> itemIds = managementUIState.getAssignedList().keySet();
Long distId;
List<TargetIdName> targetIdSetList;
List<TargetIdName> tempIdList;
final ActionType actionType = ((AbstractActionTypeOptionGroupLayout.ActionTypeOption) actionTypeOptionGroupLayout
.getActionTypeOptionGroup().getValue()).getActionType();
final long forcedTimeStamp = actionTypeOptionGroupLayout.getActionTypeOptionGroup()
.getValue() == AbstractActionTypeOptionGroupLayout.ActionTypeOption.AUTO_FORCED
final ActionType actionType = ((ActionTypeOption) actionTypeOptionGroupLayout.getActionTypeOptionGroup()
.getValue()).getActionType();
final long forcedTimeStamp = (((ActionTypeOption) actionTypeOptionGroupLayout.getActionTypeOptionGroup()
.getValue()) == ActionTypeOption.AUTO_FORCED)
? actionTypeOptionGroupLayout.getForcedTimeDateField().getValue().getTime()
: RepositoryModelConstants.NO_FORCE_TIME;
final Map<Long, List<TargetIdName>> saveAssignedList = Maps.newHashMapWithExpectedSize(itemIds.size());
for (final TargetIdName itemId : itemIds) {
final DistributionSetIdName distitem = managementUIState.getAssignedList().get(itemId);
distId = distitem.getId();
if (saveAssignedList.containsKey(distId)) {
targetIdSetList = saveAssignedList.get(distId);
} else {
targetIdSetList = new ArrayList<>();
}
targetIdSetList.add(itemId);
saveAssignedList.put(distId, targetIdSetList);
}
final String maintenanceSchedule = maintenanceWindowLayout.getMaintenanceSchedule();
final String maintenanceDuration = maintenanceWindowLayout.getMaintenanceDuration();
final String maintenanceTimeZone = maintenanceWindowLayout.getMaintenanceTimeZone();
for (final Map.Entry<Long, List<TargetIdName>> mapEntry : saveAssignedList.entrySet()) {
tempIdList = saveAssignedList.get(mapEntry.getKey());
final DistributionSetAssignmentResult distributionSetAssignmentResult = deploymentManagement
.assignDistributionSet(mapEntry.getKey(),
tempIdList.stream().map(t -> maintenanceWindowLayout.isEnabled()
? new TargetWithActionType(t.getControllerId(), actionType, forcedTimeStamp,
maintenanceSchedule, maintenanceDuration, maintenanceTimeZone)
: new TargetWithActionType(t.getControllerId(), actionType, forcedTimeStamp))
.collect(Collectors.toList()));
if (distributionSetAssignmentResult.getAssigned() > 0) {
notification.displaySuccess(
i18n.getMessage("message.target.assignment", distributionSetAssignmentResult.getAssigned()));
}
if (distributionSetAssignmentResult.getAlreadyAssigned() > 0) {
notification.displaySuccess(i18n.getMessage("message.target.alreadyAssigned",
distributionSetAssignmentResult.getAlreadyAssigned()));
}
final Set<Long> dsIds = distributionSets.stream().map(DistributionSet::getId).collect(Collectors.toSet());
final List<TargetWithActionType> trgActionType = targets.stream()
.map(t -> maintenanceWindowLayout.isEnabled()
? new TargetWithActionType(t.getControllerId(), actionType, forcedTimeStamp,
maintenanceSchedule, maintenanceDuration, maintenanceTimeZone)
: new TargetWithActionType(t.getControllerId(), actionType, forcedTimeStamp))
.collect(Collectors.toList());
final List<DistributionSetAssignmentResult> results = deploymentManagement.assignDistributionSets(dsIds,
trgActionType);
// use the last one for the notification box
final DistributionSetAssignmentResult assignmentResult = results.get(results.size() - 1);
if (assignmentResult.getAssigned() > 0) {
notification.displaySuccess(i18n.getMessage("message.target.assignment", assignmentResult.getAssigned()));
}
refreshPinnedDetails(saveAssignedList, managementUIState, eventBus, eventSource);
managementUIState.getAssignedList().clear();
if (assignmentResult.getAlreadyAssigned() > 0) {
notification.displaySuccess(
i18n.getMessage("message.target.alreadyAssigned", assignmentResult.getAlreadyAssigned()));
}
final Set<Long> targetIds = targets.stream().map(Target::getId).collect(Collectors.toSet());
refreshPinnedDetails(dsIds, targetIds, managementUIState, eventBus, eventSource);
notification.displaySuccess(i18n.getMessage("message.target.ds.assign.success"));
eventBus.publish(eventSource, SaveActionWindowEvent.SAVED_ASSIGNMENTS);
}
private static void refreshPinnedDetails(final Map<Long, List<TargetIdName>> saveAssignedList,
private static void refreshPinnedDetails(final Set<Long> dsIds, final Set<Long> targetIds,
final ManagementUIState managementUIState, final UIEventBus eventBus, final Object eventSource) {
final Optional<Long> pinnedDist = managementUIState.getTargetTableFilters().getPinnedDistId();
final Optional<TargetIdName> pinnedTarget = managementUIState.getDistributionTableFilters().getPinnedTarget();
if (pinnedDist.isPresent()) {
if (saveAssignedList.keySet().contains(pinnedDist.get())) {
if (dsIds.contains(pinnedDist.get())) {
eventBus.publish(eventSource, PinUnpinEvent.PIN_DISTRIBUTION);
}
} else if (pinnedTarget.isPresent()) {
final Set<TargetIdName> assignedTargetIds = managementUIState.getAssignedList().keySet();
if (assignedTargetIds.contains(pinnedTarget.get())) {
eventBus.publish(eventSource, PinUnpinEvent.PIN_TARGET);
}
} else if (pinnedTarget.isPresent() && targetIds.contains(pinnedTarget.get().getTargetId())) {
eventBus.publish(eventSource, PinUnpinEvent.PIN_TARGET);
}
}
@@ -187,7 +175,8 @@ public final class TargetAssignmentOperations {
* @param maintenanceWindowLayout
* the Maintenance Window Layout
* @param saveButtonToggle
* The event listener to derimne if save button should be enabled or not
* The event listener to derimne if save button should be enabled
* or not
* @param i18n
* the Vaadin Message Source for multi language
* @param uiProperties
@@ -283,4 +272,4 @@ public final class TargetAssignmentOperations {
return SPUIComponentProvider.getHelpLink(i18n, maintenanceWindowHelpUrl);
}
}
}

View File

@@ -15,10 +15,12 @@ import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.TenantMetaData;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
import org.eclipse.hawkbit.ui.common.CommonDialogWindow;
import org.eclipse.hawkbit.ui.common.CommonDialogWindow.SaveDialogCloseListener;
import org.eclipse.hawkbit.ui.common.DistributionSetTypeBeanQuery;
@@ -64,6 +66,7 @@ public class DistributionAddUpdateWindowLayout extends CustomComponent {
private final transient DistributionSetTypeManagement distributionSetTypeManagement;
private final transient SystemManagement systemManagement;
private final transient EntityFactory entityFactory;
private final transient TenantConfigurationManagement tenantConfigurationManagement;
private final DistributionSetTable distributionSetTable;
@@ -94,11 +97,14 @@ public class DistributionAddUpdateWindowLayout extends CustomComponent {
* EntityFactory
* @param distributionSetTable
* DistributionSetTable
* @param tenantConfigurationManagement
* TenantConfigurationManagement
*/
public DistributionAddUpdateWindowLayout(final VaadinMessageSource i18n, final UINotification notificationMessage,
final UIEventBus eventBus, final DistributionSetManagement distributionSetManagement,
final DistributionSetTypeManagement distributionSetTypeManagement, final SystemManagement systemManagement,
final EntityFactory entityFactory, final DistributionSetTable distributionSetTable) {
final EntityFactory entityFactory, final DistributionSetTable distributionSetTable,
final TenantConfigurationManagement tenantConfigurationManagement) {
this.i18n = i18n;
this.notificationMessage = notificationMessage;
this.eventBus = eventBus;
@@ -107,6 +113,7 @@ public class DistributionAddUpdateWindowLayout extends CustomComponent {
this.systemManagement = systemManagement;
this.entityFactory = entityFactory;
this.distributionSetTable = distributionSetTable;
this.tenantConfigurationManagement = tenantConfigurationManagement;
createRequiredComponents();
buildLayout();
}
@@ -134,8 +141,8 @@ public class DistributionAddUpdateWindowLayout extends CustomComponent {
final DistributionSet currentDS = distributionSetManagement.update(entityFactory.distributionSet()
.update(editDistId).name(distNameTextField.getValue()).description(descTextArea.getValue())
.version(distVersionTextField.getValue()).requiredMigrationStep(isMigStepReq));
notificationMessage.displaySuccess(i18n.getMessage("message.new.dist.save.success",
new Object[] { currentDS.getName(), currentDS.getVersion() }));
notificationMessage.displaySuccess(
i18n.getMessage("message.new.dist.save.success", currentDS.getName(), currentDS.getVersion()));
// update table row+details layout
eventBus.publish(this, new DistributionTableEvent(BaseEntityEventType.UPDATED_ENTITY, currentDS));
});
@@ -283,6 +290,12 @@ public class DistributionAddUpdateWindowLayout extends CustomComponent {
distsetTypeNameComboBox.setEnabled(true);
descTextArea.clear();
reqMigStepCheckbox.clear();
reqMigStepCheckbox.setVisible(!isMultiAssignmentEnabled());
}
private boolean isMultiAssignmentEnabled() {
return tenantConfigurationManagement.getConfigurationValue(TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED,
Boolean.class).getValue();
}
private void populateValuesOfDistribution(final Long editDistId) {
@@ -351,7 +364,8 @@ public class DistributionAddUpdateWindowLayout extends CustomComponent {
populateValuesOfDistribution(editDistId);
}
return new WindowBuilder(SPUIDefinitions.CREATE_UPDATE_WINDOW).caption(caption).content(this).layout(formLayout)
return new WindowBuilder(SPUIDefinitions.CREATE_UPDATE_WINDOW).caption(caption).content(this)
.id(UIComponentIdProvider.CREATE_POPUP_ID).layout(formLayout)
.i18n(i18n).saveDialogCloseListener(saveDialogCloseListener).buildCommonDialogWindow();
}

View File

@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.ui.management.dstable;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.common.detailslayout.AbstractDistributionSetDetails;
import org.eclipse.hawkbit.ui.common.detailslayout.SoftwareModuleDetailsTable;
@@ -31,10 +32,12 @@ public class DistributionDetails extends AbstractDistributionSetDetails {
final DistributionSetManagement distributionSetManagement,
final DsMetadataPopupLayout dsMetadataPopupLayout, final UINotification uiNotification,
final DistributionSetTagManagement distributionSetTagManagement,
final DistributionAddUpdateWindowLayout distributionAddUpdateWindowLayout) {
final DistributionAddUpdateWindowLayout distributionAddUpdateWindowLayout,
final TenantConfigurationManagement tenantConfigurationManagement) {
super(i18n, eventBus, permissionChecker, managementUIState, distributionAddUpdateWindowLayout,
distributionSetManagement, dsMetadataPopupLayout, uiNotification, distributionSetTagManagement,
createSoftwareModuleDetailsTable(i18n, permissionChecker, uiNotification));
createSoftwareModuleDetailsTable(i18n, permissionChecker, uiNotification),
tenantConfigurationManagement);
restoreState();
}

View File

@@ -404,84 +404,61 @@ public class DistributionTable extends AbstractNamedVersionTable<DistributionSet
assignTargetToDs(getItem(distItemId), targetManagement.get(targetIdSet));
}
private void assignTargetToDs(final Item item, final List<Target> targetDetailsList) {
private void assignTargetToDs(final Item item, final List<Target> targets) {
if (item == null || item.getItemProperty("id") == null) {
return;
}
if (targetDetailsList.isEmpty()) {
if (targets.isEmpty()) {
getNotification().displayWarning(getI18n().getMessage(TARGETS_NOT_EXISTS));
return;
}
final Long distId = (Long) item.getItemProperty("id").getValue();
selectDroppedEntities(distId);
final Optional<DistributionSet> findDistributionSetById = distributionSetManagement.get(distId);
if (!findDistributionSetById.isPresent()) {
final Optional<DistributionSet> distributionSet = distributionSetManagement.get(distId);
if (!distributionSet.isPresent()) {
getNotification().displayWarning(getI18n().getMessage(DISTRIBUTIONSET_NOT_EXISTS));
return;
}
addNewDistributionToAssignmentList(targetDetailsList, findDistributionSetById.get());
openConfirmationWindowForAssignment(findDistributionSetById.get().getName(), targetDetailsList);
openConfirmationWindowForAssignment(distributionSet.get(), targets);
}
private void addNewDistributionToAssignmentList(final List<Target> targetDetailsList,
final DistributionSet distributionSet) {
String pendingActionMessage = null;
final DistributionSetIdName distributionSetIdName = new DistributionSetIdName(distributionSet);
private void openConfirmationWindowForAssignment(final DistributionSet distributionSet,
final List<Target> targets) {
for (final Target target : targetDetailsList) {
final TargetIdName key = new TargetIdName(target);
if (managementUIState.getAssignedList().keySet().contains(key)
&& managementUIState.getAssignedList().get(key).equals(distributionSetIdName)) {
pendingActionMessage = getPendingActionMessage(pendingActionMessage, target.getControllerId(),
HawkbitCommonUtil.getDistributionNameAndVersion(distributionSetIdName.getName(),
distributionSetIdName.getVersion()));
getNotification().displayValidationError(pendingActionMessage);
} else {
managementUIState.getAssignedList().put(key, distributionSetIdName);
final String question = getAssignmentConfirmationMessage(distributionSet, targets);
final String caption = getI18n().getMessage(CAPTION_ENTITY_ASSIGN_ACTION_CONFIRMBOX);
final String okLabel = getI18n().getMessage(UIMessageIdProvider.BUTTON_OK);
final String cancelLabel = getI18n().getMessage(UIMessageIdProvider.BUTTON_CANCEL);
confirmDialog = new ConfirmationDialog(caption, question, okLabel, cancelLabel, ok -> {
if (ok && isMaintenanceWindowValid(maintenanceWindowLayout, getNotification())) {
saveAllAssignments(targets, Collections.singletonList(distributionSet), managementUIState,
actionTypeOptionGroupLayout, maintenanceWindowLayout, deploymentManagement, getNotification(),
getEventBus(), getI18n(), this);
}
}
}
}, createAssignmentTab(actionTypeOptionGroupLayout, maintenanceWindowLayout, saveButtonToggle(), getI18n(),
uiProperties), UIComponentIdProvider.DIST_SET_TO_TARGET_ASSIGNMENT_CONFIRM_ID);
private void openConfirmationWindowForAssignment(final String distributionNameToAssign,
final List<Target> targetDetailsList) {
final String confirmQuestion = createConfirmationQuestionForAssignment(distributionNameToAssign,
targetDetailsList);
createConfirmationWindowForAssignment(confirmQuestion);
UI.getCurrent().addWindow(confirmDialog.getWindow());
confirmDialog.getWindow().bringToFront();
}
private void createConfirmationWindowForAssignment(final String confirmQuestion) {
confirmDialog = new ConfirmationDialog(getI18n().getMessage(CAPTION_ENTITY_ASSIGN_ACTION_CONFIRMBOX),
confirmQuestion, getI18n().getMessage(UIMessageIdProvider.BUTTON_OK),
getI18n().getMessage(UIMessageIdProvider.BUTTON_CANCEL), ok -> {
if (ok && isMaintenanceWindowValid(maintenanceWindowLayout, getNotification())) {
saveAllAssignments(managementUIState, actionTypeOptionGroupLayout, maintenanceWindowLayout,
deploymentManagement, getNotification(), getEventBus(), getI18n(), this);
} else {
managementUIState.getAssignedList().clear();
}
}, createAssignmentTab(actionTypeOptionGroupLayout, maintenanceWindowLayout, saveButtonToggle(),
getI18n(), uiProperties),
UIComponentIdProvider.DIST_SET_TO_TARGET_ASSIGNMENT_CONFIRM_ID);
}
private Consumer<Boolean> saveButtonToggle() {
return isEnabled -> confirmDialog.getOkButton().setEnabled(isEnabled);
}
private String createConfirmationQuestionForAssignment(final String distributionNameToAssign,
final List<Target> targetDetailsList) {
if (targetDetailsList.size() == 1) {
return getI18n().getMessage(MESSAGE_CONFIRM_ASSIGN_ENTITY, distributionNameToAssign, "target",
targetDetailsList.get(0).getName());
} else {
return getI18n().getMessage(MESSAGE_CONFIRM_ASSIGN_MULTIPLE_ENTITIES, targetDetailsList.size(), "targets",
distributionNameToAssign);
private String getAssignmentConfirmationMessage(final DistributionSet distributionSet, final List<Target> targets) {
final String distributionName = distributionSet.getName();
final int targetCount = targets.size();
if (targetCount > 1) {
return getI18n().getMessage(MESSAGE_CONFIRM_ASSIGN_MULTIPLE_ENTITIES, targetCount, "targets",
distributionName);
}
return getI18n().getMessage(MESSAGE_CONFIRM_ASSIGN_ENTITY, distributionName, "target",
targets.get(0).getName());
}
@Override
@@ -516,15 +493,6 @@ public class DistributionTable extends AbstractNamedVersionTable<DistributionSet
return false;
}
private String getPendingActionMessage(final String message, final String controllerId,
final String distNameVersion) {
String pendActionMsg = getI18n().getMessage("message.target.assigned.pending");
if (null == message) {
pendActionMsg = getI18n().getMessage("message.dist.pending.action", controllerId, distNameVersion);
}
return pendActionMsg;
}
private void updateDistributionInTable(final DistributionSet editedDs) {
final Item item = getContainerDataSource().getItem(editedDs.getId());
if (item == null) {
@@ -768,4 +736,4 @@ public class DistributionTable extends AbstractNamedVersionTable<DistributionSet
return "";
}
}
}

View File

@@ -16,6 +16,7 @@ import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TargetTagManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.UiProperties;
import org.eclipse.hawkbit.ui.common.table.AbstractTableLayout;
@@ -43,11 +44,11 @@ public class DistributionTableLayout extends AbstractTableLayout<DistributionTab
final UINotification notification, final DistributionSetTagManagement distributionSetTagManagement,
final TargetTagManagement targetTagManagement, final SystemManagement systemManagement,
final TargetManagement targetManagement, final DeploymentManagement deploymentManagement,
final UiProperties uiProperties) {
final TenantConfigurationManagement configManagement, final UiProperties uiProperties) {
final DistributionAddUpdateWindowLayout distributionAddUpdateWindowLayout = new DistributionAddUpdateWindowLayout(
i18n, notification, eventBus, distributionSetManagement, distributionSetTypeManagement,
systemManagement, entityFactory, null);
systemManagement, entityFactory, null, configManagement);
final DsMetadataPopupLayout dsMetadataPopupLayout = new DsMetadataPopupLayout(i18n, notification, eventBus,
distributionSetManagement, entityFactory, permissionChecker);
@@ -60,7 +61,7 @@ public class DistributionTableLayout extends AbstractTableLayout<DistributionTab
distributionTable,
new DistributionDetails(i18n, eventBus, permissionChecker, managementUIState, distributionSetManagement,
dsMetadataPopupLayout, notification, distributionSetTagManagement,
distributionAddUpdateWindowLayout));
distributionAddUpdateWindowLayout, configManagement));
}
public DistributionTable getDistributionTable() {

View File

@@ -10,9 +10,7 @@ package org.eclipse.hawkbit.ui.management.state;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
@@ -40,8 +38,6 @@ public class ManagementUIState implements ManagementEntityState, Serializable {
private final TargetTableFilters targetTableFilters;
private final Map<TargetIdName, DistributionSetIdName> assignedList = new HashMap<>();
private final Set<DistributionSetIdName> deletedDistributionList = new HashSet<>();
private final Set<TargetIdName> deletedTargetList = new HashSet<>();
@@ -137,10 +133,6 @@ public class ManagementUIState implements ManagementEntityState, Serializable {
return distributionTableFilters;
}
public Map<TargetIdName, DistributionSetIdName> getAssignedList() {
return assignedList;
}
public Set<DistributionSetIdName> getDeletedDistributionList() {
return deletedDistributionList;
}

View File

@@ -33,6 +33,7 @@ import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.FilterParams;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TargetTagManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.event.remote.entity.RemoteEntityEvent;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Tag;
@@ -40,6 +41,7 @@ import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.UiProperties;
import org.eclipse.hawkbit.ui.common.ConfirmationDialog;
@@ -115,6 +117,8 @@ public class TargetTable extends AbstractTable<Target> {
private static final int PROPERTY_DEPT = 3;
private static final String MESSAGE_ASSIGN_TARGET_TO_MULTIPLE_DISTRIBUTIONS = "message.confirm.assign.multiple.entities.multiple.distributions";
private final transient TargetManagement targetManagement;
private final transient DistributionSetManagement distributionSetManagement;
@@ -123,6 +127,8 @@ public class TargetTable extends AbstractTable<Target> {
private final transient DeploymentManagement deploymentManagement;
private final transient TenantConfigurationManagement configManagement;
private final ManagementViewClientCriterion managementViewClientCriterion;
private final ManagementUIState managementUIState;
@@ -143,7 +149,8 @@ public class TargetTable extends AbstractTable<Target> {
final TargetManagement targetManagement, final ManagementUIState managementUIState,
final SpPermissionChecker permChecker, final ManagementViewClientCriterion managementViewClientCriterion,
final DistributionSetManagement distributionSetManagement, final TargetTagManagement tagManagement,
final DeploymentManagement deploymentManagement, final UiProperties uiProperties) {
final DeploymentManagement deploymentManagement, final TenantConfigurationManagement configManagement,
final UiProperties uiProperties) {
super(eventBus, i18n, notification, permChecker);
this.targetManagement = targetManagement;
this.managementViewClientCriterion = managementViewClientCriterion;
@@ -151,6 +158,7 @@ public class TargetTable extends AbstractTable<Target> {
this.distributionSetManagement = distributionSetManagement;
this.tagManagement = tagManagement;
this.deploymentManagement = deploymentManagement;
this.configManagement = configManagement;
this.uiProperties = uiProperties;
this.actionTypeOptionGroupLayout = new ActionTypeOptionGroupAssignmentLayout(i18n);
this.maintenanceWindowLayout = new MaintenanceWindowLayout(i18n);
@@ -355,23 +363,18 @@ public class TargetTable extends AbstractTable<Target> {
private Map<String, Object> prepareQueryConfigFilters() {
final Map<String, Object> queryConfig = Maps.newHashMapWithExpectedSize(7);
managementUIState.getTargetTableFilters().getSearchText().ifPresent(
managementUIState.getTargetTableFilters().getSearchText()
.ifPresent(value -> queryConfig.put(SPUIDefinitions.FILTER_BY_TEXT, value));
managementUIState.getTargetTableFilters().getDistributionSet()
.ifPresent(value -> queryConfig.put(SPUIDefinitions.FILTER_BY_DISTRIBUTION, value.getId()));
managementUIState.getTargetTableFilters().getPinnedDistId()
.ifPresent(value -> queryConfig.put(SPUIDefinitions.ORDER_BY_DISTRIBUTION, value));
managementUIState.getTargetTableFilters().getTargetFilterQuery()
.ifPresent(value -> queryConfig.put(SPUIDefinitions.FILTER_BY_TARGET_FILTER_QUERY, value));
value -> queryConfig.put(SPUIDefinitions.FILTER_BY_TEXT, value));
managementUIState.getTargetTableFilters().getDistributionSet().ifPresent(
value -> queryConfig.put(SPUIDefinitions.FILTER_BY_DISTRIBUTION, value.getId()));
managementUIState.getTargetTableFilters().getPinnedDistId().ifPresent(
value -> queryConfig.put(SPUIDefinitions.ORDER_BY_DISTRIBUTION, value));
managementUIState.getTargetTableFilters().getTargetFilterQuery().ifPresent(
value -> queryConfig.put(SPUIDefinitions.FILTER_BY_TARGET_FILTER_QUERY, value));
queryConfig.put(SPUIDefinitions.FILTER_BY_NO_TAG, managementUIState.getTargetTableFilters().isNoTagSelected());
if (
isFilteredByTags()) {
if (isFilteredByTags()) {
final List<String> list = new ArrayList<>(managementUIState.getTargetTableFilters().getClickedTargetTags());
queryConfig.put(SPUIDefinitions.FILTER_BY_TAG, list.toArray(new String[list.size()]));
}
@@ -853,13 +856,17 @@ public class TargetTable extends AbstractTable<Target> {
private void assignDsToTarget(final DragAndDropEvent event) {
final TableTransferable transferable = (TableTransferable) event.getTransferable();
final AbstractTable<?> source = (AbstractTable<?>) transferable.getSourceComponent();
final Set<Long> ids = source.getSelectedEntitiesByTransferable(transferable);
// only one distribution can be assigned to a target
final Long idToSelect = ids.iterator().next();
selectDraggedEntities(source, new HashSet<>(Arrays.asList(idToSelect)));
final Set<Long> dsIds = filterDistributionSetsToAssign(source.getSelectedEntitiesByTransferable(transferable));
if (dsIds.isEmpty()) {
getNotification().displayWarning(getI18n().getMessage(DISTRIBUTIONSET_NOT_EXISTS));
return;
}
selectDraggedEntities(source, dsIds);
final AbstractSelectTargetDetails dropData = (AbstractSelectTargetDetails) event.getTargetDetails();
final Object targetItemId = dropData.getItemIdOver();
LOG.debug("Adding a log to check if targetItemId is null : {} ", targetItemId);
LOG.debug("Drop target: {} ", targetItemId);
if (targetItemId == null) {
getNotification().displayWarning(getI18n().getMessage(TARGETS_NOT_EXISTS, ""));
return;
@@ -873,45 +880,57 @@ public class TargetTable extends AbstractTable<Target> {
return;
}
final TargetIdName createTargetIdName = new TargetIdName(target.get());
final List<DistributionSet> findDistributionSetById = distributionSetManagement
.get(new HashSet<>(Arrays.asList(idToSelect)));
if (findDistributionSetById.isEmpty()) {
final List<DistributionSet> distributionSets = distributionSetManagement.get(dsIds);
if (distributionSets.isEmpty()) {
getNotification().displayWarning(getI18n().getMessage(DISTRIBUTIONSET_NOT_EXISTS));
return;
}
final DistributionSet distributionSetToAssign = findDistributionSetById.get(0);
addNewTargetToAssignmentList(createTargetIdName, distributionSetToAssign);
openConfirmationWindowForAssignment(distributionSetToAssign.getName(), createTargetIdName.getTargetName());
openConfirmationWindowForAssignments(target.get(), distributionSets);
}
private void openConfirmationWindowForAssignment(final String distributionNameToAssign, final String targetName) {
confirmDialog = new ConfirmationDialog(getI18n().getMessage(CAPTION_ENTITY_ASSIGN_ACTION_CONFIRMBOX),
getI18n().getMessage(MESSAGE_CONFIRM_ASSIGN_ENTITY, distributionNameToAssign, "target", targetName),
getI18n().getMessage(UIMessageIdProvider.BUTTON_OK),
getI18n().getMessage(UIMessageIdProvider.BUTTON_CANCEL), ok -> {
if (ok && isMaintenanceWindowValid(maintenanceWindowLayout, getNotification())) {
saveAllAssignments(managementUIState, actionTypeOptionGroupLayout, maintenanceWindowLayout,
deploymentManagement, getNotification(), getEventBus(), getI18n(), this);
} else {
managementUIState.getAssignedList().clear();
}
}, createAssignmentTab(actionTypeOptionGroupLayout, maintenanceWindowLayout, saveButtonToggle(),
getI18n(), uiProperties),
UIComponentIdProvider.DIST_SET_TO_TARGET_ASSIGNMENT_CONFIRM_ID);
private Set<Long> filterDistributionSetsToAssign(final Set<Long> ids) {
if (ids.isEmpty()) {
return Collections.emptySet();
}
if (isMultiAssignmentsEnabled()) {
return new HashSet<>(ids);
}
return Collections.singleton(ids.iterator().next());
}
private void openConfirmationWindowForAssignments(final Target target,
final List<DistributionSet> distributionSets) {
final String confirmationMessage = getConfirmationMessage(target, distributionSets);
final String caption = getI18n().getMessage(CAPTION_ENTITY_ASSIGN_ACTION_CONFIRMBOX);
final String okLabel = getI18n().getMessage(UIMessageIdProvider.BUTTON_OK);
final String cancelLabel = getI18n().getMessage(UIMessageIdProvider.BUTTON_CANCEL);
confirmDialog = new ConfirmationDialog(caption, confirmationMessage, okLabel, cancelLabel, ok -> {
if (ok && isMaintenanceWindowValid(maintenanceWindowLayout, getNotification())) {
saveAllAssignments(Collections.singletonList(target), distributionSets, managementUIState,
actionTypeOptionGroupLayout, maintenanceWindowLayout, deploymentManagement, getNotification(),
getEventBus(), getI18n(), this);
}
}, createAssignmentTab(actionTypeOptionGroupLayout, maintenanceWindowLayout, saveButtonToggle(), getI18n(),
uiProperties), UIComponentIdProvider.DIST_SET_TO_TARGET_ASSIGNMENT_CONFIRM_ID);
UI.getCurrent().addWindow(confirmDialog.getWindow());
confirmDialog.getWindow().bringToFront();
}
private Consumer<Boolean> saveButtonToggle() {
return isEnabled -> confirmDialog.getOkButton().setEnabled(isEnabled);
private String getConfirmationMessage(final Target target, final List<DistributionSet> distributionSets) {
final String targetName = target.getName();
final int dsCount = distributionSets.size();
if (dsCount > 1) {
return getI18n().getMessage(MESSAGE_ASSIGN_TARGET_TO_MULTIPLE_DISTRIBUTIONS, dsCount, "target", targetName);
}
return getI18n().getMessage(MESSAGE_CONFIRM_ASSIGN_ENTITY, distributionSets.get(0).getName(), "target",
targetName);
}
private void addNewTargetToAssignmentList(final TargetIdName createTargetIdName,
final DistributionSet findDistributionSetAllById) {
final DistributionSetIdName distributionNameId = new DistributionSetIdName(findDistributionSetAllById);
managementUIState.getAssignedList().put(createTargetIdName, distributionNameId);
private Consumer<Boolean> saveButtonToggle() {
return isEnabled -> confirmDialog.getOkButton().setEnabled(isEnabled);
}
@Override
@@ -963,4 +982,11 @@ public class TargetTable extends AbstractTable<Target> {
return "";
}
}
private boolean isMultiAssignmentsEnabled() {
return configManagement
.getConfigurationValue(TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED,
Boolean.class)
.getValue();
}
}

View File

@@ -9,18 +9,22 @@
package org.eclipse.hawkbit.ui.tenantconfiguration;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.ui.UiProperties;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.tenantconfiguration.generic.BooleanConfigurationItem;
import org.eclipse.hawkbit.ui.tenantconfiguration.repository.ActionAutocleanupConfigurationItem;
import org.eclipse.hawkbit.ui.tenantconfiguration.repository.ActionAutocloseConfigurationItem;
import org.eclipse.hawkbit.ui.tenantconfiguration.repository.MultiAssignmentsConfigurationItem;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Link;
import com.vaadin.ui.Panel;
import com.vaadin.ui.VerticalLayout;
@@ -36,21 +40,30 @@ public class RepositoryConfigurationView extends BaseConfigurationView
private final VaadinMessageSource i18n;
private final UiProperties uiProperties;
private final ActionAutocloseConfigurationItem actionAutocloseConfigurationItem;
private final ActionAutocleanupConfigurationItem actionAutocleanupConfigurationItem;
private final MultiAssignmentsConfigurationItem multiAssignmentsConfigurationItem;
private CheckBox actionAutocloseCheckBox;
private CheckBox actionAutocleanupCheckBox;
private CheckBox multiAssignmentsCheckBox;
RepositoryConfigurationView(final VaadinMessageSource i18n,
final TenantConfigurationManagement tenantConfigurationManagement) {
final TenantConfigurationManagement tenantConfigurationManagement, final UiProperties uiProperties) {
this.i18n = i18n;
this.uiProperties = uiProperties;
this.actionAutocloseConfigurationItem = new ActionAutocloseConfigurationItem(tenantConfigurationManagement,
i18n);
this.actionAutocleanupConfigurationItem = new ActionAutocleanupConfigurationItem(tenantConfigurationManagement,
i18n);
this.multiAssignmentsConfigurationItem = new MultiAssignmentsConfigurationItem(tenantConfigurationManagement,
i18n);
init();
}
@@ -70,27 +83,46 @@ public class RepositoryConfigurationView extends BaseConfigurationView
header.addStyleName("config-panel-header");
vLayout.addComponent(header);
final GridLayout gridLayout = new GridLayout(2, 2);
final GridLayout gridLayout = new GridLayout(3, 3);
gridLayout.setSpacing(true);
gridLayout.setImmediate(true);
gridLayout.setColumnExpandRatio(1, 1.0F);
gridLayout.setSizeFull();
final boolean isMultiAssignmentsEnabled = multiAssignmentsConfigurationItem.isConfigEnabled();
actionAutocloseCheckBox = SPUIComponentProvider.getCheckBox("", DIST_CHECKBOX_STYLE, null, false, "");
actionAutocloseCheckBox.setId(UIComponentIdProvider.REPOSITORY_ACTIONS_AUTOCLOSE_CHECKBOX);
actionAutocloseCheckBox.setEnabled(!isMultiAssignmentsEnabled);
actionAutocloseConfigurationItem.setEnabled(!isMultiAssignmentsEnabled);
actionAutocloseCheckBox.setValue(actionAutocloseConfigurationItem.isConfigEnabled());
actionAutocloseCheckBox.addValueChangeListener(this);
actionAutocloseConfigurationItem.addChangeListener(this);
gridLayout.addComponent(actionAutocloseCheckBox, 0, 0);
gridLayout.addComponent(actionAutocloseConfigurationItem, 1, 0);
multiAssignmentsCheckBox = SPUIComponentProvider.getCheckBox("", DIST_CHECKBOX_STYLE, null, false, "");
multiAssignmentsCheckBox.setId(UIComponentIdProvider.REPOSITORY_MULTI_ASSIGNMENTS_CHECKBOX);
multiAssignmentsCheckBox.setValue(multiAssignmentsConfigurationItem.isConfigEnabled());
multiAssignmentsCheckBox.addValueChangeListener(this);
multiAssignmentsCheckBox.setEnabled(!isMultiAssignmentsEnabled);
multiAssignmentsConfigurationItem.setEnabled(!isMultiAssignmentsEnabled);
multiAssignmentsConfigurationItem.addChangeListener(this);
gridLayout.addComponent(multiAssignmentsCheckBox, 0, 1);
gridLayout.addComponent(multiAssignmentsConfigurationItem, 1, 1);
actionAutocleanupCheckBox = SPUIComponentProvider.getCheckBox("", DIST_CHECKBOX_STYLE, null, false, "");
actionAutocleanupCheckBox.setId(UIComponentIdProvider.REPOSITORY_ACTIONS_AUTOCLEANUP_CHECKBOX);
actionAutocleanupCheckBox.setValue(actionAutocleanupConfigurationItem.isConfigEnabled());
actionAutocleanupCheckBox.addValueChangeListener(this);
actionAutocleanupConfigurationItem.addChangeListener(this);
gridLayout.addComponent(actionAutocleanupCheckBox, 0, 1);
gridLayout.addComponent(actionAutocleanupConfigurationItem, 1, 1);
gridLayout.addComponent(actionAutocleanupCheckBox, 0, 2);
gridLayout.addComponent(actionAutocleanupConfigurationItem, 1, 2);
final Link linkToProvisioningHelp = SPUIComponentProvider.getHelpLink(i18n,
uiProperties.getLinks().getDocumentation().getProvisioningStateMachine());
gridLayout.addComponent(linkToProvisioningHelp, 2, 2);
gridLayout.setComponentAlignment(linkToProvisioningHelp, Alignment.BOTTOM_RIGHT);
vLayout.addComponent(gridLayout);
rootPanel.setContent(vLayout);
@@ -101,18 +133,29 @@ public class RepositoryConfigurationView extends BaseConfigurationView
public void save() {
actionAutocloseConfigurationItem.save();
actionAutocleanupConfigurationItem.save();
multiAssignmentsConfigurationItem.save();
final boolean isMultiAssignmentsEnabled = multiAssignmentsConfigurationItem.isConfigEnabled();
multiAssignmentsCheckBox.setEnabled(!isMultiAssignmentsEnabled);
multiAssignmentsConfigurationItem.setEnabled(!isMultiAssignmentsEnabled);
}
@Override
public boolean isUserInputValid() {
return actionAutocloseConfigurationItem.isUserInputValid()
&& actionAutocleanupConfigurationItem.isUserInputValid();
&& actionAutocleanupConfigurationItem.isUserInputValid()
&& multiAssignmentsConfigurationItem.isUserInputValid();
}
@Override
public void undo() {
multiAssignmentsConfigurationItem.undo();
final boolean isMultiAssignmentsEnabled = multiAssignmentsConfigurationItem.isConfigEnabled();
multiAssignmentsCheckBox.setValue(isMultiAssignmentsEnabled);
actionAutocloseConfigurationItem.undo();
actionAutocloseCheckBox.setValue(actionAutocloseConfigurationItem.isConfigEnabled());
actionAutocloseCheckBox.setEnabled(!isMultiAssignmentsEnabled);
actionAutocloseConfigurationItem.setEnabled(!isMultiAssignmentsEnabled);
actionAutocleanupConfigurationItem.undo();
actionAutocleanupCheckBox.setValue(actionAutocleanupConfigurationItem.isConfigEnabled());
}
@@ -138,6 +181,10 @@ public class RepositoryConfigurationView extends BaseConfigurationView
configurationItem = actionAutocloseConfigurationItem;
} else if (actionAutocleanupCheckBox.equals(checkBox)) {
configurationItem = actionAutocleanupConfigurationItem;
} else if (multiAssignmentsCheckBox.equals(checkBox)) {
configurationItem = multiAssignmentsConfigurationItem;
actionAutocloseCheckBox.setEnabled(!checkBox.getValue());
actionAutocloseConfigurationItem.setEnabled(!checkBox.getValue());
} else {
return;
}

View File

@@ -18,7 +18,7 @@ import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.vaadin.data.Property;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Link;
import com.vaadin.ui.Panel;
@@ -61,24 +61,26 @@ public class RolloutConfigurationView extends BaseConfigurationView
header.addStyleName("config-panel-header");
vLayout.addComponent(header);
final HorizontalLayout hLayout = new HorizontalLayout();
hLayout.setSpacing(true);
hLayout.setImmediate(true);
final GridLayout gridLayout = new GridLayout(3, 1);
gridLayout.setSpacing(true);
gridLayout.setImmediate(true);
gridLayout.setColumnExpandRatio(1, 1.0F);
gridLayout.setSizeFull();
approvalCheckbox = SPUIComponentProvider.getCheckBox("", "", null, false, "");
approvalCheckbox.setId(UIComponentIdProvider.ROLLOUT_APPROVAL_ENABLED_CHECKBOX);
approvalCheckbox.setValue(approvalConfigurationItem.isConfigEnabled());
approvalCheckbox.addValueChangeListener(this);
approvalConfigurationItem.addChangeListener(this);
hLayout.addComponent(approvalCheckbox);
hLayout.addComponent(approvalConfigurationItem);
gridLayout.addComponent(approvalCheckbox, 0, 0);
gridLayout.addComponent(approvalConfigurationItem, 1, 0);
final Link linkToApprovalHelp = SPUIComponentProvider.getHelpLink(i18n,
uiProperties.getLinks().getDocumentation().getRollout());
hLayout.addComponent(linkToApprovalHelp);
hLayout.setComponentAlignment(linkToApprovalHelp, Alignment.BOTTOM_RIGHT);
gridLayout.addComponent(linkToApprovalHelp, 2, 0);
gridLayout.setComponentAlignment(linkToApprovalHelp, Alignment.BOTTOM_RIGHT);
vLayout.addComponent(hLayout);
vLayout.addComponent(gridLayout);
rootPanel.setContent(vLayout);
setCompositionRoot(rootPanel);
}

View File

@@ -91,7 +91,8 @@ public class TenantConfigurationDashboardView extends CustomComponent implements
securityTokenGenerator, uiProperties);
this.pollingConfigurationView = new PollingConfigurationView(i18n, controllerPollProperties,
tenantConfigurationManagement);
this.repositoryConfigurationView = new RepositoryConfigurationView(i18n, tenantConfigurationManagement);
this.repositoryConfigurationView = new RepositoryConfigurationView(i18n, tenantConfigurationManagement,
uiProperties);
this.rolloutConfigurationView = new RolloutConfigurationView(i18n, tenantConfigurationManagement, uiProperties);
this.i18n = i18n;

View File

@@ -0,0 +1,111 @@
/**
* Copyright (c) 2019 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ui.tenantconfiguration.repository;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
import org.eclipse.hawkbit.ui.common.builder.LabelBuilder;
import org.eclipse.hawkbit.ui.tenantconfiguration.generic.AbstractBooleanTenantConfigurationItem;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;
/**
* This class represents the UI item for enabling /disabling the
* Multi-Assignments feature as part of the repository configuration view.
*/
public class MultiAssignmentsConfigurationItem extends AbstractBooleanTenantConfigurationItem {
private static final long serialVersionUID = 1L;
private static final String MSG_KEY_CHECKBOX = "label.configuration.repository.multiassignments";
private static final String MSG_KEY_NOTICE = "label.configuration.repository.multiassignments.notice";
private final VerticalLayout container;
private final VaadinMessageSource i18n;
private boolean isMultiAssignmentsEnabled;
private boolean multiAssignmentsEnabledChanged;
/**
* Constructor.
*
* @param tenantConfigurationManagement
* to read /write tenant-specific configuration properties
* @param i18n
* to obtain localized strings
*/
public MultiAssignmentsConfigurationItem(final TenantConfigurationManagement tenantConfigurationManagement,
final VaadinMessageSource i18n) {
super(TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED, tenantConfigurationManagement, i18n);
this.i18n = i18n;
super.init(MSG_KEY_CHECKBOX);
isMultiAssignmentsEnabled = isConfigEnabled();
container = new VerticalLayout();
container.setImmediate(true);
container.addComponent(newLabel(MSG_KEY_NOTICE));
if (isMultiAssignmentsEnabled) {
setSettingsVisible(isMultiAssignmentsEnabled);
}
}
@Override
public void configEnable() {
if (!isMultiAssignmentsEnabled) {
multiAssignmentsEnabledChanged = true;
}
isMultiAssignmentsEnabled = true;
setSettingsVisible(true);
}
@Override
public void configDisable() {
if (isMultiAssignmentsEnabled) {
multiAssignmentsEnabledChanged = true;
}
isMultiAssignmentsEnabled = false;
setSettingsVisible(false);
}
@Override
public void save() {
if (!multiAssignmentsEnabledChanged) {
return;
}
getTenantConfigurationManagement().addOrUpdateConfiguration(getConfigurationKey(), isMultiAssignmentsEnabled);
}
@Override
public void undo() {
multiAssignmentsEnabledChanged = false;
isMultiAssignmentsEnabled = getTenantConfigurationManagement()
.getConfigurationValue(getConfigurationKey(), Boolean.class).getValue();
}
private void setSettingsVisible(final boolean visible) {
if (visible) {
addComponent(container);
} else {
removeComponent(container);
}
}
private Label newLabel(final String msgKey) {
final Label label = new LabelBuilder().name(i18n.getMessage(msgKey)).buildLabel();
label.setWidthUndefined();
return label;
}
}

View File

@@ -608,6 +608,11 @@ public final class UIComponentIdProvider {
*/
public static final String DETAILS_TYPE_LABEL_ID = "details.type";
/**
* Table details Required Migration Step label id.
*/
public static final String DETAILS_REQUIRED_MIGRATION_STEP_LABEL_ID = "details.required.migration.step";
/**
* Id of show filter button in software module table.
*/
@@ -1154,6 +1159,11 @@ public final class UIComponentIdProvider {
*/
public static final String ROLLOUT_POPUP_ID = "add.update.rollout.popup";
/**
* Create popup id.
*/
public static final String CREATE_POPUP_ID = "create.popup.id";
/**
* DistributionSet table details tab id in Distributions .
*/
@@ -1240,6 +1250,12 @@ public final class UIComponentIdProvider {
*/
public static final String REPOSITORY_ACTIONS_AUTOCLEANUP_CHECKBOX = "repositoryactionsautocleanupcheckbox";
/**
* Configuration checkbox for
* {@link TenantConfigurationKey#MULTI_ASSIGNMENTS_ENABLED}.
*/
public static final String REPOSITORY_MULTI_ASSIGNMENTS_CHECKBOX = "repositorymultiassignmentscheckbox";
/**
* Configuration checkbox for
* {@link TenantConfigurationKey#ROLLOUT_APPROVAL_ENABLED}
@@ -1279,4 +1295,4 @@ public final class UIComponentIdProvider {
private UIComponentIdProvider() {
}
}
}

View File

@@ -245,6 +245,8 @@ label.configuration.repository.autocleanup.action.suffix = day(s)
label.configuration.repository.autocleanup.action.expiry.invalid = The specified number of days is invalid. Please enter a positive integer value between 1 and 1000.
label.configuration.anonymous.download = Allow targets to download artifacts without security credentials
label.configuration.repository.autocleanup.action.notice = Warning: The actions are deleted from the repository and cannot be restored
label.configuration.repository.multiassignments = Allow parallel execution of multiple distribution set assignments and rollouts
label.configuration.repository.multiassignments.notice = Warning: Once this assignment behavior is active, it cannot be deactivated.
label.unsupported.browser.ie = Sorry! Your current browser is not supported. Please use Internet Explorer 11 and above
label.auto.assign.description = When an auto assign distribution set is selected, it will be automatically assigned to all targets that match the target filter.
label.auto.assign.enable = Enable auto assignment
@@ -711,6 +713,7 @@ message.confirm.delete.entity = Are you sure you want to delete {0} {1}{2}?
caption.entity.assign.action.confirmbox = Confirm Assignment
message.confirm.assign.entity = Are you sure you want to assign distribution {0} to {1} {2}?
message.confirm.assign.multiple.entities = Are you sure you want to assign {0} {1} to distribution {2}?
message.confirm.assign.multiple.entities.multiple.distributions = Are you sure you want to assign {0} distributions to {1} {2}?
# character descriptions
character.whitespace = whitespace