Feature invalidation of distribution sets [UI part] (#1176)

* Visualization of action/button invalidate DistributionSet

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* introduced two dialogs to confirm ds invalidation

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* fixed dialog titles appear centered and added manamgement classes

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* retrieving affected entities from repository

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* considered multiselection for invalidating dist sets

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* adapt style and tooltip of invalid distributions in grid

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* showing errors for actions not allowed for invalidate DS

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* enhanced error message with dist name and version

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* added ids to the labels to be used in tests

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* added support for overwriting entity specific edit behaviour

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* Fixed incorrect label for cancelled action due to invalidation of ds in
a rollout

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* Fixed error notification to not show "please try again" for an invalid
DS

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* fixed typo

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* fixed Sonar findings

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* remove DS of a copied Rollout in case the DS is invalidated

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* changed icon of RolloutActionStatus in case of stopped Rollout because
of invalidation of DS and DS wasn't yet assigned to target. This is to
distinguish from the case of not assigned DS because of duplicate DS
assignemnt

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* Prevent editing Metadata of invalid DS

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* show DS as invalidated in Rollout view

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* incorporated code review remarks

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* invalidated DS should be removed from the list of DS to be invalidated

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* fixed missing code due to merge

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* Fixed compile error due to rebase

Signed-off-by: Markus Block <markus.block@bosch-si.com>
This commit is contained in:
Markus Block
2021-10-01 16:15:05 +02:00
committed by GitHub
parent 825cb64448
commit 56e4066f12
34 changed files with 928 additions and 93 deletions

View File

@@ -20,6 +20,7 @@ import org.eclipse.hawkbit.ui.common.data.suppliers.TargetManagementStateDataSup
import org.eclipse.hawkbit.ui.error.HawkbitUIErrorHandler;
import org.eclipse.hawkbit.ui.error.extractors.ConstraintViolationErrorExtractor;
import org.eclipse.hawkbit.ui.error.extractors.EntityNotFoundErrorExtractor;
import org.eclipse.hawkbit.ui.error.extractors.InvalidDistributionSetErrorExtractor;
import org.eclipse.hawkbit.ui.error.extractors.UiErrorDetailsExtractor;
import org.eclipse.hawkbit.ui.error.extractors.UploadErrorExtractor;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
@@ -49,7 +50,7 @@ public class MgmtUiConfiguration {
/**
* Permission checker for UI.
*
*
* @param permissionService
* PermissionService
*
@@ -63,7 +64,7 @@ public class MgmtUiConfiguration {
/**
* Utility for Vaadin messages source.
*
*
* @param source
* Delegate MessageSource
*
@@ -77,7 +78,7 @@ public class MgmtUiConfiguration {
/**
* Localized system message provider bean.
*
*
* @param uiProperties
* UiProperties
* @param i18n
@@ -93,12 +94,12 @@ public class MgmtUiConfiguration {
/**
* UI Error handler bean.
*
*
* @param i18n
* VaadinMessageSource
* @param uiErrorDetailsExtractor
* ui error details extractors
*
*
* @return UI Error handler
*/
@Bean
@@ -110,7 +111,7 @@ public class MgmtUiConfiguration {
/**
* UI Upload Error details extractor bean.
*
*
* @return UI Upload Error details extractor
*/
@Bean
@@ -120,7 +121,7 @@ public class MgmtUiConfiguration {
/**
* UI ConstraintViolation Error details extractor bean.
*
*
* @param i18n
* VaadinMessageSource
* @return UI ConstraintViolation Error details extractor
@@ -132,7 +133,7 @@ public class MgmtUiConfiguration {
/**
* UI Entity not found Error details extractor bean.
*
*
* @param i18n
* VaadinMessageSource
* @return UI EntityNotFound Error details extractor
@@ -142,6 +143,19 @@ public class MgmtUiConfiguration {
return new EntityNotFoundErrorExtractor(i18n);
}
/**
* Details extractor bean for action not possible because of distribution
* set is invalid.
*
* @param i18n
* VaadinMessageSource
* @return UI invalid distributionset Error details extractor
*/
@Bean
UiErrorDetailsExtractor invalidDistributionSetErrorExtractor(final VaadinMessageSource i18n) {
return new InvalidDistributionSetErrorExtractor(i18n);
}
/**
* Vaadin4Spring servlet bean.
*
@@ -154,7 +168,7 @@ public class MgmtUiConfiguration {
/**
* UI target entity mapper bean.
*
*
* @param i18n
* VaadinMessageSource
* @return UI target entity mapper
@@ -166,7 +180,7 @@ public class MgmtUiConfiguration {
/**
* UI Management target data supplier bean.
*
*
* @param targetManagement
* TargetManagement
* @param targetToProxyTargetMapper
@@ -183,7 +197,7 @@ public class MgmtUiConfiguration {
/**
* UI Filter target data supplier bean.
*
*
* @param targetManagement
* TargetManagement
* @param targetToProxyTargetMapper

View File

@@ -64,12 +64,12 @@ public class CommonDialogWindow extends Window {
* Different kinds of confirm buttons
*/
public enum ConfirmStyle {
SAVE, OK
SAVE, OK, CONFIRM, NEXT
}
/**
* Constructor
*
*
* @param caption
* the caption
* @param content
@@ -189,7 +189,7 @@ public class CommonDialogWindow extends Window {
/**
* Hide the line that explains the mandatory decorator
*
*
*/
public void hideMandatoryExplanation() {
if (mandatoryLabel != null) {
@@ -218,6 +218,14 @@ public class CommonDialogWindow extends Window {
confirmButton = SPUIComponentProvider.getButton(UIComponentIdProvider.SAVE_BUTTON,
i18n.getMessage(UIMessageIdProvider.BUTTON_SAVE), "", "", true, VaadinIcons.HARDDRIVE,
buttonDecorator);
} else if (confirmStyle == ConfirmStyle.NEXT) {
confirmButton = SPUIComponentProvider.getButton(UIComponentIdProvider.OK_BUTTON,
i18n.getMessage(UIMessageIdProvider.BUTTON_NEXT), "", ValoTheme.BUTTON_PRIMARY, false, null,
buttonDecorator);
} else if (confirmStyle == ConfirmStyle.CONFIRM) {
confirmButton = SPUIComponentProvider.getButton(UIComponentIdProvider.OK_BUTTON,
i18n.getMessage(UIMessageIdProvider.BUTTON_CONFIRM), "", ValoTheme.BUTTON_PRIMARY, false, null,
buttonDecorator);
} else {
confirmButton = SPUIComponentProvider.getButton(UIComponentIdProvider.OK_BUTTON,
i18n.getMessage(UIMessageIdProvider.BUTTON_OK), "", ValoTheme.BUTTON_PRIMARY, false, null,

View File

@@ -1,4 +1,4 @@
/**
/**
* Copyright (c) 2020 Bosch.IO GmbH and others.
*
* All rights reserved. This program and the accompanying materials
@@ -42,7 +42,7 @@ import com.vaadin.server.FontIcon;
import com.vaadin.ui.Label;
/**
*
*
* Generate labels with icons according to entities' states
*
*/
@@ -63,7 +63,7 @@ public final class StatusIconBuilder {
/**
* constructor
*
*
* @param i18n
* message source for internationalization
* @param getEntityStatus
@@ -101,7 +101,7 @@ public final class StatusIconBuilder {
/**
* constructor
*
*
* @param i18n
* message source for internationalization
* @param getEntityStatus
@@ -140,7 +140,7 @@ public final class StatusIconBuilder {
/**
* constructor
*
*
* @param i18n
* message source for internationalization
* @param getEntityStatus
@@ -177,7 +177,7 @@ public final class StatusIconBuilder {
/**
* constructor
*
*
* @param i18n
* message source for internationalization
* @param getEntityStatus
@@ -208,7 +208,7 @@ public final class StatusIconBuilder {
if (optionalIcon.isPresent()) {
icon = getFontIconFromStatusMap(optionalIcon.get(), getEntityStatus.apply(entity), group.orElse(null));
} else {
icon = buildDefaultStatusIcon(group.orElse(null));
icon = buildStatusIcon(group.orElse(null));
}
return getLabel(entity, icon);
@@ -233,7 +233,7 @@ public final class StatusIconBuilder {
// Actions are not created for targets when rollout's status is
// READY and when duplicate assignment is done. In these cases
// display a appropriate status with description
private ProxyFontIcon buildDefaultStatusIcon(final RolloutGroup rolloutGroup) {
private ProxyFontIcon buildStatusIcon(final RolloutGroup rolloutGroup) {
if (rolloutGroup != null && rolloutGroup.getStatus() == RolloutGroupStatus.READY) {
return new ProxyFontIcon(VaadinIcons.BULLSEYE, SPUIStyleDefinitions.STATUS_ICON_LIGHT_BLUE,
i18n.getMessage(UIMessageIdProvider.TOOLTIP_ROLLOUT_GROUP_STATUS_PREFIX
@@ -241,9 +241,15 @@ public final class StatusIconBuilder {
} else if (rolloutGroup != null && rolloutGroup.getStatus() == RolloutGroupStatus.FINISHED) {
final DistributionSet dist = rolloutGroup.getRollout().getDistributionSet();
final String ds = HawkbitCommonUtil.getFormattedNameVersion(dist.getName(), dist.getVersion());
return new ProxyFontIcon(VaadinIcons.MINUS_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_BLUE,
i18n.getMessage("message.dist.already.assigned", ds));
if (dist.isValid()) {
return new ProxyFontIcon(VaadinIcons.MINUS_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_BLUE,
i18n.getMessage(UIMessageIdProvider.MESSAGE_DISTRIBUTION_ASSIGNED, ds));
} else {
// invalidated ds, finished rollout but ds wasn't assigned
// to target
return new ProxyFontIcon(VaadinIcons.BAN, SPUIStyleDefinitions.STATUS_ICON_BLUE,
i18n.getMessage(UIMessageIdProvider.MESSAGE_DISTRIBUTION_NOT_ASSIGNED, ds));
}
} else {
return generateUnknwonStateIcon();
}
@@ -264,7 +270,7 @@ public final class StatusIconBuilder {
/**
* constructor
*
*
* @param i18n
* message source for internationalization
* @param getEntityStatus
@@ -298,7 +304,7 @@ public final class StatusIconBuilder {
/**
* constructor
*
*
* @param i18n
* message source for internationalization
* @param getEntityStatus
@@ -333,7 +339,7 @@ public final class StatusIconBuilder {
/**
* constructor
*
*
* @param i18n
* message source for internationalization
* @param getEntityStatus
@@ -366,7 +372,7 @@ public final class StatusIconBuilder {
/**
* constructor
*
*
* @param i18n
* message source for internationalization
* @param getEntityStatus
@@ -393,7 +399,7 @@ public final class StatusIconBuilder {
/**
* constructor
*
*
* @param i18n
* message source for internationalization
* @param labelIdPrefix
@@ -424,7 +430,7 @@ public final class StatusIconBuilder {
/**
* constructor
*
*
* @param i18n
* message source for internationalization
* @param labelIdPrefix
@@ -541,7 +547,7 @@ public final class StatusIconBuilder {
/**
* Generate a label from the entity according to its state
*
*
* @param entity
* to read the state from
* @return the label

View File

@@ -32,6 +32,7 @@ public class DistributionSetToProxyDistributionMapper
HawkbitCommonUtil.getFormattedNameVersion(distributionSet.getName(), distributionSet.getVersion()));
proxyDistribution.setIsComplete(distributionSet.isComplete());
proxyDistribution.setRequiredMigrationStep(distributionSet.isRequiredMigrationStep());
proxyDistribution.setIsValid(distributionSet.isValid());
final DistributionSetType type = distributionSet.getType();
final ProxyTypeInfo typeInfo = new ProxyTypeInfo(type.getId(), type.getName(), type.getKey());

View File

@@ -26,7 +26,7 @@ public class RolloutToProxyRolloutMapper extends AbstractNamedEntityToProxyNamed
mapNamedEntityAttributes(rollout, proxyRollout);
final DistributionSet ds = rollout.getDistributionSet();
proxyRollout.setDsInfo(new ProxyDistributionSetInfo(ds.getId(), ds.getName(), ds.getVersion()));
proxyRollout.setDsInfo(new ProxyDistributionSetInfo(ds.getId(), ds.getName(), ds.getVersion(), ds.isValid()));
proxyRollout
.setNumberOfGroups(rollout.getRolloutGroupsCreated() > 0 ? rollout.getRolloutGroupsCreated() : null);
proxyRollout.setForcedTime(rollout.getForcedTime() > 0 ? rollout.getForcedTime() : null);

View File

@@ -38,7 +38,7 @@ public class TargetFilterQueryToProxyTargetFilterMapper
if (distributionSet != null) {
proxyTargetFilter.setAutoAssignmentEnabled(true);
proxyTargetFilter.setDistributionSetInfo(new ProxyDistributionSetInfo(distributionSet.getId(),
distributionSet.getName(), distributionSet.getVersion()));
distributionSet.getName(), distributionSet.getVersion(), distributionSet.isValid()));
proxyTargetFilter.setAutoAssignActionType(targetFilterQuery.getAutoAssignActionType());
}

View File

@@ -49,7 +49,7 @@ public class DistributionSetStatelessDataProvider
@Override
protected Page<DistributionSet> loadBackendEntities(final PageRequest pageRequest, final String filter) {
final DistributionSetFilterBuilder builder = new DistributionSetFilterBuilder().setIsDeleted(false)
.setIsComplete(true);
.setIsComplete(true).setIsValid(true);
if (!StringUtils.isEmpty(filter)) {
builder.setFilterString(filter);

View File

@@ -28,6 +28,8 @@ public class ProxyDistributionSet extends ProxyNamedEntity implements VersionAwa
private boolean requiredMigrationStep;
private Boolean isValid;
/**
* Default constructor
*/
@@ -84,6 +86,28 @@ public class ProxyDistributionSet extends ProxyNamedEntity implements VersionAwa
this.isComplete = isComplete;
}
/**
* Flag that indicates if the distribution set is valid.
*
* @return <code>true</code> if the distribution set is valid, otherwise
* <code>false</code>
*/
public Boolean getIsValid() {
return isValid;
}
/**
* Sets the flag that indicates if the distribution set is valid
*
* @param isValid
* <code>true</code> if the distribution set is valid, otherwise
* <code>false</code>
*/
public void setIsValid(final Boolean isValid) {
this.isValid = isValid;
}
/**
* Flag that indicates if the migration step is required.
*
@@ -140,6 +164,7 @@ public class ProxyDistributionSet extends ProxyNamedEntity implements VersionAwa
ds.setName(dsInfo.getName());
ds.setVersion(dsInfo.getVersion());
ds.setNameVersion(dsInfo.getNameVersion());
ds.setIsValid(dsInfo.isValid());
return ds;
}
@@ -150,6 +175,6 @@ public class ProxyDistributionSet extends ProxyNamedEntity implements VersionAwa
* @return proxy of Id, Name and version
*/
public ProxyDistributionSetInfo getInfo() {
return new ProxyDistributionSetInfo(getId(), getName(), getVersion());
return new ProxyDistributionSetInfo(getId(), getName(), getVersion(), getIsValid());
}
}

View File

@@ -21,6 +21,7 @@ public class ProxyDistributionSetInfo extends ProxyIdentifiableEntity {
private String name;
private String version;
private String nameVersion;
private boolean isValid;
/**
* Constructor
@@ -31,7 +32,7 @@ public class ProxyDistributionSetInfo extends ProxyIdentifiableEntity {
/**
* Constructor
*
*
* @param id
* distribution set ID
* @param name
@@ -39,11 +40,12 @@ public class ProxyDistributionSetInfo extends ProxyIdentifiableEntity {
* @param version
* distribution set version
*/
public ProxyDistributionSetInfo(final Long id, final String name, final String version) {
public ProxyDistributionSetInfo(final Long id, final String name, final String version, final boolean isValid) {
super(id);
this.name = name;
this.version = version;
this.isValid = isValid;
this.nameVersion = HawkbitCommonUtil.getFormattedNameVersion(name, version);
}
@@ -71,11 +73,19 @@ public class ProxyDistributionSetInfo extends ProxyIdentifiableEntity {
this.nameVersion = nameVersion;
}
public boolean isValid() {
return isValid;
}
public void setValid(final boolean isValid) {
this.isValid = isValid;
}
@Override
public int hashCode() {
// nameVersion is ignored because it is a composition of name and
// version
return Objects.hash(getId(), getName(), getVersion());
return Objects.hash(getId(), getName(), getVersion(), isValid());
}
@Override
@@ -91,6 +101,7 @@ public class ProxyDistributionSetInfo extends ProxyIdentifiableEntity {
// nameVersion is ignored because it is a composition of name and
// version
return Objects.equals(this.getId(), other.getId()) && Objects.equals(this.getName(), other.getName())
&& Objects.equals(this.getVersion(), other.getVersion());
&& Objects.equals(this.getVersion(), other.getVersion())
&& Objects.equals(this.isValid(), other.isValid());
}
}

View File

@@ -184,7 +184,7 @@ public class SoftwareModuleDetailsGrid extends Grid<ProxySoftwareModuleDetails>
if (smId != null && !StringUtils.isEmpty(smNameVersion)) {
smLabelWithUnassignButtonLayout.addComponent(buildSmLabel(smId, smNameVersion));
if (isUnassignSmAllowed && permissionChecker.hasUpdateRepositoryPermission()) {
if (isUnassignSmAllowed && permissionChecker.hasUpdateRepositoryPermission() && masterEntity.getIsValid()) {
smLabelWithUnassignButtonLayout.addComponent(buildSmUnassignButton(smId, smNameVersion));
}
}

View File

@@ -29,6 +29,7 @@ import org.eclipse.hawkbit.ui.common.grid.support.DeleteSupport;
import org.eclipse.hawkbit.ui.common.grid.support.SelectionSupport;
import org.eclipse.hawkbit.ui.common.state.GridLayoutUiState;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.UINotification;
import com.vaadin.ui.Button;
@@ -114,11 +115,30 @@ public abstract class AbstractDsGrid<F extends DsFilterParams> extends AbstractG
}
protected Column<ProxyDistributionSet, String> addNameColumn() {
return GridComponentBuilder.addNameColumn(this, i18n, DS_NAME_ID);
final Column<ProxyDistributionSet, String> nameColumn = GridComponentBuilder.addNameColumn(this, i18n,
DS_NAME_ID);
nameColumn.setDescriptionGenerator(this::createTooltipText);
return nameColumn;
}
protected String createTooltipText(final ProxyDistributionSet distributionSet) {
final StringBuilder tooltipText = new StringBuilder(distributionSet.getNameVersion());
if (!distributionSet.getIsComplete()) {
tooltipText.append(" - ");
tooltipText.append(i18n.getMessage(UIMessageIdProvider.TOOLTIP_DISTRIBUTIONSET_INCOMPLETE));
}
if (!distributionSet.getIsValid()) {
tooltipText.append(" - ");
tooltipText.append(i18n.getMessage(UIMessageIdProvider.TOOLTIP_DISTRIBUTIONSET_INVALID));
}
return tooltipText.toString();
}
protected Column<ProxyDistributionSet, String> addVersionColumn() {
return GridComponentBuilder.addVersionColumn(this, i18n, ProxyDistributionSet::getVersion, DS_VERSION_ID);
final Column<ProxyDistributionSet, String> versionColumn = GridComponentBuilder.addVersionColumn(this, i18n,
ProxyDistributionSet::getVersion, DS_VERSION_ID);
versionColumn.setDescriptionGenerator(this::createTooltipText);
return versionColumn;
}
protected Column<ProxyDistributionSet, Button> addDeleteColumn() {

View File

@@ -66,6 +66,11 @@ public class DistributionSetDetailsHeader extends AbstractDetailsHeader<ProxyDis
return UIComponentIdProvider.DS_EDIT_BUTTON;
}
@Override
protected boolean editSelectedEntityAllowed() {
return selectedEntity != null && selectedEntity.getIsValid();
}
@Override
protected void onEdit() {
if (selectedEntity == null) {

View File

@@ -72,6 +72,10 @@ public abstract class AbstractDetailsHeader<T> extends AbstractMasterAwareGridHe
return permChecker.hasUpdateRepositoryPermission();
}
protected boolean editSelectedEntityAllowed() {
return true;
}
// can be overriden in child classes for entity-specific permission
protected boolean hasMetadataReadPermission() {
return permChecker.hasReadRepositoryPermission();
@@ -107,6 +111,8 @@ public abstract class AbstractDetailsHeader<T> extends AbstractMasterAwareGridHe
public void masterEntityChanged(final T entity) {
super.masterEntityChanged(entity);
selectedEntity = entity;
if (entity == null) {
disableEdit();
disableMetaData();
@@ -115,7 +121,6 @@ public abstract class AbstractDetailsHeader<T> extends AbstractMasterAwareGridHe
enableMetaData();
}
selectedEntity = entity;
}
private void disableEdit() {
@@ -131,13 +136,13 @@ public abstract class AbstractDetailsHeader<T> extends AbstractMasterAwareGridHe
}
private void enableEdit() {
if (editDetailsHeaderSupport != null) {
if (editDetailsHeaderSupport != null && editSelectedEntityAllowed()) {
editDetailsHeaderSupport.enableEditIcon();
}
}
private void enableMetaData() {
if (metaDataDetailsHeaderSupport != null) {
if (metaDataDetailsHeaderSupport != null && editSelectedEntityAllowed()) {
metaDataDetailsHeaderSupport.enableMetaDataIcon();
}
}

View File

@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.ui.common.grid.support.assignment;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.repository.model.AbstractAssignmentResult;
@@ -18,7 +19,7 @@ import org.springframework.util.CollectionUtils;
/**
* Support for assigning the items between two grids.
*
*
* @param <S>
* The item-type of source items
* @param <T>
@@ -27,6 +28,7 @@ import org.springframework.util.CollectionUtils;
public abstract class AssignmentSupport<S, T> {
protected final UINotification notification;
protected final VaadinMessageSource i18n;
protected final List<String> lastSpecificErrorMessages = new ArrayList<>();
protected AssignmentSupport(final UINotification notification, final VaadinMessageSource i18n) {
this.notification = notification;
@@ -46,7 +48,7 @@ public abstract class AssignmentSupport<S, T> {
if (sourceItemsToAssign instanceof List) {
assignSourceItemsToTargetItem((List<S>) sourceItemsToAssign, targetItem);
} else {
showGenericErrorNotification();
showErrorNotification();
}
}
@@ -60,26 +62,35 @@ public abstract class AssignmentSupport<S, T> {
*/
public void assignSourceItemsToTargetItem(final List<S> sourceItemsToAssign, final T targetItem) {
if (sourceItemsToAssign.isEmpty()) {
showGenericErrorNotification();
showErrorNotification();
return;
}
final List<S> filteredSourceItems = getFilteredSourceItems(sourceItemsToAssign, targetItem);
if (filteredSourceItems.isEmpty()) {
showGenericErrorNotification();
showErrorNotification();
return;
}
performAssignment(filteredSourceItems, targetItem);
}
private void showGenericErrorNotification() {
notification.displayValidationError(i18n.getMessage("message.action.did.not.work"));
private void showErrorNotification() {
if (lastSpecificErrorMessages.isEmpty()) {
notification.displayValidationError(i18n.getMessage("message.action.did.not.work"));
} else {
lastSpecificErrorMessages.forEach(notification::displayValidationError);
lastSpecificErrorMessages.clear();
}
}
protected void addSpecificValidationErrorMessage(final String errorMessage) {
lastSpecificErrorMessages.add(errorMessage);
}
/**
* Can be overriden in child classes in order to filter source items list.
*
*
* @param targetItem
* may be used for further filtering of source items
*/

View File

@@ -23,6 +23,7 @@ import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSet;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTarget;
import org.eclipse.hawkbit.ui.management.miscs.DeploymentAssignmentWindowController;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
/**
* Support for assigning the distribution sets to target.
@@ -64,9 +65,27 @@ public class DistributionSetsToTargetAssignmentSupport
@Override
protected List<ProxyDistributionSet> getFilteredSourceItems(final List<ProxyDistributionSet> sourceItemsToAssign,
final ProxyTarget targetItem) {
if (!areSourceDsValid(sourceItemsToAssign)) {
return Collections.emptyList();
}
return isMultiAssignmentEnabled() ? sourceItemsToAssign : Collections.singletonList(sourceItemsToAssign.get(0));
}
private boolean areSourceDsValid(final List<ProxyDistributionSet> sourceItemsToAssign) {
return sourceItemsToAssign.stream().allMatch(this::isSourceDsValid);
}
private boolean isSourceDsValid(final ProxyDistributionSet distributionSet) {
if (!distributionSet.getIsValid()) {
addSpecificValidationErrorMessage(i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_DISTRIBUTIONSET_INVALID,
distributionSet.getNameVersion()));
return false;
}
return true;
}
private boolean isMultiAssignmentEnabled() {
return systemSecurityContext.runAsSystem(() -> configManagement
.getConfigurationValue(TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED, Boolean.class).getValue());

View File

@@ -31,6 +31,7 @@ import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload.EntityModi
import org.eclipse.hawkbit.ui.common.event.EventTopics;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.UINotification;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.util.CollectionUtils;
@@ -38,7 +39,7 @@ import org.vaadin.spring.events.EventBus.UIEventBus;
/**
* Support for assigning software modules to distribution set.
*
*
*/
public class SwModulesToDistributionSetAssignmentSupport
extends DeploymentAssignmentSupport<ProxySoftwareModule, ProxyDistributionSet> {
@@ -110,18 +111,25 @@ public class SwModulesToDistributionSetAssignmentSupport
private boolean isTargetDsValid(final ProxyDistributionSet ds, final DistributionSetType dsType) {
if (dsType == null) {
notification.displayValidationError(i18n.getMessage("message.dist.type.notfound", ds.getNameVersion()));
addSpecificValidationErrorMessage(i18n.getMessage("message.dist.type.notfound", ds.getNameVersion()));
return false;
}
if (!ds.getIsValid()) {
/* Distribution is invalidated */
addSpecificValidationErrorMessage(
i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_DISTRIBUTIONSET_INVALID, ds.getNameVersion()));
return false;
}
if (targetManagement.existsByInstalledOrAssignedDistributionSet(ds.getId())) {
/* Distribution is already assigned/installed */
notification.displayValidationError(i18n.getMessage("message.dist.inuse", ds.getNameVersion()));
addSpecificValidationErrorMessage(i18n.getMessage("message.dist.inuse", ds.getNameVersion()));
return false;
}
if (dsManagement.isInUse(ds.getId())) {
notification.displayValidationError(
addSpecificValidationErrorMessage(
i18n.getMessage("message.error.notification.ds.target.assigned", ds.getName(), ds.getVersion()));
return false;
}
@@ -137,8 +145,8 @@ public class SwModulesToDistributionSetAssignmentSupport
private boolean checkDuplicateSmToDsAssignment(final ProxySoftwareModule sm, final ProxyDistributionSet ds,
final Collection<Long> smIdsAlreadyAssignedToDs) {
if (!CollectionUtils.isEmpty(smIdsAlreadyAssignedToDs) && smIdsAlreadyAssignedToDs.contains(sm.getId())) {
notification.displayValidationError(i18n.getMessage("message.software.dist.already.assigned",
sm.getNameAndVersion(), ds.getNameVersion()));
addSpecificValidationErrorMessage(i18n.getMessage("message.software.dist.already.assigned", sm.getNameAndVersion(),
ds.getNameVersion()));
return false;
}
@@ -150,9 +158,8 @@ public class SwModulesToDistributionSetAssignmentSupport
if (!dsType.containsModuleType(sm.getTypeInfo().getId())) {
final String smTypeName = smTypeManagement.get(sm.getTypeInfo().getId()).map(SoftwareModuleType::getName)
.orElse("");
notification.displayValidationError(i18n.getMessage("message.software.dist.type.notallowed",
sm.getNameAndVersion(), ds.getNameVersion(), smTypeName));
addSpecificValidationErrorMessage(i18n.getMessage("message.software.dist.type.notallowed", sm.getNameAndVersion(),
ds.getNameVersion(), smTypeName));
return false;
}

View File

@@ -14,12 +14,13 @@ import java.util.stream.Collectors;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.common.ConfirmationDialog;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.ConfirmationDialog;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSet;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTarget;
import org.eclipse.hawkbit.ui.management.miscs.DeploymentAssignmentWindowController;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
/**
* Support for assigning targets to distribution set.
@@ -53,6 +54,25 @@ public class TargetsToDistributionSetAssignmentSupport
: Collections.singletonList(SpPermission.UPDATE_TARGET);
}
@Override
protected List<ProxyTarget> getFilteredSourceItems(final List<ProxyTarget> sourceItemsToAssign,
final ProxyDistributionSet targetItem) {
if (!isTargetDsValid(targetItem)) {
return Collections.emptyList();
}
return sourceItemsToAssign;
}
private boolean isTargetDsValid(final ProxyDistributionSet distributionSet) {
if (!distributionSet.getIsValid()) {
addSpecificValidationErrorMessage(i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_DISTRIBUTIONSET_INVALID,
distributionSet.getNameVersion()));
return false;
}
return true;
}
@Override
protected void performAssignment(final List<ProxyTarget> sourceItemsToAssign,
final ProxyDistributionSet targetItem) {

View File

@@ -88,7 +88,7 @@ public class DistributionSetGrid extends AbstractDsGrid<DsDistributionsFilterPar
initFilterMappings();
getFilterSupport().setFilter(new DsDistributionsFilterParams());
initIsCompleteStyleGenerator();
initStyleGenerator();
init();
}
@@ -99,8 +99,20 @@ public class DistributionSetGrid extends AbstractDsGrid<DsDistributionsFilterPar
dSTypeFilterLayoutUiState.getClickedTypeId());
}
private void initIsCompleteStyleGenerator() {
setStyleGenerator(ds -> ds.getIsComplete() ? null : SPUIDefinitions.DISABLE_DISTRIBUTION);
private void initStyleGenerator() {
setStyleGenerator(DistributionSetGrid::getRowStyle);
}
private static String getRowStyle(final ProxyDistributionSet ds) {
final StringBuilder style = new StringBuilder();
if (!ds.getIsComplete()) {
style.append(SPUIDefinitions.INCOMPLETE_DISTRIBUTION);
}
if (!ds.getIsValid()) {
style.append(" ");
style.append(SPUIDefinitions.INVALID_DISTRIBUTION);
}
return style.toString();
}
@Override

View File

@@ -16,6 +16,7 @@ import java.util.stream.Collectors;
import org.eclipse.hawkbit.ui.common.notification.ParallelNotification;
import org.eclipse.hawkbit.ui.error.extractors.UiErrorDetailsExtractor;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.UINotification;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.slf4j.Logger;
@@ -76,7 +77,7 @@ public class HawkbitUIErrorHandler implements ErrorHandler {
/**
* Method to find the {@link Page} to show notification on.
*
*
* @param event
* error event
* @return current {@link Page} for error notification
@@ -117,8 +118,8 @@ public class HawkbitUIErrorHandler implements ErrorHandler {
private void showGenericErrorNotification(final Page page, final ErrorEvent event) {
LOG.error("Unexpected Ui error occured", event.getThrowable());
final Notification notification = buildErrorNotification(i18n.getMessage("caption.error"),
i18n.getMessage("message.error"));
final Notification notification = buildErrorNotification(i18n.getMessage(UIMessageIdProvider.CAPTION_ERROR),
i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR));
showErrorNotification(page, notification);
}
@@ -129,7 +130,7 @@ public class HawkbitUIErrorHandler implements ErrorHandler {
/**
* Method to build an error notification based on caption and description.
*
*
* @param caption
* notification caption
* @param description
@@ -143,7 +144,7 @@ public class HawkbitUIErrorHandler implements ErrorHandler {
/**
* Method to show notification on the given page.
*
*
* @param page
* page to show notification on
* @param notification

View File

@@ -17,6 +17,7 @@ import javax.validation.ConstraintViolationException;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.hawkbit.ui.error.UiErrorDetails;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.util.CollectionUtils;
@@ -43,7 +44,8 @@ public class ConstraintViolationErrorExtractor extends AbstractSingleUiErrorDeta
getViolationsDescription(ex).ifPresent(violationsDescription -> descriptionBuilder.append(":")
.append(System.lineSeparator()).append(violationsDescription));
return UiErrorDetails.create(i18n.getMessage("caption.error"), descriptionBuilder.toString());
return UiErrorDetails.create(i18n.getMessage(UIMessageIdProvider.CAPTION_ERROR),
descriptionBuilder.toString());
});
}

View File

@@ -0,0 +1,40 @@
/**
* Copyright (c) 2021 Bosch.IO 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.error.extractors;
import java.util.Optional;
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
import org.eclipse.hawkbit.ui.error.UiErrorDetails;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
/**
* UI error details extractor for {@link InvalidDistributionSetException}.
*/
public class InvalidDistributionSetErrorExtractor extends AbstractSingleUiErrorDetailsExtractor {
private final VaadinMessageSource i18n;
/**
* Constructor for {@link InvalidDistributionSetException}.
*
* @param i18n
* Message source used for localization
*/
public InvalidDistributionSetErrorExtractor(final VaadinMessageSource i18n) {
this.i18n = i18n;
}
@Override
protected Optional<UiErrorDetails> findDetails(final Throwable error) {
return findExceptionOf(error, InvalidDistributionSetException.class)
.map(ex -> UiErrorDetails.create(i18n.getMessage(UIMessageIdProvider.CAPTION_ERROR),
i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_DISTRIBUTIONSET_INVALID, "")));
}
}

View File

@@ -14,6 +14,7 @@ import java.util.Map;
import java.util.concurrent.Executor;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.DistributionSetInvalidationManagement;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
@@ -88,8 +89,9 @@ public class DeploymentView extends AbstractEventListenersAwareView implements B
final UINotification uiNotification, final ManagementUIState managementUIState,
final DeploymentManagement deploymentManagement, final DistributionSetManagement distributionSetManagement,
final SoftwareModuleManagement smManagement,
final DistributionSetTypeManagement distributionSetTypeManagement, final TargetManagement targetManagement,
final EntityFactory entityFactory, final UiProperties uiProperties,
final DistributionSetTypeManagement distributionSetTypeManagement,
final DistributionSetInvalidationManagement dsInvalidationManagement,
final TargetManagement targetManagement, final EntityFactory entityFactory, final UiProperties uiProperties,
final TargetTagManagement targetTagManagement,
final DistributionSetTagManagement distributionSetTagManagement,
final TargetFilterQueryManagement targetFilterQueryManagement, final SystemManagement systemManagement,
@@ -130,7 +132,7 @@ public class DeploymentView extends AbstractEventListenersAwareView implements B
this.distributionTagLayout = new DistributionTagLayout(uiDependencies, distributionSetTagManagement,
distributionSetManagement, managementUIState.getDistributionTagLayoutUiState());
this.distributionGridLayout = new DistributionGridLayout(uiDependencies, targetManagement,
distributionSetManagement, smManagement, distributionSetTypeManagement,
distributionSetManagement, dsInvalidationManagement, smManagement, distributionSetTypeManagement,
distributionSetTagManagement, systemManagement, deploymentManagement, configManagement,
systemSecurityContext, uiProperties, managementUIState.getDistributionGridLayoutUiState(),
managementUIState.getDistributionTagLayoutUiState(),

View File

@@ -16,6 +16,7 @@ import java.util.Map;
import java.util.Optional;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.DistributionSetInvalidationManagement;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -42,6 +43,7 @@ import org.eclipse.hawkbit.ui.common.grid.support.assignment.TargetsToDistributi
import org.eclipse.hawkbit.ui.common.state.TagFilterLayoutUiState;
import org.eclipse.hawkbit.ui.management.miscs.DeploymentAssignmentWindowController;
import org.eclipse.hawkbit.ui.management.targettable.TargetGridLayoutUiState;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
@@ -58,6 +60,7 @@ public class DistributionGrid extends AbstractDsGrid<DsManagementFilterParams> {
private static final long serialVersionUID = 1L;
private static final String DS_PIN_BUTTON_ID = "dsPinnButton";
private static final String DS_INVALIDATE_BUTTON_ID = "dsInvalidateButton";
private final TargetGridLayoutUiState targetGridLayoutUiState;
private final DistributionGridLayoutUiState distributionGridLayoutUiState;
@@ -67,6 +70,8 @@ public class DistributionGrid extends AbstractDsGrid<DsManagementFilterParams> {
private final transient PinSupport<ProxyDistributionSet, String> pinSupport;
private final transient InvalidateDistributionSetSupport invalidateDistributionSetSupport;
/**
* Constructor for DistributionGrid
*
@@ -76,6 +81,8 @@ public class DistributionGrid extends AbstractDsGrid<DsManagementFilterParams> {
* TargetManagement
* @param distributionSetManagement
* DistributionSetManagement
* @param dsInvalidationManagement
* {@link DistributionSetInvalidationManagement}
* @param deploymentManagement
* DeploymentManagement
* @param uiProperties
@@ -88,8 +95,10 @@ public class DistributionGrid extends AbstractDsGrid<DsManagementFilterParams> {
* TagFilterLayoutUiState
*/
public DistributionGrid(final CommonUiDependencies uiDependencies, final TargetManagement targetManagement,
final DistributionSetManagement distributionSetManagement, final DeploymentManagement deploymentManagement,
final UiProperties uiProperties, final DistributionGridLayoutUiState distributionGridLayoutUiState,
final DistributionSetManagement distributionSetManagement,
final DistributionSetInvalidationManagement dsInvalidationManagement,
final DeploymentManagement deploymentManagement, final UiProperties uiProperties,
final DistributionGridLayoutUiState distributionGridLayoutUiState,
final TargetGridLayoutUiState targetGridLayoutUiState,
final TagFilterLayoutUiState distributionTagLayoutUiState) {
super(uiDependencies, distributionSetManagement, distributionGridLayoutUiState, EventView.DEPLOYMENT);
@@ -129,8 +138,10 @@ public class DistributionGrid extends AbstractDsGrid<DsManagementFilterParams> {
DsManagementFilterParams::new, getSelectionSupport()::deselectAll));
initFilterMappings();
getFilterSupport().setFilter(new DsManagementFilterParams());
this.invalidateDistributionSetSupport = new InvalidateDistributionSetSupport(this, i18n, notification,
dsInvalidationManagement);
initTargetPinningStyleGenerator();
initStyleGenerator();
init();
}
@@ -179,8 +190,24 @@ public class DistributionGrid extends AbstractDsGrid<DsManagementFilterParams> {
return installedDsId != null ? Collections.singletonList(installedDsId) : Collections.emptyList();
}
private void initTargetPinningStyleGenerator() {
setStyleGenerator(ds -> pinSupport.getAssignedOrInstalledRowStyle(ds.getId()));
private void initStyleGenerator() {
setStyleGenerator(this::getRowStyle);
}
private String getRowStyle(final ProxyDistributionSet distributionSet) {
final StringBuilder style = new StringBuilder();
final String assignedInstalledStyle = pinSupport.getAssignedOrInstalledRowStyle(distributionSet.getId());
if (assignedInstalledStyle != null) {
style.append(assignedInstalledStyle);
}
if (!distributionSet.getIsValid()) {
style.append(" ");
style.append(SPUIDefinitions.INVALID_DISTRIBUTION);
}
return style.toString();
}
@Override
@@ -194,7 +221,7 @@ public class DistributionGrid extends AbstractDsGrid<DsManagementFilterParams> {
addVersionColumn();
GridComponentBuilder.joinToActionColumn(i18n, getDefaultHeaderRow(),
Arrays.asList(addPinColumn(), addDeleteColumn()));
Arrays.asList(addPinColumn(), addDeleteColumn(), addInvalidateColumn()));
}
private Column<ProxyDistributionSet, Button> addPinColumn() {
@@ -206,6 +233,16 @@ public class DistributionGrid extends AbstractDsGrid<DsManagementFilterParams> {
pinSupport::getPinningStyle);
}
private Column<ProxyDistributionSet, Button> addInvalidateColumn() {
final ValueProvider<ProxyDistributionSet, Button> buttonProvider = ds -> GridComponentBuilder.buildActionButton(
i18n, clickEvent -> invalidateDistributionSetSupport.openConsequencesWindowOnInvalidateAction(ds),
VaadinIcons.BAN, UIMessageIdProvider.TOOLTIP_INVALIDATE_DISTRIBUTIONSET,
SPUIStyleDefinitions.STATUS_ICON_NEUTRAL, UIComponentIdProvider.DIST_INVALIDATE_ICON + "." + ds.getId(),
ds.getIsValid());
return GridComponentBuilder.addIconColumn(this, buttonProvider, DS_INVALIDATE_BUTTON_ID, null);
}
@Override
public void restoreState() {
final Long pinnedDsId = distributionGridLayoutUiState.getPinnedDsId();

View File

@@ -13,6 +13,7 @@ import java.util.Collections;
import java.util.List;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.DistributionSetInvalidationManagement;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
@@ -66,6 +67,8 @@ public class DistributionGridLayout extends AbstractDistributionSetGridLayout {
* TargetManagement
* @param distributionSetManagement
* DistributionSetManagement
* @param dsInvalidationManagement
* {@link DistributionSetInvalidationManagement}
* @param smManagement
* SoftwareModuleManagement
* @param distributionSetTypeManagement
@@ -90,12 +93,15 @@ public class DistributionGridLayout extends AbstractDistributionSetGridLayout {
* TargetGridLayoutUiState
*/
public DistributionGridLayout(final CommonUiDependencies uiDependencies, final TargetManagement targetManagement,
final DistributionSetManagement distributionSetManagement, final SoftwareModuleManagement smManagement,
final DistributionSetManagement distributionSetManagement,
final DistributionSetInvalidationManagement dsInvalidationManagement,
final SoftwareModuleManagement smManagement,
final DistributionSetTypeManagement distributionSetTypeManagement,
final DistributionSetTagManagement distributionSetTagManagement, final SystemManagement systemManagement,
final DeploymentManagement deploymentManagement, final TenantConfigurationManagement configManagement,
final SystemSecurityContext systemSecurityContext, final UiProperties uiProperties,
final DistributionGridLayoutUiState distributionGridLayoutUiState,
final DistributionSetTagManagement distributionSetTagManagement,
final SystemManagement systemManagement, final DeploymentManagement deploymentManagement,
final TenantConfigurationManagement configManagement, final SystemSecurityContext systemSecurityContext,
final UiProperties uiProperties, final DistributionGridLayoutUiState distributionGridLayoutUiState,
final TagFilterLayoutUiState distributionTagLayoutUiState,
final TargetGridLayoutUiState targetGridLayoutUiState) {
super(uiDependencies, systemManagement, systemSecurityContext, configManagement, distributionSetManagement,
@@ -106,8 +112,8 @@ public class DistributionGridLayout extends AbstractDistributionSetGridLayout {
this.distributionGridHeader.buildHeader();
this.distributionGrid = new DistributionGrid(uiDependencies, targetManagement, distributionSetManagement,
deploymentManagement, uiProperties, distributionGridLayoutUiState, targetGridLayoutUiState,
distributionTagLayoutUiState);
dsInvalidationManagement, deploymentManagement, uiProperties, distributionGridLayoutUiState,
targetGridLayoutUiState, distributionTagLayoutUiState);
this.distributionSetDetailsHeader = new DistributionSetDetailsHeader(uiDependencies, getDsWindowBuilder(),
getDsMetaDataWindowBuilder());

View File

@@ -0,0 +1,178 @@
/**
* Copyright (c) 2021 Bosch.IO 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.management.dstable;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
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.common.data.proxies.ProxyDistributionSet;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.UINotification;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import com.google.common.collect.Lists;
import com.vaadin.server.Sizeable;
import com.vaadin.ui.UI;
/**
* Support for invalidate a distribution set in the ds grid.
*/
public class InvalidateDistributionSetSupport {
private static final Logger LOG = LoggerFactory.getLogger(InvalidateDistributionSetSupport.class);
private final VaadinMessageSource i18n;
private final UINotification notification;
private final DistributionGrid grid;
private final DistributionSetInvalidationManagement dsInvalidationManagement;
private InvalidateDsConsequencesDialog consequencesDialog;
/**
* Constructor for InvalidateDistributionSetSupport
*
* @param grid
* Vaadin Grid
* @param i18n
* VaadinMessageSource
* @param notification
* UINotification
* @param dsInvalidationManagement
* {@link DistributionSetInvalidationManagement}
*/
public InvalidateDistributionSetSupport(final DistributionGrid grid, final VaadinMessageSource i18n,
final UINotification notification, final DistributionSetInvalidationManagement dsInvalidationManagement) {
this.grid = grid;
this.i18n = i18n;
this.notification = notification;
this.dsInvalidationManagement = dsInvalidationManagement;
}
/**
* Open confirmation pop up window for invalidate distribution set
*
* @param clickedDistributionSet
* {@link ProxyDistributionSet} that should be invalidated
*/
public void openConsequencesWindowOnInvalidateAction(final ProxyDistributionSet clickedDistributionSet) {
final List<ProxyDistributionSet> allDistributionSetsForInvalidation = getDistributionSetsForInvalidation(
clickedDistributionSet);
consequencesDialog = new InvalidateDsConsequencesDialog(allDistributionSetsForInvalidation, i18n, ok -> {
if (ok) {
openAffectedEntitiesWindowOnInvalidateAction(allDistributionSetsForInvalidation);
}
});
consequencesDialog.getWindow().setWidth(40.0F, Sizeable.Unit.PERCENTAGE);
UI.getCurrent().addWindow(consequencesDialog.getWindow());
consequencesDialog.getWindow().bringToFront();
}
private void openAffectedEntitiesWindowOnInvalidateAction(
final List<ProxyDistributionSet> allDistributionSetsForInvalidation) {
final DistributionSetInvalidationCount entitiesForInvalidationCount = dsInvalidationManagement
.countEntitiesForInvalidation(
getDistributionSetInvalidation(consequencesDialog.isStopRolloutsSelected(),
getDistributionSetIds(allDistributionSetsForInvalidation), CancelationType.NONE));
final InvalidateDsAffectedEntitiesDialog affectedEntitiesDialog = new InvalidateDsAffectedEntitiesDialog(
allDistributionSetsForInvalidation, i18n, ok -> {
if (ok) {
handleOkForInvalidateDistributionSet(allDistributionSetsForInvalidation);
}
}, entitiesForInvalidationCount.getRolloutsCount(),
entitiesForInvalidationCount.getAutoAssignmentCount());
affectedEntitiesDialog.getWindow().setWidth(40.0F, Sizeable.Unit.PERCENTAGE);
UI.getCurrent().addWindow(affectedEntitiesDialog.getWindow());
affectedEntitiesDialog.getWindow().bringToFront();
}
private void handleOkForInvalidateDistributionSet(
final List<ProxyDistributionSet> allDistributionSetsForInvalidation) {
try {
dsInvalidationManagement.invalidateDistributionSet(
getDistributionSetInvalidation(consequencesDialog.isStopRolloutsSelected(),
getDistributionSetIds(allDistributionSetsForInvalidation), CancelationType.NONE));
notification.displaySuccess(createSuccessNotificationText(allDistributionSetsForInvalidation));
grid.refreshAll();
} catch (final RuntimeException ex) {
LOG.warn("Invalidating DistributionSets '{}' failed: {}", StringUtils.collectionToCommaDelimitedString(
getDistributionSetIds(allDistributionSetsForInvalidation)), ex.getMessage());
notification.displayWarning(createFailureNotificationText(allDistributionSetsForInvalidation));
throw ex;
}
}
private DistributionSetInvalidation getDistributionSetInvalidation(final boolean stopRollouts,
final List<Long> distSetIds, final CancelationType cancelationType) {
return new DistributionSetInvalidation(distSetIds, cancelationType, stopRollouts);
}
private String createFailureNotificationText(final List<ProxyDistributionSet> allDistributionSetsForInvalidation) {
String failureNotificationText = "";
if (allDistributionSetsForInvalidation.size() == 1) {
failureNotificationText = i18n.getMessage(
UIMessageIdProvider.MESSAGE_INVALIDATE_DISTRIBUTIONSET_FAIL_SINGULAR,
allDistributionSetsForInvalidation.get(0).getNameVersion());
} else {
failureNotificationText = i18n.getMessage(
UIMessageIdProvider.MESSAGE_INVALIDATE_DISTRIBUTIONSET_FAIL_PLURAL,
allDistributionSetsForInvalidation.size());
}
return failureNotificationText;
}
private String createSuccessNotificationText(final List<ProxyDistributionSet> allDistributionSetsForInvalidation) {
String successNotificationText = "";
if (allDistributionSetsForInvalidation.size() == 1) {
successNotificationText = i18n.getMessage(
UIMessageIdProvider.MESSAGE_INVALIDATE_DISTRIBUTIONSET_SUCCESS_SINGULAR,
allDistributionSetsForInvalidation.get(0).getNameVersion());
} else {
successNotificationText = i18n.getMessage(
UIMessageIdProvider.MESSAGE_INVALIDATE_DISTRIBUTIONSET_SUCCESS_PLURAL,
allDistributionSetsForInvalidation.size());
}
return successNotificationText;
}
private static List<Long> getDistributionSetIds(
final List<ProxyDistributionSet> allDistributionSetsForInvalidation) {
return allDistributionSetsForInvalidation.stream().map(ProxyDistributionSet::getId)
.collect(Collectors.toList());
}
private List<ProxyDistributionSet> getDistributionSetsForInvalidation(final ProxyDistributionSet clickedItem) {
final List<ProxyDistributionSet> selectedItems = Lists.newArrayList(grid.getSelectedItems());
if (selectedItems.contains(clickedItem)) {
// consider only valid DS for invalidation
return selectedItems.stream().filter(ProxyDistributionSet::getIsValid).collect(Collectors.toList());
} else {
// only clicked item should be invalidated if it is not part of the
// selection
grid.deselectAll();
grid.select(clickedItem);
return Collections.singletonList(clickedItem);
}
}
}

View File

@@ -0,0 +1,133 @@
/**
* Copyright (c) 2021 Bosch.IO 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.management.dstable;
import java.util.List;
import java.util.function.Consumer;
import org.eclipse.hawkbit.repository.model.Rollout;
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.decorators.SPUIButtonStyleTiny;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
/**
* Showing the affected entities for invalidating a distribution set.
*/
public class InvalidateDsAffectedEntitiesDialog {
private final Consumer<Boolean> callback;
private final CommonDialogWindow window;
private final VaadinMessageSource i18n;
/**
* Constructor for {@link InvalidateDsAffectedEntitiesDialog}
*
* @param allDistributionSetsForInvalidation
* {@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
*/
public InvalidateDsAffectedEntitiesDialog(final List<ProxyDistributionSet> allDistributionSetsForInvalidation,
final VaadinMessageSource i18n, final Consumer<Boolean> callback, final long affectedRollouts,
final long affectedAutoAssignments) {
this.i18n = i18n;
final VerticalLayout content = new VerticalLayout();
content.setSpacing(true);
content.setMargin(true);
final Label consequencesLabel = new Label(createConsequencesText(allDistributionSetsForInvalidation));
consequencesLabel.setWidthFull();
content.addComponent(consequencesLabel);
final Label stoppedRolloutsLabel = new Label(i18n.getMessage(
UIMessageIdProvider.MESSAGE_INVALIDATE_DISTRIBUTIONSET_AFFECTED_ENTITIES_ROLLOUTS, affectedRollouts));
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));
stoppedAutoAssignmentsLabel.setId(UIComponentIdProvider.INVALIDATE_DS_AFFECTED_ENTITIES_AUTOASSIGNMENTS);
content.addComponent(stoppedAutoAssignmentsLabel);
final WindowBuilder windowBuilder = new WindowBuilder(SPUIDefinitions.CREATE_UPDATE_WINDOW)
.id(UIComponentIdProvider.INVALIDATE_DS_AFFECTED_ENTITIES)
.caption(i18n.getMessage(UIMessageIdProvider.CAPTION_INVALIDATE_DISTRIBUTIONSET_AFFECTED_ENTITIES))
.content(content).cancelButtonClickListener(e -> callback.accept(false))
.saveDialogCloseListener(getSaveDialogCloseListener()).hideMandatoryExplanation()
.buttonDecorator(SPUIButtonStyleTiny.class).confirmStyle(ConfirmStyle.CONFIRM).i18n(i18n);
this.window = windowBuilder.buildCommonDialogWindow();
window.setSaveButtonEnabled(true);
window.addStyleName(SPUIStyleDefinitions.CONFIRMBOX_WINDOW_STYLE);
this.callback = callback;
}
private String createConsequencesText(final List<ProxyDistributionSet> allDistributionSetsForInvalidation) {
String consequencesText = "";
if (allDistributionSetsForInvalidation.size() == 1) {
final ProxyDistributionSet distributionSet = allDistributionSetsForInvalidation.get(0);
consequencesText = i18n.getMessage(
UIMessageIdProvider.MESSAGE_INVALIDATE_DISTRIBUTIONSET_AFFECTED_ENTITIES_INTRO_SINGULAR,
HawkbitCommonUtil.getFormattedNameVersion(distributionSet.getName(), distributionSet.getVersion()));
} else {
consequencesText = i18n.getMessage(
UIMessageIdProvider.MESSAGE_INVALIDATE_DISTRIBUTIONSET_AFFECTED_ENTITIES_INTRO_PLURAL,
allDistributionSetsForInvalidation.size());
}
return consequencesText;
}
private SaveDialogCloseListener getSaveDialogCloseListener() {
return new SaveDialogCloseListener() {
@Override
public void saveOrUpdate() {
callback.accept(true);
}
@Override
public boolean canWindowSaveOrUpdate() {
return true;
}
};
}
/**
* @return confirmation window
*/
public Window getWindow() {
return window;
}
}

View File

@@ -0,0 +1,136 @@
/**
* Copyright (c) 2021 Bosch.IO 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.management.dstable;
import java.util.List;
import java.util.function.Consumer;
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.decorators.SPUIButtonStyleTiny;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
/**
* Showing the consequences for invalidating distribution set.
*/
public class InvalidateDsConsequencesDialog {
private final Consumer<Boolean> callback;
private final CommonDialogWindow window;
private final CheckBox stopRolloutsCheckBox;
private final VaadinMessageSource i18n;
/**
* Constructor for {@link InvalidateDsConsequencesDialog}
*
* @param allDistributionSetsForInvalidation
* {@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) {
this.i18n = i18n;
final VerticalLayout content = new VerticalLayout();
content.setSpacing(true);
content.setMargin(true);
final Label consequencesLabel = new Label(createConsequencesText(allDistributionSetsForInvalidation));
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(stopRolloutsCheckBox);
final WindowBuilder windowBuilder = new WindowBuilder(SPUIDefinitions.CREATE_UPDATE_WINDOW)
.id(UIComponentIdProvider.INVALIDATE_DS_CONSEQUENCES)
.caption(createCaption(allDistributionSetsForInvalidation)).content(content)
.cancelButtonClickListener(e -> callback.accept(false))
.saveDialogCloseListener(getSaveDialogCloseListener()).hideMandatoryExplanation()
.buttonDecorator(SPUIButtonStyleTiny.class).confirmStyle(ConfirmStyle.NEXT).i18n(i18n);
this.window = windowBuilder.buildCommonDialogWindow();
window.setSaveButtonEnabled(true);
window.addStyleName(SPUIStyleDefinitions.CONFIRMBOX_WINDOW_STYLE);
this.callback = callback;
}
private SaveDialogCloseListener getSaveDialogCloseListener() {
return new SaveDialogCloseListener() {
@Override
public void saveOrUpdate() {
callback.accept(true);
}
@Override
public boolean canWindowSaveOrUpdate() {
return true;
}
};
}
private String createCaption(final List<ProxyDistributionSet> allDistributionSetsForInvalidation) {
String caption = "";
if (allDistributionSetsForInvalidation.size() == 1) {
caption = i18n.getMessage(UIMessageIdProvider.CAPTION_INVALIDATE_DISTRIBUTIONSET_CONSEQUENCES_SINGULAR,
allDistributionSetsForInvalidation.get(0).getNameVersion());
} else {
caption = i18n.getMessage(UIMessageIdProvider.CAPTION_INVALIDATE_DISTRIBUTIONSET_CONSEQUENCES_PLURAL,
allDistributionSetsForInvalidation.size());
}
return caption;
}
private String createConsequencesText(final List<ProxyDistributionSet> allDistributionSetsForInvalidation) {
if (allDistributionSetsForInvalidation.size() == 1) {
return i18n.getMessage(UIMessageIdProvider.MESSAGE_INVALIDATE_DISTRIBUTIONSET_CONSEQUENCES_SINGULAR);
} else {
return i18n.getMessage(UIMessageIdProvider.MESSAGE_INVALIDATE_DISTRIBUTIONSET_CONSEQUENCES_PLURAL,
allDistributionSetsForInvalidation.size());
}
}
/**
* Returns the user selection stop rollouts
*
* @return boolean value of checkbox stop rollouts
*/
boolean isStopRolloutsSelected() {
return stopRolloutsCheckBox.getValue();
}
/**
* @return confirmation window
*/
public Window getWindow() {
return window;
}
}

View File

@@ -49,6 +49,7 @@ import org.eclipse.hawkbit.ui.common.grid.support.SelectionSupport;
import org.eclipse.hawkbit.ui.rollout.DistributionBarHelper;
import org.eclipse.hawkbit.ui.rollout.RolloutManagementUIState;
import org.eclipse.hawkbit.ui.rollout.window.RolloutWindowBuilder;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
@@ -137,6 +138,7 @@ public class RolloutGrid extends AbstractGrid<ProxyRollout, String> {
UIComponentIdProvider.ROLLOUT_STATUS_LABEL_ID);
actionTypeIconSupplier = new ActionTypeIconSupplier<>(i18n, ProxyRollout::getActionType,
UIComponentIdProvider.ROLLOUT_ACTION_TYPE_LABEL_ID);
init();
}
@@ -266,8 +268,9 @@ public class RolloutGrid extends AbstractGrid<ProxyRollout, String> {
GridComponentBuilder.addDescriptionColumn(this, i18n, DESC_ID).setHidable(true).setHidden(true);
GridComponentBuilder.addColumn(this, ProxyRollout::getDsNameVersion).setId(DIST_NAME_VERSION_ID)
.setCaption(i18n.getMessage("header.distributionset")).setHidable(true).setExpandRatio(2);
GridComponentBuilder.addColumn(this, ProxyRollout::getDsNameVersion, this::getDistributionCellStyle)
.setId(DIST_NAME_VERSION_ID).setCaption(i18n.getMessage("header.distributionset"))
.setDescriptionGenerator(this::createDSTooltipText).setHidable(true).setExpandRatio(2);
GridComponentBuilder
.addIconColumn(this, rolloutStatusIconSupplier::getLabel, STATUS_ID, i18n.getMessage("header.status"))
@@ -464,4 +467,20 @@ public class RolloutGrid extends AbstractGrid<ProxyRollout, String> {
onSelectedRolloutDeleted(selectedRolloutId);
}
}
private String getDistributionCellStyle(final ProxyRollout rollout) {
if (!rollout.getDsInfo().isValid()) {
return SPUIDefinitions.INVALID_DISTRIBUTION;
}
return null;
}
protected String createDSTooltipText(final ProxyRollout rollout) {
final StringBuilder tooltipText = new StringBuilder(rollout.getDsInfo().getNameVersion());
if (!rollout.getDsInfo().isValid()) {
tooltipText.append(" - ");
tooltipText.append(i18n.getMessage(UIMessageIdProvider.TOOLTIP_DISTRIBUTIONSET_INVALID));
}
return tooltipText.toString();
}
}

View File

@@ -61,6 +61,7 @@ public class CopyRolloutWindowController extends AddRolloutWindowController {
proxyRolloutWindow.setName(getI18n().getMessage("textfield.rollout.copied.name", proxyRolloutWindow.getName()));
removeDistributionSetIfInvalid(proxyRolloutWindow);
setTargetFilterId(proxyRolloutWindow);
if (proxyRolloutWindow.getForcedTime() == null
@@ -84,6 +85,14 @@ public class CopyRolloutWindowController extends AddRolloutWindowController {
return proxyRolloutWindow;
}
private void removeDistributionSetIfInvalid(final ProxyRolloutWindow proxyRolloutWindow) {
final boolean dsIsValid = proxyRolloutWindow.getRolloutForm().getDistributionSetInfo().isValid();
if (!dsIsValid) {
proxyRolloutWindow.getRolloutForm().setDistributionSetInfo(null);
}
}
private void setTargetFilterId(final ProxyRolloutWindow proxyRolloutWindow) {
final Page<TargetFilterQuery> filterQueries = targetFilterQueryManagement.findByQuery(PageRequest.of(0, 1),
proxyRolloutWindow.getTargetFilterQuery());

View File

@@ -203,7 +203,12 @@ public final class SPUIDefinitions {
public static final String FILTER_RESET_ICON = "filter-reset-icon";
/* Action History */
public static final String DISABLE_DISTRIBUTION = "incomplete-distribution";
public static final String INCOMPLETE_DISTRIBUTION = "incomplete-distribution";
/**
* marker for invalid distribution sets
*/
public static final String INVALID_DISTRIBUTION = "invalid-distribution";
/**
* Filter by type layout width.

View File

@@ -52,9 +52,13 @@ public final class UIComponentIdProvider {
*/
public static final String TARGET_PIN_ICON = "target.pin.icon";
/**
* ID-Targ.PIN.
* ID-DistributionSet pin icon.
*/
public static final String DIST_PIN_ICON = "dist.pin.icon";
/**
* ID-DistributionSet invalidate icon.
*/
public static final String DIST_INVALIDATE_ICON = "dist.invalidate.icon";
/**
* ID-Targ.DELETE.
*/
@@ -1360,6 +1364,28 @@ public final class UIComponentIdProvider {
public static final String DIST_SET_SELECT_CONS_WINDOW_ID = "distribution.set.select.consequences.window";
public static final String DIST_SET_SELECT_ENABLE_ID = "distribution.set.select.enable";
/**
* Distribution set invalidate consequences window id
*/
public static final String INVALIDATE_DS_CONSEQUENCES = "invalidate.distributionset.consequences.window";
/**
* Distribution set invalidate affected entities window id
*/
public static final String INVALIDATE_DS_AFFECTED_ENTITIES = "invalidate.distributionset.affectedentities.window";
/**
* Distribution set invalidate affected rollouts label id
*/
public static final String INVALIDATE_DS_AFFECTED_ENTITIES_ROLLOUTS = "invalidate.distributionset.affectedentities.rollouts";
/**
* Distribution set invalidate affected autoassignments label id
*/
public static final String INVALIDATE_DS_AFFECTED_ENTITIES_AUTOASSIGNMENTS = "invalidate.distributionset.affectedentities.autoassignments";
/**
* Distribution set invalidate consequences window, stop rollouts checkbox
*/
public static final String INVALIDATE_DS_STOP_ROLLOUTS = "invalidate.distributionset.consequences.stop.rollouts.checkbox";
/**
* Id of the unread notification button
*/

View File

@@ -25,6 +25,10 @@ public final class UIMessageIdProvider {
public static final String BUTTON_SAVE = "button.save";
public static final String BUTTON_NEXT = "button.next";
public static final String BUTTON_CONFIRM = "button.confirm";
public static final String BUTTON_NO_AUTO_ASSIGNMENT = "button.no.auto.assignment";
public static final String BUTTON_AUTO_ASSIGNMENT_DESCRIPTION = "button.auto.assignment.desc";
@@ -71,6 +75,12 @@ public final class UIMessageIdProvider {
public static final String CAPTION_ENTITY_ASSIGN_ACTION_CONFIRMBOX = "caption.entity.assign.action.confirmbox";
public static final String CAPTION_INVALIDATE_DISTRIBUTIONSET_CONSEQUENCES_SINGULAR = "caption.invalidate.distributionset.consequences.singular";
public static final String CAPTION_INVALIDATE_DISTRIBUTIONSET_CONSEQUENCES_PLURAL = "caption.invalidate.distributionset.consequences.plural";
public static final String CAPTION_INVALIDATE_DISTRIBUTIONSET_AFFECTED_ENTITIES = "caption.invalidate.distributionset.affected.entities";
public static final String CAPTION_CONFIG_CREATE = "caption.config.create";
public static final String CAPTION_CONFIG_EDIT = "caption.config.edit";
@@ -93,6 +103,8 @@ public final class UIMessageIdProvider {
public static final String LABEL_AUTO_ASSIGNMENT_ENABLE = "label.auto.assign.enable";
public static final String LABEL_INVALIDATE_DS_STOP_ROLLOUTS = "label.invalidate.distributionset.stop.rollouts";
public static final String MESSAGE_NO_DATA = "message.no.data";
public static final String MESSAGE_DATA_AVAILABLE = "message.data.available";
@@ -111,12 +123,18 @@ public final class UIMessageIdProvider {
public static final String MESSAGE_AUTOASSIGN_CREATE_ERROR_MISSINGELEMENTS = "message.autoassign.create.error.missingElements";
public static final String MESSAGE_DISTRIBUTION_ASSIGNED = "message.dist.already.assigned";
public static final String MESSAGE_DISTRIBUTION_NOT_ASSIGNED = "message.dist.not.assigned";
public static final String MESSAGE_ERROR_NAMEREQUIRED = "message.error.nameRequired";
public static final String MESSAGE_ERROR_VERSIONREQUIRED = "message.error.versionRequired";
public static final String MESSAGE_ERROR_DISTRIBUTIONSET_REQUIRED = "message.error.distributionSetRequired";
public static final String MESSAGE_ERROR_DISTRIBUTIONSET_INVALID = "message.error.distributionset.invalid";
public static final String MESSAGE_ERROR_TFQ_REQUIRED = "message.error.tfqRequired";
public static final String MESSAGE_FILTER_QUERY_ERROR_NOTVALIDE = "message.filter.query.error.notValide";
@@ -171,6 +189,12 @@ public final class UIMessageIdProvider {
public static final String TOOLTIP_DISTRIBUTION_SET_PIN = "tooltip.distribution.set.pin";
public static final String TOOLTIP_INVALIDATE_DISTRIBUTIONSET = "tooltip.invalidate.distributionset";
public static final String TOOLTIP_DISTRIBUTIONSET_INVALID = "tooltip.distributionset.invalid";
public static final String TOOLTIP_DISTRIBUTIONSET_INCOMPLETE = "tooltip.distributionset.incomplete";
public static final String TOOLTIP_TIMEFORCED_ITEM = "tooltip.timeforced.item";
public static final String TOOLTIP_TIMEFORCED_FORCED_IN = "tooltip.timeforced.forced.in";
@@ -233,12 +257,36 @@ public final class UIMessageIdProvider {
public static final String CAPTION_SOFTWARE_MODULE = "caption.software.module";
public static final String CAPTION_ERROR = "caption.error";
public static final String MESSAGE_ERROR = "message.error";
public static final String MESSAGE_TARGET_BULKUPLOAD_RESULT_SUCCESS = "message.bulk.upload.result.success";
public static final String MESSAGE_TARGET_BULKUPLOAD_RESULT_FAIL = "message.bulk.upload.result.fail";
public static final String MESSAGE_CLEAR_FILE_UPLOAD_QUEUE = "message.clear.file.upload.queue.confirm";
public static final String MESSAGE_INVALIDATE_DISTRIBUTIONSET_CONSEQUENCES_SINGULAR = "message.invalidate.distributionset.consequences.singular";
public static final String MESSAGE_INVALIDATE_DISTRIBUTIONSET_CONSEQUENCES_PLURAL = "message.invalidate.distributionset.consequences.plural";
public static final String MESSAGE_INVALIDATE_DISTRIBUTIONSET_AFFECTED_ENTITIES_INTRO_SINGULAR = "message.invalidate.distributionset.affected.entities.intro.singular";
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_ROLLOUTS = "message.invalidate.distributionset.affected.entities.rollouts";
public static final String MESSAGE_INVALIDATE_DISTRIBUTIONSET_AFFECTED_ENTITIES_AUTOASSIGNMENTS = "message.invalidate.distributionset.affected.entities.autoassignments";
public static final String MESSAGE_INVALIDATE_DISTRIBUTIONSET_SUCCESS_SINGULAR = "message.invalidate.distributionset.success.singular";
public static final String MESSAGE_INVALIDATE_DISTRIBUTIONSET_SUCCESS_PLURAL = "message.invalidate.distributionset.success.plural";
public static final String MESSAGE_INVALIDATE_DISTRIBUTIONSET_FAIL_SINGULAR = "message.invalidate.distributionset.fail.singular";
public static final String MESSAGE_INVALIDATE_DISTRIBUTIONSET_FAIL_PLURAL = "message.invalidate.distributionset.fail.plural";
public static final String VAADIN_SYSTEM_SESSIONEXPIRED_CAPTION = "vaadin.system.sessionexpired.caption";
public static final String VAADIN_SYSTEM_SESSIONEXPIRED_MESSAGE = "vaadin.system.sessionexpired.message";

View File

@@ -201,6 +201,14 @@
.v-grid-row.incomplete-distribution>.v-grid-cell {
color: $disabled-row-color-grey !important;
}
// Disabled row/cell style when distribution is invalid
.v-grid-row.invalid-distribution,
.v-grid-row.invalid-distribution>.v-grid-cell,
td.v-grid-cell.invalid-distribution {
color: $disabled-row-color-grey !important;
text-decoration: line-through !important;
}
.v-link {
text-decoration: none;

View File

@@ -34,6 +34,8 @@ button.actions = You have actions
button.no.actions = No actions
button.ok = OK
button.cancel = Cancel
button.next = Next
button.confirm = Confirm
button.upload.file = Upload File
button.no.auto.assignment = none
button.auto.assignment.desc = Select auto assign distribution set
@@ -154,6 +156,9 @@ caption.config.edit = edit
caption.config.delete = delete
caption.metadata.popup = Metadata of
caption.invalidate.distributionset.consequences.singular = Invalidate distribution set - {0}
caption.invalidate.distributionset.consequences.plural = Invalidate {0} distribution sets
caption.invalidate.distributionset.affected.entities = Invalidation confirmation
caption.confirm.assign.consequences = Auto assign consequences
caption.auto.assignment.ds = Auto assignment
@@ -249,6 +254,7 @@ label.approval.remark = Remark (optional)
label.drop.area.upload = Drop Files to upload
label.errorthreshold.option.percent = %
label.errorthreshold.option.count = Count
label.invalidate.distributionset.stop.rollouts = Stop rollouts
# TextFields prefix with - textfield
textfield.name = Name
@@ -369,6 +375,9 @@ tooltip.target.status.pending = Status pending
tooltip.target.status.registered = Status registered
tooltip.target.pin = Pin target
tooltip.distribution.set.pin = Pin distribution set
tooltip.invalidate.distributionset = Invalidate distribution set..
tooltip.distributionset.invalid = invalid
tooltip.distributionset.incomplete = incomplete
tooltip.in.time = In Time
# Notification messages prefix with - message
@@ -463,6 +472,7 @@ message.error.missing.filtername = Please select target filter name
message.error.missing.controllerId = Missing Controller Id
message.error.missing.nameorversion = Missing Name or Version
message.error.missing.nameorversionortype = Missing Name or Version or Type
message.error.distributionset.invalid = Action not allowed for invalid distribution set {0}
message.type.delete = Please unclick the type {0}, then try to delete
message.error.dist.set.type.update= Distribution set type is already assigned to set(s) and cannot be changed
message.no.directory.upload = Directory upload is not supported
@@ -478,7 +488,7 @@ message.bulk.upload.upload.started = Uploading a file..
message.bulk.upload.provisioning.started = Provisioning targets..
message.bulk.upload.assignment.started = Assigning tags and DS..
message.bulk.upload.tag.assignment.failed = Tag {0} assignment failed as tag no longer exists
message.bulk.upload.tag.assignments.failed= Few tag assignments failed as tags no longer exists
message.bulk.upload.tag.assignments.failed= Few tag assignments failed as tags no longer exists
message.confirm.assign.consequences.none = This auto assignment will not have any effect on the currently available targets. In future added targets might match the filter and will receive the selected distribution set automatically.
message.confirm.assign.consequences.text = When you confirm this auto assignment, {0} targets which match the filter will immediately get assigned with the selected distribution set.
message.maintenancewindow.schedule.required.error = Please provide a Cron expression
@@ -501,6 +511,16 @@ message.forcedTime.cannotBeEmpty = Forced time can not be empty
message.forcedTime.missing = Force time is not specified for the time-forced assignment
message.scheduledTime.cannotBeEmpty = Scheduled time can not be empty
message.clear.file.upload.queue.confirm = There is still at least one queued file upload pending. By leaving this view the upload queue will be cleared. \nAre you sure you want to leave this view?
message.invalidate.distributionset.success.singular = Distribution set {0} invalidated successfully
message.invalidate.distributionset.success.plural = {0} distribution sets invalidated successfully
message.invalidate.distributionset.fail.singular = Distribution set {0} invalidation failed
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.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.rollouts = {0} rollout(s) will be stopped
message.invalidate.distributionset.affected.entities.autoassignments = {0} auto assignment(s) will be stopped
# action info
action.target.table.selectall = Select all (Ctrl+A)
@@ -728,6 +748,7 @@ message.rollout.noofgroups.or.targetfilter.missing = Please enter number of grou
message.rollouts = Rollouts
label.target.per.group = Targets per group:
message.dist.already.assigned = Distribution {0} is already assigned to target
message.dist.not.assigned = Distribution {0} was not assigned to target
message.error.creating.rollout = Server error. Error creating Rollout. Please contact the administrator
message.error.starting.rollout = Server error. Error starting Rollout. Please contact the administrator