diff --git a/docs/content/concepts/rollout-management.md b/docs/content/concepts/rollout-management.md
index fe1cb2eed..a809aeaac 100644
--- a/docs/content/concepts/rollout-management.md
+++ b/docs/content/concepts/rollout-management.md
@@ -8,6 +8,7 @@ Software update operations in large scale IoT scenarios with hundreds of thousan
That includes:
+
- _Technical Scalability_ by means of horizontal scale of the hawkBit server cluster in the cloud.
- _Global_ artifact _content delivery_ capacities.
- _Functional Scalability_ by means of:
@@ -20,6 +21,7 @@ That includes:
Eclipse hawkBit sees these capabilities under the term Rollout Management.
The following capabilities are currently supported by the _Rollout Management_:
+
- Create, update and start of rollouts.
- Selection of targets as input for the rollout based on _target filter_ functionality.
- Selection of a _DistributionSet_.
diff --git a/docs/content/ui.md b/docs/content/ui.md
index caf243a62..d655007a2 100644
--- a/docs/content/ui.md
+++ b/docs/content/ui.md
@@ -31,12 +31,12 @@ Target status overview, target management and manual deployments.
- Start roll out by drag and drop targets on a DS.
- Target list supports CTRL-A for "select all".
-- Delete sets, tags or targets by dragging them on delete icon.
- Select _Target_ to see _Action_ History.
- Bulk target upload: create bulk targets by upload.
-
+- DS invalidation allows to mark broken updates and avoid the distribution of such
Hints for bulk upload:
+
- Expected file type : csv.
- Expected file format : Each line with two values (ControllerID,Target Name). ControllerID is mandatory.
- Example:
@@ -47,6 +47,20 @@ Controller_id_2,targetName2

+### Distribution set invalidation
+
+It is possible to mark broken updates and avoid the distribution of such by invalidating the corresponding distribution
+set in the Distributions list of the Deployment view.
+
+Invalidating a distribution set removes all auto-assignments that reference this distribution set. Optionally, all
+rollouts that reference the distribution set can be stopped and existing update actions are removed, either by a
+soft-cancel or a forced-cancel.
+
+Invalidated distribution sets cannot be valid again, but remain invalid. They cannot be assigned to targets, neither
+through a rollout, auto-assignment nor a single assignment.
+
+
+
## Distribution Management
### Purpose
@@ -148,4 +162,4 @@ In order to activate the auto-assignment, one should first click on _Auto assign
As long as the auto-assignment stays active, the scheduler will try to assign selected distribution set to corresponding custom filter targets, that have never seen it before.
-
\ No newline at end of file
+
diff --git a/docs/static/images/ui/artifact_mgmt.png b/docs/static/images/ui/artifact_mgmt.png
old mode 100644
new mode 100755
index aec5b8655..86cf99e8b
Binary files a/docs/static/images/ui/artifact_mgmt.png and b/docs/static/images/ui/artifact_mgmt.png differ
diff --git a/docs/static/images/ui/deployment_ds_invalidation.png b/docs/static/images/ui/deployment_ds_invalidation.png
new file mode 100755
index 000000000..be545943f
Binary files /dev/null and b/docs/static/images/ui/deployment_ds_invalidation.png differ
diff --git a/docs/static/images/ui/deployment_mgmt.png b/docs/static/images/ui/deployment_mgmt.png
old mode 100644
new mode 100755
index 8546b07eb..dd1316dd9
Binary files a/docs/static/images/ui/deployment_mgmt.png and b/docs/static/images/ui/deployment_mgmt.png differ
diff --git a/docs/static/images/ui/distribution_mgmt.png b/docs/static/images/ui/distribution_mgmt.png
old mode 100644
new mode 100755
index 287301bc8..1131cb97c
Binary files a/docs/static/images/ui/distribution_mgmt.png and b/docs/static/images/ui/distribution_mgmt.png differ
diff --git a/docs/static/images/ui/rollout_groups.png b/docs/static/images/ui/rollout_groups.png
old mode 100644
new mode 100755
index 972b75bfb..bd79c4342
Binary files a/docs/static/images/ui/rollout_groups.png and b/docs/static/images/ui/rollout_groups.png differ
diff --git a/docs/static/images/ui/rollout_mgmt.png b/docs/static/images/ui/rollout_mgmt.png
old mode 100644
new mode 100755
index 23f60ec0d..0ddfb50c0
Binary files a/docs/static/images/ui/rollout_mgmt.png and b/docs/static/images/ui/rollout_mgmt.png differ
diff --git a/docs/static/images/ui/target_filter.png b/docs/static/images/ui/target_filter.png
old mode 100644
new mode 100755
index a6bd8a529..fa6645f34
Binary files a/docs/static/images/ui/target_filter.png and b/docs/static/images/ui/target_filter.png differ
diff --git a/docs/static/images/ui/target_filter_auto_assignment.png b/docs/static/images/ui/target_filter_auto_assignment.png
old mode 100644
new mode 100755
index a6a5c0168..0076211f0
Binary files a/docs/static/images/ui/target_filter_auto_assignment.png and b/docs/static/images/ui/target_filter_auto_assignment.png differ
diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetInvalidation.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetInvalidation.java
index 398766126..91bf45150 100644
--- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetInvalidation.java
+++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetInvalidation.java
@@ -65,7 +65,7 @@ public class DistributionSetInvalidation {
* distribution set
*/
public enum CancelationType {
- FORCE, SOFT, NONE;
+ FORCE, SOFT, NONE
}
}
diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetInvalidationCount.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetInvalidationCount.java
index d0bdf37ac..bdd89e9c6 100644
--- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetInvalidationCount.java
+++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetInvalidationCount.java
@@ -38,4 +38,4 @@ public class DistributionSetInvalidationCount {
return actionCount;
}
-}
\ No newline at end of file
+}
diff --git a/hawkbit-rest/hawkbit-rest-docs/src/main/asciidoc/distributionsets-api-guide.adoc b/hawkbit-rest/hawkbit-rest-docs/src/main/asciidoc/distributionsets-api-guide.adoc
index c04e00011..b0c39c6da 100644
--- a/hawkbit-rest/hawkbit-rest-docs/src/main/asciidoc/distributionsets-api-guide.adoc
+++ b/hawkbit-rest/hawkbit-rest-docs/src/main/asciidoc/distributionsets-api-guide.adoc
@@ -835,7 +835,12 @@ include::../errors/429.adoc[]
=== Implementation Notes
-Invalidate a distribution set. Once a distribution set is invalidated, it can not be valid again. An invalidated distribution set cannot be assigned to targets anymore. The distribution set that is going to be invalidated will be removed from all auto assignments. Furthermore, the user can choose to cancel all rollouts and (force) cancel all actions connected to this distribution set. Required permission: UPDATE_REPOSITORY
+Invalidate a distribution set.
+Once a distribution set is invalidated, it can not be valid again.
+An invalidated distribution set cannot be assigned to targets anymore.
+The distribution set that is going to be invalidated will be removed from all auto assignments.
+Furthermore, the user can choose to cancel all rollouts and (force) cancel all actions connected to this distribution set.
+Required permission: UPDATE_REPOSITORY, UPDATE_TARGET
=== Invalidate a distribution set
diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/SpPermissionChecker.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/SpPermissionChecker.java
index 9093c7d2d..db81ebf28 100644
--- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/SpPermissionChecker.java
+++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/SpPermissionChecker.java
@@ -168,4 +168,22 @@ public class SpPermissionChecker implements Serializable {
public boolean hasRolloutApprovalPermission() {
return hasRolloutReadPermission() && permissionService.hasPermission(SpPermission.APPROVE_ROLLOUT);
}
+
+ /**
+ *
+ * @return true if auto assignment can be added/updated to target filter
+ */
+ public boolean hasAutoAssignmentUpdatePermission() {
+ return hasUpdateTargetPermission() && hasReadRepositoryPermission();
+ }
+
+ /**
+ *
+ * @return true if default invalidation of distribution set is
+ * allowed
+ */
+ public boolean hasDistributionSetInvalidatePermission() {
+ return hasUpdateRepositoryPermission() && hasUpdateTargetPermission();
+ }
+
}
diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/UiProperties.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/UiProperties.java
index c342b077f..cc0520bae 100644
--- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/UiProperties.java
+++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/UiProperties.java
@@ -279,8 +279,16 @@ public class UiProperties implements Serializable {
*/
private String rolloutView = "";
+ /**
+ * Link to documentation of state machine
+ */
private String provisioningStateMachine = "";
+ /**
+ * Link to documentation of distribution set invalidation
+ */
+ private String distributionSetInvalidation = "";
+
/**
* @return Link to documentation of deployment view
*/
@@ -352,6 +360,13 @@ public class UiProperties implements Serializable {
return provisioningStateMachine;
}
+ /**
+ * @return Link to documentation of distribution set invalidation
+ */
+ public String getDistributionSetInvalidation() {
+ return distributionSetInvalidation;
+ }
+
public void setDeploymentView(final String deploymentView) {
this.deploymentView = deploymentView;
}
@@ -414,6 +429,15 @@ public class UiProperties implements Serializable {
this.provisioningStateMachine = provisioningStateMachine;
}
+ /**
+ * Sets the link to the distribution set invalidation documentation
+ *
+ * @param distributionSetInvalidation
+ * Link
+ */
+ public void setDistributionSetInvalidation(String distributionSetInvalidation) {
+ this.distributionSetInvalidation = distributionSetInvalidation;
+ }
}
private final Documentation documentation = new Documentation();
diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/DragAndDropSupport.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/DragAndDropSupport.java
index 2ff4f8548..2b444f487 100644
--- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/DragAndDropSupport.java
+++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/DragAndDropSupport.java
@@ -229,8 +229,8 @@ public class DragAndDropSupport {
final List requiredPermissions = assignmentStrategy.getMissingPermissionsForDrop();
if (!CollectionUtils.isEmpty(requiredPermissions)) {
- notification
- .displayValidationError(i18n.getMessage("message.permission.insufficient", requiredPermissions));
+ notification.displayValidationError(
+ i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_PERMISSION_INSUFFICIENT, requiredPermissions));
return false;
}
diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterGrid.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterGrid.java
index a4408c20a..3f377c2d5 100644
--- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterGrid.java
+++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterGrid.java
@@ -183,7 +183,7 @@ public class TargetFilterGrid extends AbstractGrid onClickOfAutoAssignmentLink(targetFilter));
final String description = i18n.getMessage(UIMessageIdProvider.BUTTON_AUTO_ASSIGNMENT_DESCRIPTION);
@@ -202,8 +202,8 @@ public class TargetFilterGrid extends AbstractGrid {
DsManagementFilterParams::new, getSelectionSupport()::deselectAll));
initFilterMappings();
getFilterSupport().setFilter(new DsManagementFilterParams());
- this.invalidateDistributionSetSupport = new InvalidateDistributionSetSupport(this, i18n, notification,
- dsInvalidationManagement);
+ this.invalidateDistributionSetSupport = new InvalidateDistributionSetSupport(this, i18n, uiProperties,
+ notification, permissionChecker, dsInvalidationManagement);
initStyleGenerator();
init();
@@ -239,7 +239,7 @@ public class DistributionGrid extends AbstractDsGrid {
i18n, clickEvent -> invalidateDistributionSetSupport.openConsequencesWindowOnInvalidateAction(ds),
VaadinIcons.BAN, UIMessageIdProvider.TOOLTIP_INVALIDATE_DISTRIBUTIONSET,
SPUIStyleDefinitions.STATUS_ICON_NEUTRAL, UIComponentIdProvider.DIST_INVALIDATE_ICON + "." + ds.getId(),
- ds.getIsValid());
+ ds.getIsValid() && permissionChecker.hasDistributionSetInvalidatePermission());
return GridComponentBuilder.addIconColumn(this, buttonProvider, DS_INVALIDATE_BUTTON_ID, null);
}
diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/InvalidateDistributionSetSupport.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/InvalidateDistributionSetSupport.java
index bfa7a8d24..37de27e6c 100644
--- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/InvalidateDistributionSetSupport.java
+++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/InvalidateDistributionSetSupport.java
@@ -12,10 +12,13 @@ import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
+import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.repository.DistributionSetInvalidationManagement;
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation;
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation.CancelationType;
import org.eclipse.hawkbit.repository.model.DistributionSetInvalidationCount;
+import org.eclipse.hawkbit.ui.SpPermissionChecker;
+import org.eclipse.hawkbit.ui.UiProperties;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSet;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.UINotification;
@@ -35,7 +38,10 @@ public class InvalidateDistributionSetSupport {
private static final Logger LOG = LoggerFactory.getLogger(InvalidateDistributionSetSupport.class);
private final VaadinMessageSource i18n;
+ private final UiProperties uiProperties;
private final UINotification notification;
+ private final SpPermissionChecker permissionChecker;
+
private final DistributionGrid grid;
private final DistributionSetInvalidationManagement dsInvalidationManagement;
@@ -55,10 +61,14 @@ public class InvalidateDistributionSetSupport {
* {@link DistributionSetInvalidationManagement}
*/
public InvalidateDistributionSetSupport(final DistributionGrid grid, final VaadinMessageSource i18n,
- final UINotification notification, final DistributionSetInvalidationManagement dsInvalidationManagement) {
+ final UiProperties uiProperties, final UINotification notification,
+ final SpPermissionChecker permissionChecker,
+ final DistributionSetInvalidationManagement dsInvalidationManagement) {
this.grid = grid;
this.i18n = i18n;
+ this.uiProperties = uiProperties;
this.notification = notification;
+ this.permissionChecker = permissionChecker;
this.dsInvalidationManagement = dsInvalidationManagement;
}
@@ -72,11 +82,12 @@ public class InvalidateDistributionSetSupport {
final List allDistributionSetsForInvalidation = getDistributionSetsForInvalidation(
clickedDistributionSet);
- consequencesDialog = new InvalidateDsConsequencesDialog(allDistributionSetsForInvalidation, i18n, ok -> {
- if (ok) {
- openAffectedEntitiesWindowOnInvalidateAction(allDistributionSetsForInvalidation);
- }
- });
+ consequencesDialog = new InvalidateDsConsequencesDialog(allDistributionSetsForInvalidation, i18n, uiProperties,
+ ok -> {
+ if (Boolean.TRUE.equals(ok) && hasSufficientPermission()) {
+ openAffectedEntitiesWindowOnInvalidateAction(allDistributionSetsForInvalidation);
+ }
+ });
consequencesDialog.getWindow().setWidth(40.0F, Sizeable.Unit.PERCENTAGE);
UI.getCurrent().addWindow(consequencesDialog.getWindow());
@@ -89,15 +100,15 @@ public class InvalidateDistributionSetSupport {
final DistributionSetInvalidationCount entitiesForInvalidationCount = dsInvalidationManagement
.countEntitiesForInvalidation(
getDistributionSetInvalidation(consequencesDialog.isStopRolloutsSelected(),
- getDistributionSetIds(allDistributionSetsForInvalidation), CancelationType.NONE));
+ getDistributionSetIds(allDistributionSetsForInvalidation),
+ consequencesDialog.getCancelationType()));
final InvalidateDsAffectedEntitiesDialog affectedEntitiesDialog = new InvalidateDsAffectedEntitiesDialog(
allDistributionSetsForInvalidation, i18n, ok -> {
- if (ok) {
+ if (Boolean.TRUE.equals(ok) && hasSufficientPermission()) {
handleOkForInvalidateDistributionSet(allDistributionSetsForInvalidation);
}
- }, entitiesForInvalidationCount.getRolloutsCount(),
- entitiesForInvalidationCount.getAutoAssignmentCount());
+ }, entitiesForInvalidationCount);
affectedEntitiesDialog.getWindow().setWidth(40.0F, Sizeable.Unit.PERCENTAGE);
UI.getCurrent().addWindow(affectedEntitiesDialog.getWindow());
@@ -106,11 +117,11 @@ public class InvalidateDistributionSetSupport {
private void handleOkForInvalidateDistributionSet(
final List allDistributionSetsForInvalidation) {
-
try {
dsInvalidationManagement.invalidateDistributionSet(
getDistributionSetInvalidation(consequencesDialog.isStopRolloutsSelected(),
- getDistributionSetIds(allDistributionSetsForInvalidation), CancelationType.NONE));
+ getDistributionSetIds(allDistributionSetsForInvalidation),
+ consequencesDialog.getCancelationType()));
notification.displaySuccess(createSuccessNotificationText(allDistributionSetsForInvalidation));
grid.refreshAll();
} catch (final RuntimeException ex) {
@@ -121,6 +132,21 @@ public class InvalidateDistributionSetSupport {
}
}
+ private boolean hasSufficientPermission() {
+ if (consequencesDialog.isStopRolloutsSelected() && !permissionChecker.hasRolloutUpdatePermission()) {
+ notification.displayValidationError(i18n.getMessage(
+ UIMessageIdProvider.MESSAGE_ERROR_PERMISSION_INSUFFICIENT, SpPermission.UPDATE_ROLLOUT));
+ return false;
+ }
+ if (consequencesDialog.getCancelationType() != CancelationType.NONE
+ && !permissionChecker.hasUpdateTargetPermission()) {
+ notification.displayValidationError(i18n
+ .getMessage(UIMessageIdProvider.MESSAGE_ERROR_PERMISSION_INSUFFICIENT, SpPermission.UPDATE_TARGET));
+ return false;
+ }
+ return true;
+ }
+
private DistributionSetInvalidation getDistributionSetInvalidation(final boolean stopRollouts,
final List distSetIds, final CancelationType cancelationType) {
return new DistributionSetInvalidation(distSetIds, cancelationType, stopRollouts);
diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/InvalidateDsAffectedEntitiesDialog.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/InvalidateDsAffectedEntitiesDialog.java
index 768c7cbb1..5c997ee33 100644
--- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/InvalidateDsAffectedEntitiesDialog.java
+++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/InvalidateDsAffectedEntitiesDialog.java
@@ -11,6 +11,8 @@ package org.eclipse.hawkbit.ui.management.dstable;
import java.util.List;
import java.util.function.Consumer;
+import org.eclipse.hawkbit.repository.model.DistributionSetInvalidationCount;
+import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.ui.common.CommonDialogWindow;
import org.eclipse.hawkbit.ui.common.CommonDialogWindow.ConfirmStyle;
@@ -44,20 +46,19 @@ public class InvalidateDsAffectedEntitiesDialog {
* Constructor for {@link InvalidateDsAffectedEntitiesDialog}
*
* @param allDistributionSetsForInvalidation
- * {@link List} of {@link ProxyDistributionSet} that are selected
- * for invalidation
+ * {@link List} of {@link ProxyDistributionSet} that are selected for
+ * invalidation
* @param i18n
* {@link VaadinMessageSource}
* @param callback
* callback for dialog result
- * @param affectedRollouts
- * number of affected {@link Rollout}s
- * @param affectedAutoAssignments
- * number of affected auto assignments
+ * @param affectedEntities
+ * number of affected {@link Rollout}s, {@link Action}s and
+ * auto-assignments
*/
public InvalidateDsAffectedEntitiesDialog(final List allDistributionSetsForInvalidation,
- final VaadinMessageSource i18n, final Consumer callback, final long affectedRollouts,
- final long affectedAutoAssignments) {
+ final VaadinMessageSource i18n, final Consumer callback,
+ final DistributionSetInvalidationCount affectedEntities) {
this.i18n = i18n;
@@ -69,14 +70,21 @@ public class InvalidateDsAffectedEntitiesDialog {
consequencesLabel.setWidthFull();
content.addComponent(consequencesLabel);
- final Label stoppedRolloutsLabel = new Label(i18n.getMessage(
- UIMessageIdProvider.MESSAGE_INVALIDATE_DISTRIBUTIONSET_AFFECTED_ENTITIES_ROLLOUTS, affectedRollouts));
+ final Label stoppedSingleAssignmentsLabel = new Label(
+ i18n.getMessage(UIMessageIdProvider.MESSAGE_INVALIDATE_DISTRIBUTIONSET_AFFECTED_ENTITIES_ACTIONS,
+ affectedEntities.getActionCount()));
+ stoppedSingleAssignmentsLabel.setId(UIComponentIdProvider.INVALIDATE_DS_AFFECTED_ENTITIES_ACTIONS);
+ content.addComponent(stoppedSingleAssignmentsLabel);
+
+ final Label stoppedRolloutsLabel = new Label(
+ i18n.getMessage(UIMessageIdProvider.MESSAGE_INVALIDATE_DISTRIBUTIONSET_AFFECTED_ENTITIES_ROLLOUTS,
+ affectedEntities.getRolloutsCount()));
stoppedRolloutsLabel.setId(UIComponentIdProvider.INVALIDATE_DS_AFFECTED_ENTITIES_ROLLOUTS);
content.addComponent(stoppedRolloutsLabel);
final Label stoppedAutoAssignmentsLabel = new Label(i18n.getMessage(
UIMessageIdProvider.MESSAGE_INVALIDATE_DISTRIBUTIONSET_AFFECTED_ENTITIES_AUTOASSIGNMENTS,
- affectedAutoAssignments));
+ affectedEntities.getAutoAssignmentCount()));
stoppedAutoAssignmentsLabel.setId(UIComponentIdProvider.INVALIDATE_DS_AFFECTED_ENTITIES_AUTOASSIGNMENTS);
content.addComponent(stoppedAutoAssignmentsLabel);
diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/InvalidateDsConsequencesDialog.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/InvalidateDsConsequencesDialog.java
index a332fd6af..fc5b13e57 100644
--- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/InvalidateDsConsequencesDialog.java
+++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/InvalidateDsConsequencesDialog.java
@@ -11,11 +11,18 @@ package org.eclipse.hawkbit.ui.management.dstable;
import java.util.List;
import java.util.function.Consumer;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.RadioButtonGroup;
+import com.vaadin.ui.themes.ValoTheme;
+import org.eclipse.hawkbit.repository.model.DistributionSetInvalidation.CancelationType;
+import org.eclipse.hawkbit.ui.UiProperties;
import org.eclipse.hawkbit.ui.common.CommonDialogWindow;
import org.eclipse.hawkbit.ui.common.CommonDialogWindow.ConfirmStyle;
import org.eclipse.hawkbit.ui.common.CommonDialogWindow.SaveDialogCloseListener;
import org.eclipse.hawkbit.ui.common.builder.WindowBuilder;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSet;
+import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleTiny;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
@@ -35,27 +42,35 @@ public class InvalidateDsConsequencesDialog {
private final Consumer callback;
+ private final VaadinMessageSource i18n;
+
+ private final UiProperties uiProperties;
+
private final CommonDialogWindow window;
private final CheckBox stopRolloutsCheckBox;
- private final VaadinMessageSource i18n;
+ private final RadioButtonGroup cancelationTypeGroup;
/**
* Constructor for {@link InvalidateDsConsequencesDialog}
*
* @param allDistributionSetsForInvalidation
- * {@link List} of {@link ProxyDistributionSet} that are selected
- * for invalidation
+ * {@link List} of {@link ProxyDistributionSet} that are selected for
+ * invalidation
* @param i18n
* {@link VaadinMessageSource}
* @param callback
* callback for dialog result
*/
public InvalidateDsConsequencesDialog(final List allDistributionSetsForInvalidation,
- final VaadinMessageSource i18n, final Consumer callback) {
+ final VaadinMessageSource i18n, final UiProperties uiProperties, final Consumer callback) {
this.i18n = i18n;
+ this.uiProperties = uiProperties;
+ this.cancelationTypeGroup = createCancelationTypeOptionGroup();
+ this.stopRolloutsCheckBox = createStopRolloutsCheckbox();
+
final VerticalLayout content = new VerticalLayout();
content.setSpacing(true);
content.setMargin(true);
@@ -64,10 +79,11 @@ public class InvalidateDsConsequencesDialog {
consequencesLabel.setWidthFull();
content.addComponent(consequencesLabel);
- stopRolloutsCheckBox = new CheckBox();
- stopRolloutsCheckBox.setId(UIComponentIdProvider.INVALIDATE_DS_STOP_ROLLOUTS);
- stopRolloutsCheckBox.setCaption(i18n.getMessage(UIMessageIdProvider.LABEL_INVALIDATE_DS_STOP_ROLLOUTS));
+ content.addComponent(createCancelationTypeInfo());
+ content.addComponent(cancelationTypeGroup);
content.addComponent(stopRolloutsCheckBox);
+ content.addComponent(createConsequencesHint());
+ addValueChangeListeners();
final WindowBuilder windowBuilder = new WindowBuilder(SPUIDefinitions.CREATE_UPDATE_WINDOW)
.id(UIComponentIdProvider.INVALIDATE_DS_CONSEQUENCES)
@@ -118,6 +134,48 @@ public class InvalidateDsConsequencesDialog {
}
}
+ private CheckBox createStopRolloutsCheckbox() {
+ final CheckBox checkBox = new CheckBox();
+ checkBox.setId(UIComponentIdProvider.INVALIDATE_DS_STOP_ROLLOUTS);
+ checkBox.setCaption(i18n.getMessage(UIMessageIdProvider.LABEL_INVALIDATE_DS_STOP_ROLLOUTS));
+ return checkBox;
+ }
+
+ private HorizontalLayout createCancelationTypeInfo() {
+ final HorizontalLayout horizontalLabelInfo = new HorizontalLayout();
+ final Label typeLabel = new Label(
+ i18n.getMessage(UIMessageIdProvider.LABEL_INVALIDATE_DS_TYPE_OF_CANCELLATION));
+ final Link linkToInvalidationHelp = SPUIComponentProvider.getHelpLink(i18n,
+ uiProperties.getLinks().getDocumentation().getDistributionSetInvalidation());
+ horizontalLabelInfo.addComponent(typeLabel);
+ horizontalLabelInfo.addComponent(linkToInvalidationHelp);
+ return horizontalLabelInfo;
+ }
+
+ private RadioButtonGroup createCancelationTypeOptionGroup() {
+ final RadioButtonGroup cancellationTypeOptions = new RadioButtonGroup<>();
+ cancellationTypeOptions.setId(UIComponentIdProvider.INVALIDATE_DS_CANCELATION_TYPE);
+ cancellationTypeOptions.addStyleName(ValoTheme.OPTIONGROUP_HORIZONTAL);
+ cancellationTypeOptions.setSizeUndefined();
+
+ cancellationTypeOptions.setItems(CancelationType.values());
+ cancellationTypeOptions.setItemCaptionGenerator(this::getCancelationTypeCaptionMessageId);
+ cancellationTypeOptions.setItemDescriptionGenerator(this::getCancelationTypeToolTipMessageId);
+
+ // default shall be "None"
+ cancellationTypeOptions.setSelectedItem(CancelationType.NONE);
+
+ return cancellationTypeOptions;
+ }
+
+ private Label createConsequencesHint() {
+ String hint = i18n.getMessage(UIMessageIdProvider.MESSAGE_INVALIDATE_DISTRIBUTIONSET_UNREPEATABLE_HINT);
+ final Label hintLabel = new Label(hint);
+ hintLabel.setWidthFull();
+ hintLabel.setStyleName(ValoTheme.LABEL_TINY);
+ return hintLabel;
+ }
+
/**
* Returns the user selection stop rollouts
*
@@ -127,10 +185,52 @@ public class InvalidateDsConsequencesDialog {
return stopRolloutsCheckBox.getValue();
}
+ CancelationType getCancelationType() {
+ return cancelationTypeGroup.getValue();
+ }
+
+ private void addValueChangeListeners() {
+ cancelationTypeGroup.addValueChangeListener(event -> {
+ if (event.getValue() == CancelationType.NONE) {
+ stopRolloutsCheckBox.setValue(false);
+ stopRolloutsCheckBox.setEnabled(true);
+ } else {
+ stopRolloutsCheckBox.setValue(true);
+ stopRolloutsCheckBox.setEnabled(false);
+ }
+ });
+ }
+
/**
* @return confirmation window
*/
public Window getWindow() {
return window;
}
+
+ private String getCancelationTypeCaptionMessageId(CancelationType item) {
+ switch (item) {
+ case FORCE:
+ return i18n.getMessage(UIMessageIdProvider.LABEL_CANCEL_ACTION_FORCE);
+ case SOFT:
+ return i18n.getMessage(UIMessageIdProvider.LABEL_CANCEL_ACTION_SOFT);
+ case NONE:
+ return i18n.getMessage(UIMessageIdProvider.LABEL_CANCEL_ACTION_NONE);
+ default:
+ return null;
+ }
+ }
+
+ private String getCancelationTypeToolTipMessageId(CancelationType item) {
+ switch (item) {
+ case FORCE:
+ return i18n.getMessage(UIMessageIdProvider.TOOLTIP_DISTRIBUTIONSET_INVALIDATE_FORCED);
+ case SOFT:
+ return i18n.getMessage(UIMessageIdProvider.TOOLTIP_DISTRIBUTIONSET_INVALIDATE_SOFT);
+ case NONE:
+ return i18n.getMessage(UIMessageIdProvider.TOOLTIP_DISTRIBUTIONSET_INVALIDATE_NONE);
+ default:
+ return null;
+ }
+ }
}
diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIComponentIdProvider.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIComponentIdProvider.java
index 56e7ce656..ad653cf45 100644
--- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIComponentIdProvider.java
+++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIComponentIdProvider.java
@@ -1373,6 +1373,10 @@ public final class UIComponentIdProvider {
* Distribution set invalidate affected entities window id
*/
public static final String INVALIDATE_DS_AFFECTED_ENTITIES = "invalidate.distributionset.affectedentities.window";
+ /**
+ * Distribution set invalidate affected actions label id
+ */
+ public static final String INVALIDATE_DS_AFFECTED_ENTITIES_ACTIONS = "invalidate.distributionset.affectedentities.actions";
/**
* Distribution set invalidate affected rollouts label id
*/
@@ -1385,7 +1389,10 @@ public final class UIComponentIdProvider {
* Distribution set invalidate consequences window, stop rollouts checkbox
*/
public static final String INVALIDATE_DS_STOP_ROLLOUTS = "invalidate.distributionset.consequences.stop.rollouts.checkbox";
-
+ /**
+ * Distribution set invalidate consequences window, cancelation type radio button group
+ */
+ public static final String INVALIDATE_DS_CANCELATION_TYPE = "invalidate.distributionset.consequences.cancelation.type.radio";
/**
* Id of the unread notification button
*/
diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIMessageIdProvider.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIMessageIdProvider.java
index 18f19ee63..1f9b2010a 100644
--- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIMessageIdProvider.java
+++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIMessageIdProvider.java
@@ -105,6 +105,14 @@ public final class UIMessageIdProvider {
public static final String LABEL_INVALIDATE_DS_STOP_ROLLOUTS = "label.invalidate.distributionset.stop.rollouts";
+ public static final String LABEL_INVALIDATE_DS_TYPE_OF_CANCELLATION = "label.invalidate.ds.cancelation.type";
+
+ public static final String LABEL_CANCEL_ACTION_NONE = "label.cancel.action.none";
+
+ public static final String LABEL_CANCEL_ACTION_FORCE = "label.cancel.action.force";
+
+ public static final String LABEL_CANCEL_ACTION_SOFT = "label.cancel.action.soft";
+
public static final String MESSAGE_NO_DATA = "message.no.data";
public static final String MESSAGE_DATA_AVAILABLE = "message.data.available";
@@ -143,6 +151,8 @@ public final class UIMessageIdProvider {
public static final String MESSAGE_ERROR_ENTITY_READONLY = "message.entity.error.readonly";
+ public static final String MESSAGE_ERROR_PERMISSION_INSUFFICIENT = "message.permission.insufficient";
+
public static final String CRON_VALIDATION_ERROR = "message.maintenancewindow.schedule.validation.error";
public static final String TOOLTIP_OVERDUE = "tooltip.overdue";
@@ -195,6 +205,12 @@ public final class UIMessageIdProvider {
public static final String TOOLTIP_DISTRIBUTIONSET_INCOMPLETE = "tooltip.distributionset.incomplete";
+ public static final String TOOLTIP_DISTRIBUTIONSET_INVALIDATE_FORCED = "tooltip.distributionset.invalidate.forced";
+
+ public static final String TOOLTIP_DISTRIBUTIONSET_INVALIDATE_SOFT = "tooltip.distributionset.invalidate.soft";
+
+ public static final String TOOLTIP_DISTRIBUTIONSET_INVALIDATE_NONE = "tooltip.distributionset.invalidate.none";
+
public static final String TOOLTIP_TIMEFORCED_ITEM = "tooltip.timeforced.item";
public static final String TOOLTIP_TIMEFORCED_FORCED_IN = "tooltip.timeforced.forced.in";
@@ -275,6 +291,8 @@ public final class UIMessageIdProvider {
public static final String MESSAGE_INVALIDATE_DISTRIBUTIONSET_AFFECTED_ENTITIES_INTRO_PLURAL = "message.invalidate.distributionset.affected.entities.intro.plural";
+ public static final String MESSAGE_INVALIDATE_DISTRIBUTIONSET_AFFECTED_ENTITIES_ACTIONS = "message.invalidate.distributionset.affected.entities.actions";
+
public static final String MESSAGE_INVALIDATE_DISTRIBUTIONSET_AFFECTED_ENTITIES_ROLLOUTS = "message.invalidate.distributionset.affected.entities.rollouts";
public static final String MESSAGE_INVALIDATE_DISTRIBUTIONSET_AFFECTED_ENTITIES_AUTOASSIGNMENTS = "message.invalidate.distributionset.affected.entities.autoassignments";
@@ -287,6 +305,8 @@ public final class UIMessageIdProvider {
public static final String MESSAGE_INVALIDATE_DISTRIBUTIONSET_FAIL_PLURAL = "message.invalidate.distributionset.fail.plural";
+ public static final String MESSAGE_INVALIDATE_DISTRIBUTIONSET_UNREPEATABLE_HINT = "message.invalidate.distributionset.unrepeatable.hint";
+
public static final String VAADIN_SYSTEM_SESSIONEXPIRED_CAPTION = "vaadin.system.sessionexpired.caption";
public static final String VAADIN_SYSTEM_SESSIONEXPIRED_MESSAGE = "vaadin.system.sessionexpired.message";
diff --git a/hawkbit-ui/src/main/resources/hawkbit-ui-defaults.properties b/hawkbit-ui/src/main/resources/hawkbit-ui-defaults.properties
index b67a37593..8f93fb0bc 100644
--- a/hawkbit-ui/src/main/resources/hawkbit-ui-defaults.properties
+++ b/hawkbit-ui/src/main/resources/hawkbit-ui-defaults.properties
@@ -25,6 +25,7 @@ hawkbit.server.ui.links.documentation.system-configuration-view=https://www.ecli
hawkbit.server.ui.links.documentation.targetfilter-view=https://www.eclipse.org/hawkbit/ui/#target-filter-management
hawkbit.server.ui.links.documentation.upload-view=https://www.eclipse.org/hawkbit/ui/#artifact-management
hawkbit.server.ui.links.documentation.maintenance-window-view=http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html
+hawkbit.server.ui.links.documentation.distribution-set-invalidation=https://www.eclipse.org/hawkbit/ui/#distribution-set-invalidation
# UI Favicon disabled to use our Eclipse icon
spring.mvc.favicon.enabled=false
diff --git a/hawkbit-ui/src/main/resources/messages.properties b/hawkbit-ui/src/main/resources/messages.properties
index 592b0792c..06d20b1b4 100644
--- a/hawkbit-ui/src/main/resources/messages.properties
+++ b/hawkbit-ui/src/main/resources/messages.properties
@@ -255,6 +255,10 @@ label.drop.area.upload = Drop Files to upload
label.errorthreshold.option.percent = %
label.errorthreshold.option.count = Count
label.invalidate.distributionset.stop.rollouts = Stop rollouts
+label.invalidate.ds.cancelation.type = Type of cancelation:
+label.cancel.action.none = None
+label.cancel.action.force = Forced
+label.cancel.action.soft = Soft
# TextFields prefix with - textfield
textfield.name = Name
@@ -378,6 +382,9 @@ tooltip.distribution.set.pin = Pin distribution set
tooltip.invalidate.distributionset = Invalidate distribution set..
tooltip.distributionset.invalid = invalid
tooltip.distributionset.incomplete = incomplete
+tooltip.distributionset.invalidate.forced = Open actions will be canceled and force quit
+tooltip.distributionset.invalidate.soft = Open actions will be canceled
+tooltip.distributionset.invalidate.none = Open actions will not be canceled
tooltip.in.time = In Time
# Notification messages prefix with - message
@@ -517,8 +524,10 @@ message.invalidate.distributionset.fail.singular = Distribution set {0} invalida
message.invalidate.distributionset.fail.plural = Invalidation failed for {0} distribution sets
message.invalidate.distributionset.consequences.singular = By invalidating this distribution set it can no longer be used in any assignment. All active auto assignments and optionally all active rollouts of the distribution set can be stopped as well as all existing update actions will be canceled. A summary of affected entities will be shown on the next page.
message.invalidate.distributionset.consequences.plural = By invalidating this {0} distribution sets they can no longer be used in any assignment. All active auto assignments and optionally all active rollouts of the distribution sets can be stopped as well as all existing update actions will be canceled. A summary of affected entities will be shown on the next page.
+message.invalidate.distributionset.unrepeatable.hint = Note: If no cancelation type is selected, mass-cancel of actions will not be possible at a later point in time.
message.invalidate.distributionset.affected.entities.intro.singular = When you confirm the invalidation of distribution set {0} the following actions will be taken:
message.invalidate.distributionset.affected.entities.intro.plural = When you confirm the invalidation of {0} distribution sets the following actions will be taken:
+message.invalidate.distributionset.affected.entities.actions = {0} action(s) will be canceled
message.invalidate.distributionset.affected.entities.rollouts = {0} rollout(s) will be stopped
message.invalidate.distributionset.affected.entities.autoassignments = {0} auto assignment(s) will be stopped