Feature target type filter (#1197)

* Added Target type filter with drag and drop support

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Removed the unused enums and target type filter button class

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Resolved merge conflicts

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Fixed java doc issue with the method link in the comment

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Fixed the IN query overflow for target Type assignment

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Fixed Review comments

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>
This commit is contained in:
Anand Kumar
2021-10-27 15:24:09 +02:00
committed by GitHub
parent dea6fa3ce6
commit 70779d1ac7
38 changed files with 1409 additions and 398 deletions

View File

@@ -8,9 +8,18 @@
*/
package org.eclipse.hawkbit.ui.common.builder;
import com.vaadin.data.Binder;
import com.vaadin.data.Binder.Binding;
import com.vaadin.data.Binder.BindingBuilder;
import com.vaadin.data.Validator;
import com.vaadin.data.ValueProvider;
import com.vaadin.server.Setter;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.TextField;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.repository.model.NamedVersionedEntity;
import org.eclipse.hawkbit.repository.model.TargetType;
import org.eclipse.hawkbit.repository.model.Type;
import org.eclipse.hawkbit.ui.common.data.aware.ActionTypeAware;
import org.eclipse.hawkbit.ui.common.data.aware.DescriptionAware;
@@ -23,7 +32,6 @@ import org.eclipse.hawkbit.ui.common.data.aware.VersionAware;
import org.eclipse.hawkbit.ui.common.data.providers.AbstractProxyDataProvider;
import org.eclipse.hawkbit.ui.common.data.providers.DistributionSetStatelessDataProvider;
import org.eclipse.hawkbit.ui.common.data.providers.TargetFilterQueryDataProvider;
import org.eclipse.hawkbit.ui.common.data.providers.TargetTypeDataProvider;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSet;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSetInfo;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetFilterQuery;
@@ -39,17 +47,6 @@ import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.util.StringUtils;
import com.vaadin.data.Binder;
import com.vaadin.data.Binder.Binding;
import com.vaadin.data.Binder.BindingBuilder;
import com.vaadin.data.Validator;
import com.vaadin.data.ValueProvider;
import com.vaadin.server.Setter;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.TextField;
/**
* Builder class for from components
*/

View File

@@ -8,18 +8,17 @@
*/
package org.eclipse.hawkbit.ui.common.data.filters;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Objects;
import com.google.common.base.MoreObjects;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.ui.common.data.providers.TargetManagementStateDataProvider;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import com.google.common.base.MoreObjects;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Objects;
/**
* Filter params for {@link TargetManagementStateDataProvider}.
@@ -35,12 +34,14 @@ public class TargetManagementFilterParams implements Serializable {
private boolean noTagClicked;
private Collection<String> targetTags;
private Long targetFilterQueryId;
private boolean noTargetTypeClicked;
private Long targetTypeId;
/**
* Constructor for TargetManagementFilterParams to initialize
*/
public TargetManagementFilterParams() {
this(null, null, Collections.emptyList(), false, null, false, Collections.emptyList(), null);
this(null, null, Collections.emptyList(), false, null, false, Collections.emptyList(), null, false, null);
}
/**
@@ -66,7 +67,7 @@ public class TargetManagementFilterParams implements Serializable {
public TargetManagementFilterParams(final Long pinnedDistId, final String searchText,
final Collection<TargetUpdateStatus> targetUpdateStatusList, final boolean overdueState,
final Long distributionId, final boolean noTagClicked, final Collection<String> targetTags,
final Long targetFilterQueryId) {
final Long targetFilterQueryId, final boolean noTargetTypeClicked, final Long targetTypeId) {
this.pinnedDistId = pinnedDistId;
this.searchText = searchText;
this.targetUpdateStatusList = targetUpdateStatusList;
@@ -75,6 +76,8 @@ public class TargetManagementFilterParams implements Serializable {
this.noTagClicked = noTagClicked;
this.targetTags = targetTags;
this.targetFilterQueryId = targetFilterQueryId;
this.noTargetTypeClicked = noTargetTypeClicked;
this.targetTypeId = targetTypeId;
}
/**
@@ -93,6 +96,8 @@ public class TargetManagementFilterParams implements Serializable {
this.distributionId = filter.getDistributionId();
this.noTagClicked = filter.isNoTagClicked();
this.targetTags = filter.getTargetTags() != null ? new ArrayList<>(filter.getTargetTags()) : null;
this.noTargetTypeClicked = filter.isNoTargetTypeClicked();
this.targetTypeId = filter.getTargetTypeId();
this.targetFilterQueryId = filter.getTargetFilterQueryId();
}
@@ -119,7 +124,11 @@ public class TargetManagementFilterParams implements Serializable {
}
private boolean isAnyComplexFilterSelected() {
return distributionId != null || targetFilterQueryId != null;
return distributionId != null || targetFilterQueryId != null || isAnyTypeSelected();
}
private boolean isAnyTypeSelected(){
return targetTypeId != null || isNoTargetTypeClicked();
}
/**
@@ -278,6 +287,46 @@ public class TargetManagementFilterParams implements Serializable {
this.noTagClicked = noTagClicked;
}
/**
* Gets the status of no target Type clicked
*
* @return noTargetTypeClicked <code>true</code> if it is clicked, otherwise
* <code>false</code>
*/
public boolean isNoTargetTypeClicked() {
return noTargetTypeClicked;
}
/**
* Sets the state of no target type filter
*
* @param noTargetTypeClicked
* <code>true</code> if the tag is clicked, otherwise
* <code>false</code>
*/
public void setNoTargetTypeClicked(boolean noTargetTypeClicked) {
this.noTargetTypeClicked = noTargetTypeClicked;
}
/**
* Gets the targetTypeId
*
* @return targetTypeId for target type filter
*/
public Long getTargetTypeId() {
return targetTypeId;
}
/**
* Sets the targetType
*
* @param targetTypeId
* Id of targetType
*/
public void setTargetTypeId(Long targetTypeId) {
this.targetTypeId = targetTypeId;
}
// equals requires all fields in condition
@SuppressWarnings("squid:S1067")
@Override
@@ -296,13 +345,15 @@ public class TargetManagementFilterParams implements Serializable {
&& Objects.equals(this.getDistributionId(), other.getDistributionId())
&& Objects.equals(this.isNoTagClicked(), other.isNoTagClicked())
&& Objects.equals(this.getTargetTags(), other.getTargetTags())
&& Objects.equals(this.getTargetFilterQueryId(), other.getTargetFilterQueryId());
&& Objects.equals(this.getTargetFilterQueryId(), other.getTargetFilterQueryId())
&& Objects.equals(this.isNoTargetTypeClicked(), other.isNoTargetTypeClicked())
&& Objects.equals(this.getTargetTypeId(), other.getTargetTypeId());
}
@Override
public int hashCode() {
return Objects.hash(getPinnedDistId(), getSearchText(), getTargetUpdateStatusList(), isOverdueState(),
getDistributionId(), isNoTagClicked(), getTargetTags(), getTargetFilterQueryId());
getDistributionId(), isNoTagClicked(), getTargetTags(), getTargetFilterQueryId(), isNoTargetTypeClicked(), getTargetTypeId());
}
@Override
@@ -311,6 +362,7 @@ public class TargetManagementFilterParams implements Serializable {
.add("searchText", getSearchText()).add("targetUpdateStatusList", getTargetUpdateStatusList())
.add("overdueState", isOverdueState()).add("distributionId", getDistributionId())
.add("noTagClicked", isNoTagClicked()).add("targetTags", getTargetTags())
.add("targetFilterQueryId", getTargetFilterQueryId()).toString();
.add("targetFilterQueryId", getTargetFilterQueryId())
.add("noTargetTypeClicked", isNoTargetTypeClicked()).add("targetTypeId", getTargetTypeId()).toString();
}
}

View File

@@ -64,6 +64,8 @@ public class TargetManagementStateDataProvider
final boolean noTagClicked = filter.isNoTagClicked();
final String[] targetTags = filter.getTargetTags().toArray(new String[0]);
final Long targetFilterQueryId = filter.getTargetFilterQueryId();
final boolean noTargetTypeClicked = filter.isNoTargetTypeClicked();
final Long targetTypeId = filter.getTargetTypeId();
if (pinnedDistId != null) {
return targetManagement.findByFilterOrderByLinkedDistributionSet(pageRequest, pinnedDistId,
@@ -76,6 +78,12 @@ public class TargetManagementStateDataProvider
return targetManagement.findByTargetFilterQuery(pageRequest, targetFilterQueryId);
}
// Type Filter of Deployment Management view
if (targetTypeId != null || noTargetTypeClicked) {
return targetManagement.findByFilters(pageRequest, new FilterParams(searchText, distributionId, noTargetTypeClicked, targetTypeId));
}
// Simple Filter of Deployment Management view
return targetManagement.findByFilters(pageRequest, new FilterParams(targetUpdateStatusList, overdueState,
searchText, distributionId, noTagClicked, targetTags));
}
@@ -95,6 +103,8 @@ public class TargetManagementStateDataProvider
final Long distributionId = filter.getDistributionId();
final boolean noTagClicked = filter.isNoTagClicked();
final String[] targetTags = filter.getTargetTags().toArray(new String[0]);
final boolean noTargetTypeClicked = filter.isNoTargetTypeClicked();
final Long targetTypeId = filter.getTargetTypeId();
final Long targetFilterQueryId = filter.getTargetFilterQueryId();
if (filter.isAnyFilterSelected()) {
@@ -102,8 +112,14 @@ public class TargetManagementStateDataProvider
return targetManagement.countByTargetFilterQuery(targetFilterQueryId);
}
return targetManagement.countByFilters(targetUpdateStatusList, overdueState, searchText, distributionId,
noTagClicked, targetTags);
// Type Filter of Deployment Management view
if (targetTypeId != null || noTargetTypeClicked) {
return targetManagement.countByFilters(new FilterParams(searchText, distributionId, noTargetTypeClicked, targetTypeId));
}
// Simple Filter of Deployment Management view
return targetManagement.countByFilters(new FilterParams(targetUpdateStatusList, overdueState, searchText, distributionId,
noTagClicked, targetTags));
}
return targetManagement.count();

View File

@@ -31,6 +31,14 @@ public class TargetTypeDataProvider<T extends ProxyIdentifiableEntity>
private static final long serialVersionUID = 1L;
private final transient TargetTypeManagement targetTypeManagement;
/**
* Constructor
*
* @param targetTypeManagement
* TargetTypeManagement
* @param mapper
* Mapper
*/
public TargetTypeDataProvider(final TargetTypeManagement targetTypeManagement, IdentifiableEntityToProxyIdentifiableEntityMapper<T, TargetType> mapper) {
super(mapper, Sort.by(Direction.ASC, "name"));
this.targetTypeManagement = targetTypeManagement;

View File

@@ -12,5 +12,5 @@ package org.eclipse.hawkbit.ui.common.event;
* Enum constants for filter type
*/
public enum FilterType {
SEARCH, TYPE, TARGET_TYPE, TAG, NO_TAG, STATUS, OVERDUE, QUERY, DISTRIBUTION, MASTER;
SEARCH, TYPE, TAG, NO_TAG, TARGET_TYPE, NO_TARGET_TYPE, STATUS, OVERDUE, QUERY, DISTRIBUTION, MASTER;
}

View File

@@ -9,8 +9,7 @@
package org.eclipse.hawkbit.ui.common.filterlayout;
import com.vaadin.ui.Button;
import java.util.Collection;
import java.util.Map;
import org.eclipse.hawkbit.repository.TargetTypeManagement;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTarget;
@@ -20,47 +19,57 @@ import org.eclipse.hawkbit.ui.common.event.EventView;
import org.eclipse.hawkbit.ui.common.event.FilterChangedEventPayload;
import org.eclipse.hawkbit.ui.common.event.FilterType;
import org.eclipse.hawkbit.ui.common.filterlayout.AbstractFilterButtonClickBehaviour.ClickBehaviourType;
import org.eclipse.hawkbit.ui.common.state.TagFilterLayoutUiState;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.decorators.SPUITagButtonStyle;
import org.eclipse.hawkbit.ui.management.targettag.filter.TargetTagFilterLayoutUiState;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.UINotification;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
/**
* Class for defining the type filter buttons.
* Class for defining the target type filter buttons.
*/
public abstract class AbstractTargetTypeFilterButtons extends AbstractFilterButtons<ProxyTargetType, Void> {
private static final long serialVersionUID = 1L;
private final TagFilterLayoutUiState tagFilterLayoutUiState;
private final TargetTagFilterLayoutUiState targetTagFilterLayoutUiState;
protected final UINotification uiNotification;
private final Button noTargetTypeButton;
private final TargetTypeFilterButtonClick targetTypeFilterButtonClick;
private final transient TargetTypeManagement targetTypeManagement;
private final Button noTargetTypeButton;
private boolean preNoTargetTypeBtnState;
/**
* Constructor for AbstractTargetTypeFilterButtons
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param tagFilterLayoutUiState
* TagFilterLayoutUiState
* @param targetTagFilterLayoutUiState
* {@link TargetTagFilterLayoutUiState}
* @param targetTypeManagement
* TargetTypeManagement
*/
protected AbstractTargetTypeFilterButtons(final CommonUiDependencies uiDependencies,
final TagFilterLayoutUiState tagFilterLayoutUiState) {
final TargetTagFilterLayoutUiState targetTagFilterLayoutUiState,
final TargetTypeManagement targetTypeManagement) {
super(uiDependencies.getEventBus(), uiDependencies.getI18n(), uiDependencies.getUiNotification(),
uiDependencies.getPermChecker());
this.preNoTargetTypeBtnState = false;
this.uiNotification = uiDependencies.getUiNotification();
this.tagFilterLayoutUiState = tagFilterLayoutUiState;
this.targetTagFilterLayoutUiState = targetTagFilterLayoutUiState;
this.targetTypeManagement = targetTypeManagement;
this.noTargetTypeButton = buildNoTargetTypeButton();
this.targetTypeFilterButtonClick = new TargetTypeFilterButtonClick(this::onFilterChangedEvent);
}
@Override
protected TargetTypeFilterButtonClick getFilterButtonClickBehaviour() {
return targetTypeFilterButtonClick;
}
private Button buildNoTargetTypeButton() {
final Button noTargetType = SPUIComponentProvider.getButton(
getFilterButtonIdPrefix() + "." + SPUIDefinitions.NO_TARGET_TYPE_BUTTON_ID,
@@ -71,24 +80,51 @@ public abstract class AbstractTargetTypeFilterButtons extends AbstractFilterButt
final ProxyTargetType proxyTargetType = new ProxyTargetType();
proxyTargetType.setNoTargetType(true);
noTargetType.addClickListener(event -> getFilterButtonClickBehaviour().processFilterClick(proxyTargetType));
noTargetType.addStyleName("filter-drop-hint-layout");
return noTargetType;
}
@Override
protected TargetTypeFilterButtonClick getFilterButtonClickBehaviour(){
return targetTypeFilterButtonClick;
/**
* @return the noTargetType Button component
*/
public Button getNoTargetTypeButton() {
return noTargetTypeButton;
}
private void onFilterChangedEvent(final ProxyTargetType targetType,
final ClickBehaviourType clickType) {
final Long targetTypeId = ClickBehaviourType.CLICKED == clickType ? targetType.getId()
private void onFilterChangedEvent(ProxyTargetType proxyTargetType, ClickBehaviourType clickType) {
getDataCommunicator().reset();
final boolean isNoTargetTypeActive = proxyTargetType.isNoTargetType() && clickType == ClickBehaviourType.CLICKED;
if (isNoTargetTypeActive) {
getNoTargetTypeButton().addStyleName(SPUIStyleDefinitions.SP_NO_TAG_BTN_CLICKED_STYLE);
} else {
getNoTargetTypeButton().removeStyleName(SPUIStyleDefinitions.SP_NO_TAG_BTN_CLICKED_STYLE);
}
if (preNoTargetTypeBtnState != isNoTargetTypeActive){
publishNoTargetTypeChangedEvent(isNoTargetTypeActive);
}
final Long targetTypeId = ClickBehaviourType.CLICKED == clickType ? proxyTargetType.getId()
: null;
publishFilterChangedEvent(targetTypeId);
preNoTargetTypeBtnState = isNoTargetTypeActive;
}
private void publishNoTargetTypeChangedEvent(final boolean isNoTargetTypeActivated) {
eventBus.publish(EventTopics.FILTER_CHANGED, this, new FilterChangedEventPayload<>(ProxyTarget.class,
FilterType.NO_TARGET_TYPE, isNoTargetTypeActivated, EventView.DEPLOYMENT));
targetTagFilterLayoutUiState.setNoTargetTypeClicked(isNoTargetTypeActivated);
}
private void publishFilterChangedEvent(final Long targetTypeId) {
eventBus.publish(EventTopics.FILTER_CHANGED, this, new FilterChangedEventPayload<>(ProxyTarget.class,
FilterType.TARGET_TYPE, targetTypeId, EventView.DEPLOYMENT));
targetTagFilterLayoutUiState.setClickedTargetTypeFilterId(targetTypeId);
}
/**
@@ -105,52 +141,92 @@ public abstract class AbstractTargetTypeFilterButtons extends AbstractFilterButt
*/
protected abstract EventView getView();
/**
* Target type deletion operation.
*
* @param targetTypeToDelete
* target type to delete
*
* @return true if target type is deleted, in error case false.
*/
protected abstract boolean deleteTargetType(final ProxyTargetType targetTypeToDelete);
/**
* @return Button component of no target type
* Type deletion operation.
*
* @param typeToDelete
* target type to delete
* @return true if delete target type has no exception
*/
public Button getNoTargetTypeButton() {
return noTargetTypeButton;
}
protected abstract boolean deleteTargetType(final ProxyTargetType typeToDelete);
@Override
public void restoreState() {
final Map<Long, String> targetTypesToRestore = tagFilterLayoutUiState.getClickedTagIdsWithName();
final Long targetFilterTypeIdToRestore = targetTagFilterLayoutUiState.getClickedTargetTypeFilterId();
if (!CollectionUtils.isEmpty(targetTypesToRestore)) {
removeNonExistingTargetTypes(targetTypesToRestore);
if (targetFilterTypeIdToRestore != null) {
if (targetTypeExists(targetFilterTypeIdToRestore)) {
targetTypeFilterButtonClick
.setPreviouslyClickedFilterId(targetTagFilterLayoutUiState.getClickedTargetTypeFilterId());
} else {
targetTagFilterLayoutUiState.setClickedTargetTypeFilterId(null);
}
}
if (tagFilterLayoutUiState.isNoTagClicked()) {
if (targetTagFilterLayoutUiState.isNoTargetTypeClicked()) {
getNoTargetTypeButton().addStyleName(SPUIStyleDefinitions.SP_NO_TAG_BTN_CLICKED_STYLE);
}
}
private void removeNonExistingTargetTypes(final Map<Long, String> targetTypeIdsWithName) {
final Collection<Long> targetTypeIds = targetTypeIdsWithName.keySet();
final Collection<Long> existingTargetTypeIds = filterExistingTargetTypeIds(targetTypeIds);
if (targetTypeIds.size() != existingTargetTypeIds.size()) {
targetTypeIds.retainAll(existingTargetTypeIds);
/**
* Reset filter on target type updated
*
* @param updatedTargetTypeIds
* Collections of updated target type Ids
*/
public void resetFilterOnTargetTypeUpdated(Collection<Long> updatedTargetTypeIds) {
if (isClickedTargetTypeInIds(updatedTargetTypeIds)) {
publishFilterChangedEvent(targetTypeFilterButtonClick.getPreviouslyClickedFilterId());
}
}
/**
* Filters out non-existant target type by ids.
* Reset filter on target type deleted
*
* @param targetTypeIds
* provided target type ids
* @return filtered list of existing target type ids
* @param deletedTargetTargetTypeIds
* Collections of updated target type Ids
*/
protected abstract Collection<Long> filterExistingTargetTypeIds(final Collection<Long> targetTypeIds);
public void resetFilterOnTargetTypeDeleted(final Collection<Long> deletedTargetTargetTypeIds) {
if (isClickedTargetTypeInIds(deletedTargetTargetTypeIds)) {
targetTypeFilterButtonClick.setPreviouslyClickedFilterId(null);
publishFilterChangedEvent(null);
}
}
private boolean isClickedTargetTypeInIds(final Collection<Long> targetTypeIds) {
final Long clickedTargetTypeId = targetTypeFilterButtonClick.getPreviouslyClickedFilterId();
return clickedTargetTypeId != null && targetTypeIds.contains(clickedTargetTypeId);
}
/**
* Reevaluate filter
*/
public void reevaluateFilter() {
final Long clickedTargetTypeId = targetTypeFilterButtonClick.getPreviouslyClickedFilterId();
if (clickedTargetTypeId != null && !targetTypeExists(clickedTargetTypeId)) {
targetTypeFilterButtonClick.setPreviouslyClickedFilterId(null);
publishFilterChangedEvent(null);
}
}
private boolean targetTypeExists(Long targetTypeId) {
return targetTypeManagement.get(targetTypeId).isPresent();
}
/**
* Remove applied target type filter
*/
public void clearAppliedTargetTypeFilter() {
if (targetTagFilterLayoutUiState.isNoTargetTypeClicked()) {
targetTagFilterLayoutUiState.setNoTargetTypeClicked(false);
getNoTargetTypeButton().removeStyleName(SPUIStyleDefinitions.SP_NO_TAG_BTN_CLICKED_STYLE);
}
if (targetTypeFilterButtonClick.getPreviouslyClickedFilterId() != null) {
targetTypeFilterButtonClick.setPreviouslyClickedFilterId(null);
targetTagFilterLayoutUiState.setClickedTargetTypeFilterId(null);
}
}
}

View File

@@ -17,24 +17,61 @@ import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetType;
public class TargetTypeFilterButtonClick extends AbstractFilterSingleButtonClick<ProxyTargetType> {
private static final long serialVersionUID = 1L;
private boolean noTargetTypeBtnClicked;
private final transient BiConsumer<ProxyTargetType, ClickBehaviourType> filterChangedCallback;
TargetTypeFilterButtonClick(final BiConsumer<ProxyTargetType, ClickBehaviourType> filterChangedCallback) {
/**
* Constructor
*
* @param filterChangedCallback
* filterChangedCallback
*/
public TargetTypeFilterButtonClick(
final BiConsumer<ProxyTargetType, ClickBehaviourType> filterChangedCallback) {
this.filterChangedCallback = filterChangedCallback;
this.noTargetTypeBtnClicked = false;
}
@Override
public void processFilterClick(final ProxyTargetType clickedFilter) {
if (isFilterPreviouslyClicked(clickedFilter) || isNoTargetTypePreviouslyClicked(clickedFilter)) {
previouslyClickedFilterId = null;
filterUnClicked(clickedFilter);
} else {
previouslyClickedFilterId = clickedFilter.getId();
filterClicked(clickedFilter);
}
}
@Override
protected void filterUnClicked(ProxyTargetType clickedFilter) {
if (clickedFilter.isNoTargetType()){
noTargetTypeBtnClicked = false;
}
filterChangedCallback.accept(clickedFilter, ClickBehaviourType.UNCLICKED);
}
@Override
protected void filterClicked(ProxyTargetType clickedFilter) {
noTargetTypeBtnClicked = clickedFilter.isNoTargetType();
filterChangedCallback.accept(clickedFilter, ClickBehaviourType.CLICKED);
}
@Override
public boolean isFilterPreviouslyClicked(final ProxyTargetType clickedFilter) {
return false;
return (previouslyClickedFilterId != null && previouslyClickedFilterId.equals(clickedFilter.getId()));
}
private boolean isNoTargetTypePreviouslyClicked(ProxyTargetType clickedFilter) {
return clickedFilter.isNoTargetType() && isNoTargetTypeBtnClicked();
}
/**
* @return true if no target type button clicked
*/
public boolean isNoTargetTypeBtnClicked() {
return noTargetTypeBtnClicked;
}
}

View File

@@ -0,0 +1,52 @@
/**
* 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.grid.support.assignment;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTarget;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetType;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
import org.eclipse.hawkbit.ui.common.event.EventTopics;
import org.vaadin.spring.events.EventBus;
/**
* Support for assigning/un-assigning targets to target type.
*
*/
public abstract class AbstractTargetsToTargetTypeAssignmentSupport extends AssignmentSupport<ProxyTarget, ProxyTargetType> {
private final SpPermissionChecker permChecker;
private final EventBus.UIEventBus eventBus;
protected AbstractTargetsToTargetTypeAssignmentSupport(final CommonUiDependencies uiDependencies) {
super(uiDependencies.getUiNotification(), uiDependencies.getI18n());
this.permChecker = uiDependencies.getPermChecker();
this.eventBus = uiDependencies.getEventBus();
}
@Override
public List<String> getMissingPermissionsForDrop() {
return permChecker.hasUpdateTargetPermission() ? Collections.emptyList()
: Collections.singletonList(SpPermission.UPDATE_TARGET);
}
protected void publishTypeAssignmentEvent(final List<ProxyTarget> sourceItemsToAssign) {
final List<Long> assignedTargetIds = sourceItemsToAssign.stream().map(ProxyIdentifiableEntity::getId)
.collect(Collectors.toList());
eventBus.publish(EventTopics.ENTITY_MODIFIED, this,
new EntityModifiedEventPayload(EntityModifiedEventPayload.EntityModifiedEventType.ENTITY_UPDATED,
ProxyTarget.class, assignedTargetIds));
}
}

View File

@@ -0,0 +1,83 @@
/**
* 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.grid.support.assignment;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.model.AbstractAssignmentResult;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTarget;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetType;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.springframework.util.CollectionUtils;
/**
* Support for un-assigning the {@link ProxyTarget} items from a {@link ProxyTargetType}.
*
*/
public class TargetsToNoTargetTypeAssignmentSupport extends AbstractTargetsToTargetTypeAssignmentSupport {
private final TargetManagement targetManagement;
private static final String CAPTION_TYPE = "caption.type";
private static final String CAPTION_TARGET = "caption.target";
/**
* Constructor for TargetsToTargetTypeAssignmentSupport
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param targetManagement
* TargetManagement
*/
public TargetsToNoTargetTypeAssignmentSupport(final CommonUiDependencies uiDependencies,
final TargetManagement targetManagement) {
super(uiDependencies);
this.targetManagement = targetManagement;
}
@Override
protected void performAssignment(List<ProxyTarget> sourceItemsToAssign, ProxyTargetType targetItem) {
if (hasRequiredPermissions()) {
final AbstractAssignmentResult<Target> typesAssignmentResult = initiateTargetTypeUnAssignment(
sourceItemsToAssign);
final String assignmentMsg = createAssignmentMessage(typesAssignmentResult, i18n.getMessage(CAPTION_TARGET),
i18n.getMessage(CAPTION_TYPE), "");
notification.displaySuccess(assignmentMsg);
publishTypeAssignmentEvent(sourceItemsToAssign);
}
}
/**
*
* @return false if required permissions are missing
*/
private boolean hasRequiredPermissions() {
final List<String> requiredPermissions = getMissingPermissionsForDrop();
if (!CollectionUtils.isEmpty(requiredPermissions)) {
notification
.displayValidationError(i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_PERMISSION_INSUFFICIENT, requiredPermissions));
return false;
}
return true;
}
protected AbstractAssignmentResult<Target> initiateTargetTypeUnAssignment(final List<ProxyTarget> sourceItems) {
final Collection<String> controllerIdsToAssign = sourceItems.stream().map(ProxyTarget::getControllerId)
.collect(Collectors.toList());
return targetManagement.unAssignType(controllerIdsToAssign);
}
}

View File

@@ -0,0 +1,98 @@
/**
* 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.grid.support.assignment;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.model.AbstractAssignmentResult;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTarget;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetType;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
/**
* Support for assigning the {@link ProxyTarget} items to {@link ProxyTargetType}.
*
*/
public class TargetsToTargetTypeAssignmentSupport extends AbstractTargetsToTargetTypeAssignmentSupport {
private final TargetManagement targetManagement;
private static final String CAPTION_TYPE = "caption.type";
private static final String CAPTION_TARGET = "caption.target";
/**
* Constructor for TargetsToTargetTypeAssignmentSupport
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param targetManagement
* TargetManagement
*/
public TargetsToTargetTypeAssignmentSupport(final CommonUiDependencies uiDependencies, final TargetManagement targetManagement) {
super(uiDependencies);
this.targetManagement = targetManagement;
}
@Override
protected List<ProxyTarget> getFilteredSourceItems(List<ProxyTarget> sourceItemsToAssign, ProxyTargetType targetItem) {
if (!isAssignmentValid(sourceItemsToAssign, targetItem)) {
return Collections.emptyList();
}
return sourceItemsToAssign;
}
/**
*
* @param sourceItemsToAssign
* @param targetItem
* @return false if some targets already have a type assigned
*/
private boolean isAssignmentValid(List<ProxyTarget> sourceItemsToAssign, ProxyTargetType targetItem) {
if(sourceItemsToAssign.size() > 1) {
List<ProxyTarget> targetsWithDifferentType = sourceItemsToAssign.stream().filter(
target -> target.getTypeInfo() != null && !target.getTypeInfo().getId().equals(targetItem.getId()))
.collect(Collectors.toList());
if (!targetsWithDifferentType.isEmpty()) {
notification.displayValidationError(i18n.getMessage(UIMessageIdProvider.MESSAGE_TARGET_TARGETTYPE_ASSIGNED));
return false;
}
}
return true;
}
@Override
protected void performAssignment(final List<ProxyTarget> sourceItemsToAssign, final ProxyTargetType targetItem) {
final Long typeId = targetItem.getId();
final AbstractAssignmentResult<Target> typesAssignmentResult = initiateTargetTypeAssignment(sourceItemsToAssign,
typeId);
final String assignmentMsg = createAssignmentMessage(typesAssignmentResult,
i18n.getMessage(CAPTION_TARGET),
i18n.getMessage(CAPTION_TYPE), targetItem.getName());
notification.displaySuccess(assignmentMsg);
publishTypeAssignmentEvent(sourceItemsToAssign);
}
private AbstractAssignmentResult<Target> initiateTargetTypeAssignment(final List<ProxyTarget> sourceItems,
final Long typeId) {
final Collection<String> controllerIdsToAssign = sourceItems.stream().map(ProxyTarget::getControllerId)
.collect(Collectors.toList());
return targetManagement.assignType(controllerIdsToAssign, typeId);
}
}

View File

@@ -0,0 +1,85 @@
/**
* 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.grid.support.assignment;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.model.TargetTypeAssignmentResult;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTarget;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetType;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
import org.eclipse.hawkbit.ui.common.event.EventTopics;
import org.vaadin.spring.events.EventBus;
/**
* Support for assigning the {@link ProxyTargetType} items to {@link ProxyTarget}.
*
*/
public class TypeToTargetAssignmentSupport extends AssignmentSupport<ProxyTargetType, ProxyTarget> {
private final TargetManagement targetManagement;
private final EventBus.UIEventBus eventBus;
private final SpPermissionChecker permChecker;
private static final String CAPTION_TYPE = "caption.type";
private static final String CAPTION_TARGET = "caption.target";
/**
* Constructor for TypeToTargetAssignmentSupport
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param targetManagement
* TargetManagement
*/
public TypeToTargetAssignmentSupport(final CommonUiDependencies uiDependencies, final TargetManagement targetManagement) {
super(uiDependencies.getUiNotification(), uiDependencies.getI18n());
this.eventBus = uiDependencies.getEventBus();
this.permChecker = uiDependencies.getPermChecker();
this.targetManagement = targetManagement;
}
@Override
public List<String> getMissingPermissionsForDrop() {
return permChecker.hasUpdateTargetPermission() ? Collections.emptyList()
: Collections.singletonList(SpPermission.UPDATE_TARGET);
}
@Override
protected void performAssignment(List<ProxyTargetType> sourceItemsToAssign, ProxyTarget targetItem) {
final String controllerId = targetItem.getControllerId();
// multi-type assignment is not supported
final Long typeId = sourceItemsToAssign.get(0).getId();
TargetTypeAssignmentResult targetTypeAssignmentResult = initiateTargetTypeAssignment(typeId, controllerId);
final String assignmentMsg = createAssignmentMessage(targetTypeAssignmentResult, i18n.getMessage(CAPTION_TARGET),
i18n.getMessage(CAPTION_TYPE), sourceItemsToAssign.get(0).getName());
notification.displaySuccess(assignmentMsg);
publishTypeAssignmentEvent(sourceItemsToAssign);
}
protected TargetTypeAssignmentResult initiateTargetTypeAssignment(final Long targetType, final String controllerId) {
return targetManagement.assignType(Collections.singletonList(controllerId), targetType);
}
protected void publishTypeAssignmentEvent(final List<ProxyTargetType> sourceItemsToAssign) {
final List<Long> assignedTargetIds = sourceItemsToAssign.stream().map(ProxyIdentifiableEntity::getId)
.collect(Collectors.toList());
eventBus.publish(EventTopics.ENTITY_MODIFIED, this, new EntityModifiedEventPayload(
EntityModifiedEventPayload.EntityModifiedEventType.ENTITY_UPDATED, ProxyTarget.class, assignedTargetIds));
}
}

View File

@@ -18,8 +18,26 @@ public class TagFilterLayoutUiState extends HidableLayoutUiState {
private static final long serialVersionUID = 1L;
private boolean noTagClicked;
private boolean noTargetTypeClicked;
private final Map<Long, String> clickedTagIdsWithName = new HashMap<>();
/**
* @return True if no targetType is clicked or selected
*/
public boolean isNoTargetTypeClicked() {
return noTargetTypeClicked;
}
/**
* Sets the status of no targetType clicked
*
* @param noTargetTypeClicked
* boolean
*/
public void setNoTargetTypeClicked(boolean noTargetTypeClicked) {
this.noTargetTypeClicked = noTargetTypeClicked;
}
/**
* @return True if not tag is clicked or selected
*/

View File

@@ -134,6 +134,7 @@ public class TargetCountMessageLabel extends AbstractFooterSupport implements Co
appendSearchMsg(filterMessageBuilder, targetFilterParams.getSearchText());
appendDsMsg(filterMessageBuilder, targetFilterParams.getDistributionId());
appendCustomFilterQueryMsg(filterMessageBuilder, targetFilterParams.getTargetFilterQueryId());
appendTargetTypeFilterMsg(filterMessageBuilder, targetFilterParams.isNoTargetTypeClicked(), targetFilterParams.getTargetTypeId());
String filterMessage = filterMessageBuilder.toString().trim();
if (filterMessage.endsWith(",")) {
@@ -186,6 +187,12 @@ public class TargetCountMessageLabel extends AbstractFooterSupport implements Co
}
}
private void appendTargetTypeFilterMsg(final StringBuilder filterMessageBuilder, boolean noTargetTypeClicked, final Long targetTypeId) {
if (targetTypeId != null || noTargetTypeClicked) {
appendFilterMsg(filterMessageBuilder, i18n.getMessage("label.filter.target.type"));
}
}
/**
* Update pinning details
*

View File

@@ -50,6 +50,7 @@ import org.eclipse.hawkbit.ui.common.grid.support.SelectionSupport;
import org.eclipse.hawkbit.ui.common.grid.support.assignment.AssignmentSupport;
import org.eclipse.hawkbit.ui.common.grid.support.assignment.DistributionSetsToTargetAssignmentSupport;
import org.eclipse.hawkbit.ui.common.grid.support.assignment.TargetTagsToTargetAssignmentSupport;
import org.eclipse.hawkbit.ui.common.grid.support.assignment.TypeToTargetAssignmentSupport;
import org.eclipse.hawkbit.ui.management.dstable.DistributionGridLayoutUiState;
import org.eclipse.hawkbit.ui.management.miscs.DeploymentAssignmentWindowController;
import org.eclipse.hawkbit.ui.management.targettag.filter.TargetTagFilterLayoutUiState;
@@ -157,9 +158,12 @@ public class TargetGrid extends AbstractGrid<ProxyTarget, TargetManagementFilter
uiDependencies, systemSecurityContext, configManagement, assignmentController);
final TargetTagsToTargetAssignmentSupport targetTagsToTargetAssignment = new TargetTagsToTargetAssignmentSupport(
uiDependencies, targetManagement);
final TypeToTargetAssignmentSupport typeToTargetAssignmentSupport = new TypeToTargetAssignmentSupport(
uiDependencies, targetManagement);
sourceTargetAssignmentStrategies.put(UIComponentIdProvider.DIST_TABLE_ID, distributionsToTargetAssignment);
sourceTargetAssignmentStrategies.put(UIComponentIdProvider.TARGET_TAG_TABLE_ID, targetTagsToTargetAssignment);
sourceTargetAssignmentStrategies.put(UIComponentIdProvider.TARGET_TYPE_TABLE_ID, typeToTargetAssignmentSupport);
setDragAndDropSupportSupport(new DragAndDropSupport<>(this, i18n, uiDependencies.getUiNotification(),
sourceTargetAssignmentStrategies, eventBus));
@@ -263,6 +267,10 @@ public class TargetGrid extends AbstractGrid<ProxyTarget, TargetManagementFilter
targetTagFilterLayoutUiState.isNoTagClicked());
getFilterSupport().addMapping(FilterType.TAG, TargetManagementFilterParams::setTargetTags,
targetTagFilterLayoutUiState.getClickedTagIdsWithName().values());
getFilterSupport().addMapping(FilterType.NO_TARGET_TYPE, TargetManagementFilterParams::setNoTargetTypeClicked,
targetTagFilterLayoutUiState.isNoTargetTypeClicked());
getFilterSupport().addMapping(FilterType.TARGET_TYPE, TargetManagementFilterParams::setTargetTypeId,
targetTagFilterLayoutUiState.getClickedTargetTypeFilterId());
getFilterSupport().addMapping(FilterType.QUERY, TargetManagementFilterParams::setTargetFilterQueryId,
targetTagFilterLayoutUiState.getClickedTargetFilterQueryId());
getFilterSupport().addMapping(FilterType.DISTRIBUTION, TargetManagementFilterParams::setDistributionId,
@@ -280,28 +288,23 @@ public class TargetGrid extends AbstractGrid<ProxyTarget, TargetManagementFilter
}
/**
* Update filter on custom tab selection
* Update filter on filter tab selection
*/
public void onCustomTabSelected() {
public void resetAllFilters(){
getFilter().ifPresent(filter -> {
filter.setDistributionId(null);
filter.setNoTagClicked(false);
filter.setNoTargetTypeClicked(false);
filter.setOverdueState(false);
filter.setSearchText(null);
filter.setTargetTags(Collections.emptyList());
filter.setTargetUpdateStatusList(Collections.emptyList());
filter.setTargetTypeId(null);
filter.setTargetFilterQueryId(null);
getFilterSupport().refreshFilter();
});
}
/**
* Update filter on simple tab selection
*/
public void onSimpleTabSelected() {
getFilterSupport().updateFilter(TargetManagementFilterParams::setTargetFilterQueryId, null);
}
@Override
public void addColumns() {
addNameColumn();

View File

@@ -140,7 +140,8 @@ public class TargetGridHeader extends AbstractEntityGridHeader {
super.restoreState();
if (targetTagFilterLayoutUiState.isCustomFilterTabSelected()) {
onSimpleFilterReset();
onFilterReset();
disabledSearchIcon();
}
if (isBulkUploadInProgress()) {
@@ -153,12 +154,10 @@ public class TargetGridHeader extends AbstractEntityGridHeader {
}
/**
* Reset the distribution set filer drop area support
* Reset the distribution set filer drop area support and the search
*/
public void onSimpleFilterReset() {
public void onFilterReset() {
getSearchHeaderSupport().resetSearch();
getSearchHeaderSupport().disableSearch();
distributionSetFilterDropAreaSupport.reset();
}
@@ -248,4 +247,10 @@ public class TargetGridHeader extends AbstractEntityGridHeader {
public void enableSearchIcon() {
getSearchHeaderSupport().enableSearch();
}
/**
* Disable search icon in the search header
*/
public void disabledSearchIcon() {
getSearchHeaderSupport().disableSearch();
}
}

View File

@@ -204,15 +204,21 @@ public class TargetGridLayout extends AbstractGridComponentLayout {
*/
public void onTargetFilterTabChanged(final TargetFilterTabChangedEventPayload eventPayload) {
final boolean isCustomFilterTabSelected = TargetFilterTabChangedEventPayload.CUSTOM == eventPayload;
final boolean isTargetTypeFilterTabSelected = TargetFilterTabChangedEventPayload.TARGET_TYPE == eventPayload;
final boolean isSimpleTypeFilterTabSelected = TargetFilterTabChangedEventPayload.SIMPLE == eventPayload;
targetGridHeader.onFilterReset();
if (isCustomFilterTabSelected) {
targetGridHeader.onSimpleFilterReset();
targetGrid.onCustomTabSelected();
} else {
targetGridHeader.disabledSearchIcon();
}
if(isTargetTypeFilterTabSelected){
targetGridHeader.enableSearchIcon();
}
if (isSimpleTypeFilterTabSelected){
targetGridHeader.enableSearchIcon();
targetGrid.onSimpleTabSelected();
}
targetGrid.resetAllFilters();
countMessageLabel.updateFilteredCount();
}

View File

@@ -38,6 +38,8 @@ public class TargetWindowLayout extends AbstractEntityWindowLayout<ProxyTarget>
*
* @param i18n
* I18N
* @param targetTypeManagement
* TargetTypeManagement
*/
public TargetWindowLayout(final VaadinMessageSource i18n, final TargetTypeManagement targetTypeManagement) {
super();

View File

@@ -8,12 +8,9 @@
*/
package org.eclipse.hawkbit.ui.management.targettag.filter;
import com.vaadin.ui.Accordion;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.themes.ValoTheme;
import java.util.Arrays;
import java.util.List;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TargetTagManagement;
@@ -40,6 +37,11 @@ import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.vaadin.spring.events.EventBus.UIEventBus;
import com.vaadin.ui.Accordion;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.themes.ValoTheme;
/**
* Target filter tabsheet with 'simple' and 'complex' filter options.
*/
@@ -77,7 +79,8 @@ public class MultipleTargetFilter extends Accordion {
this.filterByButtons = new TargetTagFilterButtons(uiDependencies, targetTagManagement, targetManagement,
targetTagFilterLayoutUiState, targetTagWindowBuilder);
this.targetTypeFilterButtons = new TargetTypeFilterButtons(uiDependencies, targetTypeManagement, targetTagFilterLayoutUiState, targetTypeWindowBuilder);
this.targetTypeFilterButtons = new TargetTypeFilterButtons(uiDependencies, targetTypeManagement, targetManagement,
targetTagFilterLayoutUiState, targetTypeWindowBuilder);
this.filterByStatusFooter = new FilterByStatusLayout(i18n, eventBus, targetTagFilterLayoutUiState);
this.simpleFilterTab = buildSimpleFilterTab();
this.targetTypeFilterTab = buildTargetTypeFilterTab();
@@ -98,8 +101,7 @@ public class MultipleTargetFilter extends Accordion {
this.targetTypeGridActionsVisibilityListener = new GridActionsVisibilityListener(eventBus, layoutViewAware,
targetTypeFilterButtons::hideActionColumns, targetTypeFilterButtons::showEditColumn, targetTypeFilterButtons::showDeleteColumn);
this.entityTargetTypeModifiedListener = new EntityModifiedListener.Builder<>(eventBus, ProxyTargetType.class)
.parentEntityType(ProxyTarget.class).viewAware(layoutViewAware)
.entityModifiedAwareSupports(getTargetTypeModifiedAwareSupports()).build();
.viewAware(layoutViewAware).entityModifiedAwareSupports(getTargetTypeModifiedAwareSupports()).build();
init();
addTabs();
@@ -165,7 +167,8 @@ public class MultipleTargetFilter extends Accordion {
private List<EntityModifiedAwareSupport> getTargetTypeModifiedAwareSupports() {
return Arrays.asList(EntityModifiedGridRefreshAwareSupport.of(targetTypeFilterButtons::refreshAll),
EntityModifiedGenericSupport.of(null, null, null));
EntityModifiedGenericSupport.of(null, targetTypeFilterButtons::resetFilterOnTargetTypeUpdated,
targetTypeFilterButtons::resetFilterOnTargetTypeDeleted));
}
private List<EntityModifiedAwareSupport> getFilterQueryModifiedAwareSupports() {
@@ -191,9 +194,9 @@ public class MultipleTargetFilter extends Accordion {
public void selectedTabChanged() {
final String selectedTabId = getTab(getSelectedTab()).getId();
if (UIComponentIdProvider.SIMPLE_FILTER_ACCORDION_TAB.equals(selectedTabId)) {
customFilterTab.clearAppliedTargetFilterQuery();
targetTypeFilterButtons.clearAppliedTargetTypeFilter();
targetTagFilterLayoutUiState.setCustomFilterTabSelected(false);
targetTagFilterLayoutUiState.setTargetTypeFilterTabSelected(false);
@@ -201,13 +204,19 @@ public class MultipleTargetFilter extends Accordion {
eventBus.publish(EventTopics.TARGET_FILTER_TAB_CHANGED, this, TargetFilterTabChangedEventPayload.SIMPLE);
}
if (UIComponentIdProvider.TARGET_TYPE_FILTER_ACCORDION_TAB.equals(selectedTabId)){
customFilterTab.clearAppliedTargetFilterQuery();
filterByButtons.clearTargetTagFilters();
filterByStatusFooter.clearStatusAndOverdueFilters();
targetTagFilterLayoutUiState.setTargetTypeFilterTabSelected(true);
targetTagFilterLayoutUiState.setCustomFilterTabSelected(false);
eventBus.publish(EventTopics.TARGET_FILTER_TAB_CHANGED, this, TargetFilterTabChangedEventPayload.TARGET_TYPE);
}
if (UIComponentIdProvider.CUSTOM_FILTER_ACCORDION_TAB.equals(selectedTabId)){
filterByButtons.clearTargetTagFilters();
filterByStatusFooter.clearStatusAndOverdueFilters();
targetTypeFilterButtons.clearAppliedTargetTypeFilter();
targetTagFilterLayoutUiState.setCustomFilterTabSelected(true);
targetTagFilterLayoutUiState.setTargetTypeFilterTabSelected(false);
@@ -223,20 +232,14 @@ public class MultipleTargetFilter extends Accordion {
public void restoreState() {
if (targetTagFilterLayoutUiState.isCustomFilterTabSelected()) {
customFilterTab.restoreState();
setSelectedTab(customFilterTab);
}
if (targetTagFilterLayoutUiState.isCustomFilterTabSelected()) {
filterByButtons.restoreState();
filterByStatusFooter.restoreState();
setSelectedTab(simpleFilterTab);
}
if (targetTagFilterLayoutUiState.isTargetTypeFilterTabSelected()) {
filterByButtons.restoreState();
filterByStatusFooter.restoreState();
} else if (targetTagFilterLayoutUiState.isTargetTypeFilterTabSelected()){
targetTypeFilterButtons.restoreState();
setSelectedTab(targetTypeFilterTab);
} else {
filterByButtons.restoreState();
filterByStatusFooter.restoreState();
setSelectedTab(simpleFilterTab);
}
}
@@ -246,6 +249,7 @@ public class MultipleTargetFilter extends Accordion {
public void onViewEnter() {
filterByButtons.reevaluateFilter();
customFilterTab.reevaluateFilter();
targetTypeFilterButtons.reevaluateFilter();
}
/**

View File

@@ -21,11 +21,19 @@ public class TargetTagFilterLayoutUiState extends TagFilterLayoutUiState {
private static final long serialVersionUID = 1L;
private Long clickedTargetFilterQueryId;
private Long clickedTargetTypeFilterId;
private final Collection<TargetUpdateStatus> clickedTargetUpdateStatusFilters = new ArrayList<>();
private boolean isOverdueFilterClicked;
private boolean isCustomFilterTabSelected;
private boolean isTargetTypeFilterTabSelected;
public Long getClickedTargetTypeFilterId() {
return clickedTargetTypeFilterId;
}
public void setClickedTargetTypeFilterId(Long clickedTargetTypeFilterId) {
this.clickedTargetTypeFilterId = clickedTargetTypeFilterId;
}
/**
* @return Id of clicked target filter query

View File

@@ -8,11 +8,12 @@
*/
package org.eclipse.hawkbit.ui.management.targettag.filter;
import com.vaadin.ui.Button;
import com.vaadin.ui.UI;
import com.vaadin.ui.Window;
import java.util.Collection;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.Identifiable;
import com.vaadin.ui.dnd.DropTargetExtension;
import com.vaadin.ui.dnd.event.DropEvent;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TargetTypeManagement;
import org.eclipse.hawkbit.repository.exception.TargetTypeInUseException;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
@@ -25,31 +26,59 @@ import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
import org.eclipse.hawkbit.ui.common.event.EventTopics;
import org.eclipse.hawkbit.ui.common.event.EventView;
import org.eclipse.hawkbit.ui.common.filterlayout.AbstractTargetTypeFilterButtons;
import org.eclipse.hawkbit.ui.common.state.TagFilterLayoutUiState;
import org.eclipse.hawkbit.ui.common.grid.support.DragAndDropSupport;
import org.eclipse.hawkbit.ui.common.grid.support.assignment.AssignmentSupport;
import org.eclipse.hawkbit.ui.common.grid.support.assignment.TargetsToNoTargetTypeAssignmentSupport;
import org.eclipse.hawkbit.ui.common.grid.support.assignment.TargetsToTargetTypeAssignmentSupport;
import org.eclipse.hawkbit.ui.common.layout.listener.EntityDraggingListener;
import org.eclipse.hawkbit.ui.management.targettag.targettype.TargetTypeWindowBuilder;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Target Type filter buttons table.
*/
@SuppressWarnings("squid:S2160")
public class TargetTypeFilterButtons extends AbstractTargetTypeFilterButtons {
private static final long serialVersionUID = 1L;
private final transient TargetTypeManagement targetTypeManagement;
private final transient TargetTypeWindowBuilder targetTypeWindowBuilder;
private static final Logger LOG = LoggerFactory.getLogger(TargetTypeFilterButtons.class);
TargetTypeFilterButtons(final CommonUiDependencies uiDependencies,
final TargetTypeManagement targetTypeManagement, final TagFilterLayoutUiState tagFilterLayoutUiState,
final TargetTypeWindowBuilder targetTypeWindowBuilder) {
super(uiDependencies, tagFilterLayoutUiState);
private final transient TargetManagement targetManagement;
private final transient TargetTypeManagement targetTypeManagement;
private final transient TargetTypeWindowBuilder targetTypeWindowBuilder;
private final transient CommonUiDependencies uiDependencies;
private transient EntityDraggingListener draggingListener;
TargetTypeFilterButtons(final CommonUiDependencies uiDependencies,
final TargetTypeManagement targetTypeManagement, final TargetManagement targetManagement, final TargetTagFilterLayoutUiState targetTagFilterLayoutUiState,
final TargetTypeWindowBuilder targetTypeWindowBuilder) {
super(uiDependencies, targetTagFilterLayoutUiState, targetTypeManagement);
this.targetManagement = targetManagement;
this.targetTypeManagement = targetTypeManagement;
this.targetTypeWindowBuilder = targetTypeWindowBuilder;
this.uiDependencies = uiDependencies;
final Map<String, AssignmentSupport<?, ProxyTargetType>> sourceTargetAssignmentStrategies = new HashMap<>();
final TargetsToTargetTypeAssignmentSupport targetsToTargetTypeAssignment = new TargetsToTargetTypeAssignmentSupport(uiDependencies,
targetManagement);
sourceTargetAssignmentStrategies.put(UIComponentIdProvider.TARGET_TABLE_ID, targetsToTargetTypeAssignment);
setDropSupportToNoType();
setDragAndDropSupportSupport(new DragAndDropSupport<>(this, i18n, uiNotification,
sourceTargetAssignmentStrategies, eventBus));
getDragAndDropSupportSupport().ignoreSelection(true);
getDragAndDropSupportSupport().addDragAndDrop();
init();
setDataProvider(
@@ -74,7 +103,17 @@ public class TargetTypeFilterButtons extends AbstractTargetTypeFilterButtons {
@Override
protected boolean deleteFilterButtons(Collection<ProxyTargetType> filterButtonsToDelete) {
final ProxyTargetType targetTypeToDelete = filterButtonsToDelete.iterator().next();
return deleteTargetType(targetTypeToDelete);
final String targetTypeToDeleteName = targetTypeToDelete.getName();
final Long targetTypeToDeleteId = targetTypeToDelete.getId();
final Long clickedTargetTypeId = getFilterButtonClickBehaviour().getPreviouslyClickedFilterId();
if (clickedTargetTypeId != null && clickedTargetTypeId.equals(targetTypeToDeleteId)) {
uiNotification.displayValidationError(i18n.getMessage("message.targettype.delete", targetTypeToDeleteName));
} else {
return deleteTargetType(targetTypeToDelete);
}
return false;
}
@Override
@@ -113,12 +152,8 @@ public class TargetTypeFilterButtons extends AbstractTargetTypeFilterButtons {
LOG.trace("Target type already in use exception: {}", exception.getMessage());
uiNotification.displayValidationError(i18n.getMessage(exception.getMessage()));
}
return false;
}
@Override
protected Collection<Long> filterExistingTargetTypeIds(Collection<Long> targetTypeIds) {
return targetTypeManagement.get(targetTypeIds).stream().map(Identifiable::getId).collect(Collectors.toSet());
return false;
}
@Override
@@ -131,4 +166,43 @@ public class TargetTypeFilterButtons extends AbstractTargetTypeFilterButtons {
return permissionChecker.hasUpdateRepositoryPermission();
}
private void setDropSupportToNoType() {
final TargetsToNoTargetTypeAssignmentSupport targetsToNoTargetTypeAssignmentSupport = new TargetsToNoTargetTypeAssignmentSupport(
uiDependencies, targetManagement);
final DropTargetExtension<Button> dropExtension = new DropTargetExtension<>(getNoTargetTypeButton());
dropExtension.addDropListener(event -> {
List<ProxyTarget> droppedTargets = getDroppedTargets(event);
targetsToNoTargetTypeAssignmentSupport.assignSourceItemsToTargetItem(droppedTargets, null);
});
addDropStylingListener();
}
private void addDropStylingListener() {
if (draggingListener == null) {
draggingListener = new EntityDraggingListener(eventBus,
Collections.singletonList(UIComponentIdProvider.TARGET_TABLE_ID), getNoTargetTypeButton());
}
draggingListener.subscribe();
}
private static List<ProxyTarget> getDroppedTargets(final DropEvent<?> dropEvent) {
final List<ProxyTarget> list = new ArrayList<>();
dropEvent.getDragSourceExtension().ifPresent(dragSource -> {
final Object dragData = dragSource.getDragData();
if (dragData instanceof ProxyTarget) {
list.add((ProxyTarget) dragData);
}
if (dragData instanceof List
&& ((List<?>) dragData).stream().allMatch(element -> element instanceof ProxyTarget)) {
list.addAll(((List<?>) dragData).stream().map(element -> (ProxyTarget) element)
.collect(Collectors.toList()));
}
});
return list;
}
}

View File

@@ -8,10 +8,6 @@
*/
package org.eclipse.hawkbit.ui.management.targettag.targettype;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.TargetTypeManagement;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.TargetType;
@@ -26,6 +22,11 @@ import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
import org.eclipse.hawkbit.ui.common.targettype.ProxyTargetTypeValidator;
import org.springframework.util.StringUtils;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Controller for update target type window
*/

View File

@@ -24,6 +24,7 @@ import org.eclipse.hawkbit.repository.event.remote.SoftwareModuleTypeDeletedEven
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetFilterQueryDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetTagDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetTypeDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagUpdatedEvent;
@@ -40,6 +41,8 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetFilterQueryCreat
import org.eclipse.hawkbit.repository.event.remote.entity.TargetFilterQueryUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.push.event.ActionChangedEvent;
@@ -71,7 +74,8 @@ public class HawkbitEventPermissionChecker implements UIEventPermissionChecker {
Arrays.asList(TargetCreatedEvent.class, TargetUpdatedEvent.class, TargetDeletedEvent.class,
TargetTagCreatedEvent.class, TargetTagUpdatedEvent.class, TargetTagDeletedEvent.class,
ActionChangedEvent.class, TargetFilterQueryCreatedEvent.class,
TargetFilterQueryUpdatedEvent.class, TargetFilterQueryDeletedEvent.class),
TargetFilterQueryUpdatedEvent.class, TargetFilterQueryDeletedEvent.class,
TargetTypeCreatedEvent.class, TargetTypeUpdatedEvent.class, TargetTypeDeletedEvent.class),
permChecker::hasTargetReadPermission);
eventPermissionRules.put(Arrays.asList(DistributionSetCreatedEvent.class, DistributionSetUpdatedEvent.class,

View File

@@ -20,6 +20,7 @@ import org.eclipse.hawkbit.repository.event.remote.SoftwareModuleTypeDeletedEven
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetFilterQueryDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetTagDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetTypeDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagUpdatedEvent;
@@ -36,6 +37,8 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetFilterQueryCreat
import org.eclipse.hawkbit.repository.event.remote.entity.TargetFilterQueryUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyAction;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSet;
@@ -45,6 +48,7 @@ import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTag;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTarget;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetFilterQuery;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetType;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload.EntityModifiedEventType;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayloadIdentifier;
@@ -134,6 +138,13 @@ public class HawkbitEventProvider implements UIEventProvider {
ProxyTargetFilterQuery.class, EntityModifiedEventType.ENTITY_UPDATED));
EVENTS.put(TargetFilterQueryDeletedEvent.class, new EntityModifiedEventPayloadIdentifier(
ProxyTargetFilterQuery.class, EntityModifiedEventType.ENTITY_REMOVED));
EVENTS.put(TargetTypeCreatedEvent.class, new EntityModifiedEventPayloadIdentifier(
ProxyTargetType.class, EntityModifiedEventType.ENTITY_ADDED));
EVENTS.put(TargetTypeUpdatedEvent.class, new EntityModifiedEventPayloadIdentifier(
ProxyTargetType.class, EntityModifiedEventType.ENTITY_UPDATED));
EVENTS.put(TargetTypeDeletedEvent.class, new EntityModifiedEventPayloadIdentifier(
ProxyTargetType.class, EntityModifiedEventType.ENTITY_REMOVED));
}
@Override

View File

@@ -161,6 +161,8 @@ public final class UIMessageIdProvider {
public static final String MESSAGE_ERROR = "message.error";
public static final String MESSAGE_TARGET_TARGETTYPE_ASSIGNED = "message.target.targetype.assign.error";
public static final String MESSAGE_ERROR_PERMISSION_INSUFFICIENT = "message.permission.insufficient";
public static final String MESSAGE_ERROR_TARGET_TYPE_INCOMPATIBLE = "message.target.type.incompatible";

View File

@@ -22,7 +22,11 @@
.filter-drop-hint-layout.show-drop-hint {
border: 1px dashed $hawkbit-primary-color !important;
}
.filter-drop-hint-layout.show-drop-hint.v-button-dragtarget{
background-color: desaturate(lighten($hawkbit-primary-color, 50%), 20%);
}
.filter-drop-hint-layout.show-drop-hint.v-horizontallayout-drag-center{
background-color: desaturate(lighten($hawkbit-primary-color, 50%), 20%);
}

View File

@@ -226,6 +226,7 @@ label.filter.tags = Tags
label.filter.text = Search Text
label.filter.dist = Distribution
label.filter.custom = Custom
label.filter.target.type = Target Type
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
label.target.id = Controller Id
@@ -617,6 +618,7 @@ message.dist.type.notfound = Distribution set type for {0} was not found
message.assign.discard.success = All assignments are discarded successfully !
message.target.ds.assign.success = Assignment saved successfully !
message.target.ds.multiassign.error = Cannot assign multiple distribution sets to a target!
message.target.targetype.assign.error = One or more targets are already assigned to a target type
message.bulk.upload.assignment.failed = Distribution set assignment failed as distribution set no longer exists!
message.bulk.upload.result.success = Successful: {0}
message.bulk.upload.result.fail = Failed: {0}