View-scoped event listeners (#1134)

* added UI EntityNotFound error details extractor

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* changed Target count label to not rely on grid data change events but rather on EntityModified UI events to decide how to react dependand on the event type

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* added current view check on entity modified events

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* unsubscribe/resubscribe event listeners on view leave/enter, reselect grid entities on view enter

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* fixed target grid count reset on initial load and after view change

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* re-evaluate filters on Deployment View enter

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* added on view enter logic for rest of the views

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* introduced event listener aware layout and view, adapted code accordingly

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* fixed bulk upload

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* added missing docs

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* adapted software module deselection upon master entity change

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* fixed npe in case master support is not present (Artifact View)

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* restructured amqp assignDistributionSetMultipleTimes test

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>

* added waiting for the messages to be dispached by test

Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>
This commit is contained in:
Bondar Bogdan
2021-07-22 11:00:05 +02:00
committed by GitHub
parent 1a285849e6
commit ace2f00742
75 changed files with 1603 additions and 600 deletions

View File

@@ -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),

View File

@@ -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> uiErrorDetailsExtractor) {
return new HawkbitUIErrorHandler(i18n, uiErrorDetailsExtractor);
final List<UiErrorDetailsExtractor> 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

View File

@@ -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<EventLayout, VisibilityHandler> 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);
}
}

View File

@@ -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();
}

View File

@@ -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<ProxySoftwareModule, SwFilt
setFilterSupport(new FilterSupport<>(
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());

View File

@@ -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));

View File

@@ -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);
}
}

View File

@@ -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();
}

View File

@@ -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<EventListenersAwareLayout> 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<EventListenersAwareLayout> 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();
}
}

View File

@@ -0,0 +1,40 @@
/**
* Copyright (c) 2021 Bosch.IO GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ui.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() {
}
}

View File

@@ -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();
}

View File

@@ -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<ProxyRolloutGroup, RolloutGroup> {
/**
* 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();

View File

@@ -19,18 +19,6 @@ import org.eclipse.hawkbit.ui.common.data.proxies.ProxyRollout;
*/
public class RolloutToProxyRolloutMapper extends AbstractNamedEntityToProxyNamedEntityMapper<ProxyRollout, Rollout> {
/**
* 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();

View File

@@ -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<ProxyTarget> dataCommunicator;

View File

@@ -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<ProxyTarget> dataCommunicator;

View File

@@ -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 <F>
* Generic filter type
* @return the distributionGrid
*/
public abstract <T extends DsFilterParams> AbstractDsGrid<T> getDistributionGrid();
public abstract <F extends DsFilterParams> AbstractDsGrid<F> 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);
}
}

View File

@@ -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 <F>
* Generic type
* Generic filter type
*/
public abstract class AbstractDsGrid<F> extends AbstractGrid<ProxyDistributionSet, F> {
public abstract class AbstractDsGrid<F extends DsFilterParams> extends AbstractGrid<ProxyDistributionSet, F> {
private static final long serialVersionUID = 1L;
protected static final String DS_NAME_ID = "dsName";

View File

@@ -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);
}
}

View File

@@ -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() {

View File

@@ -56,9 +56,10 @@ public abstract class AbstractTagFilterButtons extends AbstractFilterButtons<Pro
* @param tagFilterLayoutUiState
* TagFilterLayoutUiState
*/
public AbstractTagFilterButtons(final CommonUiDependencies uiDependencies,
protected AbstractTagFilterButtons(final CommonUiDependencies uiDependencies,
final TagFilterLayoutUiState tagFilterLayoutUiState) {
super(uiDependencies.getEventBus(), uiDependencies.getI18n(), uiDependencies.getUiNotification(), uiDependencies.getPermChecker());
super(uiDependencies.getEventBus(), uiDependencies.getI18n(), uiDependencies.getUiNotification(),
uiDependencies.getPermChecker());
this.uiNotification = uiDependencies.getUiNotification();
this.tagFilterLayoutUiState = tagFilterLayoutUiState;
@@ -99,8 +100,18 @@ public abstract class AbstractTagFilterButtons extends AbstractFilterButtons<Pro
tagFilterLayoutUiState.setClickedTagIdsWithName(activeTagIdsWithName);
}
/**
* Provides type of the master entity.
*
* @return type of the master entity
*/
protected abstract Class<? extends ProxyIdentifiableEntity> 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<Pro
}
}
/**
* Tag deletion operation.
*
* @param tagToDelete
* tag to delete
*/
protected abstract void deleteTag(final ProxyTag tagToDelete);
/**
@@ -183,6 +200,13 @@ public abstract class AbstractTagFilterButtons extends AbstractFilterButtons<Pro
updateWindow.setVisible(Boolean.TRUE);
}
/**
* Provides the window for updating tag
*
* @param clickedFilter
* tag to update
* @return update window
*/
protected abstract Window getUpdateWindow(final ProxyTag clickedFilter);
/**
@@ -212,6 +236,7 @@ public abstract class AbstractTagFilterButtons extends AbstractFilterButtons<Pro
final Map<Long, String> tagsToRestore = tagFilterLayoutUiState.getClickedTagIdsWithName();
if (!CollectionUtils.isEmpty(tagsToRestore)) {
removeNonExistingTags(tagsToRestore);
getFilterButtonClickBehaviour().setPreviouslyClickedFilterIdsWithName(tagsToRestore);
}
@@ -219,4 +244,35 @@ public abstract class AbstractTagFilterButtons extends AbstractFilterButtons<Pro
getNoTagButton().addStyleName(SPUIStyleDefinitions.SP_NO_TAG_BTN_CLICKED_STYLE);
}
}
private boolean removeNonExistingTags(final Map<Long, String> tagIdsWithName) {
final Collection<Long> tagIds = tagIdsWithName.keySet();
final Collection<Long> 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<Long> filterExistingTagIds(final Collection<Long> tagIds);
/**
* Re-evaluates a filter (usually after view enter).
*
*/
public void reevaluateFilter() {
final Map<Long, String> clickedTags = getFilterButtonClickBehaviour().getPreviouslyClickedFilterIdsWithName();
if (!CollectionUtils.isEmpty(clickedTags) && removeNonExistingTags(clickedTags)) {
publishFilterChangedEvent(clickedTags);
}
}
}

View File

@@ -45,9 +45,10 @@ public abstract class AbstractTypeFilterButtons extends AbstractFilterButtons<Pr
* @param typeFilterLayoutUiState
* TypeFilterLayoutUiState
*/
public AbstractTypeFilterButtons(final CommonUiDependencies uiDependencies,
protected AbstractTypeFilterButtons(final CommonUiDependencies uiDependencies,
final TypeFilterLayoutUiState typeFilterLayoutUiState) {
super(uiDependencies.getEventBus(), uiDependencies.getI18n(), uiDependencies.getUiNotification(), uiDependencies.getPermChecker());
super(uiDependencies.getEventBus(), uiDependencies.getI18n(), uiDependencies.getUiNotification(),
uiDependencies.getPermChecker());
this.uiNotification = uiDependencies.getUiNotification();
this.typeFilterLayoutUiState = typeFilterLayoutUiState;
@@ -74,8 +75,18 @@ public abstract class AbstractTypeFilterButtons extends AbstractFilterButtons<Pr
typeFilterLayoutUiState.setClickedTypeId(typeId);
}
/**
* Provides type of the master entity.
*
* @return type of the master entity
*/
protected abstract Class<? extends ProxyIdentifiableEntity> getFilterMasterEntityType();
/**
* Provides event view filter.
*
* @return event view filter.
*/
protected abstract EventView getView();
@Override
@@ -106,8 +117,21 @@ public abstract class AbstractTypeFilterButtons extends AbstractFilterButtons<Pr
}
}
protected abstract boolean isDefaultType(final ProxyType typeToDelete);
/**
* Checks if provided type is the default one.
*
* @param type
* provided type
* @return default type check
*/
protected abstract boolean isDefaultType(final ProxyType type);
/**
* Type deletion operation.
*
* @param typeToDelete
* type to delete
*/
protected abstract void deleteType(final ProxyType typeToDelete);
/**
@@ -144,6 +168,13 @@ public abstract class AbstractTypeFilterButtons extends AbstractFilterButtons<Pr
updateWindow.setVisible(Boolean.TRUE);
}
/**
* Provides the window for updating type
*
* @param clickedFilter
* type to update
* @return update window
*/
protected abstract Window getUpdateWindow(final ProxyType clickedFilter);
@Override
@@ -154,4 +185,26 @@ public abstract class AbstractTypeFilterButtons extends AbstractFilterButtons<Pr
getFilterButtonClickBehaviour().setPreviouslyClickedFilterId(lastClickedTypeId);
}
}
/**
* Check if provided type exists by id.
*
* @param typeId
* provided type id
* @return if type exists
*/
protected abstract boolean typeExists(final Long typeId);
/**
* Re-evaluates a filter (usually after view enter).
*
*/
public void reevaluateFilter() {
final Long clickedTypeId = getFilterButtonClickBehaviour().getPreviouslyClickedFilterId();
if (clickedTypeId != null && !typeExists(clickedTypeId)) {
getFilterButtonClickBehaviour().setPreviouslyClickedFilterId(null);
publishFilterChangedEvent(null);
}
}
}

View File

@@ -188,12 +188,9 @@ public class DistributionSetFilterDropAreaSupport implements HeaderSupport {
if (draggingListener == null) {
draggingListener = new EntityDraggingListener(eventBus,
Collections.singletonList(UIComponentIdProvider.DIST_TABLE_ID), dropAreaLayout);
return;
}
if (!draggingListener.isSubscribed()) {
draggingListener.subscribe();
}
draggingListener.subscribe();
}
@Override

View File

@@ -66,15 +66,15 @@ public class DragAndDropSupport<T extends ProxyIdentifiableEntity> {
* 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<T, ?> grid, final VaadinMessageSource i18n,
final UINotification notification,
@@ -95,7 +95,8 @@ public class DragAndDropSupport<T extends ProxyIdentifiableEntity> {
/**
* 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<T extends ProxyIdentifiableEntity> {
/**
* @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<T extends ProxyIdentifiableEntity> {
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,

View File

@@ -169,6 +169,13 @@ public class FilterSupport<T, F> {
return filterDataProvider;
}
/**
* @return Original data provider
*/
public DataProvider<T, F> getOriginalDataProvider() {
return filterDataProvider.getDataProvider();
}
/**
* Verifies if filter type is supported
*
@@ -294,5 +301,14 @@ public class FilterSupport<T, F> {
this.customFilter = filter;
refreshAll();
}
/**
* Gets original data provider.
*
* @return original data provider
*/
public DataProvider<T, F> getDataProvider() {
return dataProvider;
}
}
}

View File

@@ -19,7 +19,7 @@ import org.eclipse.hawkbit.ui.common.layout.MasterEntityAwareComponent;
* Filter support in Master entity
*
* @param <M>
* Generic type of ProxyIdentifiableEntity
* Generic type of master entity
*/
public class MasterEntitySupport<M extends ProxyIdentifiableEntity> implements MasterEntityAwareComponent<M> {
private final FilterSupport<?, ?> filterSupport;
@@ -31,7 +31,7 @@ public class MasterEntitySupport<M extends ProxyIdentifiableEntity> 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<M extends ProxyIdentifiableEntity> 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<M, ?> masterEntityToFilterMapper) {
@@ -57,16 +57,18 @@ public class MasterEntitySupport<M extends ProxyIdentifiableEntity> 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();
}
/**

View File

@@ -230,7 +230,7 @@ public class SelectionSupport<T extends ProxyIdentifiableEntity> {
}
/**
* @return Id of elected entity from the grid
* @return Id of selected entity from the grid
*/
public Optional<Long> getSelectedEntityId() {
if (isNoSelectionModel() && selectedEntityIdUiStateProvider != null) {
@@ -350,6 +350,16 @@ public class SelectionSupport<T extends ProxyIdentifiableEntity> {
}
}
/**
* Re-fetches and re-selects currently selected entity
*/
public void reselectCurrentEntity() {
getSelectedEntityId().ifPresent(selectedEntityId -> {
deselectAll();
selectEntityById(selectedEntityId);
});
}
@PreDestroy
void destroy() {
removeListeners();

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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<BulkUploadEventPayload> bulkUploadCallback) {
super(eventBus, EventTopics.BULK_UPLOAD_CHANGED);

View File

@@ -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 <T>
* Generic typ of ProxyIdentifiableEntity
*/
public class EntityModifiedListener<T extends ProxyIdentifiableEntity> extends TopicEventListener {
public final class EntityModifiedListener<T extends ProxyIdentifiableEntity> extends ViewAwareListener {
private final Class<T> entityType;
private final Class<? extends ProxyIdentifiableEntity> parentEntityType;
private final Supplier<Optional<Long>> parentEntityIdProvider;
@@ -48,14 +51,16 @@ public class EntityModifiedListener<T extends ProxyIdentifiableEntity> 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<T> entityType,
private EntityModifiedListener(final UIEventBus eventBus, final Class<T> entityType,
final Class<? extends ProxyIdentifiableEntity> parentEntityType,
final Supplier<Optional<Long>> parentEntityIdProvider,
final Supplier<Optional<Long>> parentEntityIdProvider, final EventViewAware viewAware,
final List<EntityModifiedAwareSupport> 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<T extends ProxyIdentifiableEntity> 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<T extends ProxyIdentifiableEntity> 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<? extends ProxyIdentifiableEntity> type) {
return entityType != null && entityType.equals(type);
}
@@ -161,6 +184,7 @@ public class EntityModifiedListener<T extends ProxyIdentifiableEntity> extends T
private final Class<T> entityType;
private Class<? extends ProxyIdentifiableEntity> parentEntityType;
private Supplier<Optional<Long>> parentEntityIdProvider;
private EventViewAware viewAware;
private List<EntityModifiedAwareSupport> entityModifiedAwareSupports;
/**
@@ -202,6 +226,18 @@ public class EntityModifiedListener<T extends ProxyIdentifiableEntity> extends T
return this;
}
/**
* Set View aware
*
* @param viewAware
* View aware
* @return builder
*/
public Builder<T> viewAware(final EventViewAware viewAware) {
this.viewAware = viewAware;
return this;
}
/**
* Build entity modified support for layout
*
@@ -220,7 +256,7 @@ public class EntityModifiedListener<T extends ProxyIdentifiableEntity> extends T
*/
public EntityModifiedListener<T> build() {
return new EntityModifiedListener<>(eventBus, entityType, parentEntityType, parentEntityIdProvider,
entityModifiedAwareSupports);
viewAware, entityModifiedAwareSupports);
}
}
}

View File

@@ -27,6 +27,7 @@ import org.vaadin.spring.events.annotation.EventBusListenerMethod;
public class FilterChangedListener<T extends ProxyIdentifiableEntity> extends ViewAwareListener {
private final Class<T> entityType;
private final FilterSupport<T, ?> filterSupport;
private final Runnable updateFilterCountInfo;
/**
* Constructor for FilterChangedListener
@@ -42,10 +43,30 @@ public class FilterChangedListener<T extends ProxyIdentifiableEntity> extends Vi
*/
public FilterChangedListener(final UIEventBus eventBus, final Class<T> entityType, final EventViewAware viewAware,
final FilterSupport<T, ?> 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<T> entityType, final EventViewAware viewAware,
final FilterSupport<T, ?> 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<T extends ProxyIdentifiableEntity> extends Vi
if (filterSupport.isFilterTypeSupported(filterType)) {
filterSupport.updateFilter(filterType, eventPayload.getFilterValue());
if (updateFilterCountInfo != null) {
updateFilterCountInfo.run();
}
}
}

View File

@@ -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<String> topics,
protected LayoutViewAwareListener(final UIEventBus eventBus, final Collection<String> topics,
final EventLayoutViewAware layoutViewAware) {
super(eventBus, topics);

View File

@@ -26,6 +26,7 @@ import org.vaadin.spring.events.annotation.EventBusListenerMethod;
public class PinningChangedListener<F> extends TopicEventListener {
private final Class<? extends ProxyIdentifiableEntity> entityType;
private final PinSupport<? extends ProxyIdentifiableEntity, F> pinSupport;
private final Runnable updatePinCountInfo;
/**
* Constructor for PinningChangedListener
@@ -39,10 +40,28 @@ public class PinningChangedListener<F> extends TopicEventListener {
*/
public PinningChangedListener(final UIEventBus eventBus, final Class<? extends ProxyIdentifiableEntity> entityType,
final PinSupport<? extends ProxyIdentifiableEntity, F> 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<? extends ProxyIdentifiableEntity> entityType,
final PinSupport<? extends ProxyIdentifiableEntity, F> 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<F> extends TopicEventListener {
} else {
pinSupport.updatePinFilter(null);
}
if (updatePinCountInfo != null) {
updatePinCountInfo.run();
}
}
private boolean suitableEntityType(final Class<? extends ProxyIdentifiableEntity> type) {

View File

@@ -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<String> 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<String> topics) {
protected TopicEventListener(final EventBus eventBus, final Collection<String> 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;
}
}

View File

@@ -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<String> topics,
protected ViewAwareListener(final UIEventBus eventBus, final Collection<String> 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;
}
}

View File

@@ -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<Long> entityIds) {
countAwareComponent.updateCountOnEntitiesAdded(entityIds.size());
}
@Override
public void onEntitiesUpdated(final Collection<Long> entityIds) {
countAwareComponent.updateCountOnEntitiesUpdated();
}
@Override
public void onEntitiesDeleted(final Collection<Long> entityIds) {
countAwareComponent.updateCountOnEntitiesDeleted(entityIds.size());
}
}

View File

@@ -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);
}

View File

@@ -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<EventLayout, VisibilityHandler> 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();
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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<UiErrorDetails> findDetails(final Throwable error) {
return findExceptionOf(error, EntityNotFoundException.class)
.map(ex -> UiErrorDetails.create(i18n.getMessage("caption.entity.missing.error"), ex.getMessage()));
}
}

View File

@@ -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<EventLayout, VisibilityHandler> 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();
}
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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)

View File

@@ -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;
}
}
}

View File

@@ -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);
}

View File

@@ -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<Long> filterExistingTagIds(final Collection<Long> tagIds) {
return distributionSetTagManagement.get(tagIds).stream().map(Identifiable::getId).collect(Collectors.toSet());
}
}

View File

@@ -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();
}

View File

@@ -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<ProxyTarget, TargetManagementFilterParams> 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<ProxyTarget, TargetManagementFilterParams> 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<TargetUpdateStatus> 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<TargetUpdateStatus> status) {
if (!status.isEmpty()) {
appendFilterMsg(filterMessageBuilder, i18n.getMessage("label.filter.status"));
}
}
private static String getTagsMsg(final Boolean noTargetTagSelected, final Collection<String> 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<String> 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();
}
}

View File

@@ -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);
}
/**

View File

@@ -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<MasterEntityAwareComponent<ProxyTarget>> 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<EntityModifiedAwareSupport> 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();

View File

@@ -59,7 +59,8 @@ public class MultipleTargetFilter extends Accordion {
private final transient EntityModifiedListener<ProxyTag> entityTagModifiedListener;
private final transient EntityModifiedListener<ProxyTargetFilterQuery> 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();

View File

@@ -44,6 +44,7 @@ public class TargetFilterQueryButtons extends AbstractGrid<ProxyTargetFilterQuer
private static final String FILTER_BUTTON_COLUMN_ID = "filterButton";
private final transient TargetFilterQueryManagement targetFilterQueryManagement;
private final TargetTagFilterLayoutUiState targetTagFilterLayoutUiState;
private final CustomTargetTagFilterButtonClick customTargetTagFilterButtonClick;
@@ -53,6 +54,7 @@ public class TargetFilterQueryButtons extends AbstractGrid<ProxyTargetFilterQuer
final TargetTagFilterLayoutUiState targetTagFilterLayoutUiState) {
super(i18n, eventBus);
this.targetFilterQueryManagement = targetFilterQueryManagement;
this.targetTagFilterLayoutUiState = targetTagFilterLayoutUiState;
this.customTargetTagFilterButtonClick = new CustomTargetTagFilterButtonClick(this::onFilterChangedEvent);
@@ -141,7 +143,7 @@ public class TargetFilterQueryButtons extends AbstractGrid<ProxyTargetFilterQuer
* Reselect filter when target filter query updated
*
* @param updatedTargetFilterQueryIds
* List of update query id
* List of update query id
*/
public void reselectFilterOnTfqUpdated(final Collection<Long> updatedTargetFilterQueryIds) {
if (isClickedTfqInIds(updatedTargetFilterQueryIds)) {
@@ -159,7 +161,7 @@ public class TargetFilterQueryButtons extends AbstractGrid<ProxyTargetFilterQuer
* Reselect filter when target filter query deleted
*
* @param deletedTargetFilterQueryIds
* List of deleted query id
* List of deleted query id
*/
public void resetFilterOnTfqDeleted(final Collection<Long> deletedTargetFilterQueryIds) {
if (isClickedTfqInIds(deletedTargetFilterQueryIds)) {
@@ -173,8 +175,29 @@ public class TargetFilterQueryButtons extends AbstractGrid<ProxyTargetFilterQuer
final Long targetFilterQueryIdToRestore = targetTagFilterLayoutUiState.getClickedTargetFilterQueryId();
if (targetFilterQueryIdToRestore != null) {
customTargetTagFilterButtonClick
.setPreviouslyClickedFilterId(targetTagFilterLayoutUiState.getClickedTargetFilterQueryId());
if (targetFilterQueryExists(targetFilterQueryIdToRestore)) {
customTargetTagFilterButtonClick
.setPreviouslyClickedFilterId(targetTagFilterLayoutUiState.getClickedTargetFilterQueryId());
} else {
targetTagFilterLayoutUiState.setClickedTargetFilterQueryId(null);
}
}
}
private boolean targetFilterQueryExists(final Long targetFilterQueryId) {
return targetFilterQueryManagement.get(targetFilterQueryId).isPresent();
}
/**
* Re-evaluates a filter (usually after view enter).
*
*/
public void reevaluateFilter() {
final Long clickedTargetFilterQueryId = customTargetTagFilterButtonClick.getPreviouslyClickedFilterId();
if (clickedTargetFilterQueryId != null && !targetFilterQueryExists(clickedTargetFilterQueryId)) {
customTargetTagFilterButtonClick.setPreviouslyClickedFilterId(null);
publishFilterChangedEvent(null);
}
}
}

View File

@@ -8,8 +8,11 @@
*/
package org.eclipse.hawkbit.ui.management.targettag.filter;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.Identifiable;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TargetTagManagement;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
@@ -106,4 +109,9 @@ public class TargetTagFilterButtons extends AbstractTagFilterButtons {
protected Window getUpdateWindow(final ProxyTag clickedFilter) {
return targetTagWindowBuilder.getWindowForUpdate(clickedFilter);
}
@Override
protected Collection<Long> filterExistingTagIds(final Collection<Long> tagIds) {
return targetTagManagement.get(tagIds).stream().map(Identifiable::getId).collect(Collectors.toSet());
}
}

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -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<EventLayout, VisibilityHandler> 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();
}
}

View File

@@ -244,7 +244,7 @@ public class RolloutGrid extends AbstractGrid<ProxyRollout, String> {
}
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<ProxyRollout, String> {
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<ProxyRollout, String> {
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<ProxyRollout> refetchedRollout = mapIdToProxyEntity(selectedRolloutId);
refetchedRollout.ifPresent(rollout -> {
getSelectionSupport().sendSelectionChangedEvent(SelectionChangedEventType.ENTITY_SELECTED, rollout);
rolloutManagementUIState.setSelectedRolloutName(rollout.getName());
});
if (!refetchedRollout.isPresent()) {
onSelectedRolloutDeleted(selectedRolloutId);
}
}
}

View File

@@ -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();
}

View File

@@ -163,6 +163,10 @@ public class RolloutGroupGrid extends AbstractGrid<ProxyRolloutGroup, Long> {
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<ProxyRolloutGroup, Long> {
}
private void updateGridItem(final RolloutGroup rolloutGroup) {
final ProxyRolloutGroup proxyRolloutGroup = RolloutGroupToProxyRolloutGroupMapper.mapGroup(rolloutGroup);
getDataProvider().refreshItem(proxyRolloutGroup);
getDataProvider().refreshItem(rolloutGroupMapper.map(rolloutGroup));
}
@Override

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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<String> 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();

View File

@@ -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;
}
}

View File

@@ -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