diff --git a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageDispatcherServiceIntegrationTest.java b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageDispatcherServiceIntegrationTest.java index 568548c4c..5a3fec237 100644 --- a/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageDispatcherServiceIntegrationTest.java +++ b/hawkbit-dmf/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/integration/AmqpMessageDispatcherServiceIntegrationTest.java @@ -8,9 +8,23 @@ */ package org.eclipse.hawkbit.integration; -import io.qameta.allure.Description; -import io.qameta.allure.Feature; -import io.qameta.allure.Story; +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.hawkbit.dmf.amqp.api.EventTopic.DOWNLOAD; +import static org.eclipse.hawkbit.dmf.amqp.api.MessageType.EVENT; +import static org.eclipse.hawkbit.repository.model.Action.ActionType.DOWNLOAD_ONLY; + +import java.util.AbstractMap.SimpleEntry; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.stream.Collectors; + import org.eclipse.hawkbit.dmf.amqp.api.EventTopic; import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey; import org.eclipse.hawkbit.dmf.json.model.DmfActionRequest; @@ -55,22 +69,9 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.springframework.amqp.core.Message; -import java.util.AbstractMap.SimpleEntry; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.stream.Collectors; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.hawkbit.dmf.amqp.api.EventTopic.DOWNLOAD; -import static org.eclipse.hawkbit.dmf.amqp.api.MessageType.EVENT; -import static org.eclipse.hawkbit.repository.model.Action.ActionType.DOWNLOAD_ONLY; +import io.qameta.allure.Description; +import io.qameta.allure.Feature; +import io.qameta.allure.Story; @Feature("Component Tests - Device Management Federation API") @Story("Amqp Message Dispatcher Service") @@ -147,33 +148,37 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpSer @Expect(type = SoftwareModuleCreatedEvent.class, count = 6), @Expect(type = SoftwareModuleUpdatedEvent.class, count = 12), @Expect(type = DistributionSetCreatedEvent.class, count = 2), - @Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetPollEvent.class, count = 2) }) + @Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetPollEvent.class, count = 3) }) public void assignDistributionSetMultipleTimes() { final String controllerId = TARGET_PREFIX + "assignDistributionSetMultipleTimes"; final DistributionSetAssignmentResult assignmentResult = registerTargetAndAssignDistributionSet(controllerId); + waitUntilEventMessagesAreDispatchedToTarget(EventTopic.DOWNLOAD_AND_INSTALL); + final DistributionSet distributionSet2 = testdataFactory.createDistributionSet(); - testdataFactory.addSoftwareModuleMetadata(distributionSet2); - - // first assignment will be canceled -> Open cancellations -> No message through the DMF + // first assignment will be canceled -> Open cancellations assignDistributionSet(distributionSet2.getId(), controllerId); - - // should not get the message of the second assignment - assertDownloadAndInstallMessage(assignmentResult.getDistributionSet().getModules(), controllerId); - + waitUntilEventMessagesAreDispatchedToTarget(EventTopic.CANCEL_DOWNLOAD); assertCancelActionMessage(getFirstAssignedActionId(assignmentResult), controllerId); + // cancelation message is returned upon polling createAndSendThingCreated(controllerId, TENANT_EXIST); - waitUntilTargetHasStatus(controllerId, TargetUpdateStatus.PENDING); + waitUntilEventMessagesAreDispatchedToTarget(EventTopic.CANCEL_DOWNLOAD); assertCancelActionMessage(getFirstAssignedActionId(assignmentResult), controllerId); - // confirm the cancel of the first action should lead to expose the latest action + // confirm the cancel of the first action should lead to expose the + // latest action createAndSendActionStatusUpdateMessage(controllerId, getFirstAssignedActionId(assignmentResult), DmfActionStatus.CANCELED); - + waitUntilEventMessagesAreDispatchedToTarget(EventTopic.DOWNLOAD_AND_INSTALL); // verify latest action is exposed assertDownloadAndInstallMessage(distributionSet2.getModules(), controllerId); + + // latest action is returned upon polling + createAndSendThingCreated(controllerId, TENANT_EXIST); + waitUntilEventMessagesAreDispatchedToTarget(EventTopic.DOWNLOAD_AND_INSTALL); + assertDownloadAndInstallMessage(distributionSet2.getModules(), controllerId); } @Test @@ -401,8 +406,8 @@ public class AmqpMessageDispatcherServiceIntegrationTest extends AbstractAmqpSer @Test @Description("If multi assignment is enabled finishing one rollout does not affect other rollouts of the target.") @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = MultiActionAssignEvent.class, count = 3), @Expect(type = ActionCreatedEvent.class, count = 3), - @Expect(type = ActionUpdatedEvent.class, count = 5), + @Expect(type = MultiActionAssignEvent.class, count = 3), + @Expect(type = ActionCreatedEvent.class, count = 3), @Expect(type = ActionUpdatedEvent.class, count = 5), @Expect(type = SoftwareModuleCreatedEvent.class, count = 6), @Expect(type = DistributionSetCreatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 5), @Expect(type = TargetPollEvent.class, count = 1), diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/MgmtUiConfiguration.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/MgmtUiConfiguration.java index 5fea47789..a5f53aee9 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/MgmtUiConfiguration.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/MgmtUiConfiguration.java @@ -19,6 +19,7 @@ import org.eclipse.hawkbit.ui.common.data.suppliers.TargetManagementStateDataSup import org.eclipse.hawkbit.ui.common.data.suppliers.TargetManagementStateDataSupplierImpl; import org.eclipse.hawkbit.ui.error.HawkbitUIErrorHandler; import org.eclipse.hawkbit.ui.error.extractors.ConstraintViolationErrorExtractor; +import org.eclipse.hawkbit.ui.error.extractors.EntityNotFoundErrorExtractor; import org.eclipse.hawkbit.ui.error.extractors.UiErrorDetailsExtractor; import org.eclipse.hawkbit.ui.error.extractors.UploadErrorExtractor; import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; @@ -93,13 +94,18 @@ public class MgmtUiConfiguration { /** * UI Error handler bean. * + * @param i18n + * VaadinMessageSource + * @param uiErrorDetailsExtractor + * ui error details extractors + * * @return UI Error handler */ @Bean @ConditionalOnMissingBean ErrorHandler uiErrorHandler(final VaadinMessageSource i18n, - final List uiErrorDetailsExtractor) { - return new HawkbitUIErrorHandler(i18n, uiErrorDetailsExtractor); + final List uiErrorDetailsExtractors) { + return new HawkbitUIErrorHandler(i18n, uiErrorDetailsExtractors); } /** @@ -115,6 +121,8 @@ public class MgmtUiConfiguration { /** * UI ConstraintViolation Error details extractor bean. * + * @param i18n + * VaadinMessageSource * @return UI ConstraintViolation Error details extractor */ @Bean @@ -122,6 +130,18 @@ public class MgmtUiConfiguration { return new ConstraintViolationErrorExtractor(i18n); } + /** + * UI Entity not found Error details extractor bean. + * + * @param i18n + * VaadinMessageSource + * @return UI EntityNotFound Error details extractor + */ + @Bean + UiErrorDetailsExtractor entityNotFoundErrorExtractor(final VaadinMessageSource i18n) { + return new EntityNotFoundErrorExtractor(i18n); + } + /** * Vaadin4Spring servlet bean. * @@ -135,6 +155,8 @@ public class MgmtUiConfiguration { /** * UI target entity mapper bean. * + * @param i18n + * VaadinMessageSource * @return UI target entity mapper */ @Bean @@ -145,6 +167,10 @@ public class MgmtUiConfiguration { /** * UI Management target data supplier bean. * + * @param targetManagement + * TargetManagement + * @param targetToProxyTargetMapper + * UI target entity mapper * @return UI target data supplier for Management view */ @Bean @@ -158,6 +184,10 @@ public class MgmtUiConfiguration { /** * UI Filter target data supplier bean. * + * @param targetManagement + * TargetManagement + * @param targetToProxyTargetMapper + * UI target entity mapper * @return UI target data supplier for Filter view */ @Bean diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/UploadArtifactView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/UploadArtifactView.java index 92911e6b1..10c931bd1 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/UploadArtifactView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/UploadArtifactView.java @@ -10,11 +10,10 @@ package org.eclipse.hawkbit.ui.artifacts; import static org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress.FileUploadStatus.UPLOAD_STARTED; +import java.util.Arrays; import java.util.EnumMap; import java.util.Map; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; import javax.servlet.MultipartConfigElement; import org.eclipse.hawkbit.repository.ArtifactManagement; @@ -27,6 +26,7 @@ import org.eclipse.hawkbit.ui.artifacts.details.ArtifactDetailsGridLayout; import org.eclipse.hawkbit.ui.artifacts.smtable.SoftwareModuleGridLayout; import org.eclipse.hawkbit.ui.artifacts.smtype.filter.SMTypeFilterLayout; import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress; +import org.eclipse.hawkbit.ui.common.AbstractEventListenersAwareView; import org.eclipse.hawkbit.ui.common.CommonUiDependencies; import org.eclipse.hawkbit.ui.common.ConfirmationDialog; import org.eclipse.hawkbit.ui.common.event.EventLayout; @@ -47,7 +47,6 @@ import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; import org.springframework.beans.factory.annotation.Autowired; import org.vaadin.spring.events.EventBus.UIEventBus; -import com.vaadin.navigator.View; import com.vaadin.navigator.ViewBeforeLeaveEvent; import com.vaadin.server.Page; import com.vaadin.server.Page.BrowserWindowResizeEvent; @@ -56,14 +55,13 @@ import com.vaadin.spring.annotation.SpringView; import com.vaadin.spring.annotation.UIScope; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.UI; -import com.vaadin.ui.VerticalLayout; /** * Display artifacts upload view. */ @UIScope @SpringView(name = UploadArtifactView.VIEW_NAME, ui = AbstractHawkbitUI.class) -public class UploadArtifactView extends VerticalLayout implements View, BrowserWindowResizeListener { +public class UploadArtifactView extends AbstractEventListenersAwareView implements BrowserWindowResizeListener { private static final long serialVersionUID = 1L; public static final String VIEW_NAME = "spUpload"; @@ -107,6 +105,8 @@ public class UploadArtifactView extends VerticalLayout implements View, BrowserW artifactUploadState.getArtifactDetailsGridLayoutUiState(), artifactManagement, softwareModuleManagement, multipartConfigElement); + addEventAwareLayouts(Arrays.asList(smTypeFilterLayout, smGridLayout, artifactDetailsGridLayout)); + final Map layoutVisibilityHandlers = new EnumMap<>(EventLayout.class); layoutVisibilityHandlers.put(EventLayout.SM_TYPE_FILTER, new VisibilityHandler(this::showSmTypeLayout, this::hideSmTypeLayout)); @@ -129,16 +129,16 @@ public class UploadArtifactView extends VerticalLayout implements View, BrowserW } } - @PostConstruct - void init() { + @Override + protected void init() { if (permChecker.hasReadRepositoryPermission()) { - buildLayout(); - restoreState(); + super.init(); Page.getCurrent().addBrowserWindowResizeListener(this); } } - private void buildLayout() { + @Override + protected void buildLayout() { setMargin(false); setSpacing(false); setSizeFull(); @@ -164,24 +164,33 @@ public class UploadArtifactView extends VerticalLayout implements View, BrowserW mainLayout.setExpandRatio(artifactDetailsGridLayout, 0.5F); } - private void restoreState() { + @Override + protected void restoreState() { + if (permChecker.hasReadRepositoryPermission()) { + restoreSmWidgetsState(); + restoreArtifactWidgetsState(); + } + + super.restoreState(); + } + + private void restoreSmWidgetsState() { if (artifactUploadState.getSmTypeFilterLayoutUiState().isHidden() || artifactUploadState.getArtifactDetailsGridLayoutUiState().isMaximized()) { hideSmTypeLayout(); } else { showSmTypeLayout(); } - smTypeFilterLayout.restoreState(); if (artifactUploadState.getSmGridLayoutUiState().isMaximized()) { maximizeSmGridLayout(); } - smGridLayout.restoreState(); + } + private void restoreArtifactWidgetsState() { if (artifactUploadState.getArtifactDetailsGridLayoutUiState().isMaximized()) { maximizeArtifactGridLayout(); } - artifactDetailsGridLayout.restoreState(); } private void showSmTypeLayout() { @@ -265,16 +274,29 @@ public class UploadArtifactView extends VerticalLayout implements View, BrowserW } } - @PreDestroy - void destroy() { + @Override + public String getViewName() { + return UploadArtifactView.VIEW_NAME; + } + + @Override + protected void subscribeListeners() { + if (permChecker.hasReadRepositoryPermission()) { + layoutVisibilityListener.subscribe(); + layoutResizeListener.subscribe(); + } + + super.subscribeListeners(); + } + + @Override + protected void unsubscribeListeners() { if (permChecker.hasReadRepositoryPermission()) { layoutVisibilityListener.unsubscribe(); layoutResizeListener.unsubscribe(); - - smTypeFilterLayout.unsubscribeListener(); - smGridLayout.unsubscribeListener(); - artifactDetailsGridLayout.unsubscribeListener(); } + + super.unsubscribeListeners(); } @Override @@ -286,10 +308,12 @@ public class UploadArtifactView extends VerticalLayout implements View, BrowserW if (Boolean.TRUE.equals(ok)) { // Clear all queued file uploads artifactUploadState.clearFileStates(); - event.navigate(); + super.beforeLeave(event); } else { - // Send a PostViewChangeEvent to the DashboardMenu as if the navigation actually - // happened to prevent the DashboardMenu navigation from getting stuck + // 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)); } @@ -297,7 +321,7 @@ public class UploadArtifactView extends VerticalLayout implements View, BrowserW UI.getCurrent().addWindow(confirmDeleteDialog.getWindow()); confirmDeleteDialog.getWindow().bringToFront(); } else { - event.navigate(); + super.beforeLeave(event); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGridLayout.java index c27c742d1..3b7154468 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGridLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGridLayout.java @@ -58,7 +58,8 @@ public class ArtifactDetailsGridLayout extends AbstractGridComponentLayout { * @param multipartConfigElement * MultipartConfigElement */ - public ArtifactDetailsGridLayout(final CommonUiDependencies uiDependencies, final ArtifactUploadState artifactUploadState, + public ArtifactDetailsGridLayout(final CommonUiDependencies uiDependencies, + final ArtifactUploadState artifactUploadState, final ArtifactDetailsGridLayoutUiState artifactDetailsGridLayoutUiState, final ArtifactManagement artifactManagement, final SoftwareModuleManagement softwareManagement, final MultipartConfigElement multipartConfigElement) { @@ -66,8 +67,8 @@ public class ArtifactDetailsGridLayout extends AbstractGridComponentLayout { this.artifactDetailsGrid = new ArtifactDetailsGrid(uiDependencies, artifactManagement); if (uiDependencies.getPermChecker().hasCreateRepositoryPermission()) { - this.uploadDropAreaLayout = new UploadDropAreaLayout(uiDependencies, artifactUploadState, multipartConfigElement, - softwareManagement, artifactManagement); + this.uploadDropAreaLayout = new UploadDropAreaLayout(uiDependencies, artifactUploadState, + multipartConfigElement, softwareManagement, artifactManagement); buildLayout(artifactDetailsHeader, artifactDetailsGrid, uploadDropAreaLayout); } else { @@ -115,9 +116,7 @@ public class ArtifactDetailsGridLayout extends AbstractGridComponentLayout { showDetailsLayout(); } - /** - * Is called when view is shown to the user - */ + @Override public void restoreState() { artifactDetailsHeader.restoreState(); @@ -126,10 +125,14 @@ public class ArtifactDetailsGridLayout extends AbstractGridComponentLayout { } } - /** - * Unsubscribe the even listeners for selection change and fileupload - */ - public void unsubscribeListener() { + @Override + public void subscribeListeners() { + selectionChangedListener.subscribe(); + fileUploadChangedListener.subscribe(); + } + + @Override + public void unsubscribeListeners() { selectionChangedListener.unsubscribe(); fileUploadChangedListener.unsubscribe(); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGrid.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGrid.java index 974e958d9..a9cf4d02c 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGrid.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGrid.java @@ -12,6 +12,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; @@ -110,13 +111,28 @@ public class SoftwareModuleGrid extends AbstractGrid( new SoftwareModuleDataProvider(softwareModuleManagement, new AssignedSoftwareModuleToProxyMapper(softwareModuleToProxyMapper)), - SwFilterParams::new, getSelectionSupport()::deselectAll)); + SwFilterParams::new, this::afterFilterRefresh)); initFilterMappings(); getFilterSupport().setFilter(new SwFilterParams()); this.numberOfArtifactUploadsForSm = new HashMap<>(); } + private void afterFilterRefresh() { + // keep selection on master distribution set change as it does not + // filter out any software module entries, only sorts them + if (masterFilterHasNotChanged()) { + getSelectionSupport().deselectAll(); + } + } + + private boolean masterFilterHasNotChanged() { + final Long filterDsId = getFilter().map(SwFilterParams::getLastSelectedDistributionId).orElse(null); + final Long masterDsId = getMasterEntitySupport() != null ? getMasterEntitySupport().getMasterId() : null; + + return Objects.equals(filterDsId, masterDsId); + } + private void initFilterMappings() { getFilterSupport().addMapping(FilterType.SEARCH, SwFilterParams::setSearchText, smGridLayoutUiState.getSearchFilter()); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGridLayout.java index df7e83ec0..f29a63ff9 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGridLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGridLayout.java @@ -22,7 +22,6 @@ import org.eclipse.hawkbit.ui.common.event.EventLayout; import org.eclipse.hawkbit.ui.common.event.EventLayoutViewAware; import org.eclipse.hawkbit.ui.common.event.EventTopics; import org.eclipse.hawkbit.ui.common.event.EventView; -import org.eclipse.hawkbit.ui.common.event.EventViewAware; 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; @@ -81,15 +80,15 @@ public class SoftwareModuleGridLayout extends AbstractSoftwareModuleGridLayout { softwareModuleTypeManagement, getSmMetaDataWindowBuilder()); this.softwareModuleDetails.buildDetails(); + final EventLayoutViewAware layoutViewAware = new EventLayoutViewAware(EventLayout.SM_LIST, getEventView()); addEventListener(new FilterChangedListener<>(uiDependencies.getEventBus(), ProxySoftwareModule.class, - new EventViewAware(getEventView()), softwareModuleGrid.getFilterSupport())); - addEventListener(new SelectionChangedListener<>(uiDependencies.getEventBus(), - new EventLayoutViewAware(EventLayout.SM_LIST, getEventView()), getMasterSmAwareComponents())); - addEventListener(new SelectGridEntityListener<>(uiDependencies.getEventBus(), - new EventLayoutViewAware(EventLayout.SM_LIST, getEventView()), + layoutViewAware, softwareModuleGrid.getFilterSupport())); + addEventListener(new SelectionChangedListener<>(uiDependencies.getEventBus(), layoutViewAware, + getMasterSmAwareComponents())); + addEventListener(new SelectGridEntityListener<>(uiDependencies.getEventBus(), layoutViewAware, softwareModuleGrid.getSelectionSupport())); addEventListener(new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), ProxySoftwareModule.class) - .entityModifiedAwareSupports(getSmModifiedAwareSupports()).build()); + .viewAware(layoutViewAware).entityModifiedAwareSupports(getSmModifiedAwareSupports()).build()); addEventListener(new GenericEventListener<>(uiDependencies.getEventBus(), EventTopics.FILE_UPLOAD_CHANGED, this::onUploadChanged)); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterButtons.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterButtons.java index 830af7713..f90f57c9b 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterButtons.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterButtons.java @@ -114,4 +114,9 @@ public class SMTypeFilterButtons extends AbstractTypeFilterButtons { protected Window getUpdateWindow(final ProxyType clickedFilter) { return smTypeWindowBuilder.getWindowForUpdate(clickedFilter); } + + @Override + protected boolean typeExists(final Long typeId) { + return softwareModuleTypeManagement.exists(typeId); + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterLayout.java index 9b21d29be..d6f8510df 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterLayout.java @@ -65,12 +65,13 @@ public class SMTypeFilterLayout extends AbstractFilterLayout { this.smTypeFilterButtons = new SMTypeFilterButtons(uiDependencies, softwareModuleTypeManagement, smTypeWindowBuilder, smTypeFilterLayoutUiState, eventView); + final EventLayoutViewAware layoutViewAware = new EventLayoutViewAware(EventLayout.SM_TYPE_FILTER, eventView); this.gridActionsVisibilityListener = new GridActionsVisibilityListener(uiDependencies.getEventBus(), - new EventLayoutViewAware(EventLayout.SM_TYPE_FILTER, eventView), smTypeFilterButtons::hideActionColumns, - smTypeFilterButtons::showEditColumn, smTypeFilterButtons::showDeleteColumn); + layoutViewAware, smTypeFilterButtons::hideActionColumns, smTypeFilterButtons::showEditColumn, + smTypeFilterButtons::showDeleteColumn); this.entityModifiedListener = new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), - ProxyType.class).entityModifiedAwareSupports(getEntityModifiedAwareSupports()) - .parentEntityType(ProxySoftwareModule.class).build(); + ProxyType.class).parentEntityType(ProxySoftwareModule.class).viewAware(layoutViewAware) + .entityModifiedAwareSupports(getEntityModifiedAwareSupports()).build(); buildLayout(); } @@ -94,17 +95,24 @@ public class SMTypeFilterLayout extends AbstractFilterLayout { return wrapFilterContent(smTypeFilterButtons); } - /** - * Is called when view is shown to the user - */ + @Override public void restoreState() { smTypeFilterButtons.restoreState(); } - /** - * Unsubscribe the events listeners - */ - public void unsubscribeListener() { + @Override + public void onViewEnter() { + smTypeFilterButtons.reevaluateFilter(); + } + + @Override + public void subscribeListeners() { + gridActionsVisibilityListener.subscribe(); + entityModifiedListener.subscribe(); + } + + @Override + public void unsubscribeListeners() { gridActionsVisibilityListener.unsubscribe(); entityModifiedListener.unsubscribe(); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEventListenersAwareView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEventListenersAwareView.java new file mode 100644 index 000000000..8787bfea2 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEventListenersAwareView.java @@ -0,0 +1,123 @@ +/** + * Copyright (c) 2021 Bosch.IO GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.ui.common; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +import com.vaadin.navigator.View; +import com.vaadin.navigator.ViewBeforeLeaveEvent; +import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent; +import com.vaadin.ui.VerticalLayout; + +/** + * Abstract class managing event listeners aware layouts. + * + */ +public abstract class AbstractEventListenersAwareView extends VerticalLayout implements View, ViewNameAware { + private static final long serialVersionUID = 1L; + + private final transient List eventAwareLayouts = new ArrayList<>(); + private boolean initial; + + /** + * Adds event aware layout. + * + * @param eventAwareLayout + * event aware layout to add + */ + protected void addEventAwareLayout(final EventListenersAwareLayout eventAwareLayout) { + if (eventAwareLayout != null) { + eventAwareLayouts.add(eventAwareLayout); + } + } + + /** + * Adds a list of event aware layouts. + * + * @param eventAwareLayouts + * event aware layouts to add + */ + protected void addEventAwareLayouts(final Collection eventAwareLayouts) { + eventAwareLayouts.forEach(this::addEventAwareLayout); + } + + @PostConstruct + protected void init() { + buildLayout(); + initial = true; + } + + /** + * Builds view layout. + * + */ + protected abstract void buildLayout(); + + @Override + public void enter(final ViewChangeEvent event) { + subscribeListeners(); + + if (initial) { + restoreState(); + initial = false; + return; + } + + updateLayoutsOnViewEnter(); + } + + /** + * Subscribes all listeners of added event aware layouts to event bus. + * + */ + protected void subscribeListeners() { + eventAwareLayouts.forEach(EventListenersAwareLayout::subscribeListeners); + } + + /** + * Restores session state of added event aware layouts. + * + */ + protected void restoreState() { + eventAwareLayouts.forEach(EventListenersAwareLayout::restoreState); + } + + /** + * Called on on view enter for added event aware layouts to update their + * state. + * + */ + protected void updateLayoutsOnViewEnter() { + eventAwareLayouts.forEach(EventListenersAwareLayout::onViewEnter); + } + + @Override + public void beforeLeave(final ViewBeforeLeaveEvent event) { + unsubscribeListeners(); + event.navigate(); + } + + /** + * Unsubscribes all listeners of added event aware layouts to event bus. + * + */ + protected void unsubscribeListeners() { + eventAwareLayouts.forEach(EventListenersAwareLayout::unsubscribeListeners); + } + + @PreDestroy + public void destroy() { + unsubscribeListeners(); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/EventListenersAwareLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/EventListenersAwareLayout.java new file mode 100644 index 000000000..b4c351727 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/EventListenersAwareLayout.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2021 Bosch.IO GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.ui.common; + +/** + * Interface for event aware event listeners + * + */ +public interface EventListenersAwareLayout { + + /** + * Restore components state + */ + default void restoreState() { + } + + /** + * Update components on view enter + */ + default void onViewEnter() { + } + + /** + * Subscribe event listeners + */ + default void subscribeListeners() { + } + + /** + * Unsubscribe event listeners + */ + default void unsubscribeListeners() { + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/ViewNameAware.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/ViewNameAware.java new file mode 100644 index 000000000..176116440 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/ViewNameAware.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2021 Bosch.IO GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.ui.common; + +/** + * Interface for getting view name + * + */ +@FunctionalInterface +public interface ViewNameAware { + + /** + * Provides the name of a view + * + * @return view name + */ + String getViewName(); +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/RolloutGroupToProxyRolloutGroupMapper.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/RolloutGroupToProxyRolloutGroupMapper.java index 7101d5b68..a6c246b1f 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/RolloutGroupToProxyRolloutGroupMapper.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/RolloutGroupToProxyRolloutGroupMapper.java @@ -8,7 +8,6 @@ */ package org.eclipse.hawkbit.ui.common.data.mappers; -import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.ui.common.data.proxies.ProxyRolloutGroup; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; @@ -20,18 +19,6 @@ import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; public class RolloutGroupToProxyRolloutGroupMapper extends AbstractNamedEntityToProxyNamedEntityMapper { - /** - * Maps the rollout group to proxy rollout group - * - * @param group - * RolloutGroup - * - * @return the corresponding Rollout group - */ - public static ProxyRolloutGroup mapGroup(final RolloutGroup group) { - return new RolloutGroupToProxyRolloutGroupMapper().map(group); - } - @Override public ProxyRolloutGroup map(final RolloutGroup rolloutGroup) { final ProxyRolloutGroup proxyRolloutGroup = new ProxyRolloutGroup(); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/RolloutToProxyRolloutMapper.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/RolloutToProxyRolloutMapper.java index 160a701c3..e55ff1e42 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/RolloutToProxyRolloutMapper.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/RolloutToProxyRolloutMapper.java @@ -19,18 +19,6 @@ import org.eclipse.hawkbit.ui.common.data.proxies.ProxyRollout; */ public class RolloutToProxyRolloutMapper extends AbstractNamedEntityToProxyNamedEntityMapper { - /** - * Maps the rollout to Proxy rollout - * - * @param rollout - * Rollout - * - * @return ProxyRollout - */ - public static ProxyRollout mapRollout(final Rollout rollout) { - return new RolloutToProxyRolloutMapper().map(rollout); - } - @Override public ProxyRollout map(final Rollout rollout) { final ProxyRollout proxyRollout = new ProxyRollout(); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/suppliers/TargetFilterStateDataSupplierImpl.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/suppliers/TargetFilterStateDataSupplierImpl.java index ab5c08616..509869969 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/suppliers/TargetFilterStateDataSupplierImpl.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/suppliers/TargetFilterStateDataSupplierImpl.java @@ -8,6 +8,8 @@ */ package org.eclipse.hawkbit.ui.common.data.suppliers; +import java.io.Serializable; + import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.ui.common.data.mappers.TargetToProxyTargetMapper; import org.eclipse.hawkbit.ui.common.data.providers.TargetFilterStateDataProvider; @@ -21,7 +23,9 @@ import com.vaadin.data.provider.DataProvider; * implementation. * */ -public class TargetFilterStateDataSupplierImpl implements TargetFilterStateDataSupplier { +public class TargetFilterStateDataSupplierImpl implements TargetFilterStateDataSupplier, Serializable { + private static final long serialVersionUID = 1L; + private final TargetFilterStateDataProvider dataProvider; private final DataCommunicator dataCommunicator; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/suppliers/TargetManagementStateDataSupplierImpl.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/suppliers/TargetManagementStateDataSupplierImpl.java index 3744b6636..e1735e219 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/suppliers/TargetManagementStateDataSupplierImpl.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/suppliers/TargetManagementStateDataSupplierImpl.java @@ -8,6 +8,8 @@ */ package org.eclipse.hawkbit.ui.common.data.suppliers; +import java.io.Serializable; + import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.ui.common.data.filters.TargetManagementFilterParams; import org.eclipse.hawkbit.ui.common.data.mappers.TargetToProxyTargetMapper; @@ -22,7 +24,9 @@ import com.vaadin.data.provider.DataProvider; * implementation. * */ -public class TargetManagementStateDataSupplierImpl implements TargetManagementStateDataSupplier { +public class TargetManagementStateDataSupplierImpl implements TargetManagementStateDataSupplier, Serializable { + private static final long serialVersionUID = 1L; + private final TargetManagementStateDataProvider dataProvider; private final DataCommunicator dataCommunicator; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/distributionset/AbstractDistributionSetGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/distributionset/AbstractDistributionSetGridLayout.java index 2aea38ea9..91475b8d2 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/distributionset/AbstractDistributionSetGridLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/distributionset/AbstractDistributionSetGridLayout.java @@ -51,7 +51,7 @@ public abstract class AbstractDistributionSetGridLayout extends AbstractGridComp * @param eventView * EventView */ - public AbstractDistributionSetGridLayout(final CommonUiDependencies uiDependencies, + protected AbstractDistributionSetGridLayout(final CommonUiDependencies uiDependencies, final SystemManagement systemManagement, final SystemSecurityContext systemSecurityContext, final TenantConfigurationManagement configManagement, final DistributionSetManagement distributionSetManagement, @@ -94,9 +94,11 @@ public abstract class AbstractDistributionSetGridLayout extends AbstractGridComp /** * Returns the {@link AbstractDsGrid} * + * @param + * Generic filter type * @return the distributionGrid */ - public abstract AbstractDsGrid getDistributionGrid(); + public abstract AbstractDsGrid getDistributionGrid(); /** * Returns the {@link DistributionSetGridHeader} @@ -135,9 +137,7 @@ public abstract class AbstractDistributionSetGridLayout extends AbstractGridComp showDetailsLayout(); } - /** - * Restore the distribution grid state - */ + @Override public void restoreState() { getDistributionSetGridHeader().restoreState(); getDistributionGrid().restoreState(); @@ -147,10 +147,18 @@ public abstract class AbstractDistributionSetGridLayout extends AbstractGridComp listeners.add(listener); } - /** - * Unsubscribe the event listeners. - */ - public void unsubscribeListener() { + @Override + public void onViewEnter() { + getDistributionGrid().getSelectionSupport().reselectCurrentEntity(); + } + + @Override + public void subscribeListeners() { + listeners.forEach(TopicEventListener::subscribe); + } + + @Override + public void unsubscribeListeners() { listeners.forEach(TopicEventListener::unsubscribe); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/distributionset/AbstractDsGrid.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/distributionset/AbstractDsGrid.java index d951a0428..ac1faed73 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/distributionset/AbstractDsGrid.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/distributionset/AbstractDsGrid.java @@ -15,6 +15,7 @@ import java.util.stream.Collectors; import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.ui.common.CommonUiDependencies; import org.eclipse.hawkbit.ui.common.builder.GridComponentBuilder; +import org.eclipse.hawkbit.ui.common.data.filters.DsFilterParams; import org.eclipse.hawkbit.ui.common.data.mappers.DistributionSetToProxyDistributionMapper; import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSet; import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity; @@ -36,9 +37,9 @@ import com.vaadin.ui.Button; * Abstract class of distribution set grid * * @param - * Generic type + * Generic filter type */ -public abstract class AbstractDsGrid extends AbstractGrid { +public abstract class AbstractDsGrid extends AbstractGrid { private static final long serialVersionUID = 1L; protected static final String DS_NAME_ID = "dsName"; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/EventView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/EventView.java index e405cd27f..a0ad7ad38 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/EventView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/EventView.java @@ -8,9 +8,50 @@ */ package org.eclipse.hawkbit.ui.common.event; +import org.eclipse.hawkbit.ui.artifacts.UploadArtifactView; +import org.eclipse.hawkbit.ui.distributions.DistributionsView; +import org.eclipse.hawkbit.ui.filtermanagement.FilterManagementView; +import org.eclipse.hawkbit.ui.management.DeploymentView; +import org.eclipse.hawkbit.ui.rollout.RolloutView; + /** * Enum constants for event view */ public enum EventView { - DEPLOYMENT, ROLLOUT, TARGET_FILTER, DISTRIBUTIONS, UPLOAD; + DEPLOYMENT(DeploymentView.VIEW_NAME), ROLLOUT(RolloutView.VIEW_NAME), TARGET_FILTER( + FilterManagementView.VIEW_NAME), DISTRIBUTIONS( + DistributionsView.VIEW_NAME), UPLOAD(UploadArtifactView.VIEW_NAME); + + private final String viewName; + + /** + * Constructor. + * + * @param viewName + * View name + */ + EventView(final String viewName) { + this.viewName = viewName; + } + + /** + * Get view name. + * + * @return view name + */ + public String getViewName() { + return viewName; + } + + /** + * Matches event view with provided view name. + * + * @param viewName + * View name to match + * + * @return match + */ + public boolean matchByViewName(final String viewName) { + return this.viewName.equals(viewName); + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterLayout.java index 528017a0b..ae99a1147 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterLayout.java @@ -8,6 +8,7 @@ */ package org.eclipse.hawkbit.ui.common.filterlayout; +import org.eclipse.hawkbit.ui.common.EventListenersAwareLayout; import org.eclipse.hawkbit.ui.common.grid.header.AbstractGridHeader; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; @@ -19,7 +20,7 @@ import com.vaadin.ui.VerticalLayout; /** * Parent class for filter button layout. */ -public abstract class AbstractFilterLayout extends VerticalLayout { +public abstract class AbstractFilterLayout extends VerticalLayout implements EventListenersAwareLayout { private static final long serialVersionUID = 1L; protected void buildLayout() { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractTagFilterButtons.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractTagFilterButtons.java index 998b95fe0..8c97eb4de 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractTagFilterButtons.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractTagFilterButtons.java @@ -56,9 +56,10 @@ public abstract class AbstractTagFilterButtons extends AbstractFilterButtons getFilterMasterEntityType(); + /** + * Provides event view filter. + * + * @return event view filter. + */ protected abstract EventView getView(); private void onNoTagChangedEvent(final ClickBehaviourType clickType) { @@ -146,6 +157,12 @@ public abstract class AbstractTagFilterButtons extends AbstractFilterButtons tagsToRestore = tagFilterLayoutUiState.getClickedTagIdsWithName(); if (!CollectionUtils.isEmpty(tagsToRestore)) { + removeNonExistingTags(tagsToRestore); getFilterButtonClickBehaviour().setPreviouslyClickedFilterIdsWithName(tagsToRestore); } @@ -219,4 +244,35 @@ public abstract class AbstractTagFilterButtons extends AbstractFilterButtons tagIdsWithName) { + final Collection tagIds = tagIdsWithName.keySet(); + final Collection existingTagIds = filterExistingTagIds(tagIds); + if (tagIds.size() != existingTagIds.size()) { + return tagIds.retainAll(existingTagIds); + } + + return false; + } + + /** + * Filters out non-existant tags by ids. + * + * @param tagIds + * provided tag ids + * @return filtered list of existing tag ids + */ + protected abstract Collection filterExistingTagIds(final Collection tagIds); + + /** + * Re-evaluates a filter (usually after view enter). + * + */ + public void reevaluateFilter() { + final Map clickedTags = getFilterButtonClickBehaviour().getPreviouslyClickedFilterIdsWithName(); + + if (!CollectionUtils.isEmpty(clickedTags) && removeNonExistingTags(clickedTags)) { + publishFilterChangedEvent(clickedTags); + } + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractTypeFilterButtons.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractTypeFilterButtons.java index d8f9f7d47..570489549 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractTypeFilterButtons.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractTypeFilterButtons.java @@ -45,9 +45,10 @@ public abstract class AbstractTypeFilterButtons extends AbstractFilterButtons getFilterMasterEntityType(); + /** + * Provides event view filter. + * + * @return event view filter. + */ protected abstract EventView getView(); @Override @@ -106,8 +117,21 @@ public abstract class AbstractTypeFilterButtons extends AbstractFilterButtons { * Constructor for DragAndDropSupport * * @param grid - * Vaadin Grid + * Vaadin Grid * @param i18n - * VaadinMessageSource + * VaadinMessageSource * @param notification - * UINotification + * UINotification * @param sourceTargetAssignmentStrategies - * Key value pair of target and assignments + * Key value pair of target and assignments * @param eventBus - * UIEventBus + * UIEventBus */ public DragAndDropSupport(final AbstractGrid grid, final VaadinMessageSource i18n, final UINotification notification, @@ -95,7 +95,8 @@ public class DragAndDropSupport { /** * workaround for target/ds tags that currently do not support selection * - * @param ignoreSelection Set to true for distribution set and targets + * @param ignoreSelection + * Set to true for distribution set and targets */ public void ignoreSelection(final boolean ignoreSelection) { this.ignoreSelection = ignoreSelection; @@ -137,9 +138,9 @@ public class DragAndDropSupport { /** * @param dragOrDropExtension - * AbstractExtension + * AbstractExtension * @param dragOrDropDescription - * Description for drag and drop + * Description for drag and drop * * @return true if grid supports drag and drop else false */ @@ -213,12 +214,9 @@ public class DragAndDropSupport { private void addGridDropStylingListener() { if (draggingListener == null) { draggingListener = new EntityDraggingListener(eventBus, sourceTargetAssignmentStrategies.keySet(), grid); - return; } - if (!draggingListener.isSubscribed()) { - draggingListener.subscribe(); - } + draggingListener.subscribe(); } private boolean isDropValid(final String sourceId, final T dropTargetItem, diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/FilterSupport.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/FilterSupport.java index 9a8f63735..7924021e2 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/FilterSupport.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/FilterSupport.java @@ -169,6 +169,13 @@ public class FilterSupport { return filterDataProvider; } + /** + * @return Original data provider + */ + public DataProvider getOriginalDataProvider() { + return filterDataProvider.getDataProvider(); + } + /** * Verifies if filter type is supported * @@ -294,5 +301,14 @@ public class FilterSupport { this.customFilter = filter; refreshAll(); } + + /** + * Gets original data provider. + * + * @return original data provider + */ + public DataProvider getDataProvider() { + return dataProvider; + } } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/MasterEntitySupport.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/MasterEntitySupport.java index 5ead94b85..bf888d87f 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/MasterEntitySupport.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/MasterEntitySupport.java @@ -19,7 +19,7 @@ import org.eclipse.hawkbit.ui.common.layout.MasterEntityAwareComponent; * Filter support in Master entity * * @param - * Generic type of ProxyIdentifiableEntity + * Generic type of master entity */ public class MasterEntitySupport implements MasterEntityAwareComponent { private final FilterSupport filterSupport; @@ -31,7 +31,7 @@ public class MasterEntitySupport implements M * Constructor for MasterEntitySupport * * @param filterSupport - * Filter support + * Filter support */ public MasterEntitySupport(final FilterSupport filterSupport) { this(filterSupport, null); @@ -41,9 +41,9 @@ public class MasterEntitySupport implements M * Constructor for MasterEntitySupport * * @param filterSupport - * Filter support + * Filter support * @param masterEntityToFilterMapper - * Master entity to filter mapper + * Master entity to filter mapper */ public MasterEntitySupport(final FilterSupport filterSupport, final Function masterEntityToFilterMapper) { @@ -57,16 +57,18 @@ public class MasterEntitySupport implements M return; } - final Long masterEntityId = masterEntity != null ? masterEntity.getId() : null; - masterId = masterEntityId; + filterSupport.updateFilter(FilterType.MASTER, getMasterEntityFilter(masterEntity)); - if (masterEntity != null) { - filterSupport.updateFilter(FilterType.MASTER, - masterEntityToFilterMapper != null ? masterEntityToFilterMapper.apply(masterEntity) - : masterEntityId); - } else { - filterSupport.updateFilter(FilterType.MASTER, null); + masterId = masterEntity != null ? masterEntity.getId() : null; + } + + private Object getMasterEntityFilter(final M masterEntity) { + if (masterEntity == null) { + return null; } + + return masterEntityToFilterMapper != null ? masterEntityToFilterMapper.apply(masterEntity) + : masterEntity.getId(); } /** diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/SelectionSupport.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/SelectionSupport.java index a86f6ab3c..310f9705f 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/SelectionSupport.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/SelectionSupport.java @@ -230,7 +230,7 @@ public class SelectionSupport { } /** - * @return Id of elected entity from the grid + * @return Id of selected entity from the grid */ public Optional getSelectedEntityId() { if (isNoSelectionModel() && selectedEntityIdUiStateProvider != null) { @@ -350,6 +350,16 @@ public class SelectionSupport { } } + /** + * Re-fetches and re-selects currently selected entity + */ + public void reselectCurrentEntity() { + getSelectedEntityId().ifPresent(selectedEntityId -> { + deselectAll(); + selectEntityById(selectedEntityId); + }); + } + @PreDestroy void destroy() { removeListeners(); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/AbstractFooterSupport.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/AbstractFooterSupport.java index bf47b19c9..b4aa82fd8 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/AbstractFooterSupport.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/AbstractFooterSupport.java @@ -35,9 +35,9 @@ public abstract class AbstractFooterSupport { } /** - * Get the count message label. + * Get the footer message label. * - * @return count message + * @return footer message */ protected abstract Label getFooterMessageLabel(); } \ No newline at end of file diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/AbstractGridComponentLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/AbstractGridComponentLayout.java index 693785d9f..7c5e4a33b 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/AbstractGridComponentLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/AbstractGridComponentLayout.java @@ -8,6 +8,7 @@ */ package org.eclipse.hawkbit.ui.common.layout; +import org.eclipse.hawkbit.ui.common.EventListenersAwareLayout; import org.eclipse.hawkbit.ui.common.detailslayout.AbstractGridDetailsLayout; import org.eclipse.hawkbit.ui.common.grid.AbstractGrid; import org.eclipse.hawkbit.ui.common.grid.header.AbstractDetailsHeader; @@ -24,7 +25,7 @@ import com.vaadin.ui.VerticalLayout; * {@link AbstractGridHeader}, grid {@link AbstractGrid}, optional grid details * {@link AbstractGridDetailsLayout} and optional footer. */ -public abstract class AbstractGridComponentLayout extends VerticalLayout { +public abstract class AbstractGridComponentLayout extends VerticalLayout implements EventListenersAwareLayout { private static final long serialVersionUID = 1L; private Component detailsLayout; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/CountAwareComponent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/CountAwareComponent.java new file mode 100644 index 000000000..f833cb69a --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/CountAwareComponent.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2021 Bosch.IO GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.ui.common.layout; + +/** + * Interface for count aware component. + * + */ +public interface CountAwareComponent { + + /** + * Adapts count on entities added. + * + * @param count + * added entities count + */ + void updateCountOnEntitiesAdded(final int count); + + /** + * Adapts count on entities updated. + * + */ + void updateCountOnEntitiesUpdated(); + + /** + * Adapts count on entities deleted. + * + * @param count + * deleted entities count + */ + void updateCountOnEntitiesDeleted(final int count); +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/BulkUploadChangedListener.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/BulkUploadChangedListener.java index c39c536fb..3c77b6ac2 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/BulkUploadChangedListener.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/BulkUploadChangedListener.java @@ -12,7 +12,7 @@ import java.util.function.Consumer; import org.eclipse.hawkbit.ui.common.event.BulkUploadEventPayload; import org.eclipse.hawkbit.ui.common.event.EventTopics; -import org.vaadin.spring.events.EventBus.UIEventBus; +import org.vaadin.spring.events.EventBus; import org.vaadin.spring.events.EventScope; import org.vaadin.spring.events.annotation.EventBusListenerMethod; @@ -32,7 +32,7 @@ public class BulkUploadChangedListener extends TopicEventListener { * @param bulkUploadCallback * Bulk upload callback event */ - public BulkUploadChangedListener(final UIEventBus eventBus, + public BulkUploadChangedListener(final EventBus eventBus, final Consumer bulkUploadCallback) { super(eventBus, EventTopics.BULK_UPLOAD_CHANGED); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/EntityModifiedListener.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/EntityModifiedListener.java index 4b8b57790..7c22504a6 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/EntityModifiedListener.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/EntityModifiedListener.java @@ -14,15 +14,18 @@ import java.util.Optional; import java.util.function.Consumer; import java.util.function.Supplier; +import org.eclipse.hawkbit.ui.common.ViewNameAware; import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity; import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload; import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload.EntityModifiedEventType; import org.eclipse.hawkbit.ui.common.event.EventTopics; +import org.eclipse.hawkbit.ui.common.event.EventViewAware; import org.springframework.util.CollectionUtils; import org.vaadin.spring.events.EventBus.UIEventBus; import org.vaadin.spring.events.EventScope; import org.vaadin.spring.events.annotation.EventBusListenerMethod; +import com.vaadin.navigator.View; import com.vaadin.ui.UI; /** @@ -31,7 +34,7 @@ import com.vaadin.ui.UI; * @param * Generic typ of ProxyIdentifiableEntity */ -public class EntityModifiedListener extends TopicEventListener { +public final class EntityModifiedListener extends ViewAwareListener { private final Class entityType; private final Class parentEntityType; private final Supplier> parentEntityIdProvider; @@ -48,14 +51,16 @@ public class EntityModifiedListener extends T * Identifiable entity * @param parentEntityIdProvider * Parent entity id provider + * @param viewAware + * View aware * @param entityModifiedAwareSupports * List of entity modified aware support */ - public EntityModifiedListener(final UIEventBus eventBus, final Class entityType, + private EntityModifiedListener(final UIEventBus eventBus, final Class entityType, final Class parentEntityType, - final Supplier> parentEntityIdProvider, + final Supplier> parentEntityIdProvider, final EventViewAware viewAware, final List entityModifiedAwareSupports) { - super(eventBus, EventTopics.ENTITY_MODIFIED); + super(eventBus, EventTopics.ENTITY_MODIFIED, viewAware); this.entityType = entityType; this.parentEntityType = parentEntityType; @@ -65,7 +70,7 @@ public class EntityModifiedListener extends T @EventBusListenerMethod(scope = EventScope.UI) private void onEntityModifiedEvent(final EntityModifiedEventPayload eventPayload) { - if (!suitableEntityType(eventPayload.getEntityType()) + if (!suitableView() || !suitableEntityType(eventPayload.getEntityType()) || !suitableParentEntity(eventPayload.getParentType(), eventPayload.getParentId())) { return; } @@ -90,6 +95,24 @@ public class EntityModifiedListener extends T } } + private boolean suitableView() { + // if view is not explicitly defined allow events from all views + if (getView() == null) { + return true; + } + + return getView().matchByViewName(getCurrentViewName()); + } + + private String getCurrentViewName() { + final View currentView = UI.getCurrent().getNavigator().getCurrentView(); + if (currentView instanceof ViewNameAware) { + return ((ViewNameAware) currentView).getViewName(); + } + + return ""; + } + private boolean suitableEntityType(final Class type) { return entityType != null && entityType.equals(type); } @@ -161,6 +184,7 @@ public class EntityModifiedListener extends T private final Class entityType; private Class parentEntityType; private Supplier> parentEntityIdProvider; + private EventViewAware viewAware; private List entityModifiedAwareSupports; /** @@ -202,6 +226,18 @@ public class EntityModifiedListener extends T return this; } + /** + * Set View aware + * + * @param viewAware + * View aware + * @return builder + */ + public Builder viewAware(final EventViewAware viewAware) { + this.viewAware = viewAware; + return this; + } + /** * Build entity modified support for layout * @@ -220,7 +256,7 @@ public class EntityModifiedListener extends T */ public EntityModifiedListener build() { return new EntityModifiedListener<>(eventBus, entityType, parentEntityType, parentEntityIdProvider, - entityModifiedAwareSupports); + viewAware, entityModifiedAwareSupports); } } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/FilterChangedListener.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/FilterChangedListener.java index 7e90eb309..976313ac6 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/FilterChangedListener.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/FilterChangedListener.java @@ -27,6 +27,7 @@ import org.vaadin.spring.events.annotation.EventBusListenerMethod; public class FilterChangedListener extends ViewAwareListener { private final Class entityType; private final FilterSupport filterSupport; + private final Runnable updateFilterCountInfo; /** * Constructor for FilterChangedListener @@ -42,10 +43,30 @@ public class FilterChangedListener extends Vi */ public FilterChangedListener(final UIEventBus eventBus, final Class entityType, final EventViewAware viewAware, final FilterSupport filterSupport) { + this(eventBus, entityType, viewAware, filterSupport, null); + } + + /** + * Constructor for FilterChangedListener + * + * @param eventBus + * UIEventBus + * @param entityType + * Generic type entity + * @param viewAware + * EventViewAware + * @param filterSupport + * Generic type filter support + * @param updateFilterCountInfo + * Callback to update entities count info on filter change + */ + public FilterChangedListener(final UIEventBus eventBus, final Class entityType, final EventViewAware viewAware, + final FilterSupport filterSupport, final Runnable updateFilterCountInfo) { super(eventBus, EventTopics.FILTER_CHANGED, viewAware); this.entityType = entityType; this.filterSupport = filterSupport; + this.updateFilterCountInfo = updateFilterCountInfo; } @EventBusListenerMethod(scope = EventScope.UI) @@ -58,6 +79,9 @@ public class FilterChangedListener extends Vi if (filterSupport.isFilterTypeSupported(filterType)) { filterSupport.updateFilter(filterType, eventPayload.getFilterValue()); + if (updateFilterCountInfo != null) { + updateFilterCountInfo.run(); + } } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/LayoutViewAwareListener.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/LayoutViewAwareListener.java index 610fd4717..6ea39ccbd 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/LayoutViewAwareListener.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/LayoutViewAwareListener.java @@ -31,7 +31,7 @@ public abstract class LayoutViewAwareListener extends TopicEventListener { * @param layoutViewAware * EventLayoutViewAware */ - public LayoutViewAwareListener(final UIEventBus eventBus, final String topic, + protected LayoutViewAwareListener(final UIEventBus eventBus, final String topic, final EventLayoutViewAware layoutViewAware) { super(eventBus, topic); @@ -48,7 +48,7 @@ public abstract class LayoutViewAwareListener extends TopicEventListener { * @param layoutViewAware * EventLayoutViewAware */ - public LayoutViewAwareListener(final UIEventBus eventBus, final Collection topics, + protected LayoutViewAwareListener(final UIEventBus eventBus, final Collection topics, final EventLayoutViewAware layoutViewAware) { super(eventBus, topics); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/PinningChangedListener.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/PinningChangedListener.java index bfbf7ef4b..200810963 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/PinningChangedListener.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/PinningChangedListener.java @@ -26,6 +26,7 @@ import org.vaadin.spring.events.annotation.EventBusListenerMethod; public class PinningChangedListener extends TopicEventListener { private final Class entityType; private final PinSupport pinSupport; + private final Runnable updatePinCountInfo; /** * Constructor for PinningChangedListener @@ -39,10 +40,28 @@ public class PinningChangedListener extends TopicEventListener { */ public PinningChangedListener(final UIEventBus eventBus, final Class entityType, final PinSupport pinSupport) { + this(eventBus, entityType, pinSupport, null); + } + + /** + * Constructor for PinningChangedListener + * + * @param eventBus + * UIEventBus + * @param entityType + * Identifiable Entity type + * @param pinSupport + * Pin support + * @param updatePinCountInfo + * Callback to update pinned entities count info on pin change + */ + public PinningChangedListener(final UIEventBus eventBus, final Class entityType, + final PinSupport pinSupport, final Runnable updatePinCountInfo) { super(eventBus, EventTopics.PINNING_CHANGED); this.entityType = entityType; this.pinSupport = pinSupport; + this.updatePinCountInfo = updatePinCountInfo; } @EventBusListenerMethod(scope = EventScope.UI) @@ -56,6 +75,10 @@ public class PinningChangedListener extends TopicEventListener { } else { pinSupport.updatePinFilter(null); } + + if (updatePinCountInfo != null) { + updatePinCountInfo.run(); + } } private boolean suitableEntityType(final Class type) { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/TopicEventListener.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/TopicEventListener.java index 44aa8cefa..919f477c0 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/TopicEventListener.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/TopicEventListener.java @@ -11,31 +11,33 @@ package org.eclipse.hawkbit.ui.common.layout.listener; import java.util.Collection; import java.util.Collections; -import org.vaadin.spring.events.EventBus.UIEventBus; +import org.vaadin.spring.events.EventBus; /** * Abstract class for event listener */ public abstract class TopicEventListener { - private final UIEventBus eventBus; + private final EventBus eventBus; private final Collection topics; private boolean subscribed; - protected TopicEventListener(final UIEventBus eventBus, final String topic) { + protected TopicEventListener(final EventBus eventBus, final String topic) { this(eventBus, Collections.singleton(topic)); } - protected TopicEventListener(final UIEventBus eventBus, final Collection topics) { + protected TopicEventListener(final EventBus eventBus, final Collection topics) { this.eventBus = eventBus; this.topics = topics; - - subscribe(); } /** * Subscribe the event */ public void subscribe() { + if (subscribed) { + return; + } + topics.forEach(topic -> eventBus.subscribe(this, topic)); subscribed = true; } @@ -44,6 +46,10 @@ public abstract class TopicEventListener { * Unsubscribe the event */ public void unsubscribe() { + if (!subscribed) { + return; + } + eventBus.unsubscribe(this); subscribed = false; } @@ -55,7 +61,7 @@ public abstract class TopicEventListener { return subscribed; } - protected UIEventBus getEventBus() { + protected EventBus getEventBus() { return eventBus; } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/ViewAwareListener.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/ViewAwareListener.java index 909816f15..6b5b2b225 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/ViewAwareListener.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/ViewAwareListener.java @@ -30,7 +30,7 @@ public abstract class ViewAwareListener extends TopicEventListener { * @param viewAware * EventViewAware */ - public ViewAwareListener(final UIEventBus eventBus, final String topic, final EventViewAware viewAware) { + protected ViewAwareListener(final UIEventBus eventBus, final String topic, final EventViewAware viewAware) { super(eventBus, topic); this.viewAware = viewAware; @@ -46,7 +46,7 @@ public abstract class ViewAwareListener extends TopicEventListener { * @param viewAware * EventViewAware */ - public ViewAwareListener(final UIEventBus eventBus, final Collection topics, + protected ViewAwareListener(final UIEventBus eventBus, final Collection topics, final EventViewAware viewAware) { super(eventBus, topics); @@ -64,6 +64,6 @@ public abstract class ViewAwareListener extends TopicEventListener { * @return View */ public EventView getView() { - return viewAware.getView(); + return viewAware != null ? viewAware.getView() : null; } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/support/EntityModifiedCountAwareSupport.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/support/EntityModifiedCountAwareSupport.java new file mode 100644 index 000000000..c8be90284 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/support/EntityModifiedCountAwareSupport.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2021 Bosch.IO GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.ui.common.layout.listener.support; + +import java.util.Collection; + +import org.eclipse.hawkbit.ui.common.layout.CountAwareComponent; +import org.eclipse.hawkbit.ui.common.layout.listener.EntityModifiedListener.EntityModifiedAwareSupport; + +/** + * Support for entity modified adapting entities count. + */ +public class EntityModifiedCountAwareSupport implements EntityModifiedAwareSupport { + private final CountAwareComponent countAwareComponent; + + /** + * Constructor. + * + * @param countAwareComponent + * Component that adapts its count + */ + public EntityModifiedCountAwareSupport(final CountAwareComponent countAwareComponent) { + this.countAwareComponent = countAwareComponent; + } + + /** + * Static method for constructing EntityModifiedCountSupport + * + * @param countAwareComponent + * Component that adapts its count + * @return instance of {@link EntityModifiedCountAwareSupport} + */ + public static EntityModifiedCountAwareSupport of(final CountAwareComponent countAwareComponent) { + return new EntityModifiedCountAwareSupport(countAwareComponent); + } + + @Override + public void onEntitiesAdded(final Collection entityIds) { + countAwareComponent.updateCountOnEntitiesAdded(entityIds.size()); + } + + @Override + public void onEntitiesUpdated(final Collection entityIds) { + countAwareComponent.updateCountOnEntitiesUpdated(); + } + + @Override + public void onEntitiesDeleted(final Collection entityIds) { + countAwareComponent.updateCountOnEntitiesDeleted(entityIds.size()); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/softwaremodule/AbstractSoftwareModuleGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/softwaremodule/AbstractSoftwareModuleGridLayout.java index f7e42927b..965690508 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/softwaremodule/AbstractSoftwareModuleGridLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/softwaremodule/AbstractSoftwareModuleGridLayout.java @@ -45,7 +45,7 @@ public abstract class AbstractSoftwareModuleGridLayout extends AbstractGridCompo * @param eventView * EventView */ - public AbstractSoftwareModuleGridLayout(final CommonUiDependencies uiDependencies, + protected AbstractSoftwareModuleGridLayout(final CommonUiDependencies uiDependencies, final SoftwareModuleManagement softwareModuleManagement, final SoftwareModuleTypeManagement softwareModuleTypeManagement, final EventView eventView) { @@ -117,22 +117,28 @@ public abstract class AbstractSoftwareModuleGridLayout extends AbstractGridCompo showDetailsLayout(); } - /** - * Is called when view is shown to the user - */ + protected void addEventListener(final TopicEventListener listener) { + listeners.add(listener); + } + + @Override public void restoreState() { getSoftwareModuleGridHeader().restoreState(); getSoftwareModuleGrid().restoreState(); } - protected void addEventListener(final TopicEventListener listener) { - listeners.add(listener); + @Override + public void onViewEnter() { + getSoftwareModuleGrid().getSelectionSupport().reselectCurrentEntity(); } - /** - * Unsubscribe the event listeners. - */ - public void unsubscribeListener() { + @Override + public void subscribeListeners() { + listeners.forEach(TopicEventListener::subscribe); + } + + @Override + public void unsubscribeListeners() { listeners.forEach(TopicEventListener::unsubscribe); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/DistributionsView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/DistributionsView.java index a808159e5..fb843e97e 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/DistributionsView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/DistributionsView.java @@ -8,12 +8,10 @@ */ package org.eclipse.hawkbit.ui.distributions; +import java.util.Arrays; import java.util.EnumMap; import java.util.Map; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; - import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetTagManagement; @@ -28,6 +26,7 @@ import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.ui.AbstractHawkbitUI; import org.eclipse.hawkbit.ui.SpPermissionChecker; +import org.eclipse.hawkbit.ui.common.AbstractEventListenersAwareView; import org.eclipse.hawkbit.ui.common.CommonUiDependencies; import org.eclipse.hawkbit.ui.common.event.EventLayout; import org.eclipse.hawkbit.ui.common.event.EventView; @@ -47,14 +46,12 @@ import org.springframework.beans.factory.annotation.Autowired; import org.vaadin.spring.events.EventBus.UIEventBus; import com.vaadin.annotations.JavaScript; -import com.vaadin.navigator.View; import com.vaadin.server.Page; import com.vaadin.server.Page.BrowserWindowResizeEvent; import com.vaadin.server.Page.BrowserWindowResizeListener; import com.vaadin.spring.annotation.SpringView; import com.vaadin.spring.annotation.UIScope; import com.vaadin.ui.HorizontalLayout; -import com.vaadin.ui.VerticalLayout; /** * Manage distributions and distributions type view. @@ -62,7 +59,7 @@ import com.vaadin.ui.VerticalLayout; @UIScope @SpringView(name = DistributionsView.VIEW_NAME, ui = AbstractHawkbitUI.class) @JavaScript("vaadin://js/dynamicStylesheet.js") -public class DistributionsView extends VerticalLayout implements View, BrowserWindowResizeListener { +public class DistributionsView extends AbstractEventListenersAwareView implements BrowserWindowResizeListener { private static final long serialVersionUID = 1L; public static final String VIEW_NAME = "distributions"; @@ -94,8 +91,8 @@ public class DistributionsView extends VerticalLayout implements View, BrowserWi this.permChecker = permChecker; this.manageDistUIState = manageDistUIState; - final CommonUiDependencies uiDependencies = new CommonUiDependencies(i18n, entityFactory, eventBus, uiNotification, - permChecker); + final CommonUiDependencies uiDependencies = new CommonUiDependencies(i18n, entityFactory, eventBus, + uiNotification, permChecker); if (permChecker.hasReadRepositoryPermission()) { this.dsTypeFilterLayout = new DSTypeFilterLayout(uiDependencies, softwareModuleTypeManagement, @@ -113,6 +110,9 @@ public class DistributionsView extends VerticalLayout implements View, BrowserWi this.distSMTypeFilterLayout = new DistSMTypeFilterLayout(uiDependencies, softwareModuleTypeManagement, manageDistUIState.getSmTypeFilterLayoutUiState()); + addEventAwareLayouts(Arrays.asList(dsTypeFilterLayout, distributionSetGridLayout, swModuleGridLayout, + distSMTypeFilterLayout)); + final Map layoutVisibilityHandlers = new EnumMap<>(EventLayout.class); layoutVisibilityHandlers.put(EventLayout.DS_TYPE_FILTER, new VisibilityHandler(this::showDsTypeLayout, this::hideDsTypeLayout)); @@ -138,16 +138,16 @@ public class DistributionsView extends VerticalLayout implements View, BrowserWi } } - @PostConstruct - void init() { + @Override + protected void init() { if (permChecker.hasReadRepositoryPermission()) { - buildLayout(); - restoreState(); + super.init(); Page.getCurrent().addBrowserWindowResizeListener(this); } } - private void buildLayout() { + @Override + protected void buildLayout() { setMargin(false); setSpacing(false); setSizeFull(); @@ -175,24 +175,33 @@ public class DistributionsView extends VerticalLayout implements View, BrowserWi mainLayout.setExpandRatio(distSMTypeFilterLayout, 0F); } - private void restoreState() { + @Override + protected void restoreState() { + if (permChecker.hasReadRepositoryPermission()) { + restoreDsWidgetsState(); + restoreSmWidgetsState(); + } + + super.restoreState(); + } + + private void restoreDsWidgetsState() { if (manageDistUIState.getDsTypeFilterLayoutUiState().isHidden() || manageDistUIState.getSwModuleGridLayoutUiState().isMaximized()) { hideDsTypeLayout(); } else { showDsTypeLayout(); } - dsTypeFilterLayout.restoreState(); if (manageDistUIState.getDistributionSetGridLayoutUiState().isMaximized()) { maximizeDsGridLayout(); } - distributionSetGridLayout.restoreState(); + } + private void restoreSmWidgetsState() { if (manageDistUIState.getSwModuleGridLayoutUiState().isMaximized()) { maximizeSmGridLayout(); } - swModuleGridLayout.restoreState(); if (manageDistUIState.getSmTypeFilterLayoutUiState().isHidden() || manageDistUIState.getDistributionSetGridLayoutUiState().isMaximized()) { @@ -200,7 +209,6 @@ public class DistributionsView extends VerticalLayout implements View, BrowserWi } else { showSmTypeLayout(); } - distSMTypeFilterLayout.restoreState(); } private void showDsTypeLayout() { @@ -300,16 +308,28 @@ public class DistributionsView extends VerticalLayout implements View, BrowserWi } } - @PreDestroy - void destroy() { + @Override + public String getViewName() { + return DistributionsView.VIEW_NAME; + } + + @Override + protected void subscribeListeners() { + if (permChecker.hasReadRepositoryPermission()) { + layoutVisibilityListener.subscribe(); + layoutResizeListener.subscribe(); + } + + super.subscribeListeners(); + } + + @Override + protected void unsubscribeListeners() { if (permChecker.hasReadRepositoryPermission()) { layoutVisibilityListener.unsubscribe(); layoutResizeListener.unsubscribe(); - - dsTypeFilterLayout.unsubscribeListener(); - distributionSetGridLayout.unsubscribeListener(); - swModuleGridLayout.unsubscribeListener(); - distSMTypeFilterLayout.unsubscribeListener(); } + + super.unsubscribeListeners(); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/filter/DSTypeFilterButtons.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/filter/DSTypeFilterButtons.java index c1f3d6a47..e6058454b 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/filter/DSTypeFilterButtons.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/filter/DSTypeFilterButtons.java @@ -109,4 +109,9 @@ public class DSTypeFilterButtons extends AbstractTypeFilterButtons { protected Window getUpdateWindow(final ProxyType clickedFilter) { return dsTypeWindowBuilder.getWindowForUpdate(clickedFilter); } + + @Override + protected boolean typeExists(final Long typeId) { + return distributionSetTypeManagement.exists(typeId); + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/filter/DSTypeFilterLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/filter/DSTypeFilterLayout.java index df0b92305..337b929bf 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/filter/DSTypeFilterLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/filter/DSTypeFilterLayout.java @@ -65,20 +65,22 @@ public class DSTypeFilterLayout extends AbstractFilterLayout { final DistributionSetTypeManagement distributionSetTypeManagement, final DistributionSetManagement distributionSetManagement, final SystemManagement systemManagement, final TypeFilterLayoutUiState dSTypeFilterLayoutUiState) { - final DsTypeWindowBuilder dsTypeWindowBuilder = new DsTypeWindowBuilder(uiDependencies, distributionSetTypeManagement, - distributionSetManagement, softwareModuleTypeManagement); + final DsTypeWindowBuilder dsTypeWindowBuilder = new DsTypeWindowBuilder(uiDependencies, + distributionSetTypeManagement, distributionSetManagement, softwareModuleTypeManagement); - this.dsTypeFilterHeader = new DSTypeFilterHeader(uiDependencies, dsTypeWindowBuilder, dSTypeFilterLayoutUiState); - this.dSTypeFilterButtons = new DSTypeFilterButtons(uiDependencies, distributionSetTypeManagement, systemManagement, - dsTypeWindowBuilder, dSTypeFilterLayoutUiState); + this.dsTypeFilterHeader = new DSTypeFilterHeader(uiDependencies, dsTypeWindowBuilder, + dSTypeFilterLayoutUiState); + this.dSTypeFilterButtons = new DSTypeFilterButtons(uiDependencies, distributionSetTypeManagement, + systemManagement, dsTypeWindowBuilder, dSTypeFilterLayoutUiState); + final EventLayoutViewAware layoutViewAware = new EventLayoutViewAware(EventLayout.DS_TYPE_FILTER, + EventView.DISTRIBUTIONS); this.gridActionsVisibilityListener = new GridActionsVisibilityListener(uiDependencies.getEventBus(), - new EventLayoutViewAware(EventLayout.DS_TYPE_FILTER, EventView.DISTRIBUTIONS), - dSTypeFilterButtons::hideActionColumns, dSTypeFilterButtons::showEditColumn, + layoutViewAware, dSTypeFilterButtons::hideActionColumns, dSTypeFilterButtons::showEditColumn, dSTypeFilterButtons::showDeleteColumn); - this.entityModifiedListener = new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), ProxyType.class) - .entityModifiedAwareSupports(getEntityModifiedAwareSupports()) - .parentEntityType(ProxyDistributionSet.class).build(); + this.entityModifiedListener = new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), + ProxyType.class).parentEntityType(ProxyDistributionSet.class).viewAware(layoutViewAware) + .entityModifiedAwareSupports(getEntityModifiedAwareSupports()).build(); buildLayout(); } @@ -98,17 +100,24 @@ public class DSTypeFilterLayout extends AbstractFilterLayout { return wrapFilterContent(dSTypeFilterButtons); } - /** - * Restore state of distribution set filter button - */ + @Override public void restoreState() { dSTypeFilterButtons.restoreState(); } - /** - * Unsubscribe event listener - */ - public void unsubscribeListener() { + @Override + public void onViewEnter() { + dSTypeFilterButtons.reevaluateFilter(); + } + + @Override + public void subscribeListeners() { + gridActionsVisibilityListener.subscribe(); + entityModifiedListener.subscribe(); + } + + @Override + public void unsubscribeListeners() { gridActionsVisibilityListener.unsubscribe(); entityModifiedListener.unsubscribe(); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetGridLayout.java index 51adbd93b..a474e1c7b 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetGridLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetGridLayout.java @@ -32,7 +32,6 @@ import org.eclipse.hawkbit.ui.common.distributionset.DistributionSetGridHeader; 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.EventViewAware; 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; @@ -110,25 +109,25 @@ public class DistributionSetGridLayout extends AbstractDistributionSetGridLayout this.distributionSetDetailsHeader = new DistributionSetDetailsHeader(uiDependencies, getDsWindowBuilder(), getDsMetaDataWindowBuilder()); - this.distributionSetDetails = new DistributionSetDetails(uiDependencies, distributionSetManagement, smManagement, - distributionSetTypeManagement, distributionSetTagManagement, configManagement, systemSecurityContext, - getDsMetaDataWindowBuilder()); + this.distributionSetDetails = new DistributionSetDetails(uiDependencies, distributionSetManagement, + smManagement, distributionSetTypeManagement, distributionSetTagManagement, configManagement, + systemSecurityContext, getDsMetaDataWindowBuilder()); this.distributionSetDetails.setUnassignSmAllowed(true); this.distributionSetDetails.addTfqDetailsGrid(targetFilterQueryManagement); this.distributionSetDetails.buildDetails(); + final EventLayoutViewAware layoutViewAware = new EventLayoutViewAware(EventLayout.DS_LIST, getEventView()); addEventListener(new FilterChangedListener<>(uiDependencies.getEventBus(), ProxyDistributionSet.class, - new EventViewAware(getEventView()), distributionSetGrid.getFilterSupport())); - addEventListener(new SelectionChangedListener<>(uiDependencies.getEventBus(), - new EventLayoutViewAware(EventLayout.DS_LIST, getEventView()), getDsEntityAwareComponents())); - addEventListener(new SelectGridEntityListener<>(uiDependencies.getEventBus(), - new EventLayoutViewAware(EventLayout.DS_LIST, getEventView()), + layoutViewAware, distributionSetGrid.getFilterSupport())); + addEventListener(new SelectionChangedListener<>(uiDependencies.getEventBus(), layoutViewAware, + getDsEntityAwareComponents())); + addEventListener(new SelectGridEntityListener<>(uiDependencies.getEventBus(), layoutViewAware, distributionSetGrid.getSelectionSupport())); addEventListener(new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), ProxyDistributionSet.class) - .entityModifiedAwareSupports(getDsModifiedAwareSupports()).build()); + .viewAware(layoutViewAware).entityModifiedAwareSupports(getDsModifiedAwareSupports()).build()); addEventListener(new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), ProxyTag.class) - .entityModifiedAwareSupports(getTagModifiedAwareSupports()).parentEntityType(ProxyDistributionSet.class) - .build()); + .parentEntityType(ProxyDistributionSet.class).viewAware(layoutViewAware) + .entityModifiedAwareSupports(getTagModifiedAwareSupports()).build()); buildLayout(distributionSetGridHeader, distributionSetGrid, distributionSetDetailsHeader, distributionSetDetails); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtable/SwModuleGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtable/SwModuleGridLayout.java index 0ea7ddf15..5905460d4 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtable/SwModuleGridLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtable/SwModuleGridLayout.java @@ -25,7 +25,6 @@ import org.eclipse.hawkbit.ui.common.detailslayout.SoftwareModuleDetailsHeader; 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.EventViewAware; 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; @@ -65,7 +64,8 @@ public class SwModuleGridLayout extends AbstractSoftwareModuleGridLayout { * @param swModuleGridLayoutUiState * GridLayoutUiState */ - public SwModuleGridLayout(final CommonUiDependencies uiDependencies, final SoftwareModuleManagement softwareModuleManagement, + public SwModuleGridLayout(final CommonUiDependencies uiDependencies, + final SoftwareModuleManagement softwareModuleManagement, final SoftwareModuleTypeManagement softwareModuleTypeManagement, final ArtifactManagement artifactManagement, final TypeFilterLayoutUiState smTypeFilterLayoutUiState, final GridLayoutUiState swModuleGridLayoutUiState) { @@ -88,16 +88,18 @@ public class SwModuleGridLayout extends AbstractSoftwareModuleGridLayout { softwareModuleTypeManagement, getSmMetaDataWindowBuilder()); this.swModuleDetails.buildDetails(); + final EventLayoutViewAware smLayoutViewAware = new EventLayoutViewAware(EventLayout.SM_LIST, getEventView()); + final EventLayoutViewAware dsLayoutViewAware = new EventLayoutViewAware(EventLayout.DS_LIST, getEventView()); addEventListener(new FilterChangedListener<>(uiDependencies.getEventBus(), ProxySoftwareModule.class, - new EventViewAware(getEventView()), swModuleGrid.getFilterSupport())); - addEventListener(new SelectionChangedListener<>(uiDependencies.getEventBus(), - new EventLayoutViewAware(EventLayout.DS_LIST, getEventView()), getMasterDsAwareComponents())); - addEventListener(new SelectionChangedListener<>(uiDependencies.getEventBus(), - new EventLayoutViewAware(EventLayout.SM_LIST, getEventView()), getMasterSmAwareComponents())); - addEventListener(new SelectGridEntityListener<>(uiDependencies.getEventBus(), - new EventLayoutViewAware(EventLayout.SM_LIST, getEventView()), swModuleGrid.getSelectionSupport())); + smLayoutViewAware, swModuleGrid.getFilterSupport())); + addEventListener(new SelectionChangedListener<>(uiDependencies.getEventBus(), dsLayoutViewAware, + getMasterDsAwareComponents())); + addEventListener(new SelectionChangedListener<>(uiDependencies.getEventBus(), smLayoutViewAware, + getMasterSmAwareComponents())); + addEventListener(new SelectGridEntityListener<>(uiDependencies.getEventBus(), smLayoutViewAware, + swModuleGrid.getSelectionSupport())); addEventListener(new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), ProxySoftwareModule.class) - .entityModifiedAwareSupports(getSmModifiedAwareSupports()).build()); + .viewAware(smLayoutViewAware).entityModifiedAwareSupports(getSmModifiedAwareSupports()).build()); buildLayout(swModuleGridHeader, swModuleGrid, softwareModuleDetailsHeader, swModuleDetails); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/error/extractors/EntityNotFoundErrorExtractor.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/error/extractors/EntityNotFoundErrorExtractor.java new file mode 100644 index 000000000..36aea48fe --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/error/extractors/EntityNotFoundErrorExtractor.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2021 Bosch.IO GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.ui.error.extractors; + +import java.util.Optional; + +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.ui.error.UiErrorDetails; +import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; + +/** + * UI error details extractor for {@link EntityNotFoundException}. + */ +public class EntityNotFoundErrorExtractor extends AbstractSingleUiErrorDetailsExtractor { + private final VaadinMessageSource i18n; + + /** + * Constructor for EntityNotFoundErrorExtractor. + * + * @param i18n + * Message source used for localization + */ + public EntityNotFoundErrorExtractor(final VaadinMessageSource i18n) { + this.i18n = i18n; + } + + @Override + protected Optional findDetails(final Throwable error) { + return findExceptionOf(error, EntityNotFoundException.class) + .map(ex -> UiErrorDetails.create(i18n.getMessage("caption.entity.missing.error"), ex.getMessage())); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/FilterManagementView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/FilterManagementView.java index 123f737a9..e09f44af2 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/FilterManagementView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/FilterManagementView.java @@ -8,12 +8,10 @@ */ package org.eclipse.hawkbit.ui.filtermanagement; +import java.util.Arrays; import java.util.EnumMap; import java.util.Map; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; - import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; @@ -22,6 +20,7 @@ import org.eclipse.hawkbit.repository.rsql.RsqlValidationOracle; import org.eclipse.hawkbit.ui.AbstractHawkbitUI; import org.eclipse.hawkbit.ui.SpPermissionChecker; import org.eclipse.hawkbit.ui.UiProperties; +import org.eclipse.hawkbit.ui.common.AbstractEventListenersAwareView; import org.eclipse.hawkbit.ui.common.CommonUiDependencies; import org.eclipse.hawkbit.ui.common.data.suppliers.TargetFilterStateDataSupplier; import org.eclipse.hawkbit.ui.common.event.EventLayout; @@ -36,18 +35,16 @@ import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; import org.springframework.beans.factory.annotation.Autowired; import org.vaadin.spring.events.EventBus.UIEventBus; -import com.vaadin.navigator.View; import com.vaadin.spring.annotation.SpringView; import com.vaadin.spring.annotation.UIScope; import com.vaadin.ui.Alignment; -import com.vaadin.ui.VerticalLayout; /** * View for custom target filter management. */ @UIScope @SpringView(name = FilterManagementView.VIEW_NAME, ui = AbstractHawkbitUI.class) -public class FilterManagementView extends VerticalLayout implements View { +public class FilterManagementView extends AbstractEventListenersAwareView { private static final long serialVersionUID = 1L; public static final String VIEW_NAME = "targetFilters"; @@ -78,6 +75,8 @@ public class FilterManagementView extends VerticalLayout implements View { rsqlValidationOracle, targetFilterQueryManagement, targetFilterStateDataSupplier, filterManagementUIState.getDetailsLayoutUiState()); + addEventAwareLayouts(Arrays.asList(targetFilterGridLayout, targetFilterDetailsLayout)); + final Map layoutVisibilityHandlers = new EnumMap<>(EventLayout.class); layoutVisibilityHandlers.put(EventLayout.TARGET_FILTER_QUERY_LIST, new VisibilityHandler(this::showTfqListLayout, this::showTfqFormLayout)); @@ -87,13 +86,8 @@ public class FilterManagementView extends VerticalLayout implements View { new EventViewAware(EventView.TARGET_FILTER), layoutVisibilityHandlers); } - @PostConstruct - void init() { - buildLayout(); - restoreState(); - } - - private void buildLayout() { + @Override + protected void buildLayout() { setMargin(false); setSpacing(false); setSizeFull(); @@ -120,21 +114,33 @@ public class FilterManagementView extends VerticalLayout implements View { targetFilterDetailsLayout.setVisible(true); } - private void restoreState() { + @Override + protected void restoreState() { if (FilterView.FILTERS == filterManagementUIState.getCurrentView()) { showTfqListLayout(); } else if (FilterView.DETAILS == filterManagementUIState.getCurrentView()) { showTfqFormLayout(); } - targetFilterDetailsLayout.restoreState(); - targetFilterGridLayout.restoreState(); + + super.restoreState(); } - @PreDestroy - void destroy() { + @Override + public String getViewName() { + return FilterManagementView.VIEW_NAME; + } + + @Override + protected void subscribeListeners() { + layoutVisibilityListener.subscribe(); + + super.subscribeListeners(); + } + + @Override + protected void unsubscribeListeners() { layoutVisibilityListener.unsubscribe(); - targetFilterGridLayout.unsubscribeListener(); - targetFilterDetailsLayout.unsubscribeListener(); + super.unsubscribeListeners(); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterDetailsLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterDetailsLayout.java index 5a66742cf..7f6555d58 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterDetailsLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterDetailsLayout.java @@ -66,13 +66,15 @@ public class TargetFilterDetailsLayout extends AbstractGridComponentLayout { initGridDataUpdatedListener(); + final EventViewAware viewAware = new EventViewAware(EventView.TARGET_FILTER); + final EventLayoutViewAware layoutViewAware = new EventLayoutViewAware(EventLayout.TARGET_FILTER_QUERY_FORM, + EventView.TARGET_FILTER); + this.showFilterQueryFormListener = new ShowEntityFormLayoutListener<>(uiDependencies.getEventBus(), - ProxyTargetFilterQuery.class, - new EventLayoutViewAware(EventLayout.TARGET_FILTER_QUERY_FORM, EventView.TARGET_FILTER), - targetFilterDetailsGridHeader::showAddFilterLayout, + ProxyTargetFilterQuery.class, layoutViewAware, targetFilterDetailsGridHeader::showAddFilterLayout, targetFilterDetailsGridHeader::showEditFilterLayout); this.targetFilterListener = new FilterChangedListener<>(uiDependencies.getEventBus(), ProxyTarget.class, - new EventViewAware(EventView.TARGET_FILTER), targetFilterTargetGrid.getFilterSupport()); + viewAware, targetFilterTargetGrid.getFilterSupport()); buildLayout(targetFilterDetailsGridHeader, targetFilterTargetGrid, targetFilterCountMessageLabel); } @@ -82,9 +84,7 @@ public class TargetFilterDetailsLayout extends AbstractGridComponentLayout { .updateTotalFilteredTargetsCount(targetFilterTargetGrid.getDataSize())); } - /** - * restore the saved state - */ + @Override public void restoreState() { targetFilterDetailsGridHeader.restoreState(); if (targetFilterDetailsGridHeader.isFilterQueryValid()) { @@ -92,10 +92,14 @@ public class TargetFilterDetailsLayout extends AbstractGridComponentLayout { } } - /** - * unsubscribe all listener - */ - public void unsubscribeListener() { + @Override + public void subscribeListeners() { + showFilterQueryFormListener.subscribe(); + targetFilterListener.subscribe(); + } + + @Override + public void unsubscribeListeners() { showFilterQueryFormListener.unsubscribe(); targetFilterListener.unsubscribe(); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterGridLayout.java index 6280d12e7..2043f428f 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterGridLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterGridLayout.java @@ -64,12 +64,12 @@ public class TargetFilterGridLayout extends AbstractGridComponentLayout { this.targetFilterGrid = new TargetFilterGrid(uiDependencies, filterManagementUIState.getGridLayoutUiState(), targetFilterQueryManagement, autoAssignmentWindowBuilder); + final EventViewAware viewAware = new EventViewAware(EventView.TARGET_FILTER); this.targetQueryFilterListener = new FilterChangedListener<>(uiDependencies.getEventBus(), - ProxyTargetFilterQuery.class, new EventViewAware(EventView.TARGET_FILTER), - targetFilterGrid.getFilterSupport()); + ProxyTargetFilterQuery.class, viewAware, targetFilterGrid.getFilterSupport()); this.filterQueryModifiedListener = new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), - ProxyTargetFilterQuery.class).entityModifiedAwareSupports(getFilterQueryModifiedAwareSupports()) - .build(); + ProxyTargetFilterQuery.class).viewAware(viewAware) + .entityModifiedAwareSupports(getFilterQueryModifiedAwareSupports()).build(); buildLayout(targetFilterGridHeader, targetFilterGrid); } @@ -78,18 +78,20 @@ public class TargetFilterGridLayout extends AbstractGridComponentLayout { return Collections.singletonList(EntityModifiedGridRefreshAwareSupport.of(targetFilterGrid::refreshAll)); } - /** - * restore the saved state - */ + @Override public void restoreState() { targetFilterGridHeader.restoreState(); targetFilterGrid.restoreState(); } - /** - * unsubscribe all listener - */ - public void unsubscribeListener() { + @Override + public void subscribeListeners() { + targetQueryFilterListener.subscribe(); + filterQueryModifiedListener.subscribe(); + } + + @Override + public void unsubscribeListeners() { targetQueryFilterListener.unsubscribe(); filterQueryModifiedListener.unsubscribe(); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/DeploymentView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/DeploymentView.java index 73b8ccdd6..c0adaa8e9 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/DeploymentView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/DeploymentView.java @@ -8,13 +8,11 @@ */ package org.eclipse.hawkbit.ui.management; +import java.util.Arrays; import java.util.EnumMap; import java.util.Map; import java.util.concurrent.Executor; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; - import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetTagManagement; @@ -30,6 +28,7 @@ import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.ui.AbstractHawkbitUI; import org.eclipse.hawkbit.ui.SpPermissionChecker; import org.eclipse.hawkbit.ui.UiProperties; +import org.eclipse.hawkbit.ui.common.AbstractEventListenersAwareView; import org.eclipse.hawkbit.ui.common.CommonUiDependencies; import org.eclipse.hawkbit.ui.common.data.suppliers.TargetManagementStateDataSupplier; import org.eclipse.hawkbit.ui.common.event.EventLayout; @@ -51,7 +50,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.vaadin.spring.events.EventBus.UIEventBus; -import com.vaadin.navigator.View; import com.vaadin.server.Page; import com.vaadin.server.Page.BrowserWindowResizeEvent; import com.vaadin.server.Page.BrowserWindowResizeListener; @@ -59,14 +57,13 @@ import com.vaadin.spring.annotation.SpringView; import com.vaadin.spring.annotation.UIScope; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Layout; -import com.vaadin.ui.VerticalLayout; /** * Target status and deployment management view */ @UIScope @SpringView(name = DeploymentView.VIEW_NAME, ui = AbstractHawkbitUI.class) -public class DeploymentView extends VerticalLayout implements View, BrowserWindowResizeListener { +public class DeploymentView extends AbstractEventListenersAwareView implements BrowserWindowResizeListener { private static final long serialVersionUID = 1L; public static final String VIEW_NAME = "deployment"; @@ -120,6 +117,8 @@ public class DeploymentView extends VerticalLayout implements View, BrowserWindo this.actionHistoryLayout = new ActionHistoryLayout(uiDependencies, deploymentManagement, managementUIState.getActionHistoryGridLayoutUiState()); + + addEventAwareLayouts(Arrays.asList(targetTagFilterLayout, targetGridLayout, actionHistoryLayout)); } else { this.targetTagFilterLayout = null; this.targetGridLayout = null; @@ -136,6 +135,8 @@ public class DeploymentView extends VerticalLayout implements View, BrowserWindo systemSecurityContext, uiProperties, managementUIState.getDistributionGridLayoutUiState(), managementUIState.getDistributionTagLayoutUiState(), managementUIState.getTargetGridLayoutUiState()); + + addEventAwareLayouts(Arrays.asList(distributionTagLayout, distributionGridLayout)); } else { this.distributionTagLayout = null; this.distributionGridLayout = null; @@ -165,16 +166,16 @@ public class DeploymentView extends VerticalLayout implements View, BrowserWindo } } - @PostConstruct - void init() { + @Override + protected void init() { if (permChecker.hasTargetReadPermission() || permChecker.hasReadRepositoryPermission()) { - buildLayout(); - restoreState(); + super.init(); Page.getCurrent().addBrowserWindowResizeListener(this); } } - private void buildLayout() { + @Override + protected void buildLayout() { setMargin(false); setSpacing(false); setSizeFull(); @@ -248,7 +249,8 @@ public class DeploymentView extends VerticalLayout implements View, BrowserWindo mainLayout.setExpandRatio(actionHistoryLayout, 0.6F); } - private void restoreState() { + @Override + protected void restoreState() { if (permChecker.hasTargetReadPermission()) { restoreTargetWidgetsState(); } @@ -256,6 +258,8 @@ public class DeploymentView extends VerticalLayout implements View, BrowserWindo if (permChecker.hasReadRepositoryPermission()) { restoreDsWidgetsState(); } + + super.restoreState(); } private void restoreTargetWidgetsState() { @@ -266,17 +270,14 @@ public class DeploymentView extends VerticalLayout implements View, BrowserWindo } else { showTargetTagLayout(); } - targetTagFilterLayout.restoreState(); if (managementUIState.getTargetGridLayoutUiState().isMaximized()) { maximizeTargetGridLayout(); } - targetGridLayout.restoreState(); if (managementUIState.getActionHistoryGridLayoutUiState().isMaximized()) { maximizeActionHistoryGridLayout(); } - actionHistoryLayout.restoreState(); } private void restoreDsWidgetsState() { @@ -287,12 +288,10 @@ public class DeploymentView extends VerticalLayout implements View, BrowserWindo } else { showDsTagLayout(); } - distributionTagLayout.restoreState(); if (managementUIState.getDistributionGridLayoutUiState().isMaximized()) { maximizeDsGridLayout(); } - distributionGridLayout.restoreState(); } private void showTargetTagLayout() { @@ -459,22 +458,28 @@ public class DeploymentView extends VerticalLayout implements View, BrowserWindo } } - @PreDestroy - void destroy() { + @Override + public String getViewName() { + return DeploymentView.VIEW_NAME; + } + + @Override + protected void subscribeListeners() { + if (permChecker.hasTargetReadPermission() || permChecker.hasReadRepositoryPermission()) { + layoutVisibilityListener.subscribe(); + layoutResizeListener.subscribe(); + } + + super.subscribeListeners(); + } + + @Override + protected void unsubscribeListeners() { if (permChecker.hasTargetReadPermission() || permChecker.hasReadRepositoryPermission()) { layoutVisibilityListener.unsubscribe(); layoutResizeListener.unsubscribe(); } - if (permChecker.hasTargetReadPermission()) { - targetTagFilterLayout.unsubscribeListener(); - targetGridLayout.unsubscribeListener(); - actionHistoryLayout.unsubscribeListener(); - } - - if (permChecker.hasReadRepositoryPermission()) { - distributionTagLayout.unsubscribeListener(); - distributionGridLayout.unsubscribeListener(); - } + super.unsubscribeListeners(); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/ManagementUIState.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/ManagementUIState.java index 099538bcf..a12e14043 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/ManagementUIState.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/ManagementUIState.java @@ -10,12 +10,16 @@ package org.eclipse.hawkbit.ui.management; import java.io.Serializable; +import javax.annotation.PreDestroy; + +import org.eclipse.hawkbit.ui.common.layout.listener.BulkUploadChangedListener; import org.eclipse.hawkbit.ui.common.state.TagFilterLayoutUiState; import org.eclipse.hawkbit.ui.management.actionhistory.ActionHistoryGridLayoutUiState; import org.eclipse.hawkbit.ui.management.bulkupload.TargetBulkUploadUiState; import org.eclipse.hawkbit.ui.management.dstable.DistributionGridLayoutUiState; import org.eclipse.hawkbit.ui.management.targettable.TargetGridLayoutUiState; import org.eclipse.hawkbit.ui.management.targettag.filter.TargetTagFilterLayoutUiState; +import org.vaadin.spring.events.EventBus.SessionEventBus; import com.vaadin.spring.annotation.SpringComponent; import com.vaadin.spring.annotation.VaadinSessionScope; @@ -28,6 +32,8 @@ import com.vaadin.spring.annotation.VaadinSessionScope; public class ManagementUIState implements Serializable { private static final long serialVersionUID = 1L; + private final transient BulkUploadChangedListener bulkUploadListener; + private final TargetTagFilterLayoutUiState targetTagFilterLayoutUiState; private final TargetGridLayoutUiState targetGridLayoutUiState; private final TargetBulkUploadUiState targetBulkUploadUiState; @@ -35,7 +41,7 @@ public class ManagementUIState implements Serializable { private final TagFilterLayoutUiState distributionTagLayoutUiState; private final ActionHistoryGridLayoutUiState actionHistoryGridLayoutUiState; - ManagementUIState() { + ManagementUIState(final SessionEventBus sessionEventBus) { this.targetTagFilterLayoutUiState = new TargetTagFilterLayoutUiState(); this.targetGridLayoutUiState = new TargetGridLayoutUiState(); this.targetBulkUploadUiState = new TargetBulkUploadUiState(); @@ -43,11 +49,15 @@ public class ManagementUIState implements Serializable { this.distributionTagLayoutUiState = new TagFilterLayoutUiState(); this.actionHistoryGridLayoutUiState = new ActionHistoryGridLayoutUiState(); + this.bulkUploadListener = new BulkUploadChangedListener(sessionEventBus, + targetBulkUploadUiState::onBulkUploadChanged); + init(); } private void init() { distributionTagLayoutUiState.setHidden(true); + bulkUploadListener.subscribe(); } /** @@ -91,4 +101,9 @@ public class ManagementUIState implements Serializable { public TargetBulkUploadUiState getTargetBulkUploadUiState() { return targetBulkUploadUiState; } + + @PreDestroy + public void destroy() { + bulkUploadListener.unsubscribe(); + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionHistoryGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionHistoryGridLayout.java index 576f9622a..73d5d1f58 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionHistoryGridLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionHistoryGridLayout.java @@ -49,19 +49,21 @@ public class ActionHistoryGridLayout extends AbstractGridComponentLayout { * @param actionHistoryGridLayoutUiState * ActionHistoryGridLayoutUiState */ - public ActionHistoryGridLayout(final CommonUiDependencies uiDependencies, final DeploymentManagement deploymentManagement, + public ActionHistoryGridLayout(final CommonUiDependencies uiDependencies, + final DeploymentManagement deploymentManagement, final ActionHistoryGridLayoutUiState actionHistoryGridLayoutUiState) { this.actionHistoryHeader = new ActionHistoryGridHeader(uiDependencies, actionHistoryGridLayoutUiState); - this.actionHistoryGrid = new ActionHistoryGrid(uiDependencies, deploymentManagement, actionHistoryGridLayoutUiState); + this.actionHistoryGrid = new ActionHistoryGrid(uiDependencies, deploymentManagement, + actionHistoryGridLayoutUiState); final EventLayoutViewAware masterLayoutView = new EventLayoutViewAware(EventLayout.TARGET_LIST, EventView.DEPLOYMENT); - - this.masterEntityChangedListener = new SelectionChangedListener<>(uiDependencies.getEventBus(), masterLayoutView, - getMasterEntityAwareComponents()); - this.entityModifiedListener = new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), ProxyAction.class) - .entityModifiedAwareSupports(getEntityModifiedAwareSupports()).parentEntityType(ProxyTarget.class) - .parentEntityIdProvider(this::getMasterEntityId).build(); + this.masterEntityChangedListener = new SelectionChangedListener<>(uiDependencies.getEventBus(), + masterLayoutView, getMasterEntityAwareComponents()); + this.entityModifiedListener = new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), + ProxyAction.class).parentEntityType(ProxyTarget.class).parentEntityIdProvider(this::getMasterEntityId) + .viewAware(masterLayoutView).entityModifiedAwareSupports(getEntityModifiedAwareSupports()) + .build(); buildLayout(actionHistoryHeader, actionHistoryGrid); } @@ -95,17 +97,24 @@ public class ActionHistoryGridLayout extends AbstractGridComponentLayout { actionHistoryGrid.createMinimizedContent(); } - /** - * restore action histors header - */ + @Override public void restoreState() { actionHistoryHeader.restoreState(); } - /** - * Unsubscribe the changed listener - */ - public void unsubscribeListener() { + @Override + public void onViewEnter() { + actionHistoryGrid.getSelectionSupport().reselectCurrentEntity(); + } + + @Override + public void subscribeListeners() { + entityModifiedListener.subscribe(); + masterEntityChangedListener.subscribe(); + } + + @Override + public void unsubscribeListeners() { entityModifiedListener.unsubscribe(); masterEntityChangedListener.unsubscribe(); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionHistoryLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionHistoryLayout.java index 12daf1548..76dc25b86 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionHistoryLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionHistoryLayout.java @@ -10,13 +10,14 @@ package org.eclipse.hawkbit.ui.management.actionhistory; import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.ui.common.CommonUiDependencies; +import org.eclipse.hawkbit.ui.common.EventListenersAwareLayout; import com.vaadin.ui.HorizontalLayout; /** * Layout responsible for action-history-grid and the corresponding header. */ -public class ActionHistoryLayout extends HorizontalLayout { +public class ActionHistoryLayout extends HorizontalLayout implements EventListenersAwareLayout { private static final long serialVersionUID = 1L; private final ActionHistoryGridLayout actionHistoryGridLayout; @@ -33,7 +34,8 @@ public class ActionHistoryLayout extends HorizontalLayout { * @param actionHistoryGridLayoutUiState * ActionHistoryGridLayoutUiState */ - public ActionHistoryLayout(final CommonUiDependencies uiDependencies, final DeploymentManagement deploymentManagement, + public ActionHistoryLayout(final CommonUiDependencies uiDependencies, + final DeploymentManagement deploymentManagement, final ActionHistoryGridLayoutUiState actionHistoryGridLayoutUiState) { this.actionHistoryGridLayout = new ActionHistoryGridLayout(uiDependencies, deploymentManagement, @@ -65,13 +67,6 @@ public class ActionHistoryLayout extends HorizontalLayout { setExpandRatio(actionStatusMsgLayout, 0.27F); } - /** - * Restore the action history grid layout - */ - public void restoreState() { - actionHistoryGridLayout.restoreState(); - } - /** * Maximize the action history grid layout */ @@ -98,12 +93,27 @@ public class ActionHistoryLayout extends HorizontalLayout { actionStatusMsgLayout.setVisible(false); } - /** - * Unsubscribe the changed listener - */ - public void unsubscribeListener() { - actionHistoryGridLayout.unsubscribeListener(); - actionStatusLayout.unsubscribeListener(); - actionStatusMsgLayout.unsubscribeListener(); + @Override + public void restoreState() { + actionHistoryGridLayout.restoreState(); + } + + @Override + public void onViewEnter() { + actionHistoryGridLayout.onViewEnter(); + } + + @Override + public void subscribeListeners() { + actionHistoryGridLayout.subscribeListeners(); + actionStatusLayout.subscribeListeners(); + actionStatusMsgLayout.subscribeListeners(); + } + + @Override + public void unsubscribeListeners() { + actionHistoryGridLayout.unsubscribeListeners(); + actionStatusLayout.unsubscribeListeners(); + actionStatusMsgLayout.unsubscribeListeners(); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionStatusGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionStatusGridLayout.java index a7a229900..bedb7601a 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionStatusGridLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionStatusGridLayout.java @@ -41,7 +41,8 @@ public class ActionStatusGridLayout extends AbstractGridComponentLayout { * @param deploymentManagement * DeploymentManagement */ - public ActionStatusGridLayout(final CommonUiDependencies uiDependencies, final DeploymentManagement deploymentManagement) { + public ActionStatusGridLayout(final CommonUiDependencies uiDependencies, + final DeploymentManagement deploymentManagement) { this.actionStatusGridHeader = new ActionStatusGridHeader(uiDependencies.getI18n()); this.actionStatusGrid = new ActionStatusGrid(uiDependencies, deploymentManagement); @@ -96,10 +97,13 @@ public class ActionStatusGridLayout extends AbstractGridComponentLayout { actionStatusGrid.getSelectionSupport().disableSelection(); } - /** - * Unsubscribe the changed listener - */ - public void unsubscribeListener() { + @Override + public void subscribeListeners() { + selectionChangedListener.subscribe(); + } + + @Override + public void unsubscribeListeners() { selectionChangedListener.unsubscribe(); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionStatusMsgGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionStatusMsgGridLayout.java index f4a30ec91..d02055023 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionStatusMsgGridLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionStatusMsgGridLayout.java @@ -40,7 +40,8 @@ public class ActionStatusMsgGridLayout extends AbstractGridComponentLayout { * @param deploymentManagement * DeploymentManagement */ - public ActionStatusMsgGridLayout(final CommonUiDependencies uiDependencies, final DeploymentManagement deploymentManagement) { + public ActionStatusMsgGridLayout(final CommonUiDependencies uiDependencies, + final DeploymentManagement deploymentManagement) { this.actionStatusMsgHeader = new ActionStatusMsgGridHeader(uiDependencies.getI18n()); this.actionStatusMsgGrid = new ActionStatusMsgGrid(uiDependencies, deploymentManagement); @@ -79,10 +80,13 @@ public class ActionStatusMsgGridLayout extends AbstractGridComponentLayout { actionStatusMsgGrid.getSelectionSupport().disableSelection(); } - /** - * Unsubscribe the changed listener - */ - public void unsubscribeListener() { + @Override + public void subscribeListeners() { + selectionChangedListener.subscribe(); + } + + @Override + public void unsubscribeListeners() { selectionChangedListener.unsubscribe(); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/bulkupload/BulkUploadWindowBuilder.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/bulkupload/BulkUploadWindowBuilder.java index 00ed4c3e8..515d30f39 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/bulkupload/BulkUploadWindowBuilder.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/bulkupload/BulkUploadWindowBuilder.java @@ -82,6 +82,7 @@ public class BulkUploadWindowBuilder { targetBulkUpdateWindowLayout = new TargetBulkUpdateWindowLayout(uiDependencies, targetManagement, deploymentManagement, tagManagement, distributionSetManagement, uiproperties, uiExecutor, targetBulkUploadUiState); + targetBulkUpdateWindowLayout.clearUiState(); } final Window bulkUploadWindow = new WindowBuilder(SPUIDefinitions.CREATE_UPDATE_WINDOW) diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/bulkupload/TargetBulkUploadUiState.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/bulkupload/TargetBulkUploadUiState.java index 8cbb0e0e6..f5aa716aa 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/bulkupload/TargetBulkUploadUiState.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/bulkupload/TargetBulkUploadUiState.java @@ -13,6 +13,7 @@ import java.util.HashMap; import java.util.Map; import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSetInfo; +import org.eclipse.hawkbit.ui.common.event.BulkUploadEventPayload; /** * Target bulk upload ui state @@ -94,4 +95,26 @@ public class TargetBulkUploadUiState implements Serializable { public void setDescription(final String description) { this.description = description; } + + /** + * Updates state on bulk upload events + * + * @param eventPayload + * BulkUploadEventPayload + */ + public void onBulkUploadChanged(final BulkUploadEventPayload eventPayload) { + switch (eventPayload.getBulkUploadState()) { + case UPLOAD_STARTED: + setInProgress(true); + break; + case UPLOAD_FAILED: + setInProgress(false); + break; + case BULK_UPLOAD_COMPLETED: + setInProgress(false); + break; + default: + break; + } + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionGridLayout.java index c75ca96a1..8f5b884a7 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionGridLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionGridLayout.java @@ -33,7 +33,6 @@ import org.eclipse.hawkbit.ui.common.distributionset.DistributionSetGridHeader; 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.EventViewAware; 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; @@ -119,17 +118,18 @@ public class DistributionGridLayout extends AbstractDistributionSetGridLayout { this.distributionDetails.setUnassignSmAllowed(false); this.distributionDetails.buildDetails(); + final EventLayoutViewAware layoutViewAware = new EventLayoutViewAware(EventLayout.DS_LIST, getEventView()); addEventListener(new FilterChangedListener<>(uiDependencies.getEventBus(), ProxyDistributionSet.class, - new EventViewAware(getEventView()), distributionGrid.getFilterSupport())); + layoutViewAware, distributionGrid.getFilterSupport())); addEventListener(new PinningChangedListener<>(uiDependencies.getEventBus(), ProxyTarget.class, distributionGrid.getPinSupport())); - addEventListener(new SelectionChangedListener<>(uiDependencies.getEventBus(), - new EventLayoutViewAware(EventLayout.DS_LIST, getEventView()), getMasterDsAwareComponents())); + addEventListener(new SelectionChangedListener<>(uiDependencies.getEventBus(), layoutViewAware, + getMasterDsAwareComponents())); addEventListener(new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), ProxyDistributionSet.class) - .entityModifiedAwareSupports(getDsModifiedAwareSupports()).build()); + .viewAware(layoutViewAware).entityModifiedAwareSupports(getDsModifiedAwareSupports()).build()); addEventListener(new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), ProxyTag.class) - .entityModifiedAwareSupports(getTagModifiedAwareSupports()).parentEntityType(ProxyDistributionSet.class) - .build()); + .parentEntityType(ProxyDistributionSet.class).viewAware(layoutViewAware) + .entityModifiedAwareSupports(getTagModifiedAwareSupports()).build()); buildLayout(distributionGridHeader, distributionGrid, distributionSetDetailsHeader, distributionDetails); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagButtons.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagButtons.java index 8964d3624..3b02d00e5 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagButtons.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagButtons.java @@ -8,10 +8,13 @@ */ package org.eclipse.hawkbit.ui.management.dstag.filter; +import java.util.Collection; import java.util.Collections; +import java.util.stream.Collectors; import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetTagManagement; +import org.eclipse.hawkbit.repository.Identifiable; import org.eclipse.hawkbit.ui.common.CommonUiDependencies; import org.eclipse.hawkbit.ui.common.data.mappers.TagToProxyTagMapper; import org.eclipse.hawkbit.ui.common.data.providers.DistributionSetTagDataProvider; @@ -124,4 +127,9 @@ public class DistributionTagButtons extends AbstractTagFilterButtons { protected Window getUpdateWindow(final ProxyTag clickedFilter) { return dsTagWindowBuilder.getWindowForUpdate(clickedFilter); } + + @Override + protected Collection filterExistingTagIds(final Collection tagIds) { + return distributionSetTagManagement.get(tagIds).stream().map(Identifiable::getId).collect(Collectors.toSet()); + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagLayout.java index 7b9def460..4ee181e8e 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagLayout.java @@ -62,20 +62,22 @@ public class DistributionTagLayout extends AbstractFilterLayout { final DistributionSetTagManagement distributionSetTagManagement, final DistributionSetManagement distributionSetManagement, final TagFilterLayoutUiState distributionTagLayoutUiState) { - final DsTagWindowBuilder dsTagWindowBuilder = new DsTagWindowBuilder(uiDependencies, distributionSetTagManagement); + final DsTagWindowBuilder dsTagWindowBuilder = new DsTagWindowBuilder(uiDependencies, + distributionSetTagManagement); this.distributionTagFilterHeader = new DistributionTagFilterHeader(uiDependencies, dsTagWindowBuilder, distributionTagLayoutUiState); this.distributionTagButtons = new DistributionTagButtons(uiDependencies, distributionSetTagManagement, distributionSetManagement, dsTagWindowBuilder, distributionTagLayoutUiState); + final EventLayoutViewAware layoutViewAware = new EventLayoutViewAware(EventLayout.DS_TAG_FILTER, + EventView.DEPLOYMENT); this.gridActionsVisibilityListener = new GridActionsVisibilityListener(uiDependencies.getEventBus(), - new EventLayoutViewAware(EventLayout.DS_TAG_FILTER, EventView.DEPLOYMENT), - distributionTagButtons::hideActionColumns, distributionTagButtons::showEditColumn, + layoutViewAware, distributionTagButtons::hideActionColumns, distributionTagButtons::showEditColumn, distributionTagButtons::showDeleteColumn); this.entityModifiedListener = new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), ProxyTag.class) - .entityModifiedAwareSupports(getEntityModifiedAwareSupports()) - .parentEntityType(ProxyDistributionSet.class).build(); + .parentEntityType(ProxyDistributionSet.class).viewAware(layoutViewAware) + .entityModifiedAwareSupports(getEntityModifiedAwareSupports()).build(); buildLayout(); } @@ -101,18 +103,25 @@ public class DistributionTagLayout extends AbstractFilterLayout { return filterButtonsLayout; } - /** - * Restore the distribution tag state - */ + @Override public void restoreState() { distributionTagFilterHeader.restoreState(); distributionTagButtons.restoreState(); } - /** - * Unsubscribe the changed listener - */ - public void unsubscribeListener() { + @Override + public void onViewEnter() { + distributionTagButtons.reevaluateFilter(); + } + + @Override + public void subscribeListeners() { + gridActionsVisibilityListener.subscribe(); + entityModifiedListener.subscribe(); + } + + @Override + public void unsubscribeListeners() { gridActionsVisibilityListener.unsubscribe(); entityModifiedListener.unsubscribe(); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetCountMessageLabel.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetCountMessageLabel.java index 02eb0b423..e23b8f7d6 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetCountMessageLabel.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetCountMessageLabel.java @@ -13,7 +13,10 @@ import java.util.Collection; import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.ui.common.data.filters.TargetManagementFilterParams; +import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTarget; +import org.eclipse.hawkbit.ui.common.grid.support.FilterSupport; import org.eclipse.hawkbit.ui.common.layout.AbstractFooterSupport; +import org.eclipse.hawkbit.ui.common.layout.CountAwareComponent; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider; @@ -21,6 +24,7 @@ import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; +import com.vaadin.data.provider.Query; import com.vaadin.shared.ui.ContentMode; import com.vaadin.ui.Label; @@ -28,24 +32,27 @@ import com.vaadin.ui.Label; * Count message label which display current filter details and details on * pinning. */ -public class TargetCountMessageLabel extends AbstractFooterSupport { +public class TargetCountMessageLabel extends AbstractFooterSupport implements CountAwareComponent { private final VaadinMessageSource i18n; - private final TargetManagement targetManagement; + private final FilterSupport gridFilterSupport; private final Label targetCountLabel; + private int totalCount; + private int filteredCount; + /** * Constructor * - * @param targetManagement - * TargetManagement * @param i18n * I18N */ - public TargetCountMessageLabel(final TargetManagement targetManagement, final VaadinMessageSource i18n) { - this.targetManagement = targetManagement; + public TargetCountMessageLabel(final VaadinMessageSource i18n, final TargetManagement targetManagement, + final FilterSupport gridFilterSupport) { this.i18n = i18n; + this.targetManagement = targetManagement; + this.gridFilterSupport = gridFilterSupport; this.targetCountLabel = new Label(); init(); @@ -59,91 +66,132 @@ public class TargetCountMessageLabel extends AbstractFooterSupport { targetCountLabel.setDescription(null); } - /** - * Display target count status on label - * - * @param count - * Total targets - * @param targetFilterParams - * TargetManagementFilterParams - */ - public void displayTargetCountStatus(final long count, final TargetManagementFilterParams targetFilterParams) { - if (targetFilterParams == null) { - return; - } - - targetCountLabel.setCaption(getTargetCountStatusMessage(count, targetFilterParams)); - - updatePinningDetails(targetFilterParams.getPinnedDistId()); + public void updateTotalCount() { + totalCount = fetchTotalCount(); + updateCountLabel(); } - private String getTargetCountStatusMessage(final long count, - final TargetManagementFilterParams targetFilterParams) { - if (!targetFilterParams.isAnyFilterSelected()) { - return getTotalTargetMessage(count).toString(); - } - - final StringBuilder message = getTotalTargetMessage(); - message.append(HawkbitCommonUtil.SP_STRING_PIPE); - message.append(i18n.getMessage("label.filter.targets")); - message.append(count); - message.append(HawkbitCommonUtil.SP_STRING_PIPE); - final String status = i18n.getMessage("label.filter.status"); - final String overdue = i18n.getMessage("label.filter.overdue"); - final String tags = i18n.getMessage("label.filter.tags"); - final String text = i18n.getMessage("label.filter.text"); - final String dists = i18n.getMessage("label.filter.dist"); - final String custom = i18n.getMessage("label.filter.custom"); - final StringBuilder filterMesgBuf = new StringBuilder(i18n.getMessage("label.filter")); - filterMesgBuf.append(" "); - filterMesgBuf.append(getStatusMsg(targetFilterParams.getTargetUpdateStatusList(), status)); - filterMesgBuf.append(getOverdueStateMsg(targetFilterParams.isOverdueState(), overdue)); - filterMesgBuf.append(getTagsMsg(targetFilterParams.isNoTagClicked(), targetFilterParams.getTargetTags(), tags)); - filterMesgBuf.append(!StringUtils.isEmpty(targetFilterParams.getSearchText()) ? text : " "); - filterMesgBuf.append(targetFilterParams.getDistributionId() != null ? dists : " "); - filterMesgBuf.append(targetFilterParams.getTargetFilterQueryId() != null ? custom : " "); - final String filterMesageChk = filterMesgBuf.toString().trim(); - String filterMesage = filterMesageChk; - if (filterMesage.endsWith(",")) { - filterMesage = filterMesageChk.substring(0, filterMesageChk.length() - 1); - } - message.append(filterMesage); - - return message.toString(); + private int fetchTotalCount() { + return gridFilterSupport.getOriginalDataProvider().size(new Query<>()); } - private StringBuilder getTotalTargetMessage(final long count) { + public void updateFilteredCount() { + if (gridFilterSupport.getFilter().isAnyFilterSelected()) { + filteredCount = fetchFilteredCount(); + } + + updateCountLabel(); + } + + private int fetchFilteredCount() { + return gridFilterSupport.getFilterDataProvider().size(new Query<>()); + } + + public void updateTotalAndFilteredCount() { + totalCount = fetchTotalCount(); + if (gridFilterSupport.getFilter().isAnyFilterSelected()) { + filteredCount = fetchFilteredCount(); + } + + updateCountLabel(); + } + + private void updateCountLabel() { + final StringBuilder countMessageBuilder = getTotalTargetsMessage(); + + final TargetManagementFilterParams targetFilterParams = gridFilterSupport.getFilter(); + if (targetFilterParams.isAnyFilterSelected()) { + appendFilteredTargetsMessage(countMessageBuilder, targetFilterParams); + } + + targetCountLabel.setCaption(countMessageBuilder.toString()); + } + + private StringBuilder getTotalTargetsMessage() { final StringBuilder message = new StringBuilder(i18n.getMessage("label.target.filter.count")); message.append(": "); - message.append(count); + message.append(totalCount); return message; } - private StringBuilder getTotalTargetMessage() { - return getTotalTargetMessage(targetManagement.count()); + private void appendFilteredTargetsMessage(final StringBuilder countMessageBuilder, + final TargetManagementFilterParams targetFilterParams) { + countMessageBuilder.append(HawkbitCommonUtil.SP_STRING_PIPE); + countMessageBuilder.append(i18n.getMessage("label.filter.targets")); + countMessageBuilder.append(filteredCount); + countMessageBuilder.append(HawkbitCommonUtil.SP_STRING_PIPE); + countMessageBuilder.append(getFilterParametersMessage(targetFilterParams)); } - private static String getStatusMsg(final Collection status, final String param) { - return status.isEmpty() ? " " : param; + private String getFilterParametersMessage(final TargetManagementFilterParams targetFilterParams) { + final StringBuilder filterMessageBuilder = new StringBuilder(i18n.getMessage("label.filter")); + + filterMessageBuilder.append(" "); + appendStatusMsg(filterMessageBuilder, targetFilterParams.getTargetUpdateStatusList()); + appendOverdueStateMsg(filterMessageBuilder, targetFilterParams.isOverdueState()); + appendTagsMsg(filterMessageBuilder, targetFilterParams.isNoTagClicked(), targetFilterParams.getTargetTags()); + appendSearchMsg(filterMessageBuilder, targetFilterParams.getSearchText()); + appendDsMsg(filterMessageBuilder, targetFilterParams.getDistributionId()); + appendCustomFilterQueryMsg(filterMessageBuilder, targetFilterParams.getTargetFilterQueryId()); + + String filterMessage = filterMessageBuilder.toString().trim(); + if (filterMessage.endsWith(",")) { + filterMessage = filterMessage.substring(0, filterMessage.length() - 1); + } + + return filterMessage; } - private static String getOverdueStateMsg(final boolean overdueState, final String param) { - return !overdueState ? " " : param; + private void appendStatusMsg(final StringBuilder filterMessageBuilder, + final Collection status) { + if (!status.isEmpty()) { + appendFilterMsg(filterMessageBuilder, i18n.getMessage("label.filter.status")); + } } - private static String getTagsMsg(final Boolean noTargetTagSelected, final Collection tags, - final String param) { - return CollectionUtils.isEmpty(tags) && Boolean.FALSE.equals(noTargetTagSelected) ? " " : param; + private static void appendFilterMsg(final StringBuilder filterMessageBuilder, final String filter) { + filterMessageBuilder.append(filter); + filterMessageBuilder.append(", "); + } + + private void appendOverdueStateMsg(final StringBuilder filterMessageBuilder, final boolean overdueState) { + if (overdueState) { + appendFilterMsg(filterMessageBuilder, i18n.getMessage("label.filter.overdue")); + } + } + + private void appendTagsMsg(final StringBuilder filterMessageBuilder, final boolean noTargetTagSelected, + final Collection tags) { + if (noTargetTagSelected || !CollectionUtils.isEmpty(tags)) { + appendFilterMsg(filterMessageBuilder, i18n.getMessage("label.filter.tags")); + } + } + + private void appendSearchMsg(final StringBuilder filterMessageBuilder, final String search) { + if (!StringUtils.isEmpty(search)) { + appendFilterMsg(filterMessageBuilder, i18n.getMessage("label.filter.text")); + } + } + + private void appendDsMsg(final StringBuilder filterMessageBuilder, final Long dsId) { + if (dsId != null) { + appendFilterMsg(filterMessageBuilder, i18n.getMessage("label.filter.dist")); + } + } + + private void appendCustomFilterQueryMsg(final StringBuilder filterMessageBuilder, final Long customFilterQueryId) { + if (customFilterQueryId != null) { + appendFilterMsg(filterMessageBuilder, i18n.getMessage("label.filter.custom")); + } } /** * Update pinning details * - * @param pinnedDsId - * Pinned distribution set id */ - public void updatePinningDetails(final Long pinnedDsId) { + public void updatePinningDetails() { + final Long pinnedDsId = gridFilterSupport.getFilter().getPinnedDistId(); if (pinnedDsId == null) { targetCountLabel.setValue(""); return; @@ -167,4 +215,21 @@ public class TargetCountMessageLabel extends AbstractFooterSupport { protected Label getFooterMessageLabel() { return targetCountLabel; } + + @Override + public void updateCountOnEntitiesAdded(final int count) { + updateTotalAndFilteredCount(); + } + + @Override + public void updateCountOnEntitiesUpdated() { + updateFilteredCount(); + updatePinningDetails(); + } + + @Override + public void updateCountOnEntitiesDeleted(final int count) { + updateTotalAndFilteredCount(); + updatePinningDetails(); + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridHeader.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridHeader.java index 83560e64c..c55f1dc13 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridHeader.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridHeader.java @@ -186,7 +186,7 @@ public class TargetGridHeader extends AbstractEntityGridHeader { bulkUploadTargetWindow.setVisible(true); } - private Boolean isBulkUploadInProgress() { + private boolean isBulkUploadInProgress() { return targetBulkUploadUiState.isInProgress(); } @@ -207,11 +207,11 @@ public class TargetGridHeader extends AbstractEntityGridHeader { final String failureReason, final float progress, final int successCount, final int failCount) { switch (state) { case UPLOAD_STARTED: - adaptbulkUploadHeaderAndUiState(true); + bulkUploadHeaderSupport.showProgressIndicator(); layout.onStartOfUpload(); break; case UPLOAD_FAILED: - adaptbulkUploadHeaderAndUiState(false); + bulkUploadHeaderSupport.hideProgressIndicator(); layout.onUploadFailure(failureReason); break; case TARGET_PROVISIONING_STARTED: @@ -227,19 +227,19 @@ public class TargetGridHeader extends AbstractEntityGridHeader { layout.onAssignmentFailure(failureReason); break; case BULK_UPLOAD_COMPLETED: - adaptbulkUploadHeaderAndUiState(false); + bulkUploadHeaderSupport.hideProgressIndicator(); layout.onUploadCompletion(successCount, failCount); break; } } - private void adaptbulkUploadHeaderAndUiState(final boolean isInProgress) { - if (isInProgress) { - bulkUploadHeaderSupport.showProgressIndicator(); - } else { + /** + * Hides progress indicator in case no bulk upload is running. + */ + public void checkBulkUpload() { + if (bulkUploadHeaderSupport != null && !isBulkUploadInProgress()) { bulkUploadHeaderSupport.hideProgressIndicator(); } - targetBulkUploadUiState.setInProgress(isInProgress); } /** diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridLayout.java index 51299a405..1a7778076 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridLayout.java @@ -29,7 +29,6 @@ import org.eclipse.hawkbit.ui.common.event.EventLayout; import org.eclipse.hawkbit.ui.common.event.EventLayoutViewAware; import org.eclipse.hawkbit.ui.common.event.EventTopics; import org.eclipse.hawkbit.ui.common.event.EventView; -import org.eclipse.hawkbit.ui.common.event.EventViewAware; import org.eclipse.hawkbit.ui.common.event.TargetFilterTabChangedEventPayload; import org.eclipse.hawkbit.ui.common.layout.AbstractGridComponentLayout; import org.eclipse.hawkbit.ui.common.layout.MasterEntityAwareComponent; @@ -41,6 +40,7 @@ import org.eclipse.hawkbit.ui.common.layout.listener.GenericEventListener; import org.eclipse.hawkbit.ui.common.layout.listener.PinningChangedListener; import org.eclipse.hawkbit.ui.common.layout.listener.SelectGridEntityListener; import org.eclipse.hawkbit.ui.common.layout.listener.SelectionChangedListener; +import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedCountAwareSupport; import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedGridRefreshAwareSupport; import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedPinAwareSupport; import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedSelectionAwareSupport; @@ -134,37 +134,33 @@ public class TargetGridLayout extends AbstractGridComponentLayout { this.targetDetails = new TargetDetails(uiDependencies, targetTagManagement, targetManagement, deploymentManagement, targetMetaDataWindowBuilder); - this.countMessageLabel = new TargetCountMessageLabel(targetManagement, uiDependencies.getI18n()); - - initGridDataUpdatedListener(); + this.countMessageLabel = new TargetCountMessageLabel(uiDependencies.getI18n(), targetManagement, + targetGrid.getFilterSupport()); + final EventLayoutViewAware layoutViewAware = new EventLayoutViewAware(EventLayout.TARGET_LIST, + EventView.DEPLOYMENT); this.filterTabChangedListener = new GenericEventListener<>(uiDependencies.getEventBus(), EventTopics.TARGET_FILTER_TAB_CHANGED, this::onTargetFilterTabChanged); this.targetFilterListener = new FilterChangedListener<>(uiDependencies.getEventBus(), ProxyTarget.class, - new EventViewAware(EventView.DEPLOYMENT), targetGrid.getFilterSupport()); + layoutViewAware, targetGrid.getFilterSupport(), countMessageLabel::updateFilteredCount); this.pinningChangedListener = new PinningChangedListener<>(uiDependencies.getEventBus(), - ProxyDistributionSet.class, targetGrid.getPinSupport()); - this.targetChangedListener = new SelectionChangedListener<>(uiDependencies.getEventBus(), - new EventLayoutViewAware(EventLayout.TARGET_LIST, EventView.DEPLOYMENT), + ProxyDistributionSet.class, targetGrid.getPinSupport(), countMessageLabel::updatePinningDetails); + this.targetChangedListener = new SelectionChangedListener<>(uiDependencies.getEventBus(), layoutViewAware, getMasterTargetAwareComponents()); - this.selectTargetListener = new SelectGridEntityListener<>(uiDependencies.getEventBus(), - new EventLayoutViewAware(EventLayout.TARGET_LIST, EventView.DEPLOYMENT), + this.selectTargetListener = new SelectGridEntityListener<>(uiDependencies.getEventBus(), layoutViewAware, targetGrid.getSelectionSupport()); this.targetModifiedListener = new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), - ProxyTarget.class).entityModifiedAwareSupports(getTargetModifiedAwareSupports()).build(); + ProxyTarget.class).viewAware(layoutViewAware) + .entityModifiedAwareSupports(getTargetModifiedAwareSupports()).build(); this.tagModifiedListener = new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), ProxyTag.class) - .entityModifiedAwareSupports(getTagModifiedAwareSupports()).parentEntityType(ProxyTarget.class).build(); + .parentEntityType(ProxyTarget.class).viewAware(layoutViewAware) + .entityModifiedAwareSupports(getTagModifiedAwareSupports()).build(); this.bulkUploadListener = new BulkUploadChangedListener(uiDependencies.getEventBus(), targetGridHeader::onBulkUploadChanged); buildLayout(targetGridHeader, targetGrid, targetDetailsHeader, targetDetails); } - private void initGridDataUpdatedListener() { - targetGrid.addDataChangedListener(event -> countMessageLabel.displayTargetCountStatus(targetGrid.getDataSize(), - targetGrid.getFilter().orElse(null))); - } - private List> getMasterTargetAwareComponents() { return Arrays.asList(targetDetailsHeader, targetDetails); } @@ -174,7 +170,8 @@ public class TargetGridLayout extends AbstractGridComponentLayout { EntityModifiedSelectionAwareSupport.of(targetGrid.getSelectionSupport(), targetGrid::mapIdToProxyEntity), EntityModifiedPinAwareSupport.of(targetGrid.getPinSupport(), true, true), - EntityModifiedGridRefreshAwareSupport.of(targetGrid::refreshAll)); + EntityModifiedGridRefreshAwareSupport.of(targetGrid::refreshAll), + EntityModifiedCountAwareSupport.of(countMessageLabel)); } private List getTagModifiedAwareSupports() { @@ -211,6 +208,8 @@ public class TargetGridLayout extends AbstractGridComponentLayout { targetGridHeader.enableSearchIcon(); targetGrid.onSimpleTabSelected(); } + + countMessageLabel.updateFilteredCount(); } /** @@ -229,18 +228,36 @@ public class TargetGridLayout extends AbstractGridComponentLayout { showDetailsLayout(); } - /** - * Restore the target grid state - */ + @Override public void restoreState() { targetGridHeader.restoreState(); targetGrid.restoreState(); + countMessageLabel.updateTotalAndFilteredCount(); + countMessageLabel.updatePinningDetails(); } - /** - * Unsubscribe all the listeners - */ - public void unsubscribeListener() { + @Override + public void onViewEnter() { + targetGridHeader.checkBulkUpload(); + targetGrid.getSelectionSupport().reselectCurrentEntity(); + countMessageLabel.updateTotalAndFilteredCount(); + countMessageLabel.updatePinningDetails(); + } + + @Override + public void subscribeListeners() { + filterTabChangedListener.subscribe(); + targetFilterListener.subscribe(); + pinningChangedListener.subscribe(); + targetChangedListener.subscribe(); + selectTargetListener.subscribe(); + targetModifiedListener.subscribe(); + tagModifiedListener.subscribe(); + bulkUploadListener.subscribe(); + } + + @Override + public void unsubscribeListeners() { filterTabChangedListener.unsubscribe(); targetFilterListener.unsubscribe(); pinningChangedListener.unsubscribe(); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/filter/MultipleTargetFilter.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/filter/MultipleTargetFilter.java index 618b44439..3546eca48 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/filter/MultipleTargetFilter.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/filter/MultipleTargetFilter.java @@ -59,7 +59,8 @@ public class MultipleTargetFilter extends Accordion { private final transient EntityModifiedListener entityTagModifiedListener; private final transient EntityModifiedListener entityFilterQueryModifiedListener; - MultipleTargetFilter(final CommonUiDependencies uiDependencies, final TargetFilterQueryManagement targetFilterQueryManagement, + MultipleTargetFilter(final CommonUiDependencies uiDependencies, + final TargetFilterQueryManagement targetFilterQueryManagement, final TargetTagManagement targetTagManagement, final TargetManagement targetManagement, final TargetTagFilterLayoutUiState targetTagFilterLayoutUiState, final TargetTagWindowBuilder targetTagWindowBuilder) { @@ -74,14 +75,16 @@ public class MultipleTargetFilter extends Accordion { this.customFilterTab = new TargetFilterQueryButtons(i18n, eventBus, targetFilterQueryManagement, targetTagFilterLayoutUiState); - this.gridActionsVisibilityListener = new GridActionsVisibilityListener(eventBus, - new EventLayoutViewAware(EventLayout.TARGET_TAG_FILTER, EventView.DEPLOYMENT), + final EventLayoutViewAware layoutViewAware = new EventLayoutViewAware(EventLayout.TARGET_TAG_FILTER, + EventView.DEPLOYMENT); + this.gridActionsVisibilityListener = new GridActionsVisibilityListener(eventBus, layoutViewAware, filterByButtons::hideActionColumns, filterByButtons::showEditColumn, filterByButtons::showDeleteColumn); this.entityTagModifiedListener = new EntityModifiedListener.Builder<>(eventBus, ProxyTag.class) - .entityModifiedAwareSupports(getTagModifiedAwareSupports()).parentEntityType(ProxyTarget.class).build(); + .parentEntityType(ProxyTarget.class).viewAware(layoutViewAware) + .entityModifiedAwareSupports(getTagModifiedAwareSupports()).build(); this.entityFilterQueryModifiedListener = new EntityModifiedListener.Builder<>(eventBus, - ProxyTargetFilterQuery.class).entityModifiedAwareSupports(getFilterQueryModifiedAwareSupports()) - .build(); + ProxyTargetFilterQuery.class).viewAware(layoutViewAware) + .entityModifiedAwareSupports(getFilterQueryModifiedAwareSupports()).build(); init(); addTabs(); @@ -176,9 +179,26 @@ public class MultipleTargetFilter extends Accordion { } /** - * Unsubscribe the event listener + * Update components on view enter */ - public void unsubscribeListener() { + public void onViewEnter() { + filterByButtons.reevaluateFilter(); + customFilterTab.reevaluateFilter(); + } + + /** + * Subscribe event listeners + */ + public void subscribeListeners() { + gridActionsVisibilityListener.subscribe(); + entityTagModifiedListener.subscribe(); + entityFilterQueryModifiedListener.subscribe(); + } + + /** + * Unsubscribe event listeners + */ + public void unsubscribeListeners() { gridActionsVisibilityListener.unsubscribe(); entityTagModifiedListener.unsubscribe(); entityFilterQueryModifiedListener.unsubscribe(); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/filter/TargetFilterQueryButtons.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/filter/TargetFilterQueryButtons.java index 90909b279..e1b158578 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/filter/TargetFilterQueryButtons.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/filter/TargetFilterQueryButtons.java @@ -44,6 +44,7 @@ public class TargetFilterQueryButtons extends AbstractGrid updatedTargetFilterQueryIds) { if (isClickedTfqInIds(updatedTargetFilterQueryIds)) { @@ -159,7 +161,7 @@ public class TargetFilterQueryButtons extends AbstractGrid deletedTargetFilterQueryIds) { if (isClickedTfqInIds(deletedTargetFilterQueryIds)) { @@ -173,8 +175,29 @@ public class TargetFilterQueryButtons extends AbstractGrid filterExistingTagIds(final Collection tagIds) { + return targetTagManagement.get(tagIds).stream().map(Identifiable::getId).collect(Collectors.toSet()); + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/filter/TargetTagFilterLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/filter/TargetTagFilterLayout.java index cfa7839fb..290afa245 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/filter/TargetTagFilterLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/filter/TargetTagFilterLayout.java @@ -52,12 +52,13 @@ public class TargetTagFilterLayout extends AbstractFilterLayout { final TargetFilterQueryManagement targetFilterQueryManagement, final TargetTagManagement targetTagManagement, final TargetManagement targetManagement, final TargetTagFilterLayoutUiState targetTagFilterLayoutUiState) { - final TargetTagWindowBuilder targetTagWindowBuilder = new TargetTagWindowBuilder(uiDependencies, targetTagManagement); + final TargetTagWindowBuilder targetTagWindowBuilder = new TargetTagWindowBuilder(uiDependencies, + targetTagManagement); this.targetTagFilterHeader = new TargetTagFilterHeader(uiDependencies, targetTagFilterLayoutUiState, targetTagWindowBuilder); - this.multipleTargetFilter = new MultipleTargetFilter(uiDependencies, targetFilterQueryManagement, targetTagManagement, - targetManagement, targetTagFilterLayoutUiState, targetTagWindowBuilder); + this.multipleTargetFilter = new MultipleTargetFilter(uiDependencies, targetFilterQueryManagement, + targetTagManagement, targetManagement, targetTagFilterLayoutUiState, targetTagWindowBuilder); this.filterTabChangedListener = new GenericEventListener<>(uiDependencies.getEventBus(), EventTopics.TARGET_FILTER_TAB_CHANGED, this::onTargetFilterTabChanged); @@ -83,19 +84,26 @@ public class TargetTagFilterLayout extends AbstractFilterLayout { return multipleTargetFilter; } - /** - * Restore the target filter state - */ + @Override public void restoreState() { targetTagFilterHeader.restoreState(); multipleTargetFilter.restoreState(); } - /** - * Unsubscribe the event listener - */ - public void unsubscribeListener() { + @Override + public void onViewEnter() { + multipleTargetFilter.onViewEnter(); + } + + @Override + public void subscribeListeners() { + filterTabChangedListener.subscribe(); + multipleTargetFilter.subscribeListeners(); + } + + @Override + public void unsubscribeListeners() { filterTabChangedListener.unsubscribe(); - multipleTargetFilter.unsubscribeListener(); + multipleTargetFilter.unsubscribeListeners(); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/DelayedEventBusPushStrategy.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/DelayedEventBusPushStrategy.java index aa2ea94ba..c4c68012e 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/DelayedEventBusPushStrategy.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/DelayedEventBusPushStrategy.java @@ -45,7 +45,6 @@ import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import org.vaadin.spring.events.EventBus; -import org.vaadin.spring.events.EventBus.SessionEventBus; import org.vaadin.spring.events.EventBus.UIEventBus; import com.nimbusds.oauth2.sdk.util.CollectionUtils; @@ -286,7 +285,7 @@ public class DelayedEventBusPushStrategy /** * An application event publisher subscriber which subscribes * {@link EntityIdEvent} from the repository to dispatch these events to the - * UI {@link SessionEventBus} . + * UI {@link UIEventBus} . * * @param applicationEvent * the entity event which has been published from the repository diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/RolloutView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/RolloutView.java index 8e01ae6b2..e2e3fe0e8 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/RolloutView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/RolloutView.java @@ -8,12 +8,10 @@ */ package org.eclipse.hawkbit.ui.rollout; +import java.util.Arrays; import java.util.EnumMap; import java.util.Map; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; - import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.QuotaManagement; @@ -26,6 +24,7 @@ import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.ui.AbstractHawkbitUI; import org.eclipse.hawkbit.ui.SpPermissionChecker; import org.eclipse.hawkbit.ui.UiProperties; +import org.eclipse.hawkbit.ui.common.AbstractEventListenersAwareView; import org.eclipse.hawkbit.ui.common.CommonUiDependencies; import org.eclipse.hawkbit.ui.common.event.EventLayout; import org.eclipse.hawkbit.ui.common.event.EventView; @@ -40,18 +39,16 @@ import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; import org.springframework.beans.factory.annotation.Autowired; import org.vaadin.spring.events.EventBus.UIEventBus; -import com.vaadin.navigator.View; import com.vaadin.spring.annotation.SpringView; import com.vaadin.spring.annotation.UIScope; import com.vaadin.ui.Alignment; -import com.vaadin.ui.VerticalLayout; /** * Rollout management view. */ @UIScope @SpringView(name = RolloutView.VIEW_NAME, ui = AbstractHawkbitUI.class) -public class RolloutView extends VerticalLayout implements View { +public class RolloutView extends AbstractEventListenersAwareView { private static final long serialVersionUID = 1L; public static final String VIEW_NAME = "rollout"; @@ -74,8 +71,8 @@ public class RolloutView extends VerticalLayout implements View { final SystemSecurityContext systemSecurityContext) { this.rolloutManagementUIState = rolloutManagementUIState; - final CommonUiDependencies uiDependencies = new CommonUiDependencies(i18n, entityFactory, eventBus, uiNotification, - permissionChecker); + final CommonUiDependencies uiDependencies = new CommonUiDependencies(i18n, entityFactory, eventBus, + uiNotification, permissionChecker); this.rolloutsLayout = new RolloutGridLayout(uiDependencies, rolloutManagementUIState, rolloutManagement, targetManagement, uiProperties, targetFilterQueryManagement, rolloutGroupManagement, quotaManagement, @@ -85,6 +82,8 @@ public class RolloutView extends VerticalLayout implements View { this.rolloutGroupTargetsLayout = new RolloutGroupTargetGridLayout(uiDependencies, rolloutGroupManagement, rolloutManagementUIState); + addEventAwareLayouts(Arrays.asList(rolloutsLayout, rolloutGroupsLayout, rolloutGroupTargetsLayout)); + final Map layoutVisibilityHandlers = new EnumMap<>(EventLayout.class); layoutVisibilityHandlers.put(EventLayout.ROLLOUT_LIST, new VisibilityHandler(this::showRolloutListLayout, this::showRolloutGroupListLayout)); @@ -96,13 +95,8 @@ public class RolloutView extends VerticalLayout implements View { layoutVisibilityHandlers); } - @PostConstruct - void init() { - buildLayout(); - restoreState(); - } - - private void buildLayout() { + @Override + protected void buildLayout() { setSpacing(false); setMargin(false); setSizeFull(); @@ -152,7 +146,8 @@ public class RolloutView extends VerticalLayout implements View { rolloutGroupTargetsLayout.setVisible(true); } - private void restoreState() { + @Override + protected void restoreState() { final EventLayout layout = rolloutManagementUIState.getCurrentLayout().orElse(EventLayout.ROLLOUT_LIST); switch (layout) { case ROLLOUT_LIST: @@ -168,17 +163,25 @@ public class RolloutView extends VerticalLayout implements View { break; } - rolloutsLayout.restoreState(); - rolloutGroupsLayout.restoreState(); - rolloutGroupTargetsLayout.restoreState(); + super.restoreState(); } - @PreDestroy - void destroy() { + @Override + public String getViewName() { + return RolloutView.VIEW_NAME; + } + + @Override + protected void subscribeListeners() { + layoutVisibilityListener.subscribe(); + + super.subscribeListeners(); + } + + @Override + protected void unsubscribeListeners() { layoutVisibilityListener.unsubscribe(); - rolloutsLayout.unsubscribeListener(); - rolloutGroupsLayout.unsubscribeListener(); - rolloutGroupTargetsLayout.unsubscribeListener(); + super.unsubscribeListeners(); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/RolloutGrid.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/RolloutGrid.java index fc487cc08..11e3dc970 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/RolloutGrid.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/RolloutGrid.java @@ -244,7 +244,7 @@ public class RolloutGrid extends AbstractGrid { } private void updateGridItem(final Rollout rollout) { - final ProxyRollout proxyRollout = RolloutToProxyRolloutMapper.mapRollout(rollout); + final ProxyRollout proxyRollout = rolloutMapper.map(rollout); if (rollout.getRolloutGroupsCreated() == 0) { final Long groupsCount = rolloutGroupManagement.countByRollout(rollout.getId()); @@ -359,6 +359,10 @@ public class RolloutGrid extends AbstractGrid { getSelectionSupport().sendSelectionChangedEvent(SelectionChangedEventType.ENTITY_SELECTED, rollout); rolloutManagementUIState.setSelectedRolloutName(rollout.getName()); + showRolloutGroupListLayout(); + } + + private void showRolloutGroupListLayout() { eventBus.publish(CommandTopics.CHANGE_LAYOUT_VISIBILITY, this, new LayoutVisibilityEventPayload( VisibilityType.SHOW, EventLayout.ROLLOUT_GROUP_LIST, EventView.ROLLOUT)); } @@ -428,14 +432,36 @@ public class RolloutGrid extends AbstractGrid { uiNotification.displayWarning( i18n.getMessage("rollout.not.exists", rolloutManagementUIState.getSelectedRolloutName())); - showRolloutListLayout(); + final EventLayout currentLayout = rolloutManagementUIState.getCurrentLayout().orElse(null); + if (currentLayout == null || currentLayout != EventLayout.ROLLOUT_LIST) { + showRolloutListLayout(); + } } private void showRolloutListLayout() { - if (rolloutManagementUIState.getCurrentLayout().map(currentLayout -> currentLayout != EventLayout.ROLLOUT_LIST) - .orElse(true)) { - eventBus.publish(CommandTopics.CHANGE_LAYOUT_VISIBILITY, this, - new LayoutVisibilityEventPayload(VisibilityType.SHOW, EventLayout.ROLLOUT_LIST, EventView.ROLLOUT)); + eventBus.publish(CommandTopics.CHANGE_LAYOUT_VISIBILITY, this, + new LayoutVisibilityEventPayload(VisibilityType.SHOW, EventLayout.ROLLOUT_LIST, EventView.ROLLOUT)); + } + + /** + * Re-fetches and re-selects currently selected rollout in order to update + * details layouts. + * + */ + public void reselectCurrentRollout() { + final Long selectedRolloutId = rolloutManagementUIState.getSelectedRolloutId(); + if (selectedRolloutId == null) { + return; + } + + final Optional refetchedRollout = mapIdToProxyEntity(selectedRolloutId); + refetchedRollout.ifPresent(rollout -> { + getSelectionSupport().sendSelectionChangedEvent(SelectionChangedEventType.ENTITY_SELECTED, rollout); + rolloutManagementUIState.setSelectedRolloutName(rollout.getName()); + }); + + if (!refetchedRollout.isPresent()) { + onSelectedRolloutDeleted(selectedRolloutId); } } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/RolloutGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/RolloutGridLayout.java index 6386d146e..60382211d 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/RolloutGridLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/RolloutGridLayout.java @@ -72,9 +72,10 @@ public class RolloutGridLayout extends AbstractGridComponentLayout { * @param systemSecurityContext * SystemSecurityContext */ - public RolloutGridLayout(final CommonUiDependencies uiDependencies, final RolloutManagementUIState rolloutManagementUIState, - final RolloutManagement rolloutManagement, final TargetManagement targetManagement, - final UiProperties uiProperties, final TargetFilterQueryManagement targetFilterQueryManagement, + public RolloutGridLayout(final CommonUiDependencies uiDependencies, + final RolloutManagementUIState rolloutManagementUIState, final RolloutManagement rolloutManagement, + final TargetManagement targetManagement, final UiProperties uiProperties, + final TargetFilterQueryManagement targetFilterQueryManagement, final RolloutGroupManagement rolloutGroupManagement, final QuotaManagement quotaManagement, final TenantConfigurationManagement tenantConfigManagement, final DistributionSetManagement distributionSetManagement, @@ -89,10 +90,12 @@ public class RolloutGridLayout extends AbstractGridComponentLayout { this.rolloutListGrid = new RolloutGrid(uiDependencies, rolloutManagement, rolloutGroupManagement, rolloutManagementUIState, tenantConfigManagement, rolloutWindowBuilder, systemSecurityContext); + final EventViewAware viewAware = new EventViewAware(EventView.ROLLOUT); this.rolloutFilterListener = new FilterChangedListener<>(uiDependencies.getEventBus(), ProxyRollout.class, - new EventViewAware(EventView.ROLLOUT), rolloutListGrid.getFilterSupport()); - this.rolloutModifiedListener = new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), ProxyRollout.class) - .entityModifiedAwareSupports(getRolloutModifiedAwareSupports()).build(); + viewAware, rolloutListGrid.getFilterSupport()); + this.rolloutModifiedListener = new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), + ProxyRollout.class).viewAware(viewAware).entityModifiedAwareSupports(getRolloutModifiedAwareSupports()) + .build(); buildLayout(rolloutListHeader, rolloutListGrid); } @@ -104,18 +107,25 @@ public class RolloutGridLayout extends AbstractGridComponentLayout { rolloutListGrid::mapIdToProxyEntity, rolloutListGrid::onSelectedRolloutDeleted)); } - /** - * Restore the rollout grid state - */ + @Override public void restoreState() { rolloutListHeader.restoreState(); rolloutListGrid.restoreState(); } - /** - * unsubscribe all listener - */ - public void unsubscribeListener() { + @Override + public void onViewEnter() { + rolloutListGrid.reselectCurrentRollout(); + } + + @Override + public void subscribeListeners() { + rolloutFilterListener.subscribe(); + rolloutModifiedListener.subscribe(); + } + + @Override + public void unsubscribeListeners() { rolloutFilterListener.unsubscribe(); rolloutModifiedListener.unsubscribe(); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupGrid.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupGrid.java index 9f8b5de2a..8ac36317a 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupGrid.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupGrid.java @@ -163,6 +163,10 @@ public class RolloutGroupGrid extends AbstractGrid { getSelectionSupport().sendSelectionChangedEvent(SelectionChangedEventType.ENTITY_SELECTED, rolloutGroup); rolloutManagementUIState.setSelectedRolloutGroupName(rolloutGroup.getName()); + showRolloutGroupTargetsListLayout(); + } + + private void showRolloutGroupTargetsListLayout() { eventBus.publish(CommandTopics.CHANGE_LAYOUT_VISIBILITY, this, new LayoutVisibilityEventPayload( VisibilityType.SHOW, EventLayout.ROLLOUT_GROUP_TARGET_LIST, EventView.ROLLOUT)); } @@ -179,8 +183,7 @@ public class RolloutGroupGrid extends AbstractGrid { } private void updateGridItem(final RolloutGroup rolloutGroup) { - final ProxyRolloutGroup proxyRolloutGroup = RolloutGroupToProxyRolloutGroupMapper.mapGroup(rolloutGroup); - getDataProvider().refreshItem(proxyRolloutGroup); + getDataProvider().refreshItem(rolloutGroupMapper.map(rolloutGroup)); } @Override diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupGridLayout.java index ea3a6d3de..c79b42e9c 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupGridLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupGridLayout.java @@ -50,19 +50,21 @@ public class RolloutGroupGridLayout extends AbstractGridComponentLayout { * @param rolloutManagementUIState * UIState */ - public RolloutGroupGridLayout(final CommonUiDependencies uiDependencies, final RolloutGroupManagement rolloutGroupManagement, + public RolloutGroupGridLayout(final CommonUiDependencies uiDependencies, + final RolloutGroupManagement rolloutGroupManagement, final RolloutManagementUIState rolloutManagementUIState) { this.rolloutGroupsListHeader = new RolloutGroupGridHeader(uiDependencies, rolloutManagementUIState); - this.rolloutGroupListGrid = new RolloutGroupGrid(uiDependencies, rolloutGroupManagement, rolloutManagementUIState); + this.rolloutGroupListGrid = new RolloutGroupGrid(uiDependencies, rolloutGroupManagement, + rolloutManagementUIState); final EventLayoutViewAware masterLayoutView = new EventLayoutViewAware(EventLayout.ROLLOUT_LIST, EventView.ROLLOUT); - - this.masterEntityChangedListener = new SelectionChangedListener<>(uiDependencies.getEventBus(), masterLayoutView, - getMasterEntityAwareComponents()); + this.masterEntityChangedListener = new SelectionChangedListener<>(uiDependencies.getEventBus(), + masterLayoutView, getMasterEntityAwareComponents()); this.entityModifiedListener = new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), - ProxyRolloutGroup.class).entityModifiedAwareSupports(getEntityModifiedAwareSupports()) - .parentEntityType(ProxyRollout.class).parentEntityIdProvider(this::getMasterEntityId).build(); + ProxyRolloutGroup.class).parentEntityType(ProxyRollout.class) + .parentEntityIdProvider(this::getMasterEntityId).viewAware(masterLayoutView) + .entityModifiedAwareSupports(getEntityModifiedAwareSupports()).build(); buildLayout(rolloutGroupsListHeader, rolloutGroupListGrid); } @@ -83,18 +85,20 @@ public class RolloutGroupGridLayout extends AbstractGridComponentLayout { return Optional.ofNullable(rolloutGroupListGrid.getMasterEntitySupport().getMasterId()); } - /** - * Restore the rollout group grid list state - */ + @Override public void restoreState() { rolloutGroupsListHeader.restoreState(); rolloutGroupListGrid.restoreState(); } - /** - * Unsubscribe the event listener - */ - public void unsubscribeListener() { + @Override + public void subscribeListeners() { + masterEntityChangedListener.subscribe(); + entityModifiedListener.subscribe(); + } + + @Override + public void unsubscribeListeners() { masterEntityChangedListener.unsubscribe(); entityModifiedListener.unsubscribe(); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetGridLayout.java index 2ccaefd79..bb712acf4 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetGridLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetGridLayout.java @@ -80,18 +80,20 @@ public class RolloutGroupTargetGridLayout extends AbstractGridComponentLayout { return Arrays.asList(rolloutGroupTargetsListHeader, rolloutGroupTargetsListGrid.getMasterEntitySupport()); } - /** - * Restore the rollout group target list state - */ + @Override public void restoreState() { rolloutGroupTargetsListHeader.restoreState(); rolloutGroupTargetsListGrid.restoreState(); } - /** - * unsubscribe all listener - */ - public void unsubscribeListener() { + @Override + public void subscribeListeners() { + rolloutChangedListener.subscribe(); + rolloutGroupChangedListener.subscribe(); + } + + @Override + public void unsubscribeListeners() { rolloutChangedListener.unsubscribe(); rolloutGroupChangedListener.unsubscribe(); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/components/RolloutFormLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/components/RolloutFormLayout.java index 04972c1ba..617350165 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/components/RolloutFormLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/components/RolloutFormLayout.java @@ -77,11 +77,11 @@ public class RolloutFormLayout extends ValidatableLayout { * Constructor for RolloutFormLayout * * @param i18n - * VaadinMessageSource + * VaadinMessageSource * @param distributionSetDataProvider - * DistributionSetStatelessDataProvider + * DistributionSetStatelessDataProvider * @param targetFilterQueryDataProvider - * TargetFilterQueryDataProvider + * TargetFilterQueryDataProvider */ public RolloutFormLayout(final VaadinMessageSource i18n, final DistributionSetStatelessDataProvider distributionSetDataProvider, @@ -206,7 +206,7 @@ public class RolloutFormLayout extends ValidatableLayout { * Add rollout form to add layout * * @param layout - * Grid layout + * Grid layout */ public void addFormToAddLayout(final GridLayout layout) { targetFilterQueryField.unbind(); @@ -218,7 +218,7 @@ public class RolloutFormLayout extends ValidatableLayout { * Add rollout form to edit layout * * @param layout - * Grid layout + * Grid layout */ public void addFormToEditLayout(final GridLayout layout) { targetFilterQueryCombo.unbind(); @@ -252,6 +252,7 @@ public class RolloutFormLayout extends ValidatableLayout { */ public void disableFieldsOnEditForInActive() { targetFilterQueryField.getComponent().setEnabled(false); + dsCombo.setEnabled(false); } /** @@ -260,7 +261,6 @@ public class RolloutFormLayout extends ValidatableLayout { public void disableFieldsOnEditForActive() { disableFieldsOnEditForInActive(); - dsCombo.setEnabled(false); actionTypeLayout.getComponent().setEnabled(false); autoStartOptionGroupLayout.getComponent().setEnabled(false); } @@ -279,7 +279,7 @@ public class RolloutFormLayout extends ValidatableLayout { * Sets the changed listener for filter query * * @param filterQueryChangedListener - * Changed listener + * Changed listener */ public void setFilterQueryChangedListener(final Consumer filterQueryChangedListener) { this.filterQueryChangedListener = filterQueryChangedListener; @@ -289,7 +289,7 @@ public class RolloutFormLayout extends ValidatableLayout { * Sets the count of total targets * * @param totalTargets - * Total targets + * Total targets */ public void setTotalTargets(final Long totalTargets) { this.totalTargets = totalTargets; @@ -301,7 +301,7 @@ public class RolloutFormLayout extends ValidatableLayout { * Sets the rollout form bean in binder * * @param bean - * ProxyRolloutForm + * ProxyRolloutForm */ public void setBean(final ProxyRolloutForm bean) { rolloutId = bean.getId(); @@ -312,7 +312,7 @@ public class RolloutFormLayout extends ValidatableLayout { * @return Updated rollout form bean * * @throws ValidationException - * ValidationException + * ValidationException */ public ProxyRolloutForm getBean() throws ValidationException { final ProxyRolloutForm bean = new ProxyRolloutForm(); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/TenantConfigurationDashboardView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/TenantConfigurationDashboardView.java index 784aa1a29..bb9ac3a00 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/TenantConfigurationDashboardView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/TenantConfigurationDashboardView.java @@ -15,6 +15,7 @@ import javax.annotation.PostConstruct; import org.eclipse.hawkbit.ui.AbstractHawkbitUI; import org.eclipse.hawkbit.ui.UiProperties; +import org.eclipse.hawkbit.ui.common.ViewNameAware; import org.eclipse.hawkbit.ui.common.data.proxies.ProxySystemConfigWindow; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleNoBorder; @@ -44,7 +45,8 @@ import com.vaadin.ui.VerticalLayout; */ @ViewScope @SpringView(name = TenantConfigurationDashboardView.VIEW_NAME, ui = AbstractHawkbitUI.class) -public class TenantConfigurationDashboardView extends CustomComponent implements View, ConfigurationItemChangeListener { +public class TenantConfigurationDashboardView extends CustomComponent + implements View, ViewNameAware, ConfigurationItemChangeListener { private static final long serialVersionUID = 1L; public static final String VIEW_NAME = "spSystemConfig"; @@ -163,4 +165,8 @@ public class TenantConfigurationDashboardView extends CustomComponent implements // This view is constructed in the init() method() } + @Override + public String getViewName() { + return TenantConfigurationDashboardView.VIEW_NAME; + } } diff --git a/hawkbit-ui/src/main/resources/messages.properties b/hawkbit-ui/src/main/resources/messages.properties index ea70577d9..0eedba716 100644 --- a/hawkbit-ui/src/main/resources/messages.properties +++ b/hawkbit-ui/src/main/resources/messages.properties @@ -106,6 +106,7 @@ caption.artifact.details.of = Artifact Details of caption.action.states= Action States caption.action.messages = Messages caption.error = Error +caption.entity.missing.error = Entity is missing caption.new.softwaremodule.application = Configure New Application caption.new.softwaremodule.os = Configure New OS caption.filter.simple = Simple Filter @@ -209,11 +210,11 @@ label.target.filter.count = Total Targets label.filter.selected = Selected: label.filter.shown = Shown: label.filter.targets = Filtered Targets: -label.filter.status = Status, -label.filter.overdue = Overdue, -label.filter.tags = Tags, +label.filter.status = Status +label.filter.overdue = Overdue +label.filter.tags = Tags label.filter.text = Search Text -label.filter.dist = Distribution, +label.filter.dist = Distribution label.filter.custom = Custom label.target.filter.truncated={0} targets has been truncated in the list due the target size limit of {1}, use filters to reduce the targets to be shown label.unknown = Unknown @@ -768,7 +769,8 @@ controller.polling.title=Polling Configuration controller.polling.time=Polling Time # entity not exist -rollout.not.exists=Rollout {0} does not exist. Maybe the rollout was deleted. +rollout.not.exists=Rollout {0} does not exist. Maybe the it was deleted. +rollout.group.not.exists=Rollout Group {0} does not exist. Maybe the it was deleted. color.not.exists=There is no mapping for the provided colour {0} caption.entity.target.tag = Target Tag