Support user consent flow (#1293)
* Introduce user consent flow * Add permissions to confirmation management * rename from consent to confirmation * Reformat code. Remove unused imports. Change and add permission checks when configuring auto-confirmation. * Do not include null values for DDI confirmation base endpoint * fix confirmation required checkbox id * Remove unused import. Fix consume/produce type of new API's. * Change term processing to proceeding when activating user consent flow * Align formatting and extend integration test cases for DMF and DDI. * Extend DMF test cases to consider auto-confirmation * Refactor action management to fix problem of handling action status updates on closed actions. * remove unsupported validation * use new confirmation api for DMF. Extend test cases., * Remove unnecessary fields. * Extend API documentation for DDI and MGMT API. * adapt ddi api docs adoc file * Fixed the duplicate migration version for db files * fix method to support confirmation * Fixed PR comments * Addressed PR comments * Fixed after merge compilation issue * Fixed after merge compilation issue * Fix failing tests in MgmtRolloutResourceTest * Fixed the permissions issue reflected by integration tests * Added back the missing line of code lost during merge * Fix the failing test on Jenkins Signed-off-by: Stanislav Trailov <stanislav.trailov@bosch.io> Signed-off-by: Dimitar Shterev <dimitar.shterev@bosch.io> Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> Signed-off-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com> Co-authored-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com>
This commit is contained in:
@@ -254,6 +254,15 @@ public class UiProperties implements Serializable {
|
||||
*/
|
||||
private String maintenanceWindowView = "";
|
||||
|
||||
/**
|
||||
* Link to documentation of the user consent and confirmation flow.
|
||||
*/
|
||||
private String userConsentAndConfirmationGuide = "";
|
||||
|
||||
public String getAutoConfirmationView() {
|
||||
return autoConfirmationView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Link to documentation of system configuration view.
|
||||
*/
|
||||
@@ -279,6 +288,11 @@ public class UiProperties implements Serializable {
|
||||
*/
|
||||
private String rolloutView = "";
|
||||
|
||||
/**
|
||||
* Link to documentation of auto confirmation view.
|
||||
*/
|
||||
private String autoConfirmationView = "";
|
||||
|
||||
/**
|
||||
* Link to documentation of state machine
|
||||
*/
|
||||
@@ -353,6 +367,13 @@ public class UiProperties implements Serializable {
|
||||
return maintenanceWindowView;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Link to documentation of the user consent and confirmation flow.
|
||||
*/
|
||||
public String getUserConsentAndConfirmationGuide() {
|
||||
return userConsentAndConfirmationGuide;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Link to documentation of provisioning state machine
|
||||
*/
|
||||
@@ -425,6 +446,10 @@ public class UiProperties implements Serializable {
|
||||
this.maintenanceWindowView = maintenanceWindowView;
|
||||
}
|
||||
|
||||
public void setUserConsentAndConfirmationGuide(final String userConsentAndConfirmationGuide) {
|
||||
this.userConsentAndConfirmationGuide = userConsentAndConfirmationGuide;
|
||||
}
|
||||
|
||||
public void setProvisioningStateMachine(final String provisioningStateMachine) {
|
||||
this.provisioningStateMachine = provisioningStateMachine;
|
||||
}
|
||||
|
||||
@@ -302,22 +302,22 @@ public class UploadArtifactView extends AbstractEventListenersAwareView implemen
|
||||
@Override
|
||||
public void beforeLeave(final ViewBeforeLeaveEvent event) {
|
||||
if (isAnyUploadInUploadQueue()) {
|
||||
final ConfirmationDialog confirmDeleteDialog = new ConfirmationDialog(i18n,
|
||||
i18n.getMessage(UIMessageIdProvider.CAPTION_CLEAR_FILE_UPLOAD_QUEUE),
|
||||
i18n.getMessage(UIMessageIdProvider.MESSAGE_CLEAR_FILE_UPLOAD_QUEUE), ok -> {
|
||||
if (Boolean.TRUE.equals(ok)) {
|
||||
// Clear all queued file uploads
|
||||
artifactUploadState.clearFileStates();
|
||||
super.beforeLeave(event);
|
||||
} else {
|
||||
// Send a PostViewChangeEvent to the DashboardMenu
|
||||
// as if the navigation actually
|
||||
// happened to prevent the DashboardMenu navigation
|
||||
// from getting stuck
|
||||
final DashboardMenuItem dashboardMenuItem = dashboardMenu.getByViewName(VIEW_NAME);
|
||||
dashboardMenu.postViewChange(DashboardEvent.createPostViewChangeEvent(dashboardMenuItem));
|
||||
}
|
||||
}, UIComponentIdProvider.UPLOAD_QUEUE_CLEAR_CONFIRMATION_DIALOG);
|
||||
final ConfirmationDialog confirmDeleteDialog = ConfirmationDialog
|
||||
.newBuilder(i18n, UIComponentIdProvider.UPLOAD_QUEUE_CLEAR_CONFIRMATION_DIALOG)
|
||||
.caption(i18n.getMessage(UIMessageIdProvider.CAPTION_CLEAR_FILE_UPLOAD_QUEUE))
|
||||
.question(i18n.getMessage(UIMessageIdProvider.MESSAGE_CLEAR_FILE_UPLOAD_QUEUE))
|
||||
.onSaveOrUpdate(() -> {
|
||||
// Clear all queued file uploads
|
||||
artifactUploadState.clearFileStates();
|
||||
super.beforeLeave(event);
|
||||
}).onCancel(() -> {
|
||||
// Send a PostViewChangeEvent to the DashboardMenu
|
||||
// as if the navigation actually
|
||||
// happened to prevent the DashboardMenu navigation
|
||||
// from getting stuck
|
||||
final DashboardMenuItem dashboardMenuItem = dashboardMenu.getByViewName(VIEW_NAME);
|
||||
dashboardMenu.postViewChange(DashboardEvent.createPostViewChangeEvent(dashboardMenuItem));
|
||||
}).build();
|
||||
UI.getCurrent().addWindow(confirmDeleteDialog.getWindow());
|
||||
confirmDeleteDialog.getWindow().bringToFront();
|
||||
} else {
|
||||
|
||||
@@ -19,6 +19,7 @@ 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.VaadinMessageSource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.vaadin.server.Resource;
|
||||
@@ -37,30 +38,12 @@ public class ConfirmationDialog implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final transient Consumer<Boolean> callback;
|
||||
private final transient Runnable callback;
|
||||
|
||||
private final CommonDialogWindow window;
|
||||
|
||||
/**
|
||||
* Constructor for configuring confirmation dialog.
|
||||
*
|
||||
* @param i18n
|
||||
* internationalization
|
||||
* @param caption
|
||||
* the dialog caption.
|
||||
* @param question
|
||||
* the question.
|
||||
* @param callback
|
||||
* the callback.
|
||||
* @param tab
|
||||
* ConfirmationTab which contains more information about the
|
||||
* action which has to be confirmed, e.g. maintenance window
|
||||
* @param id
|
||||
* the id of the confirmation window
|
||||
*/
|
||||
public ConfirmationDialog(final VaadinMessageSource i18n, final String caption, final String question,
|
||||
final Consumer<Boolean> callback, final Component tab, final String id) {
|
||||
this(i18n, caption, question, callback, null, id, tab);
|
||||
public static Builder newBuilder(final VaadinMessageSource i18n, final String id) {
|
||||
return new Builder(i18n, id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,51 +55,43 @@ public class ConfirmationDialog implements Serializable {
|
||||
* the dialog caption.
|
||||
* @param question
|
||||
* the question.
|
||||
* @param callback
|
||||
* the callback.
|
||||
* @param id
|
||||
* the id of the confirmation dialog
|
||||
*/
|
||||
public ConfirmationDialog(final VaadinMessageSource i18n, final String caption, final String question,
|
||||
final Consumer<Boolean> callback, final String id) {
|
||||
this(i18n, caption, question, callback, null, id, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for configuring confirmation dialog.
|
||||
*
|
||||
* @param i18n
|
||||
* internationalization
|
||||
* @param caption
|
||||
* the dialog caption.
|
||||
* @param question
|
||||
* the question.
|
||||
* @param callback
|
||||
* the callback.
|
||||
* @param hint
|
||||
* added in the dialog
|
||||
* @param onSaveOrUpdate
|
||||
* the callback onSaveOrUpdate.
|
||||
* @param onCancel
|
||||
* the callback on cancel.
|
||||
* @param icon
|
||||
* the icon of the dialog
|
||||
* @param id
|
||||
* the id of the confirmation dialog
|
||||
* @param tab
|
||||
* ConfirmationTab which contains more information about the
|
||||
* action which has to be confirmed, e.g. maintenance window
|
||||
* ConfirmationTab which contains more information about the action
|
||||
* which has to be confirmed, e.g. maintenance window
|
||||
*/
|
||||
public ConfirmationDialog(final VaadinMessageSource i18n, final String caption, final String question,
|
||||
final Consumer<Boolean> callback, final Resource icon, final String id, final Component tab) {
|
||||
private ConfirmationDialog(final VaadinMessageSource i18n, final String caption, final String question,
|
||||
final String hint, final Runnable onSaveOrUpdate, final Runnable onCancel, final Resource icon,
|
||||
final String id, final Component tab) {
|
||||
|
||||
final VerticalLayout content = new VerticalLayout();
|
||||
content.setMargin(false);
|
||||
content.setSpacing(false);
|
||||
|
||||
if (question != null) {
|
||||
content.addComponent(createConfirmationQuestion(question));
|
||||
content.addComponent(createConfirmationLabel(question));
|
||||
}
|
||||
if (hint != null) {
|
||||
content.addComponent(createConfirmationLabel(hint));
|
||||
}
|
||||
if (tab != null) {
|
||||
content.addComponent(tab);
|
||||
}
|
||||
final WindowBuilder windowBuilder = new WindowBuilder(SPUIDefinitions.CONFIRMATION_WINDOW).caption(caption)
|
||||
.content(content).cancelButtonClickListener(e -> callback.accept(false))
|
||||
.saveDialogCloseListener(getSaveDialogCloseListener()).hideMandatoryExplanation()
|
||||
.content(content).cancelButtonClickListener(e -> {
|
||||
if (onCancel != null) {
|
||||
onCancel.run();
|
||||
}
|
||||
}).saveDialogCloseListener(getSaveDialogCloseListener()).hideMandatoryExplanation()
|
||||
.buttonDecorator(SPUIButtonStyleTiny.class).confirmStyle(ConfirmStyle.OK).i18n(i18n);
|
||||
|
||||
if (!StringUtils.isEmpty(id)) {
|
||||
@@ -124,7 +99,7 @@ public class ConfirmationDialog implements Serializable {
|
||||
}
|
||||
this.window = windowBuilder.buildCommonDialogWindow();
|
||||
window.setSaveButtonEnabled(true);
|
||||
this.callback = callback;
|
||||
this.callback = onSaveOrUpdate;
|
||||
|
||||
if (icon != null) {
|
||||
window.setIcon(icon);
|
||||
@@ -137,7 +112,9 @@ public class ConfirmationDialog implements Serializable {
|
||||
return new SaveDialogCloseListener() {
|
||||
@Override
|
||||
public void saveOrUpdate() {
|
||||
callback.accept(true);
|
||||
if (callback != null) {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -147,10 +124,10 @@ public class ConfirmationDialog implements Serializable {
|
||||
};
|
||||
}
|
||||
|
||||
private static Label createConfirmationQuestion(final String question) {
|
||||
private static Label createConfirmationLabel(final String text) {
|
||||
// ContentMode.HTML is used instead of ContentMode.PREFORMATTED here due
|
||||
// to no linebreaks if an entity name is very long
|
||||
final String questionHtmlSave = HawkbitCommonUtil.sanitizeHtml(question);
|
||||
final String questionHtmlSave = HawkbitCommonUtil.sanitizeHtml(text);
|
||||
final Label questionLbl = new Label(questionHtmlSave, ContentMode.HTML);
|
||||
questionLbl.setWidth(100, Unit.PERCENTAGE);
|
||||
questionLbl.addStyleName(SPUIStyleDefinitions.CONFIRMBOX_QUESTION_LABEL);
|
||||
@@ -175,4 +152,75 @@ public class ConfirmationDialog implements Serializable {
|
||||
return window;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for a confirmation dialog
|
||||
*/
|
||||
public static class Builder {
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
private final String id;
|
||||
private String caption;
|
||||
private String question;
|
||||
private String hint;
|
||||
private Resource icon;
|
||||
private Component tab;
|
||||
|
||||
private Runnable callbackOnSaveOrUpdate;
|
||||
|
||||
private Runnable callbackOnCancel;
|
||||
|
||||
/**
|
||||
* private constructor
|
||||
*
|
||||
* @param i18n
|
||||
* required field
|
||||
* @param id
|
||||
* required field
|
||||
*/
|
||||
Builder(final VaadinMessageSource i18n, final String id) {
|
||||
this.i18n = i18n;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Builder caption(final String caption) {
|
||||
this.caption = caption;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder question(final String question) {
|
||||
this.question = question;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder hint(final String hint) {
|
||||
this.hint = hint;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder icon(final Resource icon) {
|
||||
this.icon = icon;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder tab(final Component tab) {
|
||||
this.tab = tab;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder onSaveOrUpdate(final Runnable callback) {
|
||||
this.callbackOnSaveOrUpdate = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder onCancel(final Runnable callback) {
|
||||
this.callbackOnCancel = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConfirmationDialog build() {
|
||||
Assert.isTrue(StringUtils.hasText(caption), "Caption cannot be null.");
|
||||
return new ConfirmationDialog(i18n, caption, question, hint, callbackOnSaveOrUpdate, callbackOnCancel, icon,
|
||||
id, tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,14 +77,14 @@ public final class FormComponentBuilder {
|
||||
* @return the TextField with its Binding
|
||||
*/
|
||||
public static <T extends NameAware> BoundComponent<TextField> createNameInput(final Binder<T> binder,
|
||||
final VaadinMessageSource i18n, final String fieldId) {
|
||||
final VaadinMessageSource i18n, final String fieldId) {
|
||||
final TextField nameInput = new TextFieldBuilder(NamedEntity.NAME_MAX_SIZE).id(fieldId)
|
||||
.caption(i18n.getMessage(TEXTFIELD_NAME)).prompt(i18n.getMessage(TEXTFIELD_NAME)).buildTextComponent();
|
||||
.caption(i18n.getMessage(TEXTFIELD_NAME)).prompt(i18n.getMessage(TEXTFIELD_NAME)).buildTextComponent();
|
||||
nameInput.setSizeUndefined();
|
||||
|
||||
final Binding<T, String> binding = binder.forField(nameInput)
|
||||
.asRequired(i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_NAMEREQUIRED))
|
||||
.bind(NameAware::getName, NameAware::setName);
|
||||
.asRequired(i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_NAMEREQUIRED))
|
||||
.bind(NameAware::getName, NameAware::setName);
|
||||
|
||||
return new BoundComponent<>(nameInput, binding);
|
||||
}
|
||||
@@ -131,13 +131,19 @@ public final class FormComponentBuilder {
|
||||
*/
|
||||
public static <T extends DescriptionAware> BoundComponent<TextArea> createDescriptionInput(final Binder<T> binder,
|
||||
final VaadinMessageSource i18n, final String fieldId) {
|
||||
return createBigTextInput(binder, i18n, fieldId, TEXTFIELD_DESCRIPTION, TEXTFIELD_DESCRIPTION,
|
||||
DescriptionAware::getDescription, DescriptionAware::setDescription);
|
||||
}
|
||||
|
||||
public static <T> BoundComponent<TextArea> createBigTextInput(final Binder<T> binder,
|
||||
final VaadinMessageSource i18n, final String fieldId, final String caption, final String prompt,
|
||||
ValueProvider<T, String> getter, Setter<T, String> setter) {
|
||||
final TextArea descriptionInput = new TextAreaBuilder(NamedEntity.DESCRIPTION_MAX_SIZE).id(fieldId)
|
||||
.caption(i18n.getMessage(TEXTFIELD_DESCRIPTION)).prompt(i18n.getMessage(TEXTFIELD_DESCRIPTION))
|
||||
.style("text-area-style").buildTextComponent();
|
||||
.caption(i18n.getMessage(caption)).prompt(i18n.getMessage(prompt)).style("text-area-style")
|
||||
.buildTextComponent();
|
||||
descriptionInput.setSizeUndefined();
|
||||
|
||||
final Binding<T, String> binding = binder.forField(descriptionInput).bind(DescriptionAware::getDescription,
|
||||
DescriptionAware::setDescription);
|
||||
final Binding<T, String> binding = binder.forField(descriptionInput).bind(getter, setter);
|
||||
|
||||
return new BoundComponent<>(descriptionInput, binding);
|
||||
}
|
||||
|
||||
@@ -289,6 +289,35 @@ public final class GridComponentBuilder {
|
||||
return column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove column based on it's id
|
||||
*
|
||||
* @param grid
|
||||
* to add the column to
|
||||
* @param columnId
|
||||
* of the column
|
||||
* @param <E>
|
||||
* entity type of the grid
|
||||
*/
|
||||
public static <E> void removeColumn(final Grid<E> grid, final String columnId) {
|
||||
grid.removeColumn(columnId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a column is present based on it's id
|
||||
*
|
||||
* @param grid
|
||||
* to add the column to
|
||||
* @param columnId
|
||||
* of the column
|
||||
* @param <E>
|
||||
* entity type of the grid
|
||||
* @return if the column is present
|
||||
*/
|
||||
public static <E> boolean isColumnPresent(final Grid<E> grid, final String columnId) {
|
||||
return grid.getColumn(columnId) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add column to grid with the standard settings
|
||||
*
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.eclipse.hawkbit.ui.common.data.proxies.ProxyAction;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyAction.IsActiveDecoration;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTarget;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyUploadProgress.ProgressSatus;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.rollout.ProxyFontIcon;
|
||||
@@ -86,6 +87,8 @@ public final class StatusIconBuilder {
|
||||
addMapping(Status.CANCEL_REJECTED, VaadinIcons.EXCLAMATION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_ORANGE);
|
||||
addMapping(Status.CANCELED, VaadinIcons.CLOSE_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_GREEN);
|
||||
addMapping(Status.ERROR, VaadinIcons.EXCLAMATION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_RED);
|
||||
addMapping(Status.WAIT_FOR_CONFIRMATION, VaadinIcons.USER_CLOCK, SPUIStyleDefinitions.STATUS_ICON_PENDING);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,6 +329,43 @@ public final class StatusIconBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate labels with confirmation icons according to entity' {@link ProxyTargetFilterQuery}
|
||||
*/
|
||||
public static class ConfirmationIconSupplier extends AbstractEntityStatusIconBuilder<ProxyTargetFilterQuery> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param labelIdPrefix
|
||||
* to generate the label ID
|
||||
*/
|
||||
public ConfirmationIconSupplier(final VaadinMessageSource i18n, final String labelIdPrefix) {
|
||||
super(i18n, labelIdPrefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Label getLabel(final ProxyTargetFilterQuery entity) {
|
||||
final ProxyFontIcon icon;
|
||||
if (entity.isAutoAssignmentEnabled() && entity.getDistributionSetInfo() != null) {
|
||||
icon = entity.isConfirmationRequired()
|
||||
? new ProxyFontIcon(VaadinIcons.USER_CLOCK, SPUIStyleDefinitions.STATUS_ICON_GREEN,
|
||||
i18n.getMessage(UIMessageIdProvider.TOOLTIP_TARGET_FILTER_CONFIRMATION_REQUIRED))
|
||||
: new ProxyFontIcon(VaadinIcons.USER_CHECK, SPUIStyleDefinitions.STATUS_ICON_RED,
|
||||
i18n.getMessage(UIMessageIdProvider.TOOLTIP_TARGET_FILTER_CONFIRMATION_NOT_REQUIRED));
|
||||
} else {
|
||||
icon = new ProxyFontIcon(VaadinIcons.MINUS_CIRCLE_O, SPUIStyleDefinitions.STATUS_ICON_NEUTRAL,
|
||||
i18n.getMessage(UIMessageIdProvider.TOOLTIP_TARGET_FILTER_CONFIRMATION_NOT_CONFIGURED));
|
||||
}
|
||||
|
||||
return getLabel(entity, icon);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate labels with icons according to entities'
|
||||
* {@link TargetUpdateStatus}
|
||||
|
||||
@@ -55,6 +55,7 @@ public class AdvancedRolloutGroupDefinitionToCreateMapper {
|
||||
return entityFactory.rolloutGroup().create().name(advancedRolloutGroupDefinition.getGroupName())
|
||||
.description(advancedRolloutGroupDefinition.getGroupName())
|
||||
.targetFilterQuery(advancedRolloutGroupDefinition.getTargetFilterQuery())
|
||||
.targetPercentage(advancedRolloutGroupDefinition.getTargetPercentage()).conditions(conditions);
|
||||
.targetPercentage(advancedRolloutGroupDefinition.getTargetPercentage()).conditions(conditions)
|
||||
.confirmationRequired(advancedRolloutGroupDefinition.isConfirmationRequired());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ public class RolloutGroupToAdvancedDefinitionMapper {
|
||||
advancedGroupRow.setTargetPercentage(rolloutGroup.getTargetPercentage());
|
||||
advancedGroupRow.setTriggerThresholdPercentage(rolloutGroup.getSuccessConditionExp());
|
||||
advancedGroupRow.setErrorThresholdPercentage(rolloutGroup.getErrorConditionExp());
|
||||
advancedGroupRow.setConfirmationRequired(rolloutGroup.isConfirmationRequired());
|
||||
|
||||
return advancedGroupRow;
|
||||
}
|
||||
@@ -83,7 +84,7 @@ public class RolloutGroupToAdvancedDefinitionMapper {
|
||||
*
|
||||
* @return List of advance rollout group
|
||||
*/
|
||||
public List<ProxyAdvancedRolloutGroup> loadRolloutGroupssFromBackend(final Long rolloutId,
|
||||
public List<ProxyAdvancedRolloutGroup> loadRolloutGroupsFromBackend(final Long rolloutId,
|
||||
final RolloutGroupManagement rolloutGroupManagement, final int pageCount) {
|
||||
return rolloutGroupManagement.findByRollout(PageRequest.of(0, pageCount), rolloutId).stream().map(this::map)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
@@ -35,6 +35,7 @@ public class RolloutGroupToProxyRolloutGroupMapper
|
||||
proxyRolloutGroup.setFinishedPercentage(formatFinishedPercentage(rolloutGroup));
|
||||
proxyRolloutGroup.setTotalTargetsCount(String.valueOf(rolloutGroup.getTotalTargets()));
|
||||
proxyRolloutGroup.setTotalTargetCountStatus(rolloutGroup.getTotalTargetCountStatus());
|
||||
proxyRolloutGroup.setConfirmationRequired(rolloutGroup.isConfirmationRequired());
|
||||
|
||||
return proxyRolloutGroup;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ public class TargetFilterQueryToProxyTargetFilterMapper
|
||||
proxyTargetFilter.setDistributionSetInfo(new ProxyDistributionSetInfo(distributionSet.getId(),
|
||||
distributionSet.getName(), distributionSet.getVersion(), distributionSet.isValid()));
|
||||
proxyTargetFilter.setAutoAssignActionType(targetFilterQuery.getAutoAssignActionType());
|
||||
proxyTargetFilter.setConfirmationRequired(targetFilterQuery.isConfirmationRequired());
|
||||
}
|
||||
|
||||
return proxyTargetFilter;
|
||||
|
||||
@@ -10,10 +10,12 @@ package org.eclipse.hawkbit.ui.common.data.mappers;
|
||||
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus;
|
||||
import org.eclipse.hawkbit.repository.model.PollStatus;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTarget;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetConfirmationOptions;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTypeInfo;
|
||||
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
|
||||
@@ -51,10 +53,16 @@ public class TargetToProxyTargetMapper extends AbstractNamedEntityToProxyNamedEn
|
||||
proxyTarget.setPollStatusToolTip(getPollStatusToolTip(target.getPollStatus()));
|
||||
proxyTarget.setSecurityToken(target.getSecurityToken());
|
||||
proxyTarget.setRequestAttributes(target.isRequestControllerAttributes());
|
||||
if (target.getTargetType() != null){
|
||||
if (target.getTargetType() != null) {
|
||||
TargetType type = target.getTargetType();
|
||||
proxyTarget.setTypeInfo(new ProxyTypeInfo(type.getId(), type.getName()));
|
||||
}
|
||||
if (target.getAutoConfirmationStatus() != null) {
|
||||
final AutoConfirmationStatus autoConfirmationStatus = target.getAutoConfirmationStatus();
|
||||
proxyTarget.setTargetConfirmationOptions(ProxyTargetConfirmationOptions.active(autoConfirmationStatus));
|
||||
} else {
|
||||
proxyTarget.setTargetConfirmationOptions(ProxyTargetConfirmationOptions.disabled(target.getControllerId()));
|
||||
}
|
||||
|
||||
return proxyTarget;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ public class ProxyAdvancedRolloutGroup implements Serializable, TargetFilterQuer
|
||||
private String triggerThresholdPercentage;
|
||||
private String errorThresholdPercentage;
|
||||
private Long targetsCount;
|
||||
private boolean confirmationRequired = true;
|
||||
|
||||
/**
|
||||
* Gets the name of the group
|
||||
@@ -131,4 +132,12 @@ public class ProxyAdvancedRolloutGroup implements Serializable, TargetFilterQuer
|
||||
public void setTargetsCount(final Long targetsCount) {
|
||||
this.targetsCount = targetsCount;
|
||||
}
|
||||
|
||||
public boolean isConfirmationRequired() {
|
||||
return confirmationRequired;
|
||||
}
|
||||
|
||||
public void setConfirmationRequired(boolean confirmationRequired) {
|
||||
this.confirmationRequired = confirmationRequired;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ public class ProxyAssignmentWindow implements Serializable, ActionTypeAware {
|
||||
private String maintenanceSchedule;
|
||||
private String maintenanceDuration;
|
||||
private String maintenanceTimeZone;
|
||||
private boolean confirmationRequired = true;
|
||||
|
||||
/**
|
||||
* Gets the actionType
|
||||
@@ -120,7 +121,7 @@ public class ProxyAssignmentWindow implements Serializable, ActionTypeAware {
|
||||
* @param maintenanceDuration
|
||||
* Duration of maintenance
|
||||
*/
|
||||
public void setMaintenanceDuration(String maintenanceDuration) {
|
||||
public void setMaintenanceDuration(final String maintenanceDuration) {
|
||||
this.maintenanceDuration = maintenanceDuration;
|
||||
}
|
||||
|
||||
@@ -139,7 +140,25 @@ public class ProxyAssignmentWindow implements Serializable, ActionTypeAware {
|
||||
* @param maintenanceTimeZone
|
||||
* Time zone of Maintenance
|
||||
*/
|
||||
public void setMaintenanceTimeZone(String maintenanceTimeZone) {
|
||||
public void setMaintenanceTimeZone(final String maintenanceTimeZone) {
|
||||
this.maintenanceTimeZone = maintenanceTimeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get as boolean if the confirmation of the assignment is required
|
||||
*
|
||||
* @return if the confirmation of the assignment is required
|
||||
*/
|
||||
public boolean isConfirmationRequired() {
|
||||
return confirmationRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the confirmation of the assignment is required
|
||||
*
|
||||
* @param confirmationRequired set required
|
||||
*/
|
||||
public void setConfirmationRequired(final boolean confirmationRequired) {
|
||||
this.confirmationRequired = confirmationRequired;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ public class ProxyRolloutGroup extends ProxyNamedEntity {
|
||||
private String errorConditionExp;
|
||||
private RolloutGroupErrorAction errorAction;
|
||||
private String errorActionExp;
|
||||
private boolean confirmationRequired;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -283,6 +284,15 @@ public class ProxyRolloutGroup extends ProxyNamedEntity {
|
||||
this.errorConditionExp = errorConditionExp;
|
||||
}
|
||||
|
||||
|
||||
public boolean isConfirmationRequired() {
|
||||
return confirmationRequired;
|
||||
}
|
||||
|
||||
public void setConfirmationRequired(final boolean confirmationRequired) {
|
||||
this.confirmationRequired = confirmationRequired;
|
||||
}
|
||||
|
||||
public RolloutGroupErrorAction getErrorAction() {
|
||||
return errorAction;
|
||||
}
|
||||
|
||||
@@ -288,6 +288,10 @@ public class ProxyRolloutWindow implements Serializable {
|
||||
return simpleGroupsDefinition.getErrorThresholdPercentage();
|
||||
}
|
||||
|
||||
public boolean isConfirmationRequired() {
|
||||
return simpleGroupsDefinition.isConfirmationRequired();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the errorThresholdPercentage
|
||||
*
|
||||
|
||||
@@ -20,6 +20,7 @@ public class ProxySimpleRolloutGroupsDefinition implements Serializable {
|
||||
private Integer numberOfGroups;
|
||||
private String triggerThresholdPercentage;
|
||||
private String errorThresholdPercentage;
|
||||
private boolean confirmationRequired = true;
|
||||
|
||||
/**
|
||||
* Gets the count of simple rollout Groups
|
||||
@@ -78,4 +79,22 @@ public class ProxySimpleRolloutGroupsDefinition implements Serializable {
|
||||
this.errorThresholdPercentage = errorThresholdPercentage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a flag if a confirmation is required by the device
|
||||
*
|
||||
* @return isConfirmationRequired as boolean flag
|
||||
*/
|
||||
public boolean isConfirmationRequired() {
|
||||
return confirmationRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the isConfirmationRequired flag
|
||||
*
|
||||
* @param confirmationRequired
|
||||
* flag
|
||||
*/
|
||||
public void setConfirmationRequired(final boolean confirmationRequired) {
|
||||
this.confirmationRequired = confirmationRequired;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ public class ProxySystemConfigRepository extends ProxySystemConfigWindow {
|
||||
private boolean actionAutoclose;
|
||||
private boolean actionAutocleanup;
|
||||
private boolean multiAssignments;
|
||||
private boolean confirmationFlow;
|
||||
private ActionAutoCleanupConfigurationItem.ActionStatusOption actionCleanupStatus;
|
||||
private String actionExpiryDays;
|
||||
|
||||
@@ -64,6 +65,27 @@ public class ProxySystemConfigRepository extends ProxySystemConfigWindow {
|
||||
this.multiAssignments = multiAssignments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flag that indicates if the user-consent option is enabled.
|
||||
*
|
||||
* @param confirmationFlow
|
||||
* <code>true</code> if the user-consent is enabled, otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
public void setConfirmationFlow(final boolean confirmationFlow) {
|
||||
this.confirmationFlow = confirmationFlow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag that indicates if the confirmation flow option is enabled.
|
||||
*
|
||||
* @return <code>true</code> if the confirmation flow is enabled, otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean isConfirmationFlow() {
|
||||
return confirmationFlow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag that indicates if the actionAutoclose option is enabled.
|
||||
*
|
||||
|
||||
@@ -44,6 +44,8 @@ public class ProxyTarget extends ProxyNamedEntity implements TypeInfoAware {
|
||||
|
||||
private ProxyTypeInfo typeInfo;
|
||||
|
||||
private transient ProxyTargetConfirmationOptions options = new ProxyTargetConfirmationOptions();
|
||||
|
||||
/**
|
||||
* Gets the controllerId
|
||||
*
|
||||
@@ -240,4 +242,23 @@ public class ProxyTarget extends ProxyNamedEntity implements TypeInfoAware {
|
||||
public ProxyTypeInfo getTypeInfo() {
|
||||
return typeInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state of the current confirmation options
|
||||
*
|
||||
* @return {@link ProxyTargetConfirmationOptions}
|
||||
*/
|
||||
public ProxyTargetConfirmationOptions getTargetConfirmationOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state of the current confirmation options
|
||||
*
|
||||
* @param options
|
||||
* the {@link ProxyTargetConfirmationOptions}
|
||||
*/
|
||||
public void setTargetConfirmationOptions(final ProxyTargetConfirmationOptions options) {
|
||||
this.options = options;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2022 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.common.data.proxies;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus;
|
||||
|
||||
/**
|
||||
* Proxy for target confirmation options.
|
||||
*/
|
||||
public class ProxyTargetConfirmationOptions {
|
||||
|
||||
private boolean isAutoConfirmationEnabled;
|
||||
private final String controllerId;
|
||||
private final String initiatedSystemUser;
|
||||
private final Long activatedAt;
|
||||
private String initiator;
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* dummy constructor needed for ProxyTargetConfirmationOptions getValue
|
||||
*/
|
||||
public ProxyTargetConfirmationOptions() {
|
||||
this.controllerId = null;
|
||||
this.initiatedSystemUser = null;
|
||||
this.activatedAt = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for ProxyTargetAttributesDetails
|
||||
*
|
||||
* @param controllerId
|
||||
* Target attribute controller id
|
||||
* @param isAutoConfirmationEnabled
|
||||
* flag if enabled
|
||||
* @param initiator
|
||||
* who initiated the auto confirmation
|
||||
* @param remark
|
||||
* optional remark
|
||||
*/
|
||||
private ProxyTargetConfirmationOptions(final boolean isAutoConfirmationEnabled, final String controllerId,
|
||||
final String initiator, final String initiatedSystemUser, final Long activatedAt, final String remark) {
|
||||
this.isAutoConfirmationEnabled = isAutoConfirmationEnabled;
|
||||
this.controllerId = controllerId;
|
||||
this.initiator = initiator;
|
||||
this.initiatedSystemUser = initiatedSystemUser;
|
||||
this.activatedAt = activatedAt;
|
||||
this.remark = remark;
|
||||
}
|
||||
|
||||
public static ProxyTargetConfirmationOptions disabled(final String controllerId) {
|
||||
return new ProxyTargetConfirmationOptions(false, controllerId, null, null, null, null);
|
||||
}
|
||||
|
||||
public static ProxyTargetConfirmationOptions active(final AutoConfirmationStatus status) {
|
||||
return new ProxyTargetConfirmationOptions(true, status.getTarget().getControllerId(), status.getInitiator(),
|
||||
status.getCreatedBy(), status.getActivatedAt(), status.getRemark());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return target attributes detail controllerId
|
||||
*/
|
||||
public String getControllerId() {
|
||||
return controllerId;
|
||||
}
|
||||
|
||||
public boolean isAutoConfirmationEnabled() {
|
||||
return isAutoConfirmationEnabled;
|
||||
}
|
||||
|
||||
public String getInitiator() {
|
||||
return initiator;
|
||||
}
|
||||
|
||||
public void setInitiator(final String initiator) {
|
||||
this.initiator = initiator;
|
||||
}
|
||||
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}
|
||||
|
||||
public void setRemark(final String remark) {
|
||||
this.remark = remark;
|
||||
}
|
||||
|
||||
public Long getActivatedAt() {
|
||||
return activatedAt;
|
||||
}
|
||||
|
||||
public String getInitiatedSystemUser() {
|
||||
return initiatedSystemUser;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.proxies;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.ui.common.data.aware.DsIdAware;
|
||||
@@ -22,6 +23,8 @@ public class ProxyTargetFilterQuery extends ProxyNamedEntity implements DsIdAwar
|
||||
|
||||
private boolean isAutoAssignmentEnabled;
|
||||
|
||||
private boolean isConfirmationRequired;
|
||||
|
||||
private ProxyDistributionSetInfo autoAssignDsInfo;
|
||||
|
||||
private ActionType autoAssignActionType;
|
||||
@@ -122,6 +125,26 @@ public class ProxyTargetFilterQuery extends ProxyNamedEntity implements DsIdAwar
|
||||
this.autoAssignDsInfo = dsInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if confirmation is required for configured auto assignment
|
||||
* (considered with confirmation flow active)
|
||||
*/
|
||||
public boolean isConfirmationRequired() {
|
||||
return isConfirmationRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify initial confirmation state of resulting {@link Action} in auto
|
||||
* assignment
|
||||
*
|
||||
* @param confirmationRequired
|
||||
* if confirmation is required for configured auto assignment
|
||||
* (considered with confirmation flow active)
|
||||
*/
|
||||
public void setConfirmationRequired(final boolean confirmationRequired) {
|
||||
isConfirmationRequired = confirmationRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Id, name and query of target filter query
|
||||
*
|
||||
@@ -148,4 +171,5 @@ public class ProxyTargetFilterQuery extends ProxyNamedEntity implements DsIdAwar
|
||||
public ProxyTargetFilterQueryInfo getInfo() {
|
||||
return new ProxyTargetFilterQueryInfo(getId(), getName(), getQuery());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ public abstract class AbstractGridDetailsLayout<T extends ProxyNamedEntity> exte
|
||||
});
|
||||
}
|
||||
|
||||
private static VerticalLayout buildTabWrapperDetailsLayout(final Component detailsComponent) {
|
||||
protected static VerticalLayout buildTabWrapperDetailsLayout(final Component detailsComponent) {
|
||||
final VerticalLayout tabWrapperDetailsLayout = new VerticalLayout();
|
||||
tabWrapperDetailsLayout.setSpacing(false);
|
||||
tabWrapperDetailsLayout.setMargin(false);
|
||||
|
||||
@@ -22,6 +22,7 @@ public final class EventTopics {
|
||||
public static final String FILE_UPLOAD_CHANGED = "fileUploadChanged";
|
||||
public static final String BULK_UPLOAD_CHANGED = "bulkUploadChanged";
|
||||
public static final String ENTITY_DRAGGING_CHANGED = "entityDraggingChanged";
|
||||
public static final String TENANT_CONFIG_CHANGED = "tenantConfigChanged";
|
||||
|
||||
private EventTopics() {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright (c) 2022 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.common.event;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Payload event for tenant config changes
|
||||
*/
|
||||
public class TenantConfigChangedEventPayload {
|
||||
|
||||
private final String tenant;
|
||||
|
||||
private final String key;
|
||||
|
||||
private final Object value;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param tenant
|
||||
* the change relates to
|
||||
* @param key
|
||||
* of the config
|
||||
* @param value
|
||||
* of the config
|
||||
*/
|
||||
public TenantConfigChangedEventPayload(@NotEmpty final String tenant, @NotEmpty final String key,
|
||||
@NotNull final TenantConfigurationValue<?> value) {
|
||||
this.tenant = tenant;
|
||||
this.key = key;
|
||||
this.value = value.getValue();
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse value into an given class if possible. If possible, the returned
|
||||
* instance of {@link Optional} contains the cast value. Otherwise, it's empty.
|
||||
*/
|
||||
public <T> Optional<T> getValue(final Class<T> fromClass) {
|
||||
return fromClass.isInstance(value) ? Optional.of(fromClass.cast(value)) : Optional.empty();
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getTenant() {
|
||||
return tenant;
|
||||
}
|
||||
}
|
||||
@@ -146,11 +146,10 @@ public class DeleteSupport<T extends ProxyIdentifiableEntity> {
|
||||
private ConfirmationDialog createConfirmationWindowForDeletion(final Set<T> itemsToBeDeleted,
|
||||
final String confirmationCaption, final String confirmationQuestion, final String successNotificationText,
|
||||
final String failureNotificationText) {
|
||||
return new ConfirmationDialog(i18n, confirmationCaption, confirmationQuestion, ok -> {
|
||||
if (ok) {
|
||||
handleOkDelete(itemsToBeDeleted, successNotificationText, failureNotificationText);
|
||||
}
|
||||
}, deletionWindowId);
|
||||
return ConfirmationDialog.newBuilder(i18n, deletionWindowId).caption(confirmationCaption)
|
||||
.question(confirmationQuestion).onSaveOrUpdate(() -> {
|
||||
handleOkDelete(itemsToBeDeleted, successNotificationText, failureNotificationText);
|
||||
}).build();
|
||||
}
|
||||
|
||||
private void handleOkDelete(final Set<T> itemsToBeDeleted, final String successNotificationText,
|
||||
|
||||
@@ -66,11 +66,12 @@ public abstract class DeploymentAssignmentSupport<S extends ProxyNamedEntity, T
|
||||
final BooleanSupplier canWindowSave, final Runnable assignmentExecutor) {
|
||||
final String caption = i18n.getMessage(UIMessageIdProvider.CAPTION_ENTITY_ASSIGN_ACTION_CONFIRMBOX);
|
||||
|
||||
return new ConfirmationDialog(i18n, caption, confirmationMessage, ok -> {
|
||||
if (ok && canWindowSave.getAsBoolean()) {
|
||||
assignmentExecutor.run();
|
||||
}
|
||||
}, content, confirmationWindowId());
|
||||
return ConfirmationDialog.newBuilder(i18n, confirmationWindowId()).caption(caption)
|
||||
.question(confirmationMessage).tab(content).onSaveOrUpdate(() -> {
|
||||
if (canWindowSave.getAsBoolean()) {
|
||||
assignmentExecutor.run();
|
||||
}
|
||||
}).build();
|
||||
}
|
||||
|
||||
protected abstract String sourceEntityTypeSing();
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* Copyright (c) 2022 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.common.layout.listener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventTopics;
|
||||
import org.eclipse.hawkbit.ui.common.event.TenantConfigChangedEventPayload;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
import org.vaadin.spring.events.EventScope;
|
||||
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
|
||||
|
||||
/**
|
||||
* Event listener for tenant configuration changes
|
||||
*/
|
||||
public class TenantConfigChangedListener extends TopicEventListener {
|
||||
|
||||
private final String tenantFilter;
|
||||
private final Collection<String> tenantConfigFilter;
|
||||
private final Consumer<TenantConfigChangedEventPayload> onApplicationScope;
|
||||
private final Consumer<TenantConfigChangedEventPayload> onUiScope;
|
||||
|
||||
/**
|
||||
* Constructor for TenantConfigChangedListener
|
||||
*
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param tenantFilter
|
||||
* filter events related to a specific tenant
|
||||
* @param tenantConfigFilter
|
||||
* filter the tenant configurations of interest listed in
|
||||
* {@link TenantConfigurationProperties.TenantConfigurationKey}
|
||||
* @param onApplicationScope
|
||||
* defines what should happen on an application wide event
|
||||
* @param onUiScope
|
||||
* defines what should happen on current UI event
|
||||
*/
|
||||
TenantConfigChangedListener(final UIEventBus eventBus, final String tenantFilter,
|
||||
final Collection<String> tenantConfigFilter,
|
||||
final Consumer<TenantConfigChangedEventPayload> onApplicationScope,
|
||||
final Consumer<TenantConfigChangedEventPayload> onUiScope) {
|
||||
super(eventBus, EventTopics.TENANT_CONFIG_CHANGED);
|
||||
|
||||
this.tenantFilter = tenantFilter;
|
||||
this.tenantConfigFilter = tenantConfigFilter;
|
||||
this.onApplicationScope = onApplicationScope;
|
||||
this.onUiScope = onUiScope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a builder instance to define the {@link TenantConfigChangedListener}
|
||||
*
|
||||
* @param eventBus
|
||||
* is required
|
||||
* @return an the empty {@link Builder}
|
||||
*/
|
||||
public static Builder newBuilder(final UIEventBus eventBus) {
|
||||
return new Builder(eventBus);
|
||||
}
|
||||
|
||||
/**
|
||||
* With scope {@link EventScope#APPLICATION} to get notified about configuration
|
||||
* changes triggered by other UI sessions/users
|
||||
*
|
||||
* @param configuration
|
||||
* the new configuration
|
||||
*/
|
||||
@EventBusListenerMethod(scope = EventScope.APPLICATION)
|
||||
private void onApplicationEvent(final TenantConfigChangedEventPayload configuration) {
|
||||
if (onApplicationScope != null && shouldProcess(configuration)) {
|
||||
onApplicationScope.accept(configuration);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* With scope {@link EventScope#UI} to get notified about configuration changes
|
||||
* triggered by the current UI
|
||||
*
|
||||
* @param configuration
|
||||
* the new configuration
|
||||
*/
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
private void onUiEvent(final TenantConfigChangedEventPayload configuration) {
|
||||
if (onUiScope != null && shouldProcess(configuration)) {
|
||||
onUiScope.accept(configuration);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldProcess(final TenantConfigChangedEventPayload configuration) {
|
||||
return (tenantFilter == null || tenantFilter.equalsIgnoreCase(configuration.getTenant()))
|
||||
&& tenantConfigFilter.contains(configuration.getKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder to define the structure of the listener
|
||||
*/
|
||||
public static class Builder {
|
||||
private final UIEventBus eventBus;
|
||||
private String tenantFilter;
|
||||
private Collection<String> tenantConfigFilter;
|
||||
private Consumer<TenantConfigChangedEventPayload> onApplicationScope;
|
||||
private Consumer<TenantConfigChangedEventPayload> onUiScope;
|
||||
|
||||
Builder(final UIEventBus eventBus) {
|
||||
this.eventBus = eventBus;
|
||||
}
|
||||
|
||||
/**
|
||||
* To filter for event for a specific tenant.
|
||||
*/
|
||||
public Builder tenantFilter(final String tenantFilter) {
|
||||
this.tenantFilter = tenantFilter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set filter for events for specific tenant configuration.
|
||||
*/
|
||||
public Builder setConfigFilter(final Collection<String> configFilter) {
|
||||
this.tenantConfigFilter = configFilter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add filter for events for specific tenant configuration.
|
||||
*/
|
||||
public Builder addConfigFilter(final String configFilter) {
|
||||
if (this.tenantConfigFilter == null) {
|
||||
this.tenantConfigFilter = new ArrayList<>();
|
||||
}
|
||||
this.tenantConfigFilter.add(configFilter);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set consumer in case of an event with scope {@link EventScope#APPLICATION}.
|
||||
*/
|
||||
public Builder applicationEventConsumer(
|
||||
final Consumer<TenantConfigChangedEventPayload> applicationEventConsumer) {
|
||||
this.onApplicationScope = applicationEventConsumer;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set consumer in case of an event with scope {@link EventScope#UI}.
|
||||
*/
|
||||
public Builder uiEventConsumer(final Consumer<TenantConfigChangedEventPayload> uiEventConsumer) {
|
||||
this.onUiScope = uiEventConsumer;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the instance based on provided values.
|
||||
*
|
||||
* @return an instance of {@link TenantConfigChangedListener}
|
||||
*/
|
||||
public TenantConfigChangedListener build() {
|
||||
return new TenantConfigChangedListener(eventBus, tenantFilter,
|
||||
tenantConfigFilter == null ? Collections.emptyList() : tenantConfigFilter, onApplicationScope,
|
||||
onUiScope);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -22,14 +22,13 @@ import com.vaadin.ui.TextArea;
|
||||
import com.vaadin.ui.TextField;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
|
||||
import static org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions.DIST_CHECKBOX_STYLE;
|
||||
|
||||
/**
|
||||
* Builder for Distribution set window layout component
|
||||
*/
|
||||
public class DsWindowLayoutComponentBuilder {
|
||||
|
||||
public static final String TEXTFIELD_NAME = "textfield.name";
|
||||
public static final String TEXTFIELD_VERSION = "textfield.version";
|
||||
public static final String TEXTFIELD_DESCRIPTION = "textfield.description";
|
||||
public static final String MIGRATION_STEP = "label.dist.required.migration.step";
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
@@ -112,7 +111,7 @@ public class DsWindowLayoutComponentBuilder {
|
||||
ProxyDistributionSet::setRequiredMigrationStep);
|
||||
|
||||
migrationRequired.setDescription(i18n.getMessage(MIGRATION_STEP));
|
||||
migrationRequired.addStyleName("dist-checkbox-style");
|
||||
migrationRequired.addStyleName(DIST_CHECKBOX_STYLE);
|
||||
migrationRequired.addStyleName(ValoTheme.CHECKBOX_SMALL);
|
||||
|
||||
return migrationRequired;
|
||||
|
||||
@@ -11,12 +11,14 @@ package org.eclipse.hawkbit.ui.filtermanagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractEntityWindowBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
|
||||
import com.vaadin.ui.Window;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
|
||||
/**
|
||||
* Builder for auto assignment window
|
||||
@@ -26,6 +28,8 @@ public class AutoAssignmentWindowBuilder extends AbstractEntityWindowBuilder<Pro
|
||||
private final TargetManagement targetManagement;
|
||||
private final TargetFilterQueryManagement targetFilterQueryManagement;
|
||||
private final DistributionSetManagement dsManagement;
|
||||
private final TenantConfigHelper tenantConfigHelper;
|
||||
private final TenantAware tenantAware;
|
||||
|
||||
/**
|
||||
* Constructor for AutoAssignmentWindowBuilder
|
||||
@@ -39,14 +43,17 @@ public class AutoAssignmentWindowBuilder extends AbstractEntityWindowBuilder<Pro
|
||||
* @param dsManagement
|
||||
* DistributionSetManagement
|
||||
*/
|
||||
public AutoAssignmentWindowBuilder(final CommonUiDependencies uiDependencies, final TargetManagement targetManagement,
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement,
|
||||
final DistributionSetManagement dsManagement) {
|
||||
public AutoAssignmentWindowBuilder(final CommonUiDependencies uiDependencies,
|
||||
final TargetManagement targetManagement, final TargetFilterQueryManagement targetFilterQueryManagement,
|
||||
final DistributionSetManagement dsManagement, final TenantConfigHelper tenantConfigHelper,
|
||||
final TenantAware tenantAware) {
|
||||
super(uiDependencies);
|
||||
|
||||
this.targetManagement = targetManagement;
|
||||
this.targetFilterQueryManagement = targetFilterQueryManagement;
|
||||
this.dsManagement = dsManagement;
|
||||
this.tenantConfigHelper = tenantConfigHelper;
|
||||
this.tenantAware = tenantAware;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,8 +70,10 @@ public class AutoAssignmentWindowBuilder extends AbstractEntityWindowBuilder<Pro
|
||||
* @return Common dialog window
|
||||
*/
|
||||
public Window getWindowForAutoAssignment(final ProxyTargetFilterQuery proxyTargetFilter) {
|
||||
return getWindowForEntity(proxyTargetFilter, new AutoAssignmentWindowController(uiDependencies, targetManagement,
|
||||
targetFilterQueryManagement, new AutoAssignmentWindowLayout(getI18n(), dsManagement)));
|
||||
return getWindowForEntity(proxyTargetFilter,
|
||||
new AutoAssignmentWindowController(uiDependencies, targetManagement, targetFilterQueryManagement,
|
||||
tenantConfigHelper, tenantAware,
|
||||
new AutoAssignmentWindowLayout(getI18n(), dsManagement, tenantConfigHelper)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractUpdateEntityWindowController;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.ConfirmationDialog;
|
||||
@@ -21,8 +22,13 @@ import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
|
||||
|
||||
import com.vaadin.icons.VaadinIcons;
|
||||
import com.vaadin.server.Sizeable;
|
||||
import com.vaadin.ui.UI;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.eclipse.hawkbit.ui.utils.UIMessageIdProvider.MESSAGE_CONFIRM_AUTO_ASSIGN_CONSEQUENCES_CONF_HINT;
|
||||
|
||||
/**
|
||||
* Controller for auto assignment window
|
||||
@@ -33,6 +39,8 @@ public class AutoAssignmentWindowController extends
|
||||
private final TargetManagement targetManagement;
|
||||
private final TargetFilterQueryManagement targetFilterQueryManagement;
|
||||
private final AutoAssignmentWindowLayout layout;
|
||||
private final TenantConfigHelper configHelper;
|
||||
private final TenantAware tenantAware;
|
||||
|
||||
/**
|
||||
* Constructor for AutoAssignmentWindowController
|
||||
@@ -48,11 +56,14 @@ public class AutoAssignmentWindowController extends
|
||||
*/
|
||||
public AutoAssignmentWindowController(final CommonUiDependencies uiDependencies,
|
||||
final TargetManagement targetManagement, final TargetFilterQueryManagement targetFilterQueryManagement,
|
||||
final TenantConfigHelper configHelper, final TenantAware tenantAware,
|
||||
final AutoAssignmentWindowLayout layout) {
|
||||
super(uiDependencies);
|
||||
|
||||
this.targetManagement = targetManagement;
|
||||
this.targetFilterQueryManagement = targetFilterQueryManagement;
|
||||
this.configHelper = configHelper;
|
||||
this.tenantAware = tenantAware;
|
||||
this.layout = layout;
|
||||
}
|
||||
|
||||
@@ -67,10 +78,12 @@ public class AutoAssignmentWindowController extends
|
||||
autoAssignmentFilter.setAutoAssignmentEnabled(true);
|
||||
autoAssignmentFilter.setAutoAssignActionType(proxyEntity.getAutoAssignActionType());
|
||||
autoAssignmentFilter.setDistributionSetInfo(proxyEntity.getDistributionSetInfo());
|
||||
autoAssignmentFilter.setConfirmationRequired(proxyEntity.isConfirmationRequired());
|
||||
} else {
|
||||
autoAssignmentFilter.setAutoAssignmentEnabled(false);
|
||||
autoAssignmentFilter.setAutoAssignActionType(ActionType.FORCED);
|
||||
autoAssignmentFilter.setDistributionSetInfo(null);
|
||||
autoAssignmentFilter.setConfirmationRequired(configHelper.isConfirmationFlowEnabled());
|
||||
}
|
||||
|
||||
return autoAssignmentFilter;
|
||||
@@ -102,8 +115,13 @@ public class AutoAssignmentWindowController extends
|
||||
: getI18n().getMessage(UIMessageIdProvider.MESSAGE_CONFIRM_AUTO_ASSIGN_CONSEQUENCES_TEXT,
|
||||
targetsForAutoAssignmentCount);
|
||||
|
||||
showConsequencesDialog(confirmationCaption, confirmationQuestion, entity.getId(), autoAssignDsId,
|
||||
entity.getAutoAssignActionType());
|
||||
final String conformationHint = configHelper.isConfirmationFlowEnabled() && !entity.isConfirmationRequired()
|
||||
? getI18n().getMessage(MESSAGE_CONFIRM_AUTO_ASSIGN_CONSEQUENCES_CONF_HINT,
|
||||
tenantAware.getCurrentUsername())
|
||||
: null;
|
||||
|
||||
showConsequencesDialog(confirmationCaption, confirmationQuestion, conformationHint, entity.getId(), autoAssignDsId,
|
||||
entity.getAutoAssignActionType(), entity.isConfirmationRequired());
|
||||
} else {
|
||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement.updateAutoAssignDS(
|
||||
getEntityFactory().targetFilterQuery().updateAutoAssign(entity.getId()).ds(null));
|
||||
@@ -112,16 +130,17 @@ public class AutoAssignmentWindowController extends
|
||||
}
|
||||
|
||||
private void showConsequencesDialog(final String confirmationCaption, final String confirmationQuestion,
|
||||
final Long targetFilterId, final Long autoAssignDsId, final ActionType autoAssignActionType) {
|
||||
final ConfirmationDialog confirmDialog = new ConfirmationDialog(getI18n(), confirmationCaption,
|
||||
confirmationQuestion, ok -> {
|
||||
if (ok) {
|
||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement.updateAutoAssignDS(
|
||||
getEntityFactory().targetFilterQuery().updateAutoAssign(targetFilterId)
|
||||
.ds(autoAssignDsId).actionType(autoAssignActionType));
|
||||
publishModifiedEvent(createModifiedEventPayload(targetFilterQuery));
|
||||
}
|
||||
}, UIComponentIdProvider.DIST_SET_SELECT_CONS_WINDOW_ID);
|
||||
final String confirmationHint, final Long targetFilterId, final Long autoAssignDsId,
|
||||
final ActionType autoAssignActionType, final boolean confirmationRequired) {
|
||||
final ConfirmationDialog confirmDialog = ConfirmationDialog
|
||||
.newBuilder(getI18n(), UIComponentIdProvider.DIST_SET_SELECT_CONS_WINDOW_ID)
|
||||
.caption(confirmationCaption).question(confirmationQuestion).hint(confirmationHint)
|
||||
.icon(StringUtils.hasText(confirmationHint) ? VaadinIcons.WARNING : null).onSaveOrUpdate(() -> {
|
||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement.updateAutoAssignDS(
|
||||
getEntityFactory().targetFilterQuery().updateAutoAssign(targetFilterId).ds(autoAssignDsId)
|
||||
.actionType(autoAssignActionType).confirmationRequired(confirmationRequired));
|
||||
publishModifiedEvent(createModifiedEventPayload(targetFilterQuery));
|
||||
}).build();
|
||||
|
||||
confirmDialog.getWindow().setWidth(40.0F, Sizeable.Unit.PERCENTAGE);
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.vaadin.ui.ComboBox;
|
||||
import com.vaadin.ui.ComponentContainer;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
|
||||
/**
|
||||
* Target add/update window layout.
|
||||
@@ -32,27 +33,35 @@ public class AutoAssignmentWindowLayout extends AbstractEntityWindowLayout<Proxy
|
||||
|
||||
private final Label descriptionLabel;
|
||||
private final CheckBox enableCheckBox;
|
||||
private final CheckBox confirmationCheckBox;
|
||||
private final ActionTypeOptionGroupAutoAssignmentLayout actionTypeOptionGroupLayout;
|
||||
private final BoundComponent<ComboBox<ProxyDistributionSet>> autoAssignDsComboBox;
|
||||
|
||||
|
||||
private final TenantConfigHelper configHelper;
|
||||
|
||||
/**
|
||||
* Constructor for AbstractTagWindowLayout
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* VaadinMessageSource
|
||||
* @param dsManagement
|
||||
* DistributionSetManagement
|
||||
* DistributionSetManagement
|
||||
* @param configHelper
|
||||
* TenantConfigHelper
|
||||
*/
|
||||
public AutoAssignmentWindowLayout(final VaadinMessageSource i18n, final DistributionSetManagement dsManagement) {
|
||||
public AutoAssignmentWindowLayout(final VaadinMessageSource i18n, final DistributionSetManagement dsManagement,
|
||||
final TenantConfigHelper configHelper) {
|
||||
super();
|
||||
|
||||
this.autoAssignComponentBuilder = new AutoAssignmentWindowLayoutComponentBuilder(i18n);
|
||||
|
||||
this.descriptionLabel = autoAssignComponentBuilder.createDescriptionLabel();
|
||||
this.enableCheckBox = autoAssignComponentBuilder.createEnableCheckbox(binder);
|
||||
this.confirmationCheckBox = autoAssignComponentBuilder.createConfirmationCheckbox(binder);
|
||||
this.actionTypeOptionGroupLayout = autoAssignComponentBuilder.createActionTypeOptionGroupLayout(binder);
|
||||
this.autoAssignDsComboBox = autoAssignComponentBuilder.createDistributionSetCombo(binder,
|
||||
new DistributionSetStatelessDataProvider(dsManagement, new DistributionSetToProxyDistributionMapper()));
|
||||
this.configHelper = configHelper;
|
||||
|
||||
addValueChangeListeners();
|
||||
}
|
||||
@@ -67,7 +76,11 @@ public class AutoAssignmentWindowLayout extends AbstractEntityWindowLayout<Proxy
|
||||
autoAssignmentLayout.addComponent(enableCheckBox);
|
||||
autoAssignmentLayout.addComponent(actionTypeOptionGroupLayout);
|
||||
autoAssignmentLayout.addComponent(autoAssignDsComboBox.getComponent());
|
||||
|
||||
|
||||
if (configHelper.isConfirmationFlowEnabled()) {
|
||||
autoAssignmentLayout.addComponent(confirmationCheckBox);
|
||||
}
|
||||
|
||||
return autoAssignmentLayout;
|
||||
}
|
||||
|
||||
@@ -85,5 +98,6 @@ public class AutoAssignmentWindowLayout extends AbstractEntityWindowLayout<Proxy
|
||||
actionTypeOptionGroupLayout.setVisible(autoAssignmentEnabled);
|
||||
autoAssignDsComboBox.getComponent().setVisible(autoAssignmentEnabled);
|
||||
autoAssignDsComboBox.setRequired(autoAssignmentEnabled);
|
||||
confirmationCheckBox.setVisible(autoAssignmentEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,13 @@ public class AutoAssignmentWindowLayoutComponentBuilder {
|
||||
ProxyTargetFilterQuery::isAutoAssignmentEnabled, ProxyTargetFilterQuery::setAutoAssignmentEnabled);
|
||||
}
|
||||
|
||||
public CheckBox createConfirmationCheckbox(final Binder<ProxyTargetFilterQuery> binder) {
|
||||
final String caption = i18n.getMessage(UIMessageIdProvider.LABEL_AUTO_ASSIGNMENT_CONFIRMATION_REQUIRED);
|
||||
return FormComponentBuilder.createCheckBox(caption, UIComponentIdProvider.ASSIGNMENT_CONFIRMATION_REQUIRED,
|
||||
binder, ProxyTargetFilterQuery::isConfirmationRequired,
|
||||
ProxyTargetFilterQuery::setConfirmationRequired);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create layout for action type option group
|
||||
*
|
||||
|
||||
@@ -16,7 +16,10 @@ import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.rsql.RsqlValidationOracle;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.ui.AbstractHawkbitUI;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.UiProperties;
|
||||
@@ -32,6 +35,7 @@ import org.eclipse.hawkbit.ui.filtermanagement.state.FilterManagementUIState;
|
||||
import org.eclipse.hawkbit.ui.filtermanagement.state.FilterManagementUIState.FilterView;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
@@ -62,14 +66,19 @@ public class FilterManagementView extends AbstractEventListenersAwareView {
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement, final SpPermissionChecker permissionChecker,
|
||||
final UINotification notification, final UiProperties uiProperties, final EntityFactory entityFactory,
|
||||
final TargetManagement targetManagement, final DistributionSetManagement distributionSetManagement,
|
||||
final TargetFilterStateDataSupplier targetFilterStateDataSupplier) {
|
||||
final TargetFilterStateDataSupplier targetFilterStateDataSupplier,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final SystemSecurityContext securityContext, final TenantAware tenantAware) {
|
||||
this.filterManagementUIState = filterManagementUIState;
|
||||
|
||||
final CommonUiDependencies uiDependencies = new CommonUiDependencies(i18n, entityFactory, eventBus,
|
||||
notification, permissionChecker);
|
||||
|
||||
final TenantConfigHelper tenantConfigHelper = TenantConfigHelper.usingContext(securityContext,
|
||||
tenantConfigurationManagement);
|
||||
|
||||
this.targetFilterGridLayout = new TargetFilterGridLayout(uiDependencies, targetFilterQueryManagement,
|
||||
targetManagement, distributionSetManagement, filterManagementUIState);
|
||||
targetManagement, distributionSetManagement, filterManagementUIState, tenantConfigHelper, tenantAware);
|
||||
|
||||
this.targetFilterDetailsLayout = new TargetFilterDetailsLayout(uiDependencies, uiProperties,
|
||||
rsqlValidationOracle, targetFilterQueryManagement, targetFilterStateDataSupplier,
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.builder.GridComponentBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.builder.StatusIconBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.builder.StatusIconBuilder.ActionTypeIconSupplier;
|
||||
import org.eclipse.hawkbit.ui.common.data.mappers.TargetFilterQueryToProxyTargetFilterMapper;
|
||||
import org.eclipse.hawkbit.ui.common.data.providers.TargetFilterQueryDataProvider;
|
||||
@@ -35,6 +36,7 @@ import org.eclipse.hawkbit.ui.filtermanagement.state.TargetFilterGridLayoutUiSta
|
||||
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.utils.TenantConfigHelper;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.vaadin.data.ValueProvider;
|
||||
@@ -46,6 +48,8 @@ import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.Window;
|
||||
|
||||
import static org.eclipse.hawkbit.ui.utils.UIComponentIdProvider.TARGET_FILTER_TABLE_CONFIRMATION_LABEL_ID;
|
||||
|
||||
/**
|
||||
* Concrete implementation of TargetFilter grid which is displayed on the
|
||||
* Filtermanagement View.
|
||||
@@ -59,10 +63,12 @@ public class TargetFilterGrid extends AbstractGrid<ProxyTargetFilterQuery, Strin
|
||||
private final UINotification notification;
|
||||
private final TargetFilterGridLayoutUiState uiState;
|
||||
private final transient TargetFilterQueryManagement targetFilterQueryManagement;
|
||||
private final transient TenantConfigHelper tenantConfigHelper;
|
||||
|
||||
private final transient AutoAssignmentWindowBuilder autoAssignmentWindowBuilder;
|
||||
|
||||
private final ActionTypeIconSupplier<ProxyTargetFilterQuery> actionTypeIconSupplier;
|
||||
private final StatusIconBuilder.ConfirmationIconSupplier confirmationIconSupplier;
|
||||
|
||||
private final transient DeleteSupport<ProxyTargetFilterQuery> targetFilterDeleteSupport;
|
||||
|
||||
@@ -77,16 +83,21 @@ public class TargetFilterGrid extends AbstractGrid<ProxyTargetFilterQuery, Strin
|
||||
* TargetFilterQueryManagement
|
||||
* @param autoAssignmentWindowBuilder
|
||||
* AutoAssignmentWindowBuilder
|
||||
* @param tenantConfigHelper
|
||||
* TenantConfigHelper
|
||||
*/
|
||||
public TargetFilterGrid(final CommonUiDependencies uiDependencies, final TargetFilterGridLayoutUiState uiState,
|
||||
public TargetFilterGrid(
|
||||
final CommonUiDependencies uiDependencies, final TargetFilterGridLayoutUiState uiState,
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement,
|
||||
final AutoAssignmentWindowBuilder autoAssignmentWindowBuilder) {
|
||||
final AutoAssignmentWindowBuilder autoAssignmentWindowBuilder,
|
||||
final TenantConfigHelper tenantConfigHelper) {
|
||||
super(uiDependencies.getI18n(), uiDependencies.getEventBus(), uiDependencies.getPermChecker());
|
||||
|
||||
this.notification = uiDependencies.getUiNotification();
|
||||
this.uiState = uiState;
|
||||
this.targetFilterQueryManagement = targetFilterQueryManagement;
|
||||
this.autoAssignmentWindowBuilder = autoAssignmentWindowBuilder;
|
||||
this.tenantConfigHelper = tenantConfigHelper;
|
||||
|
||||
this.targetFilterDeleteSupport = new DeleteSupport<>(this, i18n, notification, "caption.filter.custom",
|
||||
"caption.filter.custom.plur", ProxyTargetFilterQuery::getName, this::targetFiltersDeletionCallback,
|
||||
@@ -97,7 +108,11 @@ public class TargetFilterGrid extends AbstractGrid<ProxyTargetFilterQuery, Strin
|
||||
initFilterMappings();
|
||||
|
||||
actionTypeIconSupplier = new ActionTypeIconSupplier<>(i18n, ProxyTargetFilterQuery::getAutoAssignActionType,
|
||||
UIComponentIdProvider.TARGET_FILTER_TABLE_TYPE_LABEL_ID);
|
||||
UIComponentIdProvider.TARGET_FILTER_TABLE_TYPE_LABEL_ID);
|
||||
|
||||
confirmationIconSupplier = new StatusIconBuilder.ConfirmationIconSupplier(i18n,
|
||||
TARGET_FILTER_TABLE_CONFIRMATION_LABEL_ID);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
@@ -153,6 +168,11 @@ public class TargetFilterGrid extends AbstractGrid<ProxyTargetFilterQuery, Strin
|
||||
final Label icon = actionTypeIconSupplier.getLabel(filter);
|
||||
horizontalLayout.addComponent(icon);
|
||||
|
||||
if (tenantConfigHelper.isConfirmationFlowEnabled()) {
|
||||
final Label confirmationIcon = confirmationIconSupplier.getLabel(filter);
|
||||
horizontalLayout.addComponent(confirmationIcon);
|
||||
}
|
||||
|
||||
final Button link = buildAutoAssignmentLink(filter);
|
||||
horizontalLayout.addComponent(link);
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import java.util.List;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventView;
|
||||
@@ -24,6 +25,7 @@ import org.eclipse.hawkbit.ui.common.layout.listener.EntityModifiedListener.Enti
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.FilterChangedListener;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedGridRefreshAwareSupport;
|
||||
import org.eclipse.hawkbit.ui.filtermanagement.state.FilterManagementUIState;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
|
||||
/**
|
||||
* TargetFilter table layout.
|
||||
@@ -54,15 +56,17 @@ public class TargetFilterGridLayout extends AbstractGridComponentLayout {
|
||||
public TargetFilterGridLayout(final CommonUiDependencies uiDependencies,
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement, final TargetManagement targetManagement,
|
||||
final DistributionSetManagement distributionSetManagement,
|
||||
final FilterManagementUIState filterManagementUIState) {
|
||||
final FilterManagementUIState filterManagementUIState, final TenantConfigHelper tenantConfigHelper,
|
||||
final TenantAware tenantAware) {
|
||||
this.targetFilterGridHeader = new TargetFilterGridHeader(uiDependencies,
|
||||
filterManagementUIState.getGridLayoutUiState());
|
||||
|
||||
final AutoAssignmentWindowBuilder autoAssignmentWindowBuilder = new AutoAssignmentWindowBuilder(uiDependencies,
|
||||
targetManagement, targetFilterQueryManagement, distributionSetManagement);
|
||||
targetManagement, targetFilterQueryManagement, distributionSetManagement, tenantConfigHelper,
|
||||
tenantAware);
|
||||
|
||||
this.targetFilterGrid = new TargetFilterGrid(uiDependencies, filterManagementUIState.getGridLayoutUiState(),
|
||||
targetFilterQueryManagement, autoAssignmentWindowBuilder);
|
||||
targetFilterQueryManagement, autoAssignmentWindowBuilder, tenantConfigHelper);
|
||||
|
||||
final EventViewAware viewAware = new EventViewAware(EventView.TARGET_FILTER);
|
||||
this.targetQueryFilterListener = new FilterChangedListener<>(uiDependencies.getEventBus(),
|
||||
|
||||
@@ -13,6 +13,7 @@ import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.eclipse.hawkbit.repository.ConfirmationManagement;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetInvalidationManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
@@ -27,6 +28,7 @@ import org.eclipse.hawkbit.repository.TargetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.ui.AbstractHawkbitUI;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.UiProperties;
|
||||
@@ -98,7 +100,8 @@ public class DeploymentView extends AbstractEventListenersAwareView implements B
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement, final SystemManagement systemManagement,
|
||||
final TenantConfigurationManagement configManagement,
|
||||
final TargetManagementStateDataSupplier targetManagementStateDataSupplier,
|
||||
final SystemSecurityContext systemSecurityContext, @Qualifier("uiExecutor") final Executor uiExecutor) {
|
||||
final SystemSecurityContext systemSecurityContext, @Qualifier("uiExecutor") final Executor uiExecutor,
|
||||
final TenantAware tenantAware, final ConfirmationManagement confirmationManagement) {
|
||||
this.permChecker = permChecker;
|
||||
this.managementUIState = managementUIState;
|
||||
|
||||
@@ -115,7 +118,7 @@ public class DeploymentView extends AbstractEventListenersAwareView implements B
|
||||
configManagement, targetManagementStateDataSupplier, systemSecurityContext,
|
||||
managementUIState.getTargetTagFilterLayoutUiState(), managementUIState.getTargetGridLayoutUiState(),
|
||||
managementUIState.getTargetBulkUploadUiState(),
|
||||
managementUIState.getDistributionGridLayoutUiState());
|
||||
managementUIState.getDistributionGridLayoutUiState(), tenantAware, confirmationManagement);
|
||||
this.targetCountLayout = targetGridLayout.getCountMessageLabel().createFooterMessageComponent();
|
||||
|
||||
this.actionHistoryLayout = new ActionHistoryLayout(uiDependencies, deploymentManagement,
|
||||
|
||||
@@ -238,13 +238,11 @@ public class ActionHistoryGrid extends AbstractGrid<ProxyAction, String> {
|
||||
* as Id if the action needs to be cancelled.
|
||||
*/
|
||||
private void confirmAndCancelAction(final Long actionId) {
|
||||
final ConfirmationDialog confirmDialog = new ConfirmationDialog(i18n,
|
||||
i18n.getMessage("caption.cancel.action.confirmbox"), i18n.getMessage("message.cancel.action.confirm"),
|
||||
ok -> {
|
||||
if (ok) {
|
||||
cancelActiveAction(actionId);
|
||||
}
|
||||
}, UIComponentIdProvider.CONFIRMATION_POPUP_ID);
|
||||
final ConfirmationDialog confirmDialog = ConfirmationDialog
|
||||
.newBuilder(i18n, UIComponentIdProvider.CONFIRMATION_POPUP_ID)
|
||||
.caption(i18n.getMessage("caption.cancel.action.confirmbox"))
|
||||
.question(i18n.getMessage("message.cancel.action.confirm"))
|
||||
.onSaveOrUpdate(() -> cancelActiveAction(actionId)).build();
|
||||
UI.getCurrent().addWindow(confirmDialog.getWindow());
|
||||
confirmDialog.getWindow().bringToFront();
|
||||
}
|
||||
@@ -286,13 +284,11 @@ public class ActionHistoryGrid extends AbstractGrid<ProxyAction, String> {
|
||||
* as Id if the action needs to be forced.
|
||||
*/
|
||||
private void confirmAndForceAction(final Long actionId) {
|
||||
final ConfirmationDialog confirmDialog = new ConfirmationDialog(i18n,
|
||||
i18n.getMessage("caption.force.action.confirmbox"), i18n.getMessage("message.force.action.confirm"),
|
||||
ok -> {
|
||||
if (ok) {
|
||||
forceActiveAction(actionId);
|
||||
}
|
||||
}, UIComponentIdProvider.CONFIRMATION_POPUP_ID);
|
||||
final ConfirmationDialog confirmDialog = ConfirmationDialog
|
||||
.newBuilder(i18n, UIComponentIdProvider.CONFIRMATION_POPUP_ID)
|
||||
.caption(i18n.getMessage("caption.force.action.confirmbox"))
|
||||
.question(i18n.getMessage("message.force.action.confirm"))
|
||||
.onSaveOrUpdate(() -> forceActiveAction(actionId)).build();
|
||||
UI.getCurrent().addWindow(confirmDialog.getWindow());
|
||||
|
||||
confirmDialog.getWindow().bringToFront();
|
||||
@@ -326,13 +322,11 @@ public class ActionHistoryGrid extends AbstractGrid<ProxyAction, String> {
|
||||
* as Id if the action needs to be forced.
|
||||
*/
|
||||
private void confirmAndForceQuitAction(final Long actionId) {
|
||||
final ConfirmationDialog confirmDialog = new ConfirmationDialog(i18n,
|
||||
i18n.getMessage("caption.forcequit.action.confirmbox"),
|
||||
i18n.getMessage("message.forcequit.action.confirm"), ok -> {
|
||||
if (ok) {
|
||||
forceQuitActiveAction(actionId);
|
||||
}
|
||||
}, VaadinIcons.WARNING, UIComponentIdProvider.CONFIRMATION_POPUP_ID, null);
|
||||
final ConfirmationDialog confirmDialog = ConfirmationDialog
|
||||
.newBuilder(i18n, UIComponentIdProvider.CONFIRMATION_POPUP_ID)
|
||||
.caption(i18n.getMessage("caption.forcequit.action.confirmbox"))
|
||||
.question(i18n.getMessage("message.forcequit.action.confirm")).icon(VaadinIcons.WARNING)
|
||||
.onSaveOrUpdate(() -> forceQuitActiveAction(actionId)).build();
|
||||
UI.getCurrent().addWindow(confirmDialog.getWindow());
|
||||
|
||||
confirmDialog.getWindow().bringToFront();
|
||||
|
||||
@@ -47,12 +47,14 @@ 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.utils.TenantConfigHelper;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.vaadin.data.ValueProvider;
|
||||
import com.vaadin.icons.VaadinIcons;
|
||||
import com.vaadin.ui.Button;
|
||||
|
||||
|
||||
/**
|
||||
* Distribution set grid which is shown on the Deployment View.
|
||||
*/
|
||||
@@ -100,7 +102,7 @@ public class DistributionGrid extends AbstractDsGrid<DsManagementFilterParams> {
|
||||
final DeploymentManagement deploymentManagement, final UiProperties uiProperties,
|
||||
final DistributionGridLayoutUiState distributionGridLayoutUiState,
|
||||
final TargetGridLayoutUiState targetGridLayoutUiState,
|
||||
final TagFilterLayoutUiState distributionTagLayoutUiState) {
|
||||
final TagFilterLayoutUiState distributionTagLayoutUiState, final TenantConfigHelper tenantConfigHelper) {
|
||||
super(uiDependencies, distributionSetManagement, distributionGridLayoutUiState, EventView.DEPLOYMENT);
|
||||
|
||||
this.targetGridLayoutUiState = targetGridLayoutUiState;
|
||||
@@ -113,9 +115,9 @@ public class DistributionGrid extends AbstractDsGrid<DsManagementFilterParams> {
|
||||
this::getInstalledToTargetDsIds);
|
||||
|
||||
final Map<String, AssignmentSupport<?, ProxyDistributionSet>> sourceTargetAssignmentStrategies = new HashMap<>();
|
||||
|
||||
|
||||
final DeploymentAssignmentWindowController assignmentController = new DeploymentAssignmentWindowController(
|
||||
uiDependencies, uiProperties, deploymentManagement);
|
||||
uiDependencies, uiProperties, deploymentManagement, tenantConfigHelper);
|
||||
final TargetsToDistributionSetAssignmentSupport targetsToDsAssignment = new TargetsToDistributionSetAssignmentSupport(
|
||||
uiDependencies, assignmentController);
|
||||
final TargetTagsToDistributionSetAssignmentSupport targetTagsToDsAssignment = new TargetTagsToDistributionSetAssignmentSupport(
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedSelec
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedTagTokenAwareSupport;
|
||||
import org.eclipse.hawkbit.ui.common.state.TagFilterLayoutUiState;
|
||||
import org.eclipse.hawkbit.ui.management.targettable.TargetGridLayoutUiState;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
|
||||
/**
|
||||
* Distribution Set table layout in deployment view.
|
||||
@@ -113,9 +114,11 @@ public class DistributionGridLayout extends AbstractDistributionSetGridLayout {
|
||||
|
||||
this.distributionGrid = new DistributionGrid(uiDependencies, targetManagement, distributionSetManagement,
|
||||
dsInvalidationManagement, deploymentManagement, uiProperties, distributionGridLayoutUiState,
|
||||
targetGridLayoutUiState, distributionTagLayoutUiState);
|
||||
targetGridLayoutUiState, distributionTagLayoutUiState,
|
||||
TenantConfigHelper.usingContext(systemSecurityContext, configManagement));
|
||||
|
||||
this.distributionSetDetailsHeader = new DistributionSetDetailsHeader(uiDependencies, getDsWindowBuilder(),
|
||||
this.distributionSetDetailsHeader = new DistributionSetDetailsHeader(
|
||||
uiDependencies, getDsWindowBuilder(),
|
||||
getDsMetaDataWindowBuilder());
|
||||
|
||||
this.distributionDetails = new DistributionSetDetails(uiDependencies, distributionSetManagement, smManagement,
|
||||
|
||||
@@ -36,6 +36,10 @@ public class AssignmentWindowLayout extends VerticalLayout {
|
||||
|
||||
private final BoundComponent<ActionTypeOptionGroupAssignmentLayout> actionTypeLayout;
|
||||
private final CheckBox maintenanceWindowToggle;
|
||||
private final CheckBox confirmationRequiredToggle;
|
||||
|
||||
private final Link confirmationHelpLink;
|
||||
|
||||
private final BoundComponent<TextField> maintenanceSchedule;
|
||||
private final BoundComponent<TextField> maintenanceDuration;
|
||||
private final ComboBox<String> maintenanceTimeZoneCombo;
|
||||
@@ -47,9 +51,9 @@ public class AssignmentWindowLayout extends VerticalLayout {
|
||||
* Constructor for AssignmentWindowLayout
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* VaadinMessageSource
|
||||
* @param uiProperties
|
||||
* UiProperties
|
||||
* UiProperties
|
||||
*/
|
||||
public AssignmentWindowLayout(final VaadinMessageSource i18n, final UiProperties uiProperties) {
|
||||
this.proxyAssignmentBinder = new Binder<>();
|
||||
@@ -57,6 +61,8 @@ public class AssignmentWindowLayout extends VerticalLayout {
|
||||
|
||||
this.actionTypeLayout = componentBuilder.createActionTypeOptionGroupLayout(proxyAssignmentBinder);
|
||||
this.maintenanceWindowToggle = componentBuilder.createEnableMaintenanceWindowToggle(proxyAssignmentBinder);
|
||||
this.confirmationRequiredToggle = componentBuilder.createConfirmationToggle(proxyAssignmentBinder);
|
||||
this.confirmationHelpLink = componentBuilder.createConfirmationHelpLink(uiProperties);
|
||||
|
||||
this.maintenanceSchedule = componentBuilder.createMaintenanceSchedule(proxyAssignmentBinder);
|
||||
this.maintenanceDuration = componentBuilder.createMaintenanceDuration(proxyAssignmentBinder);
|
||||
@@ -90,6 +96,19 @@ public class AssignmentWindowLayout extends VerticalLayout {
|
||||
maintenanceWindowLayout.setVisible(false);
|
||||
maintenanceWindowLayout.setEnabled(false);
|
||||
addComponent(maintenanceWindowLayout);
|
||||
|
||||
final HorizontalLayout confirmationOptionsLayout = new HorizontalLayout();
|
||||
confirmationOptionsLayout.addComponent(confirmationRequiredToggle);
|
||||
confirmationOptionsLayout.addComponent(confirmationHelpLink);
|
||||
addComponent(confirmationOptionsLayout);
|
||||
refreshConfirmCheckBoxState(false);
|
||||
}
|
||||
|
||||
public void refreshConfirmCheckBoxState(final boolean confirmationFlowEnabled) {
|
||||
confirmationRequiredToggle.setEnabled(confirmationFlowEnabled);
|
||||
confirmationRequiredToggle.setVisible(confirmationFlowEnabled);
|
||||
confirmationHelpLink.setEnabled(confirmationFlowEnabled);
|
||||
confirmationHelpLink.setVisible(confirmationFlowEnabled);
|
||||
}
|
||||
|
||||
private void addValueChangeListeners() {
|
||||
|
||||
@@ -36,6 +36,8 @@ import com.vaadin.ui.Link;
|
||||
import com.vaadin.ui.TextField;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
|
||||
import static org.eclipse.hawkbit.ui.utils.UIMessageIdProvider.CAPTION_ACTION_CONFIRMATION_REQUIRED;
|
||||
|
||||
/**
|
||||
* Builder for Assignment window components.
|
||||
*/
|
||||
@@ -91,11 +93,22 @@ public class AssignmentWindowLayoutComponentBuilder {
|
||||
return maintenanceWindowToggle;
|
||||
}
|
||||
|
||||
public CheckBox createConfirmationToggle(final Binder<ProxyAssignmentWindow> binder) {
|
||||
final CheckBox confirmationToggle = FormComponentBuilder.createCheckBox(
|
||||
i18n.getMessage(CAPTION_ACTION_CONFIRMATION_REQUIRED),
|
||||
UIComponentIdProvider.ASSIGNMENT_CONFIRMATION_REQUIRED, binder,
|
||||
ProxyAssignmentWindow::isConfirmationRequired, ProxyAssignmentWindow::setConfirmationRequired);
|
||||
confirmationToggle.addStyleName(ValoTheme.CHECKBOX_SMALL);
|
||||
confirmationToggle.addStyleName("dist-window-maintenance-window-enable");
|
||||
|
||||
return confirmationToggle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create maintenance schedule
|
||||
*
|
||||
* @param binder
|
||||
* Proxy assignment window binder
|
||||
* Proxy assignment window binder
|
||||
*
|
||||
* @return maintenance schedule text field
|
||||
*/
|
||||
@@ -208,4 +221,15 @@ public class AssignmentWindowLayoutComponentBuilder {
|
||||
|
||||
return maintenanceHelpLink;
|
||||
}
|
||||
|
||||
public Link createConfirmationHelpLink(final UiProperties uiProperties) {
|
||||
final String confirmationFlowHelpUrl = uiProperties.getLinks().getDocumentation().getUserConsentAndConfirmationGuide();
|
||||
final Link confirmationHelpLink = new Link("", new ExternalResource(confirmationFlowHelpUrl));
|
||||
|
||||
confirmationHelpLink.setTargetName("_blank");
|
||||
confirmationHelpLink.setIcon(VaadinIcons.QUESTION_CIRCLE);
|
||||
confirmationHelpLink.setDescription(i18n.getMessage("tooltip.documentation.link"));
|
||||
|
||||
return confirmationHelpLink;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
@@ -44,6 +45,8 @@ import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
*/
|
||||
public class DeploymentAssignmentWindowController {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DeploymentAssignmentWindowController.class);
|
||||
|
||||
private final TenantConfigHelper tenantConfigHelper;
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
private final UIEventBus eventBus;
|
||||
@@ -65,11 +68,13 @@ public class DeploymentAssignmentWindowController {
|
||||
* DeploymentManagement
|
||||
*/
|
||||
public DeploymentAssignmentWindowController(final CommonUiDependencies uiDependencies,
|
||||
final UiProperties uiProperties, final DeploymentManagement deploymentManagement) {
|
||||
final UiProperties uiProperties, final DeploymentManagement deploymentManagement,
|
||||
final TenantConfigHelper tenantConfigHelper) {
|
||||
this.i18n = uiDependencies.getI18n();
|
||||
this.eventBus = uiDependencies.getEventBus();
|
||||
this.notification = uiDependencies.getUiNotification();
|
||||
this.deploymentManagement = deploymentManagement;
|
||||
this.tenantConfigHelper = tenantConfigHelper;
|
||||
|
||||
this.assignmentWindowLayout = new AssignmentWindowLayout(i18n, uiProperties);
|
||||
}
|
||||
@@ -92,8 +97,9 @@ public class DeploymentAssignmentWindowController {
|
||||
proxyAssignmentWindow.setMaintenanceTimeZone(SPDateTimeUtil.getClientTimeZoneOffsetId());
|
||||
|
||||
assignmentWindowLayout.getProxyAssignmentBinder().setBean(proxyAssignmentWindow);
|
||||
assignmentWindowLayout.refreshConfirmCheckBoxState(tenantConfigHelper.isConfirmationFlowEnabled());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save the given distribution sets to target assignments
|
||||
*
|
||||
@@ -114,13 +120,16 @@ public class DeploymentAssignmentWindowController {
|
||||
final String maintenanceDuration = proxyAssignmentWindow.getMaintenanceDuration();
|
||||
final String maintenanceTimeZone = proxyAssignmentWindow.getMaintenanceTimeZone();
|
||||
|
||||
final boolean confirmationRequired = proxyAssignmentWindow.isConfirmationRequired();
|
||||
|
||||
final Set<Long> dsIdsToAssign = proxyDistributionSets.stream().map(ProxyDistributionSet::getId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
final List<DeploymentRequest> deploymentRequests = new ArrayList<>();
|
||||
dsIdsToAssign.forEach(dsId -> proxyTargets.forEach(t -> {
|
||||
final DeploymentRequestBuilder request = DeploymentManagement.deploymentRequest(t.getControllerId(), dsId)
|
||||
.setActionType(actionType).setForceTime(forcedTimeStamp);
|
||||
.setActionType(actionType).setForceTime(forcedTimeStamp)
|
||||
.setConfirmationRequired(confirmationRequired);
|
||||
if (proxyAssignmentWindow.isMaintenanceWindowEnabled()) {
|
||||
request.setMaintenance(maintenanceSchedule, maintenanceDuration, maintenanceTimeZone);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* Copyright (c) 2022 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.targettable;
|
||||
|
||||
import com.vaadin.data.Binder;
|
||||
import com.vaadin.icons.VaadinIcons;
|
||||
import com.vaadin.ui.UI;
|
||||
import org.eclipse.hawkbit.repository.ConfirmationManagement;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractEntityWindowLayout;
|
||||
import org.eclipse.hawkbit.ui.common.CommonDialogWindow;
|
||||
import org.eclipse.hawkbit.ui.common.ConfirmationDialog;
|
||||
import org.eclipse.hawkbit.ui.common.builder.FormComponentBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.builder.TextFieldBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetConfirmationOptions;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
|
||||
import com.vaadin.ui.ComponentContainer;
|
||||
import com.vaadin.ui.FormLayout;
|
||||
import com.vaadin.ui.TextArea;
|
||||
import com.vaadin.ui.TextField;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.eclipse.hawkbit.ui.utils.UIComponentIdProvider.AUTO_CONFIRMATION_ACTIVATION_DIALOG_INITIATOR;
|
||||
import static org.eclipse.hawkbit.ui.utils.UIComponentIdProvider.AUTO_CONFIRMATION_ACTIVATION_DIALOG_REMARK;
|
||||
|
||||
/**
|
||||
* Target auto confirmation activation layout
|
||||
*/
|
||||
public class TargetAutoConfActivationLayout extends AbstractEntityWindowLayout<ProxyTargetConfirmationOptions> {
|
||||
|
||||
public static final String CAPTION_TEXTFIELD_INITIATOR = "caption.target.auto.confirmation.activate.initiator";
|
||||
public static final String PROMPT_TEXTFIELD_INITIATOR = "prompt.target.auto.confirmation.activate.initiator";
|
||||
|
||||
private final ConfirmationManagement confirmationManagement;
|
||||
private final VaadinMessageSource i18n;
|
||||
private final TextField initiator;
|
||||
private final TextArea remarkArea;
|
||||
|
||||
/**
|
||||
* Constructor for TargetAutoConfActivationLayout
|
||||
*
|
||||
* @param i18n
|
||||
* to get UI messages
|
||||
* @param confirmationManagement
|
||||
* to calculate affected actions
|
||||
*/
|
||||
public TargetAutoConfActivationLayout(final VaadinMessageSource i18n,
|
||||
final ConfirmationManagement confirmationManagement) {
|
||||
super();
|
||||
this.i18n = i18n;
|
||||
this.confirmationManagement = confirmationManagement;
|
||||
|
||||
this.initiator = createInitiatorField(binder);
|
||||
this.remarkArea = createRemarkInputArea(binder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentContainer getRootComponent() {
|
||||
final FormLayout autoConfirmationLayout = new FormLayout();
|
||||
|
||||
autoConfirmationLayout.setSpacing(true);
|
||||
autoConfirmationLayout.setMargin(true);
|
||||
autoConfirmationLayout.setSizeUndefined();
|
||||
|
||||
autoConfirmationLayout.addComponent(initiator);
|
||||
autoConfirmationLayout.addComponent(remarkArea);
|
||||
remarkArea.focus();
|
||||
return autoConfirmationLayout;
|
||||
}
|
||||
|
||||
public TextField createInitiatorField(final Binder<ProxyTargetConfirmationOptions> binder) {
|
||||
final TextField initiatorField = new TextFieldBuilder(64).id(AUTO_CONFIRMATION_ACTIVATION_DIALOG_INITIATOR)
|
||||
.caption(i18n.getMessage(CAPTION_TEXTFIELD_INITIATOR))
|
||||
.prompt(i18n.getMessage(PROMPT_TEXTFIELD_INITIATOR)).buildTextComponent();
|
||||
|
||||
binder.forField(initiatorField).bind(ProxyTargetConfirmationOptions::getInitiator,
|
||||
ProxyTargetConfirmationOptions::setInitiator);
|
||||
|
||||
initiatorField.setSizeUndefined();
|
||||
return initiatorField;
|
||||
}
|
||||
|
||||
/**
|
||||
* create remark field
|
||||
*
|
||||
* @param binder
|
||||
* binder the input will be bound to
|
||||
* @return input component
|
||||
*/
|
||||
public TextArea createRemarkInputArea(final Binder<ProxyTargetConfirmationOptions> binder) {
|
||||
return FormComponentBuilder
|
||||
.createBigTextInput(binder, i18n, AUTO_CONFIRMATION_ACTIVATION_DIALOG_REMARK,
|
||||
i18n.getMessage("caption.target.auto.confirmation.activate.remark"),
|
||||
i18n.getMessage("prompt.target.auto.confirmation.activate.remark"),
|
||||
ProxyTargetConfirmationOptions::getRemark, ProxyTargetConfirmationOptions::setRemark)
|
||||
.getComponent();
|
||||
}
|
||||
|
||||
public void setSaveCallback(final Consumer<CommonDialogWindow.SaveDialogCloseListener> saveCallback) {
|
||||
saveCallback.accept(new CommonDialogWindow.SaveDialogCloseListener() {
|
||||
@Override
|
||||
public boolean canWindowSaveOrUpdate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveOrUpdate() {
|
||||
final ProxyTargetConfirmationOptions newOptions = getEntity();
|
||||
if (newOptions != null) {
|
||||
final int count = calculateAffectedActionsOnActivation(newOptions.getControllerId());
|
||||
if (count > 0) {
|
||||
final ConfirmationDialog confirmationDialog = ConfirmationDialog.newBuilder(i18n, "test")
|
||||
.caption(i18n
|
||||
.getMessage("caption.target.auto.confirmation.activate.consequences.caption"))
|
||||
.question(i18n.getMessage(
|
||||
"caption.target.auto.confirmation.activate.consequences.question", count))
|
||||
.icon(VaadinIcons.WARNING).onSaveOrUpdate(() -> activateAutoConfirmation(newOptions))
|
||||
.build();
|
||||
UI.getCurrent().addWindow(confirmationDialog.getWindow());
|
||||
confirmationDialog.getWindow().bringToFront();
|
||||
} else {
|
||||
activateAutoConfirmation(newOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void activateAutoConfirmation(final ProxyTargetConfirmationOptions options) {
|
||||
confirmationManagement.activateAutoConfirmation(options.getControllerId(), options.getInitiator(),
|
||||
options.getRemark());
|
||||
}
|
||||
|
||||
private int calculateAffectedActionsOnActivation(final String controllerId) {
|
||||
return confirmationManagement.findActiveActionsWaitingConfirmation(controllerId).size();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2022 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.targettable;
|
||||
|
||||
import com.vaadin.server.Sizeable;
|
||||
import org.eclipse.hawkbit.repository.ConfirmationManagement;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.ui.UiProperties;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractEntityWindowBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.CommonDialogWindow;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetConfirmationOptions;
|
||||
|
||||
import com.vaadin.ui.Window;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.eclipse.hawkbit.ui.utils.UIComponentIdProvider.AUTO_CONFIRMATION_TOGGLE_DIALOG;
|
||||
|
||||
/**
|
||||
* Target auto confirmation activation windows builder
|
||||
*/
|
||||
public class TargetAutoConfActivationWindowBuilder extends AbstractEntityWindowBuilder<ProxyTargetConfirmationOptions> {
|
||||
|
||||
private final UiProperties uiProperties;
|
||||
|
||||
private final TenantAware tenantAware;
|
||||
private final ConfirmationManagement confirmationManagement;
|
||||
|
||||
protected TargetAutoConfActivationWindowBuilder(final CommonUiDependencies uiDependencies,
|
||||
final UiProperties uiProperties, final TenantAware tenantAware,
|
||||
final ConfirmationManagement confirmationManagement) {
|
||||
super(uiDependencies);
|
||||
this.uiProperties = uiProperties;
|
||||
this.tenantAware = tenantAware;
|
||||
this.confirmationManagement = confirmationManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getHelpLink() {
|
||||
return uiProperties.getLinks().getDocumentation().getAutoConfirmationView();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getWindowId() {
|
||||
return AUTO_CONFIRMATION_TOGGLE_DIALOG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Window getWindowForAdd() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Window getWindowForUpdate(final ProxyTargetConfirmationOptions entity) {
|
||||
final TargetAutoConfActivationLayout layout = new TargetAutoConfActivationLayout(uiDependencies.getI18n(),
|
||||
confirmationManagement);
|
||||
if (StringUtils.isEmpty(entity.getInitiator())) {
|
||||
entity.setInitiator(tenantAware.getCurrentUsername());
|
||||
}
|
||||
layout.setEntity(entity);
|
||||
|
||||
final CommonDialogWindow window = createWindow(layout.getRootComponent(), null);
|
||||
window.hideMandatoryExplanation();
|
||||
window.setAssistivePrefix(
|
||||
getI18n().getMessage("caption.target.auto.confirmation.activate.prefix") + " " + "<b>");
|
||||
window.setCaptionAsHtml(false);
|
||||
window.setCaption(entity.getControllerId());
|
||||
window.setAssistivePostfix("</b>");
|
||||
|
||||
layout.setSaveCallback(window::setCloseListener);
|
||||
|
||||
window.setHeight(320, Sizeable.Unit.PIXELS);
|
||||
window.setWidth(400, Sizeable.Unit.PIXELS);
|
||||
window.setSaveButtonEnabled(true);
|
||||
return window;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/**
|
||||
* Copyright (c) 2022 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.targettable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.vaadin.server.FontAwesome;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.Window;
|
||||
import org.eclipse.hawkbit.repository.ConfirmationManagement;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.UiProperties;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.ConfirmationDialog;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyKeyValueDetails;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetConfirmationOptions;
|
||||
import org.eclipse.hawkbit.ui.common.detailslayout.KeyValueDetailsComponent;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleNoBorder;
|
||||
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
|
||||
import com.vaadin.icons.VaadinIcons;
|
||||
import com.vaadin.ui.Button;
|
||||
import com.vaadin.ui.Component;
|
||||
import com.vaadin.ui.CustomField;
|
||||
import com.vaadin.ui.HorizontalLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.eclipse.hawkbit.ui.utils.UIComponentIdProvider.AUTO_CONFIRMATION_TOGGLE_DIALOG;
|
||||
import static org.eclipse.hawkbit.ui.utils.UIComponentIdProvider.AUTO_CONFIRMATION_DETAILS_ACTIVATEDAT;
|
||||
import static org.eclipse.hawkbit.ui.utils.UIComponentIdProvider.AUTO_CONFIRMATION_DETAILS_INITIATOR;
|
||||
import static org.eclipse.hawkbit.ui.utils.UIComponentIdProvider.AUTO_CONFIRMATION_DETAILS_REMARK;
|
||||
import static org.eclipse.hawkbit.ui.utils.UIComponentIdProvider.AUTO_CONFIRMATION_DETAILS_ROLLOUTS_USER;
|
||||
import static org.eclipse.hawkbit.ui.utils.UIComponentIdProvider.AUTO_CONFIRMATION_DETAILS_STATE;
|
||||
|
||||
/**
|
||||
* target auto confirmation detail component
|
||||
*/
|
||||
public class TargetConfirmationOptionsComponent extends CustomField<ProxyTargetConfirmationOptions> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final transient TargetAutoConfActivationWindowBuilder windowBuilder;
|
||||
private final transient ConfirmationManagement confirmationManagement;
|
||||
private final transient SpPermissionChecker permissionChecker;
|
||||
private final VaadinMessageSource i18n;
|
||||
private final HorizontalLayout targetConfirmationOptionsLayout;
|
||||
|
||||
/**
|
||||
* Constructor for TargetConfirmationOptionsComponent
|
||||
*
|
||||
* @param commonUiDependencies
|
||||
* the {@link CommonUiDependencies}
|
||||
* @param uiProperties
|
||||
* the {@link UiProperties}
|
||||
* @param confirmationManagement
|
||||
* the {@link ConfirmationManagement}
|
||||
* @param tenantAware
|
||||
* the {@link TenantAware}
|
||||
*/
|
||||
public TargetConfirmationOptionsComponent(final CommonUiDependencies commonUiDependencies,
|
||||
final UiProperties uiProperties, final ConfirmationManagement confirmationManagement,
|
||||
final TenantAware tenantAware) {
|
||||
this.i18n = commonUiDependencies.getI18n();
|
||||
this.confirmationManagement = confirmationManagement;
|
||||
this.permissionChecker = commonUiDependencies.getPermChecker();
|
||||
this.windowBuilder = new TargetAutoConfActivationWindowBuilder(commonUiDependencies, uiProperties, tenantAware,
|
||||
confirmationManagement);
|
||||
|
||||
this.targetConfirmationOptionsLayout = new HorizontalLayout();
|
||||
this.targetConfirmationOptionsLayout.setSpacing(true);
|
||||
this.targetConfirmationOptionsLayout.setMargin(false);
|
||||
this.targetConfirmationOptionsLayout.setSizeFull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProxyTargetConfirmationOptions getValue() {
|
||||
// keep returning same value since reloading (triggering 'doSetValue' method)
|
||||
// will be done on button click.
|
||||
return new ProxyTargetConfirmationOptions();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Component initContent() {
|
||||
return targetConfirmationOptionsLayout;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSetValue(final ProxyTargetConfirmationOptions targetConfirmationOptions) {
|
||||
targetConfirmationOptionsLayout.removeAllComponents();
|
||||
|
||||
if (targetConfirmationOptions == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean isAutoConfirmationEnabled = targetConfirmationOptions.isAutoConfirmationEnabled();
|
||||
|
||||
if (isAutoConfirmationEnabled) {
|
||||
final KeyValueDetailsComponent detailsLayout = buildAutoConfirmationDetailsLayout(
|
||||
targetConfirmationOptions);
|
||||
targetConfirmationOptionsLayout.addComponent(detailsLayout);
|
||||
targetConfirmationOptionsLayout.setExpandRatio(detailsLayout, 1.0F);
|
||||
} else {
|
||||
final KeyValueDetailsComponent component = toKeyValueDetailsComponent(
|
||||
Collections.singletonList(new ProxyKeyValueDetails(AUTO_CONFIRMATION_DETAILS_STATE,
|
||||
i18n.getMessage("label.target.auto.confirmation.state"),
|
||||
i18n.getMessage("label.target.auto.confirmation.deactivated"))));
|
||||
|
||||
targetConfirmationOptionsLayout.addComponent(component);
|
||||
targetConfirmationOptionsLayout.setExpandRatio(component, 1.0F);
|
||||
}
|
||||
|
||||
// do only provide toggle button when having permission for that
|
||||
if (permissionChecker.hasUpdateTargetPermission()) {
|
||||
final Button button = buildAutoConfirmationToggleButton(targetConfirmationOptions);
|
||||
targetConfirmationOptionsLayout.addComponent(button);
|
||||
}
|
||||
}
|
||||
|
||||
private KeyValueDetailsComponent buildAutoConfirmationDetailsLayout(final ProxyTargetConfirmationOptions options) {
|
||||
final List<ProxyKeyValueDetails> values = new ArrayList<>();
|
||||
values.add(new ProxyKeyValueDetails(AUTO_CONFIRMATION_DETAILS_STATE,
|
||||
i18n.getMessage("label.target.auto.confirmation.state"),
|
||||
i18n.getMessage("label.target.auto.confirmation.active")));
|
||||
|
||||
if (StringUtils.hasText(options.getInitiator())) {
|
||||
values.add(new ProxyKeyValueDetails(AUTO_CONFIRMATION_DETAILS_INITIATOR,
|
||||
i18n.getMessage("label.target.auto.confirmation.initiator"), options.getInitiator()));
|
||||
}
|
||||
values.add(new ProxyKeyValueDetails(AUTO_CONFIRMATION_DETAILS_ROLLOUTS_USER,
|
||||
i18n.getMessage("label.target.auto.confirmation.systemuser"), options.getInitiatedSystemUser()));
|
||||
if (StringUtils.hasText(options.getRemark())) {
|
||||
values.add(new ProxyKeyValueDetails(AUTO_CONFIRMATION_DETAILS_REMARK,
|
||||
i18n.getMessage("label.target.auto.confirmation.remark"), options.getRemark()));
|
||||
}
|
||||
values.add(new ProxyKeyValueDetails(AUTO_CONFIRMATION_DETAILS_ACTIVATEDAT,
|
||||
i18n.getMessage("label.target.auto.confirmation.activatedat"),
|
||||
SPDateTimeUtil.getFormattedDate(options.getActivatedAt())));
|
||||
|
||||
return toKeyValueDetailsComponent(values);
|
||||
}
|
||||
|
||||
private static KeyValueDetailsComponent toKeyValueDetailsComponent(final List<ProxyKeyValueDetails> values) {
|
||||
final KeyValueDetailsComponent details = new KeyValueDetailsComponent();
|
||||
details.disableSpacing();
|
||||
details.setValue(values);
|
||||
return details;
|
||||
}
|
||||
|
||||
private Button buildAutoConfirmationToggleButton(final ProxyTargetConfirmationOptions options) {
|
||||
final Button toggleAutoConfirmationButton;
|
||||
|
||||
if (options.isAutoConfirmationEnabled()) {
|
||||
toggleAutoConfirmationButton = SPUIComponentProvider.getButton(
|
||||
UIComponentIdProvider.AUTO_CONFIRMATION_DETAILS_TOGGLE, "",
|
||||
i18n.getMessage("button.target.auto.confirmation.disable"), ValoTheme.BUTTON_HUGE, true,
|
||||
FontAwesome.TOGGLE_ON, SPUIButtonStyleNoBorder.class);
|
||||
} else {
|
||||
toggleAutoConfirmationButton = SPUIComponentProvider.getButton(
|
||||
UIComponentIdProvider.AUTO_CONFIRMATION_DETAILS_TOGGLE, "",
|
||||
i18n.getMessage("button.target.auto.confirmation.activate"), ValoTheme.BUTTON_HUGE, true,
|
||||
FontAwesome.TOGGLE_OFF, SPUIButtonStyleNoBorder.class);
|
||||
}
|
||||
|
||||
toggleAutoConfirmationButton.addClickListener(e -> {
|
||||
if (options.isAutoConfirmationEnabled()) {
|
||||
final ConfirmationDialog dialog = ConfirmationDialog
|
||||
.newBuilder(i18n, AUTO_CONFIRMATION_TOGGLE_DIALOG).icon(VaadinIcons.WARNING)
|
||||
.caption(i18n.getMessage("caption.target.auto.confirmation.disable"))
|
||||
.question(i18n.getMessage("message.target.auto.confirmation.disable")).onSaveOrUpdate(() -> {
|
||||
confirmationManagement.deactivateAutoConfirmation(options.getControllerId());
|
||||
doSetValue(ProxyTargetConfirmationOptions.disabled(options.getControllerId()));
|
||||
}).build();
|
||||
|
||||
UI.getCurrent().addWindow(dialog.getWindow());
|
||||
|
||||
dialog.getWindow().bringToFront();
|
||||
} else {
|
||||
final Window window = windowBuilder.getWindowForUpdate(options);
|
||||
UI.getCurrent().addWindow(window);
|
||||
window.setVisible(Boolean.TRUE);
|
||||
}
|
||||
});
|
||||
|
||||
return toggleAutoConfirmationButton;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
package org.eclipse.hawkbit.ui.management.targettable;
|
||||
|
||||
import java.util.AbstractMap.SimpleEntry;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -17,10 +18,14 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.vaadin.ui.Component;
|
||||
import org.eclipse.hawkbit.repository.ConfirmationManagement;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.ui.UiProperties;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.data.providers.TargetMetaDataDataProvider;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyKeyValueDetails;
|
||||
@@ -36,6 +41,7 @@ import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.Window;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
|
||||
/**
|
||||
* Target details layout which is shown on the Deployment View.
|
||||
@@ -47,6 +53,7 @@ public class TargetDetails extends AbstractGridDetailsLayout<ProxyTarget> {
|
||||
|
||||
private final transient TargetManagement targetManagement;
|
||||
private final transient DeploymentManagement deploymentManagement;
|
||||
private final transient ConfirmationManagement confirmationManagement;
|
||||
|
||||
private final TargetAttributesDetailsComponent attributesLayout;
|
||||
private final KeyValueDetailsComponent assignedDsDetails;
|
||||
@@ -54,16 +61,23 @@ public class TargetDetails extends AbstractGridDetailsLayout<ProxyTarget> {
|
||||
private final transient TargetTagToken targetTagToken;
|
||||
private final MetadataDetailsGrid<String> targetMetadataGrid;
|
||||
|
||||
private final Tab confirmationOptionsTab;
|
||||
private final transient TargetMetaDataWindowBuilder targetMetaDataWindowBuilder;
|
||||
|
||||
private final transient TenantConfigHelper tenantConfigHelper;
|
||||
|
||||
TargetDetails(final CommonUiDependencies uiDependencies, final TargetTagManagement tagManagement,
|
||||
final TargetManagement targetManagement, final DeploymentManagement deploymentManagement,
|
||||
final TargetMetaDataWindowBuilder targetMetaDataWindowBuilder) {
|
||||
final ConfirmationManagement confirmationManagement,
|
||||
final TargetMetaDataWindowBuilder targetMetaDataWindowBuilder, final TenantConfigHelper tenantConfigHelper,
|
||||
final UiProperties uiProperties, final TenantAware tenantAware) {
|
||||
super(uiDependencies.getI18n());
|
||||
|
||||
this.targetManagement = targetManagement;
|
||||
this.deploymentManagement = deploymentManagement;
|
||||
this.confirmationManagement = confirmationManagement;
|
||||
this.targetMetaDataWindowBuilder = targetMetaDataWindowBuilder;
|
||||
this.tenantConfigHelper = tenantConfigHelper;
|
||||
|
||||
this.attributesLayout = buildAttributesLayout();
|
||||
|
||||
@@ -73,13 +87,16 @@ public class TargetDetails extends AbstractGridDetailsLayout<ProxyTarget> {
|
||||
|
||||
this.targetTagToken = new TargetTagToken(uiDependencies, tagManagement, targetManagement);
|
||||
|
||||
addDetailsComponents(Arrays.asList(new SimpleEntry<>(i18n.getMessage("caption.tab.details"), entityDetails),
|
||||
new SimpleEntry<>(i18n.getMessage("caption.tab.description"), entityDescription),
|
||||
new SimpleEntry<>(i18n.getMessage("caption.attributes.tab"), attributesLayout),
|
||||
new SimpleEntry<>(i18n.getMessage("header.target.assigned"), assignedDsDetails),
|
||||
new SimpleEntry<>(i18n.getMessage("header.target.installed"), installedDsDetails),
|
||||
new SimpleEntry<>(i18n.getMessage("caption.tags.tab"), getTargetTagToken().getTagPanel()),
|
||||
new SimpleEntry<>(i18n.getMessage("caption.logs.tab"), logDetails)));
|
||||
final List<Map.Entry<String, Component>> components = new ArrayList<>(
|
||||
Arrays.asList(new SimpleEntry<>(i18n.getMessage("caption.tab.details"), entityDetails),
|
||||
new SimpleEntry<>(i18n.getMessage("caption.tab.description"), entityDescription),
|
||||
new SimpleEntry<>(i18n.getMessage("caption.attributes.tab"), attributesLayout),
|
||||
new SimpleEntry<>(i18n.getMessage("header.target.assigned"), assignedDsDetails),
|
||||
new SimpleEntry<>(i18n.getMessage("header.target.installed"), installedDsDetails),
|
||||
new SimpleEntry<>(i18n.getMessage("caption.tags.tab"), getTargetTagToken().getTagPanel()),
|
||||
new SimpleEntry<>(i18n.getMessage("caption.logs.tab"), logDetails)));
|
||||
|
||||
addDetailsComponents(components);
|
||||
|
||||
if (uiDependencies.getPermChecker().hasReadRepositoryPermission()) {
|
||||
this.targetMetadataGrid = new MetadataDetailsGrid<>(i18n, uiDependencies.getEventBus(),
|
||||
@@ -91,6 +108,21 @@ public class TargetDetails extends AbstractGridDetailsLayout<ProxyTarget> {
|
||||
}
|
||||
|
||||
buildDetails();
|
||||
|
||||
// build tab separately to change visibility afterwards
|
||||
confirmationOptionsTab = addAutoConfirmationTab(uiDependencies, uiProperties, tenantAware);
|
||||
confirmationOptionsTab.setVisible(tenantConfigHelper.isConfirmationFlowEnabled());
|
||||
}
|
||||
|
||||
private Tab addAutoConfirmationTab(final CommonUiDependencies uiDependencies, final UiProperties uiProperties,
|
||||
final TenantAware tenantAware) {
|
||||
final TargetConfirmationOptionsComponent confirmationOptions = buildConfirmationOptionsLayout(uiDependencies,
|
||||
uiProperties, tenantAware);
|
||||
return addTab(buildTabWrapperDetailsLayout(confirmationOptions), i18n.getMessage("caption.tab.confirmation"));
|
||||
}
|
||||
|
||||
protected void alignWithConfirmationFlowState() {
|
||||
confirmationOptionsTab.setVisible(tenantConfigHelper.isConfirmationFlowEnabled());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -141,6 +173,17 @@ public class TargetDetails extends AbstractGridDetailsLayout<ProxyTarget> {
|
||||
return attributesDetails;
|
||||
}
|
||||
|
||||
private TargetConfirmationOptionsComponent buildConfirmationOptionsLayout(
|
||||
final CommonUiDependencies commonUiDependencies, final UiProperties uiProperties,
|
||||
final TenantAware tenantAware) {
|
||||
final TargetConfirmationOptionsComponent confirmationOptions = new TargetConfirmationOptionsComponent(
|
||||
commonUiDependencies, uiProperties, confirmationManagement, tenantAware);
|
||||
|
||||
binder.forField(confirmationOptions).bind(ProxyTarget::getTargetConfirmationOptions, null);
|
||||
|
||||
return confirmationOptions;
|
||||
}
|
||||
|
||||
private KeyValueDetailsComponent buildAssignedDsDetails() {
|
||||
final KeyValueDetailsComponent assignedDsLayout = new KeyValueDetailsComponent();
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
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.utils.TenantConfigHelper;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
@@ -153,7 +154,8 @@ public class TargetGrid extends AbstractGrid<ProxyTarget, TargetManagementFilter
|
||||
final Map<String, AssignmentSupport<?, ProxyTarget>> sourceTargetAssignmentStrategies = new HashMap<>();
|
||||
|
||||
final DeploymentAssignmentWindowController assignmentController = new DeploymentAssignmentWindowController(
|
||||
uiDependencies, uiProperties, deploymentManagement);
|
||||
uiDependencies, uiProperties, deploymentManagement,
|
||||
TenantConfigHelper.usingContext(systemSecurityContext, configManagement));
|
||||
final DistributionSetsToTargetAssignmentSupport distributionsToTargetAssignment = new DistributionSetsToTargetAssignmentSupport(
|
||||
uiDependencies, systemSecurityContext, configManagement, assignmentController);
|
||||
final TargetTagsToTargetAssignmentSupport targetTagsToTargetAssignment = new TargetTagsToTargetAssignmentSupport(
|
||||
|
||||
@@ -14,6 +14,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.eclipse.hawkbit.repository.ConfirmationManagement;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
@@ -21,6 +22,7 @@ import org.eclipse.hawkbit.repository.TargetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.ui.UiProperties;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSet;
|
||||
@@ -51,6 +53,7 @@ import org.eclipse.hawkbit.ui.management.bulkupload.BulkUploadWindowBuilder;
|
||||
import org.eclipse.hawkbit.ui.management.bulkupload.TargetBulkUploadUiState;
|
||||
import org.eclipse.hawkbit.ui.management.dstable.DistributionGridLayoutUiState;
|
||||
import org.eclipse.hawkbit.ui.management.targettag.filter.TargetTagFilterLayoutUiState;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
|
||||
/**
|
||||
* Target table layout.
|
||||
@@ -108,8 +111,13 @@ public class TargetGridLayout extends AbstractGridComponentLayout {
|
||||
* TargetBulkUploadUiState
|
||||
* @param distributionGridLayoutUiState
|
||||
* DistributionGridLayoutUiState
|
||||
* @param tenantAware
|
||||
* TenantAware
|
||||
* @param confirmationManagement
|
||||
* ConfirmationManagement
|
||||
*/
|
||||
public TargetGridLayout(final CommonUiDependencies uiDependencies, final TargetManagement targetManagement,
|
||||
public TargetGridLayout(
|
||||
final CommonUiDependencies uiDependencies, final TargetManagement targetManagement,
|
||||
final TargetTypeManagement targetTypeManagement, final DeploymentManagement deploymentManagement,
|
||||
final UiProperties uiProperties, final TargetTagManagement targetTagManagement,
|
||||
final DistributionSetManagement distributionSetManagement, final Executor uiExecutor,
|
||||
@@ -119,7 +127,8 @@ public class TargetGridLayout extends AbstractGridComponentLayout {
|
||||
final TargetTagFilterLayoutUiState targetTagFilterLayoutUiState,
|
||||
final TargetGridLayoutUiState targetGridLayoutUiState,
|
||||
final TargetBulkUploadUiState targetBulkUploadUiState,
|
||||
final DistributionGridLayoutUiState distributionGridLayoutUiState) {
|
||||
final DistributionGridLayoutUiState distributionGridLayoutUiState, final TenantAware tenantAware,
|
||||
final ConfirmationManagement confirmationManagement) {
|
||||
final TargetWindowBuilder targetWindowBuilder = new TargetWindowBuilder(uiDependencies, targetManagement,
|
||||
targetTypeManagement, EventView.DEPLOYMENT);
|
||||
final TargetMetaDataWindowBuilder targetMetaDataWindowBuilder = new TargetMetaDataWindowBuilder(uiDependencies,
|
||||
@@ -139,7 +148,8 @@ public class TargetGridLayout extends AbstractGridComponentLayout {
|
||||
this.targetDetailsHeader = new TargetDetailsHeader(uiDependencies, targetWindowBuilder,
|
||||
targetMetaDataWindowBuilder);
|
||||
this.targetDetails = new TargetDetails(uiDependencies, targetTagManagement, targetManagement,
|
||||
deploymentManagement, targetMetaDataWindowBuilder);
|
||||
deploymentManagement, confirmationManagement, targetMetaDataWindowBuilder,
|
||||
TenantConfigHelper.usingContext(systemSecurityContext, configManagement), uiProperties, tenantAware);
|
||||
|
||||
this.countMessageLabel = new TargetCountMessageLabel(uiDependencies.getI18n(),
|
||||
uiDependencies.getUiNotification(), targetManagement, targetGrid.getFilterSupport());
|
||||
@@ -265,6 +275,7 @@ public class TargetGridLayout extends AbstractGridComponentLayout {
|
||||
targetGrid.getSelectionSupport().reselectCurrentEntity();
|
||||
countMessageLabel.updateTotalAndFilteredCount();
|
||||
countMessageLabel.updatePinningDetails();
|
||||
targetDetails.alignWithConfirmationFlowState();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.ui.AbstractHawkbitUI;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.UiProperties;
|
||||
@@ -36,6 +37,7 @@ import org.eclipse.hawkbit.ui.rollout.rolloutgroup.RolloutGroupGridLayout;
|
||||
import org.eclipse.hawkbit.ui.rollout.rolloutgrouptargets.RolloutGroupTargetGridLayout;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
@@ -68,7 +70,7 @@ public class RolloutView extends AbstractEventListenersAwareView {
|
||||
final VaadinMessageSource i18n, final TargetFilterQueryManagement targetFilterQueryManagement,
|
||||
final QuotaManagement quotaManagement, final TenantConfigurationManagement tenantConfigManagement,
|
||||
final DistributionSetManagement distributionSetManagement,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware) {
|
||||
this.rolloutManagementUIState = rolloutManagementUIState;
|
||||
|
||||
final CommonUiDependencies uiDependencies = new CommonUiDependencies(i18n, entityFactory, eventBus,
|
||||
@@ -78,7 +80,8 @@ public class RolloutView extends AbstractEventListenersAwareView {
|
||||
targetManagement, uiProperties, targetFilterQueryManagement, rolloutGroupManagement, quotaManagement,
|
||||
tenantConfigManagement, distributionSetManagement, systemSecurityContext);
|
||||
this.rolloutGroupsLayout = new RolloutGroupGridLayout(uiDependencies, rolloutGroupManagement,
|
||||
rolloutManagementUIState);
|
||||
rolloutManagementUIState,
|
||||
TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigManagement), tenantAware);
|
||||
this.rolloutGroupTargetsLayout = new RolloutGroupTargetGridLayout(uiDependencies, rolloutGroupManagement,
|
||||
rolloutManagementUIState);
|
||||
|
||||
|
||||
@@ -16,6 +16,16 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.cronutils.utils.StringUtils;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.vaadin.data.ValueProvider;
|
||||
import com.vaadin.icons.VaadinIcons;
|
||||
import com.vaadin.shared.ui.ContentMode;
|
||||
import com.vaadin.ui.Button;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.Window;
|
||||
import com.vaadin.ui.renderers.HtmlRenderer;
|
||||
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
|
||||
import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
@@ -60,17 +70,6 @@ import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.cronutils.utils.StringUtils;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.vaadin.data.ValueProvider;
|
||||
import com.vaadin.icons.VaadinIcons;
|
||||
import com.vaadin.shared.ui.ContentMode;
|
||||
import com.vaadin.ui.Button;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.Window;
|
||||
import com.vaadin.ui.renderers.HtmlRenderer;
|
||||
|
||||
/**
|
||||
* Rollout list grid component.
|
||||
*/
|
||||
@@ -524,16 +523,17 @@ public class RolloutGrid extends AbstractGrid<ProxyRollout, String> {
|
||||
private ConfirmationDialog createTriggerNextGroupDialog(final Long rolloutId) {
|
||||
final String caption = i18n.getMessage("caption.rollout.confirm.trigger.next");
|
||||
final String question = i18n.getMessage("message.rollout.confirm.trigger.next");
|
||||
return new ConfirmationDialog(i18n, caption, question, ok -> {
|
||||
if (Boolean.TRUE.equals(ok)) {
|
||||
try {
|
||||
rolloutManagement.triggerNextGroup(rolloutId);
|
||||
uiNotification.displaySuccess(i18n.getMessage("message.rollout.trigger.next.group.success"));
|
||||
} catch (final RolloutIllegalStateException e) {
|
||||
LOGGER.warn("Error on manually triggering next rollout group: {}", e.getMessage());
|
||||
uiNotification.displayValidationError(i18n.getMessage("message.rollout.trigger.next.group.error"));
|
||||
}
|
||||
}
|
||||
}, UIComponentIdProvider.ROLLOUT_TRIGGER_NEXT_CONFIRMATION_DIALOG);
|
||||
|
||||
return ConfirmationDialog.newBuilder(i18n, UIComponentIdProvider.ROLLOUT_TRIGGER_NEXT_CONFIRMATION_DIALOG)
|
||||
.caption(caption).question(question).onSaveOrUpdate(() -> {
|
||||
try {
|
||||
rolloutManagement.triggerNextGroup(rolloutId);
|
||||
uiNotification.displaySuccess(i18n.getMessage("message.rollout.trigger.next.group.success"));
|
||||
} catch (final RolloutIllegalStateException e) {
|
||||
LOGGER.warn("Error on manually triggering next rollout group: {}", e.getMessage());
|
||||
uiNotification
|
||||
.displayValidationError(i18n.getMessage("message.rollout.trigger.next.group.error"));
|
||||
}
|
||||
}).build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedSelec
|
||||
import org.eclipse.hawkbit.ui.rollout.RolloutManagementUIState;
|
||||
import org.eclipse.hawkbit.ui.rollout.window.RolloutWindowBuilder;
|
||||
import org.eclipse.hawkbit.ui.rollout.window.RolloutWindowDependencies;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
|
||||
/**
|
||||
* Rollout list view.
|
||||
@@ -82,7 +83,8 @@ public class RolloutGridLayout extends AbstractGridComponentLayout {
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
final RolloutWindowDependencies rolloutWindowDependecies = new RolloutWindowDependencies(uiDependencies,
|
||||
rolloutManagement, targetManagement, uiProperties, targetFilterQueryManagement, rolloutGroupManagement,
|
||||
quotaManagement, distributionSetManagement);
|
||||
quotaManagement, distributionSetManagement,
|
||||
TenantConfigHelper.usingContext(systemSecurityContext, tenantConfigManagement));
|
||||
|
||||
final RolloutWindowBuilder rolloutWindowBuilder = new RolloutWindowBuilder(rolloutWindowDependecies);
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ import com.vaadin.shared.ui.ContentMode;
|
||||
import com.vaadin.ui.Button;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.renderers.HtmlRenderer;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
|
||||
/**
|
||||
* Rollout group list grid component.
|
||||
@@ -54,18 +55,22 @@ public class RolloutGroupGrid extends AbstractGrid<ProxyRolloutGroup, Long> {
|
||||
private final RolloutManagementUIState rolloutManagementUIState;
|
||||
private final transient RolloutGroupManagement rolloutGroupManagement;
|
||||
private final transient RolloutGroupToProxyRolloutGroupMapper rolloutGroupMapper;
|
||||
|
||||
private final transient TenantConfigHelper tenantConfigHelper;
|
||||
|
||||
private final RolloutGroupStatusIconSupplier<ProxyRolloutGroup> rolloutGroupStatusIconSupplier;
|
||||
|
||||
private final transient MasterEntitySupport<ProxyRollout> masterEntitySupport;
|
||||
|
||||
|
||||
RolloutGroupGrid(final CommonUiDependencies uiDependencies, final RolloutGroupManagement rolloutGroupManagement,
|
||||
final RolloutManagementUIState rolloutManagementUIState) {
|
||||
final RolloutManagementUIState rolloutManagementUIState, final TenantConfigHelper tenantConfigHelper) {
|
||||
super(uiDependencies.getI18n(), uiDependencies.getEventBus(), uiDependencies.getPermChecker());
|
||||
|
||||
this.rolloutManagementUIState = rolloutManagementUIState;
|
||||
this.rolloutGroupManagement = rolloutGroupManagement;
|
||||
this.rolloutGroupMapper = new RolloutGroupToProxyRolloutGroupMapper();
|
||||
this.tenantConfigHelper = tenantConfigHelper;
|
||||
|
||||
setSelectionSupport(new SelectionSupport<>(this, eventBus, EventLayout.ROLLOUT_GROUP_LIST, EventView.ROLLOUT,
|
||||
this::mapIdToProxyEntity, this::getSelectedEntityIdFromUiState, this::setSelectedEntityIdToUiState));
|
||||
@@ -147,10 +152,17 @@ public class RolloutGroupGrid extends AbstractGrid<ProxyRolloutGroup, Long> {
|
||||
.setId(SPUILabelDefinitions.ROLLOUT_GROUP_ERROR_THRESHOLD)
|
||||
.setCaption(i18n.getMessage("header.rolloutgroup.threshold.error")).setHidable(true);
|
||||
|
||||
GridComponentBuilder.addColumn(this, group -> group.getSuccessConditionExp() + "%")
|
||||
GridComponentBuilder.addColumn(this, group -> group
|
||||
.getSuccessConditionExp() + "%")
|
||||
.setId(SPUILabelDefinitions.ROLLOUT_GROUP_THRESHOLD)
|
||||
.setCaption(i18n.getMessage("header.rolloutgroup.threshold")).setHidable(true);
|
||||
|
||||
if (tenantConfigHelper.isConfirmationFlowEnabled()) {
|
||||
GridComponentBuilder.addColumn(this, group -> group.isConfirmationRequired() ? "required" : "not required")
|
||||
.setId(SPUILabelDefinitions.ROLLOUT_GROUP_CONFIRMATION_REQUIRED)
|
||||
.setCaption(i18n.getMessage("header.rolloutgroup.confirmation")).setHidable(true);
|
||||
}
|
||||
|
||||
GridComponentBuilder.addCreatedAndModifiedColumns(this, i18n)
|
||||
.forEach(col -> col.setHidable(true).setHidden(true));
|
||||
}
|
||||
@@ -198,10 +210,27 @@ public class RolloutGroupGrid extends AbstractGrid<ProxyRolloutGroup, Long> {
|
||||
}
|
||||
}
|
||||
|
||||
public void alignWithConfirmationFlowState() {
|
||||
alignWithConfirmationFlowState(tenantConfigHelper.isConfirmationFlowEnabled());
|
||||
}
|
||||
|
||||
public void alignWithConfirmationFlowState(final boolean active) {
|
||||
final boolean columnPresent = GridComponentBuilder.isColumnPresent(this,
|
||||
SPUILabelDefinitions.ROLLOUT_GROUP_CONFIRMATION_REQUIRED);
|
||||
if (active && !columnPresent) {
|
||||
GridComponentBuilder.addColumn(this, group -> group.isConfirmationRequired() ? "required" : "not required")
|
||||
.setId(SPUILabelDefinitions.ROLLOUT_GROUP_CONFIRMATION_REQUIRED)
|
||||
.setCaption(i18n.getMessage("header.rolloutgroup.confirmation")).setHidable(true);
|
||||
} else if (!active && columnPresent) {
|
||||
GridComponentBuilder.removeColumn(this, SPUILabelDefinitions.ROLLOUT_GROUP_CONFIRMATION_REQUIRED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Rollout master entity support
|
||||
*/
|
||||
public MasterEntitySupport<ProxyRollout> getMasterEntitySupport() {
|
||||
return masterEntitySupport;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,20 +13,25 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyRollout;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyRolloutGroup;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventLayout;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventLayoutViewAware;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventView;
|
||||
import org.eclipse.hawkbit.ui.common.event.TenantConfigChangedEventPayload;
|
||||
import org.eclipse.hawkbit.ui.common.layout.AbstractGridComponentLayout;
|
||||
import org.eclipse.hawkbit.ui.common.layout.MasterEntityAwareComponent;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.EntityModifiedListener;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.EntityModifiedListener.EntityModifiedAwareSupport;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.SelectionChangedListener;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.TenantConfigChangedListener;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedGridRefreshAwareSupport;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedSelectionAwareSupport;
|
||||
import org.eclipse.hawkbit.ui.rollout.RolloutManagementUIState;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
|
||||
/**
|
||||
* Groups List View.
|
||||
@@ -40,6 +45,9 @@ public class RolloutGroupGridLayout extends AbstractGridComponentLayout {
|
||||
private final transient SelectionChangedListener<ProxyRollout> masterEntityChangedListener;
|
||||
private final transient EntityModifiedListener<ProxyRolloutGroup> entityModifiedListener;
|
||||
|
||||
private final transient TenantConfigChangedListener tenantConfigChangedListener;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for RolloutGroupsListView
|
||||
*
|
||||
@@ -49,13 +57,16 @@ public class RolloutGroupGridLayout extends AbstractGridComponentLayout {
|
||||
* RolloutGroupManagement
|
||||
* @param rolloutManagementUIState
|
||||
* UIState
|
||||
* @param tenantConfigHelper
|
||||
* TenantConfigHelper
|
||||
*/
|
||||
public RolloutGroupGridLayout(final CommonUiDependencies uiDependencies,
|
||||
final RolloutGroupManagement rolloutGroupManagement,
|
||||
final RolloutManagementUIState rolloutManagementUIState) {
|
||||
final RolloutManagementUIState rolloutManagementUIState, final TenantConfigHelper tenantConfigHelper,
|
||||
final TenantAware tenantAware) {
|
||||
this.rolloutGroupsListHeader = new RolloutGroupGridHeader(uiDependencies, rolloutManagementUIState);
|
||||
this.rolloutGroupListGrid = new RolloutGroupGrid(uiDependencies, rolloutGroupManagement,
|
||||
rolloutManagementUIState);
|
||||
rolloutManagementUIState, tenantConfigHelper);
|
||||
|
||||
final EventLayoutViewAware masterLayoutView = new EventLayoutViewAware(EventLayout.ROLLOUT_LIST,
|
||||
EventView.ROLLOUT);
|
||||
@@ -65,10 +76,18 @@ public class RolloutGroupGridLayout extends AbstractGridComponentLayout {
|
||||
ProxyRolloutGroup.class).parentEntityType(ProxyRollout.class)
|
||||
.parentEntityIdProvider(this::getMasterEntityId).viewAware(masterLayoutView)
|
||||
.entityModifiedAwareSupports(getEntityModifiedAwareSupports()).build();
|
||||
this.tenantConfigChangedListener = TenantConfigChangedListener.newBuilder(uiDependencies.getEventBus())
|
||||
.tenantFilter(tenantAware.getCurrentTenant())
|
||||
.addConfigFilter(TenantConfigurationProperties.TenantConfigurationKey.USER_CONFIRMATION_ENABLED)
|
||||
.applicationEventConsumer(this::onConfirmationFlowConfigChange).build();
|
||||
|
||||
buildLayout(rolloutGroupsListHeader, rolloutGroupListGrid);
|
||||
}
|
||||
|
||||
private void onConfirmationFlowConfigChange(final TenantConfigChangedEventPayload payload) {
|
||||
payload.getValue(Boolean.class).ifPresent(rolloutGroupListGrid::alignWithConfirmationFlowState);
|
||||
}
|
||||
|
||||
private List<MasterEntityAwareComponent<ProxyRollout>> getMasterEntityAwareComponents() {
|
||||
return Arrays.asList(rolloutGroupsListHeader, rolloutGroupListGrid.getMasterEntitySupport());
|
||||
}
|
||||
@@ -85,6 +104,11 @@ public class RolloutGroupGridLayout extends AbstractGridComponentLayout {
|
||||
return Optional.ofNullable(rolloutGroupListGrid.getMasterEntitySupport().getMasterId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewEnter() {
|
||||
rolloutGroupListGrid.alignWithConfirmationFlowState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreState() {
|
||||
rolloutGroupsListHeader.restoreState();
|
||||
@@ -95,11 +119,13 @@ public class RolloutGroupGridLayout extends AbstractGridComponentLayout {
|
||||
public void subscribeListeners() {
|
||||
masterEntityChangedListener.subscribe();
|
||||
entityModifiedListener.subscribe();
|
||||
tenantConfigChangedListener.subscribe();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsubscribeListeners() {
|
||||
masterEntityChangedListener.unsubscribe();
|
||||
entityModifiedListener.unsubscribe();
|
||||
tenantConfigChangedListener.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.eclipse.hawkbit.ui.UiProperties;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
/**
|
||||
@@ -34,6 +35,7 @@ public final class RolloutWindowDependencies {
|
||||
private final DistributionSetManagement distributionSetManagement;
|
||||
private final UiProperties uiProperties;
|
||||
private final CommonUiDependencies uiDependencies;
|
||||
private final TenantConfigHelper tenantConfigHelper;
|
||||
|
||||
/**
|
||||
* Constructor for RolloutWindowDependencies
|
||||
@@ -59,7 +61,7 @@ public final class RolloutWindowDependencies {
|
||||
final TargetManagement targetManagement, final UiProperties uiProperties,
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement,
|
||||
final RolloutGroupManagement rolloutGroupManagement, final QuotaManagement quotaManagement,
|
||||
final DistributionSetManagement distributionSetManagement) {
|
||||
final DistributionSetManagement distributionSetManagement, final TenantConfigHelper tenantConfigHelper) {
|
||||
this.uiDependencies = uiDependencies;
|
||||
this.rolloutManagement = rolloutManagement;
|
||||
this.rolloutGroupManagement = rolloutGroupManagement;
|
||||
@@ -68,6 +70,7 @@ public final class RolloutWindowDependencies {
|
||||
this.uiProperties = uiProperties;
|
||||
this.targetFilterQueryManagement = targetFilterQueryManagement;
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
this.tenantConfigHelper = tenantConfigHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,4 +156,8 @@ public final class RolloutWindowDependencies {
|
||||
public CommonUiDependencies getuiDependencies() {
|
||||
return uiDependencies;
|
||||
}
|
||||
|
||||
public TenantConfigHelper getTenantConfigHelper() {
|
||||
return tenantConfigHelper;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,8 @@ public final class RolloutWindowLayoutComponentBuilder {
|
||||
* @return Layout to create simple group
|
||||
*/
|
||||
public SimpleGroupsLayout createSimpleGroupsLayout() {
|
||||
return new SimpleGroupsLayout(dependencies.getI18n(), dependencies.getQuotaManagement());
|
||||
return new SimpleGroupsLayout(dependencies.getI18n(), dependencies.getQuotaManagement(),
|
||||
dependencies.getTenantConfigHelper(), dependencies.getUiProperties());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,7 +78,8 @@ public final class RolloutWindowLayoutComponentBuilder {
|
||||
*/
|
||||
public AdvancedGroupsLayout createAdvancedGroupsLayout() {
|
||||
return new AdvancedGroupsLayout(dependencies.getI18n(), dependencies.getEntityFactory(),
|
||||
dependencies.getRolloutManagement(), dependencies.getQuotaManagement(), targetFilterQueryDataProvider);
|
||||
dependencies.getRolloutManagement(), dependencies.getQuotaManagement(), targetFilterQueryDataProvider,
|
||||
dependencies.getTenantConfigHelper());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,7 +96,7 @@ public final class RolloutWindowLayoutComponentBuilder {
|
||||
final Component advancedGroupDefinitionTab) {
|
||||
final TabSheet groupsDefinitionTabs = new TabSheet();
|
||||
groupsDefinitionTabs.setId(UIComponentIdProvider.ROLLOUT_GROUPS);
|
||||
groupsDefinitionTabs.setWidth(850, Unit.PIXELS);
|
||||
groupsDefinitionTabs.setWidth(900, Unit.PIXELS);
|
||||
groupsDefinitionTabs.setHeight(300, Unit.PIXELS);
|
||||
groupsDefinitionTabs.setStyleName(SPUIStyleDefinitions.ROLLOUT_GROUPS);
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.rollout.window.components;
|
||||
|
||||
import com.vaadin.ui.Alignment;
|
||||
import com.vaadin.ui.CheckBox;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.ui.common.builder.BoundComponent;
|
||||
import org.eclipse.hawkbit.ui.common.builder.FormComponentBuilder;
|
||||
@@ -30,6 +32,8 @@ import com.vaadin.ui.GridLayout;
|
||||
import com.vaadin.ui.TextField;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
|
||||
import static org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions.DIST_CHECKBOX_STYLE;
|
||||
|
||||
/**
|
||||
* Advance group row component
|
||||
*/
|
||||
@@ -45,6 +49,8 @@ public class AdvancedGroupRow {
|
||||
private final TextField targetPercentage;
|
||||
private final TextField triggerThreshold;
|
||||
private final TextField errorThreshold;
|
||||
private final CheckBox requireConfirmationToggle;
|
||||
private final boolean isConfirmationFlowEnabled;
|
||||
|
||||
/**
|
||||
* Constructor for AdvancedGroupRow
|
||||
@@ -55,9 +61,11 @@ public class AdvancedGroupRow {
|
||||
* TargetFilterQueryDataProvider
|
||||
*/
|
||||
public AdvancedGroupRow(final VaadinMessageSource i18n,
|
||||
final TargetFilterQueryDataProvider targetFilterQueryDataProvider) {
|
||||
final TargetFilterQueryDataProvider targetFilterQueryDataProvider,
|
||||
final boolean isConfirmationFlowEnabled) {
|
||||
this.i18n = i18n;
|
||||
this.targetFilterQueryDataProvider = targetFilterQueryDataProvider;
|
||||
this.isConfirmationFlowEnabled = isConfirmationFlowEnabled;
|
||||
|
||||
this.binder = new Binder<>();
|
||||
|
||||
@@ -66,6 +74,7 @@ public class AdvancedGroupRow {
|
||||
this.targetPercentage = createTargetPercentage();
|
||||
this.triggerThreshold = createTriggerThreshold();
|
||||
this.errorThreshold = createErrorThreshold();
|
||||
this.requireConfirmationToggle = createConfirmationToggle();
|
||||
}
|
||||
|
||||
private TextField createGroupName() {
|
||||
@@ -121,16 +130,25 @@ public class AdvancedGroupRow {
|
||||
|
||||
private TextField createErrorThreshold() {
|
||||
final TextField errorThresholdField = new TextFieldBuilder(32).prompt(i18n.getMessage("prompt.error.threshold"))
|
||||
.buildTextComponent();
|
||||
.buildTextComponent();
|
||||
errorThresholdField.setWidth(5, Unit.EM);
|
||||
|
||||
binder.forField(errorThresholdField).asRequired(i18n.getMessage("prompt.error.threshold.required")).bind(
|
||||
ProxyAdvancedRolloutGroup::getErrorThresholdPercentage,
|
||||
ProxyAdvancedRolloutGroup::setErrorThresholdPercentage);
|
||||
ProxyAdvancedRolloutGroup::getErrorThresholdPercentage,
|
||||
ProxyAdvancedRolloutGroup::setErrorThresholdPercentage);
|
||||
|
||||
return errorThresholdField;
|
||||
}
|
||||
|
||||
public CheckBox createConfirmationToggle() {
|
||||
final CheckBox checkBox = new CheckBox();
|
||||
checkBox.setWidth(5, Unit.EM);
|
||||
checkBox.setStyleName(DIST_CHECKBOX_STYLE);
|
||||
binder.forField(checkBox).bind(ProxyAdvancedRolloutGroup::isConfirmationRequired, ProxyAdvancedRolloutGroup::setConfirmationRequired);
|
||||
checkBox.setValue(true);
|
||||
return checkBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add row to group layout
|
||||
*
|
||||
@@ -145,6 +163,10 @@ public class AdvancedGroupRow {
|
||||
layout.addComponent(targetPercentage, 2, index);
|
||||
layout.addComponent(triggerThreshold, 3, index);
|
||||
layout.addComponent(errorThreshold, 4, index);
|
||||
if (isConfirmationFlowEnabled) {
|
||||
layout.addComponent(requireConfirmationToggle, 5, index);
|
||||
layout.setComponentAlignment(requireConfirmationToggle, Alignment.MIDDLE_LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,6 +181,7 @@ public class AdvancedGroupRow {
|
||||
targetPercentage.setId(UIComponentIdProvider.ROLLOUT_GROUP_TARGET_PERC_ID + "." + index);
|
||||
triggerThreshold.setId(UIComponentIdProvider.ROLLOUT_TRIGGER_THRESOLD_ID + "." + index);
|
||||
errorThreshold.setId(UIComponentIdProvider.ROLLOUT_ERROR_THRESOLD_ID + "." + index);
|
||||
requireConfirmationToggle.setId(UIComponentIdProvider.ROLLOUT_CONFIRMATION_REQUIRED + "." + index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleNoBorderWithIcon;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
@@ -65,6 +66,8 @@ public class AdvancedGroupsLayout extends ValidatableLayout {
|
||||
|
||||
private BiConsumer<List<ProxyAdvancedRolloutGroup>, Boolean> advancedGroupDefinitionsChangedListener;
|
||||
|
||||
final TenantConfigHelper tenantConfigHelper;
|
||||
|
||||
/**
|
||||
* Constructor for AdvancedGroupsLayout
|
||||
*
|
||||
@@ -81,7 +84,8 @@ public class AdvancedGroupsLayout extends ValidatableLayout {
|
||||
*/
|
||||
public AdvancedGroupsLayout(final VaadinMessageSource i18n, final EntityFactory entityFactory,
|
||||
final RolloutManagement rolloutManagement, final QuotaManagement quotaManagement,
|
||||
final TargetFilterQueryDataProvider targetFilterQueryDataProvider) {
|
||||
final TargetFilterQueryDataProvider targetFilterQueryDataProvider,
|
||||
final TenantConfigHelper tenantConfigHelper) {
|
||||
super();
|
||||
|
||||
this.i18n = i18n;
|
||||
@@ -89,6 +93,7 @@ public class AdvancedGroupsLayout extends ValidatableLayout {
|
||||
this.rolloutManagement = rolloutManagement;
|
||||
this.quotaManagement = quotaManagement;
|
||||
this.targetFilterQueryDataProvider = targetFilterQueryDataProvider;
|
||||
this.tenantConfigHelper = tenantConfigHelper;
|
||||
|
||||
this.layout = buildLayout();
|
||||
|
||||
@@ -102,7 +107,11 @@ public class AdvancedGroupsLayout extends ValidatableLayout {
|
||||
gridLayout.setSpacing(true);
|
||||
gridLayout.setSizeUndefined();
|
||||
gridLayout.setRows(3);
|
||||
gridLayout.setColumns(6);
|
||||
if (tenantConfigHelper.isConfirmationFlowEnabled()) {
|
||||
gridLayout.setColumns(7);
|
||||
} else {
|
||||
gridLayout.setColumns(6);
|
||||
}
|
||||
gridLayout.setStyleName("marginTop");
|
||||
|
||||
gridLayout.addComponent(SPUIComponentProvider.generateLabel(i18n, "caption.rollout.group.definition.desc"), 0,
|
||||
@@ -114,8 +123,11 @@ public class AdvancedGroupsLayout extends ValidatableLayout {
|
||||
}
|
||||
|
||||
private void addHeaderRow(final GridLayout gridLayout, final int headerRow) {
|
||||
final List<String> headerColumns = Arrays.asList("header.name", "header.target.filter.query",
|
||||
"header.target.percentage", "header.rolloutgroup.threshold", "header.rolloutgroup.threshold.error");
|
||||
final List<String> headerColumns = new ArrayList<>(Arrays.asList("header.name", "header.target.filter.query",
|
||||
"header.target.percentage", "header.rolloutgroup.threshold", "header.rolloutgroup.threshold.error"));
|
||||
if (tenantConfigHelper.isConfirmationFlowEnabled()) {
|
||||
headerColumns.add("header.rolloutgroup.confirmation");
|
||||
}
|
||||
for (int i = 0; i < headerColumns.size(); i++) {
|
||||
final Label label = SPUIComponentProvider.generateLabel(i18n, headerColumns.get(i));
|
||||
gridLayout.addComponent(label, i, headerRow);
|
||||
@@ -168,7 +180,8 @@ public class AdvancedGroupsLayout extends ValidatableLayout {
|
||||
}
|
||||
|
||||
private AdvancedGroupRow addGroupRow() {
|
||||
final AdvancedGroupRow groupRow = new AdvancedGroupRow(i18n, targetFilterQueryDataProvider);
|
||||
final AdvancedGroupRow groupRow = new AdvancedGroupRow(i18n, targetFilterQueryDataProvider,
|
||||
tenantConfigHelper.isConfirmationFlowEnabled());
|
||||
|
||||
addRowToLayout(groupRow);
|
||||
groupRows.add(groupRow);
|
||||
@@ -185,7 +198,9 @@ public class AdvancedGroupsLayout extends ValidatableLayout {
|
||||
|
||||
groupRow.addRowToLayout(layout, index);
|
||||
|
||||
layout.addComponent(createRemoveButton(groupRow, index), 5, index);
|
||||
final int removeButtonColumnIndex = tenantConfigHelper.isConfirmationFlowEnabled() ? 6 : 5;
|
||||
|
||||
layout.addComponent(createRemoveButton(groupRow, index), removeButtonColumnIndex, index);
|
||||
}
|
||||
|
||||
private Button createRemoveButton(final AdvancedGroupRow groupRow, final int index) {
|
||||
|
||||
@@ -10,8 +10,15 @@ package org.eclipse.hawkbit.ui.rollout.window.components;
|
||||
|
||||
import java.util.function.IntConsumer;
|
||||
|
||||
import com.vaadin.icons.VaadinIcons;
|
||||
import com.vaadin.server.ExternalResource;
|
||||
import com.vaadin.ui.Alignment;
|
||||
import com.vaadin.ui.HorizontalLayout;
|
||||
import com.vaadin.ui.Link;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.ui.UiProperties;
|
||||
import org.eclipse.hawkbit.ui.common.builder.BoundComponent;
|
||||
import org.eclipse.hawkbit.ui.common.builder.FormComponentBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.builder.LabelBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.builder.TextFieldBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySimpleRolloutGroupsDefinition;
|
||||
@@ -27,11 +34,13 @@ import com.vaadin.data.ValidationException;
|
||||
import com.vaadin.data.ValidationResult;
|
||||
import com.vaadin.data.converter.StringToIntegerConverter;
|
||||
import com.vaadin.data.validator.IntegerRangeValidator;
|
||||
import com.vaadin.ui.CheckBox;
|
||||
import com.vaadin.ui.GridLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.RadioButtonGroup;
|
||||
import com.vaadin.ui.TextField;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
|
||||
/**
|
||||
* Simple group layout component
|
||||
@@ -57,6 +66,10 @@ public class SimpleGroupsLayout extends ValidatableLayout {
|
||||
private final Label groupSizeLabel;
|
||||
private final TextField triggerThreshold;
|
||||
private final Label percentHintLabel;
|
||||
|
||||
private final CheckBox requireConfirmationToggle;
|
||||
private final Link confirmationHelpLink;
|
||||
|
||||
private final BoundComponent<TextField> errorThreshold;
|
||||
private final RadioButtonGroup<ERROR_THRESHOLD_OPTIONS> errorThresholdOptionGroup;
|
||||
|
||||
@@ -72,7 +85,8 @@ public class SimpleGroupsLayout extends ValidatableLayout {
|
||||
* @param quotaManagement
|
||||
* QuotaManagement
|
||||
*/
|
||||
public SimpleGroupsLayout(final VaadinMessageSource i18n, final QuotaManagement quotaManagement) {
|
||||
public SimpleGroupsLayout(final VaadinMessageSource i18n, final QuotaManagement quotaManagement,
|
||||
final TenantConfigHelper tenantConfigHelper, final UiProperties uiProperties) {
|
||||
super();
|
||||
|
||||
this.i18n = i18n;
|
||||
@@ -86,8 +100,10 @@ public class SimpleGroupsLayout extends ValidatableLayout {
|
||||
this.percentHintLabel = getPercentHintLabel();
|
||||
this.errorThreshold = createErrorThreshold();
|
||||
this.errorThresholdOptionGroup = createErrorThresholdOptionGroup();
|
||||
this.requireConfirmationToggle = createConfirmationToggle();
|
||||
this.confirmationHelpLink = createConfirmationHelpLink(uiProperties);
|
||||
|
||||
this.layout = buildLayout();
|
||||
this.layout = buildLayout(tenantConfigHelper.isConfirmationFlowEnabled());
|
||||
|
||||
addValueChangeListeners();
|
||||
setValidationStatusByBinder(binder);
|
||||
@@ -244,12 +260,38 @@ public class SimpleGroupsLayout extends ValidatableLayout {
|
||||
return errorThresholdOptions;
|
||||
}
|
||||
|
||||
private GridLayout buildLayout() {
|
||||
public CheckBox createConfirmationToggle() {
|
||||
final CheckBox confirmationToggle = FormComponentBuilder.createCheckBox(
|
||||
UIComponentIdProvider.ROLLOUT_CONFIRMATION_REQUIRED, binder,
|
||||
ProxySimpleRolloutGroupsDefinition::isConfirmationRequired,
|
||||
ProxySimpleRolloutGroupsDefinition::setConfirmationRequired);
|
||||
confirmationToggle.addStyleName(ValoTheme.CHECKBOX_SMALL);
|
||||
|
||||
return confirmationToggle;
|
||||
}
|
||||
|
||||
public Link createConfirmationHelpLink(final UiProperties uiProperties) {
|
||||
final String confirmationFlowHelpUrl = uiProperties.getLinks().getDocumentation()
|
||||
.getUserConsentAndConfirmationGuide();
|
||||
final Link link = new Link("", new ExternalResource(confirmationFlowHelpUrl));
|
||||
|
||||
link.setTargetName("_blank");
|
||||
link.setIcon(VaadinIcons.QUESTION_CIRCLE);
|
||||
link.setDescription(i18n.getMessage("tooltip.documentation.link"));
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
private GridLayout buildLayout(final boolean isConfirmationFlowEnabled) {
|
||||
final GridLayout gridLayout = new GridLayout();
|
||||
gridLayout.setMargin(false);
|
||||
gridLayout.setSpacing(true);
|
||||
gridLayout.setSizeUndefined();
|
||||
gridLayout.setRows(4);
|
||||
if (isConfirmationFlowEnabled) {
|
||||
gridLayout.setRows(5);
|
||||
} else {
|
||||
gridLayout.setRows(4);
|
||||
}
|
||||
gridLayout.setColumns(3);
|
||||
gridLayout.setStyleName("marginTop");
|
||||
|
||||
@@ -268,9 +310,27 @@ public class SimpleGroupsLayout extends ValidatableLayout {
|
||||
gridLayout.addComponent(errorThreshold.getComponent(), 1, 3);
|
||||
gridLayout.addComponent(errorThresholdOptionGroup, 2, 3);
|
||||
|
||||
if (isConfirmationFlowEnabled) {
|
||||
gridLayout.addComponent(SPUIComponentProvider.generateLabel(i18n, "prompt.confirmation.required"), 0, 4);
|
||||
final HorizontalLayout confirmationLayout = initializeConfirmationElements();
|
||||
gridLayout.addComponent(confirmationLayout, 1, 4);
|
||||
gridLayout.setComponentAlignment(confirmationLayout, Alignment.MIDDLE_LEFT);
|
||||
}
|
||||
|
||||
return gridLayout;
|
||||
}
|
||||
|
||||
private HorizontalLayout initializeConfirmationElements(){
|
||||
final HorizontalLayout confirmationLayout = new HorizontalLayout();
|
||||
confirmationLayout.setSpacing(false);
|
||||
confirmationLayout.setMargin(false);
|
||||
confirmationLayout.addComponent(requireConfirmationToggle);
|
||||
confirmationLayout.setComponentAlignment(requireConfirmationToggle, Alignment.MIDDLE_CENTER);
|
||||
confirmationLayout.addComponent(confirmationHelpLink);
|
||||
confirmationLayout.setComponentAlignment(confirmationHelpLink, Alignment.MIDDLE_CENTER);
|
||||
return confirmationLayout;
|
||||
}
|
||||
|
||||
private void addValueChangeListeners() {
|
||||
noOfGroupsWithBinding.getComponent().addValueChangeListener(event -> {
|
||||
errorThreshold.validate();
|
||||
|
||||
@@ -114,7 +114,8 @@ public class AddRolloutWindowController
|
||||
|
||||
Rollout rolloutToCreate;
|
||||
if (GroupDefinitionMode.SIMPLE == entity.getGroupDefinitionMode()) {
|
||||
rolloutToCreate = rolloutManagement.create(rolloutCreate, entity.getNumberOfGroups(), conditions);
|
||||
rolloutToCreate = rolloutManagement.create(rolloutCreate, entity.getNumberOfGroups(),
|
||||
entity.isConfirmationRequired(), conditions);
|
||||
} else {
|
||||
rolloutToCreate = rolloutManagement.create(rolloutCreate,
|
||||
getRolloutGroupsCreateFromDefinitions(entity.getAdvancedRolloutGroupDefinitions()), conditions);
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.eclipse.hawkbit.ui.rollout.window.RolloutWindowDependencies;
|
||||
import org.eclipse.hawkbit.ui.rollout.window.components.AutoStartOptionGroupLayout.AutoStartOption;
|
||||
import org.eclipse.hawkbit.ui.rollout.window.layouts.AddRolloutWindowLayout;
|
||||
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -37,7 +38,8 @@ public class CopyRolloutWindowController extends AddRolloutWindowController {
|
||||
private final TargetFilterQueryManagement targetFilterQueryManagement;
|
||||
private final RolloutGroupManagement rolloutGroupManagement;
|
||||
private final QuotaManagement quotaManagement;
|
||||
|
||||
private final TenantConfigHelper tenantConfigHelper;
|
||||
|
||||
/**
|
||||
* Constructor for CopyRolloutWindowController
|
||||
*
|
||||
@@ -53,6 +55,7 @@ public class CopyRolloutWindowController extends AddRolloutWindowController {
|
||||
this.targetFilterQueryManagement = dependencies.getTargetFilterQueryManagement();
|
||||
this.rolloutGroupManagement = dependencies.getRolloutGroupManagement();
|
||||
this.quotaManagement = dependencies.getQuotaManagement();
|
||||
this.tenantConfigHelper = dependencies.getTenantConfigHelper();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -107,8 +110,12 @@ public class CopyRolloutWindowController extends AddRolloutWindowController {
|
||||
proxyRolloutWindow.setGroupDefinitionMode(GroupDefinitionMode.ADVANCED);
|
||||
final RolloutGroupToAdvancedDefinitionMapper groupsMapper = new RolloutGroupToAdvancedDefinitionMapper(
|
||||
targetFilterQueryManagement);
|
||||
final List<ProxyAdvancedRolloutGroup> advancedGroupDefinitions = groupsMapper.loadRolloutGroupssFromBackend(
|
||||
final List<ProxyAdvancedRolloutGroup> advancedGroupDefinitions = groupsMapper.loadRolloutGroupsFromBackend(
|
||||
proxyRolloutWindow.getId(), rolloutGroupManagement, quotaManagement.getMaxRolloutGroupsPerRollout());
|
||||
if (!tenantConfigHelper.isConfirmationFlowEnabled()) {
|
||||
// do not require confirmation, since feature is not active and UI elements are not visible
|
||||
advancedGroupDefinitions.forEach(def -> def.setConfirmationRequired(false));
|
||||
}
|
||||
proxyRolloutWindow.setAdvancedRolloutGroupDefinitions(advancedGroupDefinitions);
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ public class UpdateRolloutWindowController
|
||||
proxyRolloutWindow.setGroupDefinitionMode(GroupDefinitionMode.ADVANCED);
|
||||
final RolloutGroupToAdvancedDefinitionMapper groupsMapper = new RolloutGroupToAdvancedDefinitionMapper(
|
||||
targetFilterQueryManagement);
|
||||
final List<ProxyAdvancedRolloutGroup> advancedGroupDefinitions = groupsMapper.loadRolloutGroupssFromBackend(
|
||||
final List<ProxyAdvancedRolloutGroup> advancedGroupDefinitions = groupsMapper.loadRolloutGroupsFromBackend(
|
||||
proxyRolloutWindow.getId(), rolloutGroupManagement, quotaManagement.getMaxRolloutGroupsPerRollout());
|
||||
proxyRolloutWindow.setAdvancedRolloutGroupDefinitions(advancedGroupDefinitions);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public abstract class AbstractRolloutWindowLayout implements EntityWindowLayout<
|
||||
rootLayout.setColumns(4);
|
||||
rootLayout.setStyleName("marginTop");
|
||||
rootLayout.setColumnExpandRatio(3, 1);
|
||||
rootLayout.setWidth(850, Unit.PIXELS);
|
||||
rootLayout.setWidth(900, Unit.PIXELS);
|
||||
|
||||
addComponents(rootLayout);
|
||||
|
||||
|
||||
@@ -31,13 +31,13 @@ import com.vaadin.ui.Panel;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions.DIST_CHECKBOX_STYLE;
|
||||
|
||||
/**
|
||||
* View to configure the authentication mode.
|
||||
*/
|
||||
public class AuthenticationConfigurationView extends BaseConfigurationView<ProxySystemConfigAuthentication> {
|
||||
|
||||
private static final String DIST_CHECKBOX_STYLE = "dist-checkbox-style";
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
|
||||
@@ -70,8 +70,8 @@ public abstract class BaseConfigurationView<B extends ProxySystemConfigWindow> e
|
||||
return enabled.getValue() && !enabled.isGlobal();
|
||||
}
|
||||
|
||||
protected <T extends Serializable> void writeConfigOption(final String key, final T value) {
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(key, value);
|
||||
protected <T extends Serializable> TenantConfigurationValue<T> writeConfigOption(final String key, final T value) {
|
||||
return tenantConfigurationManagement.addOrUpdateConfiguration(key, value);
|
||||
}
|
||||
|
||||
protected TenantConfigurationManagement getTenantConfigurationManagement() {
|
||||
|
||||
@@ -11,14 +11,18 @@ package org.eclipse.hawkbit.ui.tenantconfiguration;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||
import org.eclipse.hawkbit.ui.UiProperties;
|
||||
import org.eclipse.hawkbit.ui.common.builder.FormComponentBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySystemConfigRepository;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventTopics;
|
||||
import org.eclipse.hawkbit.ui.common.event.TenantConfigChangedEventPayload;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.tenantconfiguration.repository.ActionAutoCleanupConfigurationItem;
|
||||
import org.eclipse.hawkbit.ui.tenantconfiguration.repository.ActionAutoCloseConfigurationItem;
|
||||
import org.eclipse.hawkbit.ui.tenantconfiguration.repository.MultiAssignmentsConfigurationItem;
|
||||
import org.eclipse.hawkbit.ui.tenantconfiguration.repository.ConfirmationFlowConfigurationItem;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
|
||||
@@ -29,6 +33,7 @@ import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.Link;
|
||||
import com.vaadin.ui.Panel;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
import org.vaadin.spring.events.EventBus;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
@@ -40,13 +45,13 @@ import java.util.stream.Collectors;
|
||||
|
||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.ACTION_CLEANUP_ACTION_EXPIRY;
|
||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.ACTION_CLEANUP_ACTION_STATUS;
|
||||
import static org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions.DIST_CHECKBOX_STYLE;
|
||||
|
||||
/**
|
||||
* View to configure the authentication mode.
|
||||
*/
|
||||
public class RepositoryConfigurationView extends BaseConfigurationView<ProxySystemConfigRepository> {
|
||||
|
||||
private static final String DIST_CHECKBOX_STYLE = "dist-checkbox-style";
|
||||
private static final Set<Action.Status> EMPTY_STATUS_SET = EnumSet.noneOf(Action.Status.class);
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -54,17 +59,25 @@ public class RepositoryConfigurationView extends BaseConfigurationView<ProxySyst
|
||||
private final VaadinMessageSource i18n;
|
||||
private final UiProperties uiProperties;
|
||||
|
||||
private final transient EventBus.ApplicationEventBus eventBus;
|
||||
private final transient TenantAware tenantAware;
|
||||
|
||||
private ActionAutoCloseConfigurationItem actionAutocloseConfigurationItem;
|
||||
private ActionAutoCleanupConfigurationItem actionAutocleanupConfigurationItem;
|
||||
private MultiAssignmentsConfigurationItem multiAssignmentsConfigurationItem;
|
||||
|
||||
private CheckBox multiAssignmentsCheckBox;
|
||||
|
||||
private ConfirmationFlowConfigurationItem confirmationFlowConfigurationItem;
|
||||
|
||||
RepositoryConfigurationView(final VaadinMessageSource i18n, final UiProperties uiProperties,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final EventBus.ApplicationEventBus eventBus, final TenantAware tenantAware) {
|
||||
super(tenantConfigurationManagement);
|
||||
this.i18n = i18n;
|
||||
this.uiProperties = uiProperties;
|
||||
this.eventBus = eventBus;
|
||||
this.tenantAware = tenantAware;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,6 +86,7 @@ public class RepositoryConfigurationView extends BaseConfigurationView<ProxySyst
|
||||
this.actionAutocloseConfigurationItem = new ActionAutoCloseConfigurationItem(i18n);
|
||||
this.actionAutocleanupConfigurationItem = new ActionAutoCleanupConfigurationItem(getBinder(), i18n);
|
||||
this.multiAssignmentsConfigurationItem = new MultiAssignmentsConfigurationItem(i18n, getBinder());
|
||||
this.confirmationFlowConfigurationItem = new ConfirmationFlowConfigurationItem(i18n);
|
||||
init();
|
||||
}
|
||||
|
||||
@@ -92,7 +106,7 @@ public class RepositoryConfigurationView extends BaseConfigurationView<ProxySyst
|
||||
header.addStyleName("config-panel-header");
|
||||
vLayout.addComponent(header);
|
||||
|
||||
final GridLayout gridLayout = new GridLayout(3, 3);
|
||||
final GridLayout gridLayout = new GridLayout(3, 4);
|
||||
gridLayout.setSpacing(true);
|
||||
|
||||
gridLayout.setColumnExpandRatio(1, 1.0F);
|
||||
@@ -125,6 +139,13 @@ public class RepositoryConfigurationView extends BaseConfigurationView<ProxySyst
|
||||
gridLayout.addComponent(multiAssignmentsCheckBox, 0, 1);
|
||||
gridLayout.addComponent(multiAssignmentsConfigurationItem, 1, 1);
|
||||
|
||||
final CheckBox confirmationFlowCheckBox = FormComponentBuilder.createCheckBox(
|
||||
UIComponentIdProvider.REPOSITORY_USER_CONFIRMATION_CHECKBOX, getBinder(),
|
||||
ProxySystemConfigRepository::isConfirmationFlow, ProxySystemConfigRepository::setConfirmationFlow);
|
||||
confirmationFlowCheckBox.setStyleName(DIST_CHECKBOX_STYLE);
|
||||
gridLayout.addComponent(confirmationFlowCheckBox, 0, 2);
|
||||
gridLayout.addComponent(confirmationFlowConfigurationItem, 1, 2);
|
||||
|
||||
final CheckBox actionAutoCleanupCheckBox = FormComponentBuilder.createCheckBox(
|
||||
UIComponentIdProvider.REPOSITORY_ACTIONS_AUTOCLEANUP_CHECKBOX, getBinder(),
|
||||
ProxySystemConfigRepository::isActionAutocleanup, ProxySystemConfigRepository::setActionAutocleanup);
|
||||
@@ -136,8 +157,8 @@ public class RepositoryConfigurationView extends BaseConfigurationView<ProxySyst
|
||||
actionAutocleanupConfigurationItem.hideSettings();
|
||||
}
|
||||
});
|
||||
gridLayout.addComponent(actionAutoCleanupCheckBox, 0, 2);
|
||||
gridLayout.addComponent(actionAutocleanupConfigurationItem, 1, 2);
|
||||
gridLayout.addComponent(actionAutoCleanupCheckBox, 0, 3);
|
||||
gridLayout.addComponent(actionAutocleanupConfigurationItem, 1, 3);
|
||||
|
||||
final Link linkToProvisioningHelp = SPUIComponentProvider.getHelpLink(i18n,
|
||||
uiProperties.getLinks().getDocumentation().getProvisioningStateMachine());
|
||||
@@ -159,23 +180,34 @@ public class RepositoryConfigurationView extends BaseConfigurationView<ProxySyst
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
writeConfigOption(TenantConfigurationKey.ACTION_CLEANUP_ENABLED, getBinderBean().isActionAutocleanup());
|
||||
if (getBinderBean().isActionAutocleanup() != readConfigOption(TenantConfigurationKey.ACTION_CLEANUP_ENABLED)) {
|
||||
setConfig(TenantConfigurationKey.ACTION_CLEANUP_ENABLED, getBinderBean().isActionAutocleanup());
|
||||
}
|
||||
if (getBinderBean().isActionAutocleanup()) {
|
||||
writeConfigOption(ACTION_CLEANUP_ACTION_STATUS, getBinderBean().getActionCleanupStatus().getStatus()
|
||||
setConfig(ACTION_CLEANUP_ACTION_STATUS, getBinderBean().getActionCleanupStatus().getStatus()
|
||||
.stream().map(Action.Status::name).collect(Collectors.joining(",")));
|
||||
|
||||
writeConfigOption(TenantConfigurationKey.ACTION_CLEANUP_ACTION_EXPIRY,
|
||||
setConfig(TenantConfigurationKey.ACTION_CLEANUP_ACTION_EXPIRY,
|
||||
TimeUnit.DAYS.toMillis(Long.parseLong(getBinderBean().getActionExpiryDays())));
|
||||
}
|
||||
if (!readConfigOption(TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED)) {
|
||||
writeConfigOption(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED,
|
||||
setConfig(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED,
|
||||
getBinderBean().isActionAutoclose());
|
||||
}
|
||||
if (getBinderBean().isMultiAssignments()
|
||||
&& !readConfigOption(TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED)) {
|
||||
writeConfigOption(TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED, getBinderBean().isMultiAssignments());
|
||||
setConfig(TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED, getBinderBean().isMultiAssignments());
|
||||
this.disableMultipleAssignmentOption();
|
||||
}
|
||||
if (getBinderBean().isConfirmationFlow() != readConfigOption(TenantConfigurationKey.USER_CONFIRMATION_ENABLED)) {
|
||||
setConfig(TenantConfigurationKey.USER_CONFIRMATION_ENABLED, getBinderBean().isConfirmationFlow());
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends Serializable> void setConfig(final String key, final T value) {
|
||||
final TenantConfigurationValue<T> config = writeConfigOption(key, value);
|
||||
eventBus.publish(EventTopics.TENANT_CONFIG_CHANGED, this,
|
||||
new TenantConfigChangedEventPayload(tenantAware.getCurrentTenant(), key, config));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -183,6 +215,7 @@ public class RepositoryConfigurationView extends BaseConfigurationView<ProxySyst
|
||||
final ProxySystemConfigRepository configBean = new ProxySystemConfigRepository();
|
||||
configBean.setActionAutoclose(readConfigOption(TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED));
|
||||
configBean.setMultiAssignments(readConfigOption(TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED));
|
||||
configBean.setConfirmationFlow(readConfigOption(TenantConfigurationKey.USER_CONFIRMATION_ENABLED));
|
||||
configBean.setActionAutocleanup(readConfigOption(TenantConfigurationKey.ACTION_CLEANUP_ENABLED));
|
||||
configBean.setActionCleanupStatus(getActionStatusOption());
|
||||
configBean.setActionExpiryDays(String.valueOf(getActionExpiry()));
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.ui.MgmtUiConfiguration;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.UiProperties;
|
||||
@@ -23,6 +24,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.vaadin.spring.events.EventBus;
|
||||
|
||||
/**
|
||||
* Enables UI components for the Tenant Configuration view
|
||||
@@ -68,6 +70,10 @@ public class SystemConfigViewAutoConfiguration {
|
||||
* UiProperties
|
||||
* @param tenantConfigurationManagement
|
||||
* TenantConfigurationManagement
|
||||
* @param eventBus
|
||||
* EventBus.ApplicationEventBus
|
||||
* @param tenantAware
|
||||
* TenantAware
|
||||
* @return RepositoryConfigurationView to be shown in the Tenant Configuration
|
||||
* Page
|
||||
*/
|
||||
@@ -76,8 +82,10 @@ public class SystemConfigViewAutoConfiguration {
|
||||
@ViewScope
|
||||
@Order(value = 2)
|
||||
RepositoryConfigurationView repositoryConfigurationView(final VaadinMessageSource i18n,
|
||||
final UiProperties uiProperties, final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
return new RepositoryConfigurationView(i18n, uiProperties, tenantConfigurationManagement);
|
||||
final UiProperties uiProperties, final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final EventBus.ApplicationEventBus eventBus, final TenantAware tenantAware) {
|
||||
return new RepositoryConfigurationView(i18n, uiProperties, tenantConfigurationManagement, eventBus,
|
||||
tenantAware);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2022 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.tenantconfiguration.repository;
|
||||
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
|
||||
/**
|
||||
* This class represents the UI item for enabling/disabling the
|
||||
* User-consent flow feature as part of the repository configuration view.
|
||||
*/
|
||||
public class ConfirmationFlowConfigurationItem extends VerticalLayout {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String MSG_KEY_CHECKBOX = "label.configuration.repository.confirmationflow";
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
*/
|
||||
public ConfirmationFlowConfigurationItem(final VaadinMessageSource i18n) {
|
||||
this.setSpacing(false);
|
||||
this.setMargin(false);
|
||||
addComponent(SPUIComponentProvider.generateLabel(i18n, MSG_KEY_CHECKBOX));
|
||||
}
|
||||
}
|
||||
@@ -185,7 +185,7 @@ public final class SPUILabelDefinitions {
|
||||
public static final String VAR_TOTAL_TARGETS = "totalTargetsCount";
|
||||
|
||||
/**
|
||||
* Total target count status coulmn property name.
|
||||
* Total target count status column property name.
|
||||
*/
|
||||
public static final String VAR_TOTAL_TARGETS_COUNT_STATUS = "totalTargetCountStatus";
|
||||
|
||||
@@ -194,6 +194,11 @@ public final class SPUILabelDefinitions {
|
||||
*/
|
||||
public static final String ROLLOUT_GROUP_ERROR_THRESHOLD = "errorConditionExp";
|
||||
|
||||
/**
|
||||
* Rollout group confirmation required column property.
|
||||
*/
|
||||
public static final String ROLLOUT_GROUP_CONFIRMATION_REQUIRED = "confirmationRequired";
|
||||
|
||||
/**
|
||||
* Rollout group started date column property.
|
||||
*/
|
||||
|
||||
@@ -28,6 +28,8 @@ public final class SPUIStyleDefinitions {
|
||||
|
||||
public static final String SP_TEXTFIELD_LAYOUT_ERROR_HIGHTLIGHT = "v-textfield-error";
|
||||
|
||||
public static final String DIST_CHECKBOX_STYLE = "dist-checkbox-style";
|
||||
|
||||
/**
|
||||
* Action history message grid style.
|
||||
*/
|
||||
|
||||
@@ -385,6 +385,11 @@ public final class UIComponentIdProvider {
|
||||
*/
|
||||
public static final String MAINTENANCE_WINDOW_TIME_ZONE_ID = "maintenance.window.time.zone";
|
||||
|
||||
/**
|
||||
* Id for the confirmation required checkbox
|
||||
*/
|
||||
public static final String ASSIGNMENT_CONFIRMATION_REQUIRED = "deployment.assignment.action.confirmation.required";
|
||||
|
||||
/**
|
||||
* Id for maintenance window - label schedule translator
|
||||
*/
|
||||
@@ -1004,6 +1009,8 @@ public final class UIComponentIdProvider {
|
||||
*/
|
||||
public static final String TARGET_FILTER_TABLE_TYPE_LABEL_ID = "target.query.filter.table.typeId";
|
||||
|
||||
public static final String TARGET_FILTER_TABLE_CONFIRMATION_LABEL_ID = "target.query.filter.table.confirmationId";
|
||||
|
||||
/**
|
||||
* create or update target filter query - name label id.
|
||||
*/
|
||||
@@ -1230,6 +1237,23 @@ public final class UIComponentIdProvider {
|
||||
*/
|
||||
public static final String CONFIRMATION_POPUP_ID = "action.confirmation.popup.id";
|
||||
|
||||
public static final String AUTO_CONFIRMATION_DETAILS = "target.details.auto.confirmation";
|
||||
|
||||
public static final String AUTO_CONFIRMATION_DETAILS_TOGGLE = "target.details.auto.confirmation.toggle";
|
||||
|
||||
public static final String AUTO_CONFIRMATION_DETAILS_STATE = AUTO_CONFIRMATION_DETAILS + ".state";
|
||||
|
||||
public static final String AUTO_CONFIRMATION_DETAILS_INITIATOR = AUTO_CONFIRMATION_DETAILS + ".initiator";
|
||||
|
||||
public static final String AUTO_CONFIRMATION_DETAILS_ROLLOUTS_USER = AUTO_CONFIRMATION_DETAILS + ".rolloutsuser";
|
||||
|
||||
public static final String AUTO_CONFIRMATION_DETAILS_ACTIVATEDAT = AUTO_CONFIRMATION_DETAILS + ".activatedat";
|
||||
public static final String AUTO_CONFIRMATION_DETAILS_REMARK = AUTO_CONFIRMATION_DETAILS + ".remark";
|
||||
|
||||
public static final String AUTO_CONFIRMATION_TOGGLE_DIALOG = "target.auto.confirmation.toggle.dialog";
|
||||
public static final String AUTO_CONFIRMATION_ACTIVATION_DIALOG_INITIATOR = AUTO_CONFIRMATION_TOGGLE_DIALOG + ".initiator";
|
||||
public static final String AUTO_CONFIRMATION_ACTIVATION_DIALOG_REMARK = AUTO_CONFIRMATION_TOGGLE_DIALOG + ".remark";
|
||||
|
||||
/**
|
||||
* Validation status icon .
|
||||
*/
|
||||
@@ -1533,6 +1557,12 @@ public final class UIComponentIdProvider {
|
||||
*/
|
||||
public static final String REPOSITORY_MULTI_ASSIGNMENTS_CHECKBOX = "repositorymultiassignmentscheckbox";
|
||||
|
||||
/**
|
||||
* Configuration checkbox for
|
||||
* {@link TenantConfigurationKey#USER_CONFIRMATION_ENABLED}.
|
||||
*/
|
||||
public static final String REPOSITORY_USER_CONFIRMATION_CHECKBOX = "repositoryuserconfirmationcheckbox";
|
||||
|
||||
/**
|
||||
* Configuration checkbox for
|
||||
* {@link TenantConfigurationKey#ROLLOUT_APPROVAL_ENABLED}
|
||||
@@ -1572,6 +1602,8 @@ public final class UIComponentIdProvider {
|
||||
|
||||
public static final String ROLLOUT_START_OPTIONS_ID = "rollout.start.options.id";
|
||||
|
||||
public static final String ROLLOUT_CONFIRMATION_REQUIRED = "rollout.confirmation.required";
|
||||
|
||||
public static final String SM_TYPE_COLOR_STYLE = "sm-type-colors";
|
||||
|
||||
public static final String SM_TYPE_COLOR_CLASS = "sm-type-color";
|
||||
|
||||
@@ -49,6 +49,8 @@ public final class UIMessageIdProvider {
|
||||
|
||||
public static final String CAPTION_ACTION_TIME_FORCED = "label.action.time.forced";
|
||||
|
||||
public static final String CAPTION_ACTION_CONFIRMATION_REQUIRED = "label.action.confirmation.required";
|
||||
|
||||
public static final String CAPTION_ACTION_MESSAGES = "caption.action.messages";
|
||||
|
||||
public static final String CAPTION_ACTION_HISTORY = "caption.action.history";
|
||||
@@ -111,6 +113,8 @@ public final class UIMessageIdProvider {
|
||||
|
||||
public static final String LABEL_AUTO_ASSIGNMENT_ENABLE = "label.auto.assign.enable";
|
||||
|
||||
public static final String LABEL_AUTO_ASSIGNMENT_CONFIRMATION_REQUIRED = "label.auto.assign.confirmation.required";
|
||||
|
||||
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";
|
||||
@@ -133,6 +137,8 @@ public final class UIMessageIdProvider {
|
||||
|
||||
public static final String MESSAGE_CONFIRM_AUTO_ASSIGN_CONSEQUENCES_TEXT = "message.confirm.assign.consequences.text";
|
||||
|
||||
public static final String MESSAGE_CONFIRM_AUTO_ASSIGN_CONSEQUENCES_CONF_HINT = "message.confirm.assign.consequences.confirmation.hint";
|
||||
|
||||
public static final String MESSAGE_CONFIRM_ASSIGN_MULTIPLE_ENTITIES_TO_ENTITY = "message.confirm.assign.multiple.entities.to.entity";
|
||||
|
||||
public static final String MESSAGE_CONFIRM_DELETE_ENTITY = "message.confirm.delete.entity";
|
||||
@@ -277,6 +283,12 @@ public final class UIMessageIdProvider {
|
||||
|
||||
public static final String TOOLTIP_IN_TIME = "tooltip.in.time";
|
||||
|
||||
public static final String TOOLTIP_TARGET_FILTER_CONFIRMATION_REQUIRED = "tooltip.target.filter.confirmation.required";
|
||||
|
||||
public static final String TOOLTIP_TARGET_FILTER_CONFIRMATION_NOT_REQUIRED = "tooltip.target.filter.confirmation.not.required";
|
||||
|
||||
public static final String TOOLTIP_TARGET_FILTER_CONFIRMATION_NOT_CONFIGURED = "tooltip.target.filter.confirmation.not.configured";
|
||||
|
||||
public static final String TOOLTIP_DELETE_CUSTOM_FILTER = "tooltip.delete.custom.filter";
|
||||
|
||||
public static final String TOOLTIP_UPDATE_CUSTOM_FILTER = "tooltip.update.custom.filter";
|
||||
|
||||
@@ -139,6 +139,7 @@ caption.bulk.upload.targets = Bulk Upload
|
||||
caption.softwares.distdetail.tab = Modules
|
||||
caption.tags.tab = Tags
|
||||
caption.logs.tab = Logs
|
||||
caption.tab.confirmation = Auto-Confirmation
|
||||
caption.attributes.tab = Attributes
|
||||
caption.types.tab = Types
|
||||
caption.save.window = Action Details
|
||||
@@ -167,6 +168,17 @@ caption.invalidate.distributionset.affected.entities = Invalidation confirmation
|
||||
caption.confirm.assign.consequences = Auto assign consequences
|
||||
caption.auto.assignment.ds = Auto assignment
|
||||
|
||||
caption.target.auto.confirmation.activate.prefix = Activate automatic confirmations for
|
||||
caption.target.auto.confirmation.activate.initiator = Initiator
|
||||
prompt.target.auto.confirmation.activate.initiator = (Optional) Initiator
|
||||
caption.target.auto.confirmation.activate.remark = Remark
|
||||
prompt.target.auto.confirmation.activate.remark = (Optional) Remark
|
||||
caption.target.auto.confirmation.disable = Disable automatic confirmations
|
||||
message.target.auto.confirmation.disable = Do you want to disable automatic confirmations? \n\nThis will not have an effect on current active actions. \nFor all new assignments, the confirmation by the device will be required, before proceeding with the deployment.
|
||||
|
||||
caption.target.auto.confirmation.activate.consequences.caption = Active actions affected
|
||||
caption.target.auto.confirmation.activate.consequences.question = Currently, the confirmation is pending for {0} active action(s). \nSaving will confirm and put them to the 'RUNNING' state.
|
||||
|
||||
caption.maintenancewindow.enabled = Use maintenance window
|
||||
caption.maintenancewindow.schedule = Schedule
|
||||
caption.maintenancewindow.duration = Duration
|
||||
@@ -188,6 +200,16 @@ label.action.type = Type
|
||||
label.action.soft = Soft
|
||||
label.action.downloadonly = Download Only
|
||||
label.action.time.forced = Time Forced
|
||||
label.action.confirmation.required = Confirmation required
|
||||
label.target.auto.confirmation.active = Confirmation automatically given
|
||||
label.target.auto.confirmation.deactivated = Confirmation by device is required
|
||||
label.target.auto.confirmation.state = State
|
||||
label.target.auto.confirmation.initiator = Initiator
|
||||
label.target.auto.confirmation.systemuser = System user
|
||||
label.target.auto.confirmation.activatedat = Activated at
|
||||
label.target.auto.confirmation.remark = Remark
|
||||
button.target.auto.confirmation.activate = Activate auto-confirmation
|
||||
button.target.auto.confirmation.disable = Disable auto-confirmation
|
||||
label.name = Name
|
||||
label.version = Version
|
||||
label.vendor = Vendor
|
||||
@@ -257,9 +279,11 @@ label.configuration.anonymous.download = Allow targets to download artifacts wit
|
||||
label.configuration.repository.autocleanup.action.notice = Warning: The actions are deleted from the repository and cannot be restored
|
||||
label.configuration.repository.multiassignments = Allow parallel execution of multiple distribution set assignments and rollouts
|
||||
label.configuration.repository.multiassignments.notice = Warning: Once this assignment behavior is active, it cannot be deactivated.
|
||||
label.configuration.repository.confirmationflow = Request confirmation for actions before proceeding with download/install process.
|
||||
label.unsupported.browser.ie = Sorry! Your current browser is not supported. Please use Internet Explorer 11 and above
|
||||
label.auto.assign.description = When an auto assign distribution set is selected, it will be automatically assigned to all targets that match the target filter.
|
||||
label.auto.assign.enable = Enable auto assignment
|
||||
label.auto.assign.confirmation.required = Confirmation required
|
||||
label.approval.decision = Approval decision
|
||||
label.approval.remark = Remark (optional)
|
||||
label.drop.area.upload = Drop Files to upload
|
||||
@@ -325,6 +349,7 @@ tooltip.action.status.retrieved=Retrieved
|
||||
tooltip.action.status.download=Downloading
|
||||
tooltip.action.status.downloaded=Downloaded
|
||||
tooltip.action.status.scheduled=Scheduled
|
||||
tooltip.action.status.wait_for_confirmation=Confirmation pending
|
||||
|
||||
#action active status
|
||||
tooltip.active.action.status.active=Active
|
||||
@@ -399,6 +424,9 @@ tooltip.distributionset.invalidate.forced = Open actions will be canceled and fo
|
||||
tooltip.distributionset.invalidate.soft = Open actions will be canceled
|
||||
tooltip.distributionset.invalidate.none = Open actions will not be canceled
|
||||
tooltip.in.time = In Time
|
||||
tooltip.target.filter.confirmation.required = Confirmation required
|
||||
tooltip.target.filter.confirmation.not.required = Confirmation not required
|
||||
tooltip.target.filter.confirmation.not.configured = Not configured
|
||||
|
||||
# Notification messages prefix with - message
|
||||
message.save.success = {0} saved successfully
|
||||
@@ -513,7 +541,8 @@ message.bulk.upload.tag.assignment.failed = Tag {0} assignment failed as tag no
|
||||
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
|
||||
message.confirm.assign.consequences.confirmation.hint = Hint:\nConfirmation is not required for all future assignments.\nAssignments will be marked as confirmed by "{0}".
|
||||
message.maintenancewindow.schedule.required.error=Please provide a Cron expression
|
||||
message.maintenancewindow.schedule.validation.error = Please enter a valid Cron expression
|
||||
message.maintenancewindow.duration.required.error = Please provide a duration
|
||||
message.maintenancewindow.duration.validation.error = Please enter the duration in the format hh:mm:ss, error is at {0} position
|
||||
@@ -742,6 +771,7 @@ header.detail.status = Detail status
|
||||
|
||||
header.rolloutgroup.installed.percentage = Finished
|
||||
header.rolloutgroup.threshold.error = Error threshold
|
||||
header.rolloutgroup.confirmation = Confirmation
|
||||
header.rolloutgroup.threshold = Trigger threshold
|
||||
header.rolloutgroup.target.date = Date and time
|
||||
header.rolloutgroup.target.message = Messages
|
||||
@@ -754,6 +784,7 @@ prompt.trigger.threshold = Trigger threshold
|
||||
prompt.trigger.threshold.required = Trigger threshold is required
|
||||
prompt.error.threshold = Error threshold
|
||||
prompt.error.threshold.required = Error threshold is required
|
||||
prompt.confirmation.required = Confirmation required
|
||||
prompt.distribution.set = Distribution set
|
||||
button.rollout.groups.def.button = Define groups
|
||||
button.rollout.add.group = Add Group
|
||||
|
||||
Reference in New Issue
Block a user