Feature mass cancel running actions on ds invalidation (#1177)
* Extend DS invalidation dialog to include mass-cancellation of actions Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch.io> add component id for cancelation type radio buttons Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch.io> * add infos about ds invalidation to UI documentation; update UI images; add screenshot about ds invalidation Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch.io> * fix review findings Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch.io> * add link property to invalidation docu Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch.io> * Put invalidation counts into one object Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch.io> * add hint to invalidation dialog, that invalidation is unrepeatable Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch.io> * disable invalidate button if insufficient permission Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch.io> * fix auto assignment error with insufficient permission Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch.io> * implement permissions check for invalidation dialog Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch.io> * add update_target permission to api doc description Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch.io>
@@ -8,6 +8,7 @@ Software update operations in large scale IoT scenarios with hundreds of thousan
|
||||
<!--more-->
|
||||
|
||||
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_.
|
||||
|
||||
@@ -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.
|
||||
|
||||

|
||||

|
||||
|
||||
BIN
docs/static/images/ui/artifact_mgmt.png
vendored
Normal file → Executable file
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 110 KiB |
BIN
docs/static/images/ui/deployment_ds_invalidation.png
vendored
Executable file
|
After Width: | Height: | Size: 212 KiB |
BIN
docs/static/images/ui/deployment_mgmt.png
vendored
Normal file → Executable file
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 190 KiB |
BIN
docs/static/images/ui/distribution_mgmt.png
vendored
Normal file → Executable file
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 114 KiB |
BIN
docs/static/images/ui/rollout_groups.png
vendored
Normal file → Executable file
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 105 KiB |
BIN
docs/static/images/ui/rollout_mgmt.png
vendored
Normal file → Executable file
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 74 KiB |
BIN
docs/static/images/ui/target_filter.png
vendored
Normal file → Executable file
|
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 309 KiB |
BIN
docs/static/images/ui/target_filter_auto_assignment.png
vendored
Normal file → Executable file
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 152 KiB |
@@ -65,7 +65,7 @@ public class DistributionSetInvalidation {
|
||||
* distribution set
|
||||
*/
|
||||
public enum CancelationType {
|
||||
FORCE, SOFT, NONE;
|
||||
FORCE, SOFT, NONE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,4 +38,4 @@ public class DistributionSetInvalidationCount {
|
||||
return actionCount;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -168,4 +168,22 @@ public class SpPermissionChecker implements Serializable {
|
||||
public boolean hasRolloutApprovalPermission() {
|
||||
return hasRolloutReadPermission() && permissionService.hasPermission(SpPermission.APPROVE_ROLLOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <code>true</code> if auto assignment can be added/updated to target filter
|
||||
*/
|
||||
public boolean hasAutoAssignmentUpdatePermission() {
|
||||
return hasUpdateTargetPermission() && hasReadRepositoryPermission();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <code>true</code> if default invalidation of distribution set is
|
||||
* allowed
|
||||
*/
|
||||
public boolean hasDistributionSetInvalidatePermission() {
|
||||
return hasUpdateRepositoryPermission() && hasUpdateTargetPermission();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -229,8 +229,8 @@ public class DragAndDropSupport<T extends ProxyIdentifiableEntity> {
|
||||
|
||||
final List<String> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ public class TargetFilterGrid extends AbstractGrid<ProxyTargetFilterQuery, Strin
|
||||
}
|
||||
|
||||
final Button link = GridComponentBuilder.buildLink(targetFilter, "distSetButton", caption,
|
||||
permissionChecker.hasReadRepositoryPermission(),
|
||||
permissionChecker.hasAutoAssignmentUpdatePermission(),
|
||||
clickEvent -> onClickOfAutoAssignmentLink(targetFilter));
|
||||
|
||||
final String description = i18n.getMessage(UIMessageIdProvider.BUTTON_AUTO_ASSIGNMENT_DESCRIPTION);
|
||||
@@ -202,8 +202,8 @@ public class TargetFilterGrid extends AbstractGrid<ProxyTargetFilterQuery, Strin
|
||||
UI.getCurrent().addWindow(autoAssignmentWindow);
|
||||
autoAssignmentWindow.setVisible(Boolean.TRUE);
|
||||
} else {
|
||||
notification.displayValidationError(
|
||||
i18n.getMessage("message.permission.insufficient", SpPermission.READ_REPOSITORY));
|
||||
notification.displayValidationError(i18n.getMessage(
|
||||
UIMessageIdProvider.MESSAGE_ERROR_PERMISSION_INSUFFICIENT, SpPermission.READ_REPOSITORY));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,8 +138,8 @@ public class DistributionGrid extends AbstractDsGrid<DsManagementFilterParams> {
|
||||
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<DsManagementFilterParams> {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<ProxyDistributionSet> 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<ProxyDistributionSet> 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<Long> distSetIds, final CancelationType cancelationType) {
|
||||
return new DistributionSetInvalidation(distSetIds, cancelationType, stopRollouts);
|
||||
|
||||
@@ -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<ProxyDistributionSet> allDistributionSetsForInvalidation,
|
||||
final VaadinMessageSource i18n, final Consumer<Boolean> callback, final long affectedRollouts,
|
||||
final long affectedAutoAssignments) {
|
||||
final VaadinMessageSource i18n, final Consumer<Boolean> 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);
|
||||
|
||||
|
||||
@@ -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<Boolean> callback;
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
|
||||
private final UiProperties uiProperties;
|
||||
|
||||
private final CommonDialogWindow window;
|
||||
|
||||
private final CheckBox stopRolloutsCheckBox;
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
private final RadioButtonGroup<CancelationType> 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<ProxyDistributionSet> allDistributionSetsForInvalidation,
|
||||
final VaadinMessageSource i18n, final Consumer<Boolean> callback) {
|
||||
final VaadinMessageSource i18n, final UiProperties uiProperties, final Consumer<Boolean> 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<CancelationType> createCancelationTypeOptionGroup() {
|
||||
final RadioButtonGroup<CancelationType> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||