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:
@@ -140,4 +140,4 @@ public enum TargetFields implements FieldNameProvider {
|
||||
public String getFieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +27,11 @@ public class FilterParams {
|
||||
private final Boolean selectTargetWithNoTag;
|
||||
private final String[] filterByTagNames;
|
||||
private final Long filterByDistributionId;
|
||||
private final Boolean selectTargetWithNoTargetType;
|
||||
private final Long filterByTargetType;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Constructor for the filter parameters of a Simple Filter.
|
||||
*
|
||||
* @param filterByInstalledOrAssignedDistributionSetId
|
||||
* if set, a filter is added for the given
|
||||
@@ -56,6 +58,34 @@ public class FilterParams {
|
||||
this.filterByDistributionId = filterByInstalledOrAssignedDistributionSetId;
|
||||
this.selectTargetWithNoTag = selectTargetWithNoTag;
|
||||
this.filterByTagNames = filterByTagNames;
|
||||
this.selectTargetWithNoTargetType = false;
|
||||
this.filterByTargetType = null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for the filter parameters of a Type Filter.
|
||||
*
|
||||
* @param filterBySearchText
|
||||
* if set, a filter is added for the given search text
|
||||
* @param filterByInstalledOrAssignedDistributionSetId
|
||||
* if set, a filter is added for the given
|
||||
* {@link DistributionSet#getId()}
|
||||
* @param selectTargetWithNoType
|
||||
* if true, a filter is added with no type
|
||||
* @param filterByType
|
||||
* if set, a filter is added for the given target type
|
||||
*/
|
||||
public FilterParams(final String filterBySearchText, final Long filterByInstalledOrAssignedDistributionSetId,
|
||||
final Boolean selectTargetWithNoType, final Long filterByType) {
|
||||
this.filterBySearchText = filterBySearchText;
|
||||
this.filterByDistributionId = filterByInstalledOrAssignedDistributionSetId;
|
||||
this.filterByStatus = null;
|
||||
this.overdueState = null;
|
||||
this.selectTargetWithNoTag = false;
|
||||
this.filterByTagNames = null;
|
||||
this.selectTargetWithNoTargetType = selectTargetWithNoType;
|
||||
this.filterByTargetType = filterByType;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,4 +150,23 @@ public class FilterParams {
|
||||
public String[] getFilterByTagNames() {
|
||||
return filterByTagNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the flag indicating if no target type filter is used. <br>
|
||||
* If set to <code>false</code> this filter is disabled.
|
||||
*
|
||||
* @return the flag indicating if no target type filter is used
|
||||
*/
|
||||
public Boolean getSelectTargetWithNoTargetType() {
|
||||
return selectTargetWithNoTargetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target type
|
||||
*
|
||||
* @return the target type that are used to filter for
|
||||
*/
|
||||
public Long getFilterByTargetType() {
|
||||
return filterByTargetType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,14 +8,6 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetUpdate;
|
||||
@@ -35,12 +27,22 @@ import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTypeAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Management service for {@link Target}s.
|
||||
*
|
||||
@@ -106,11 +108,29 @@ public interface TargetManagement {
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if distribution set with given ID does not exist
|
||||
*
|
||||
* @deprecated this method {@link TargetManagement#countByFilters(FilterParams)} should be used instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
long countByFilters(Collection<TargetUpdateStatus> status, Boolean overdueState, String searchText,
|
||||
Long installedOrAssignedDistributionSetId, Boolean selectTargetWithNoTag, String... tagNames);
|
||||
|
||||
/**
|
||||
* Count {@link Target}s for all the given filter parameters.
|
||||
*
|
||||
* @param filterParams
|
||||
* the filters to apply; only filters are enabled that have
|
||||
* non-null value; filters are AND-gated
|
||||
*
|
||||
* @return the found number {@link Target}s
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
long countByFilters(@NotNull final FilterParams filterParams);
|
||||
|
||||
/**
|
||||
* Counts number of targets with given with given distribution set Id
|
||||
*
|
||||
@@ -607,6 +627,38 @@ public interface TargetManagement {
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
TargetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection<String> controllerIds, @NotEmpty String tagName);
|
||||
|
||||
|
||||
/**
|
||||
* Initiates {@link TargetType} assignment to given {@link Target}s. If some
|
||||
* targets in the list have the {@link TargetType} not yet assigned, they will
|
||||
* get assigned. If all targets are already of that type, there will be no
|
||||
* un-assignment.
|
||||
*
|
||||
* @param controllerIds
|
||||
* to set the type to
|
||||
* @param typeId
|
||||
* to assign targets to
|
||||
* @return {@link TargetTypeAssignmentResult} with all meta data of the
|
||||
* assignment outcome.
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if target type with given id does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
TargetTypeAssignmentResult assignType(@NotEmpty Collection<String> controllerIds, @NotNull Long typeId);
|
||||
|
||||
/**
|
||||
* Initiates {@link TargetType} un-assignment to given {@link Target}s. The type
|
||||
* of the targets will be set to {@code null}
|
||||
*
|
||||
* @param controllerIds
|
||||
* to remove the type from
|
||||
* @return {@link TargetTypeAssignmentResult} with all meta data of the
|
||||
* assignment outcome.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
TargetTypeAssignmentResult unAssignType(@NotEmpty Collection<String> controllerIds);
|
||||
|
||||
/**
|
||||
* Un-assign a {@link TargetTag} assignment to given {@link Target}.
|
||||
*
|
||||
@@ -638,6 +690,8 @@ public interface TargetManagement {
|
||||
*
|
||||
* @param controllerID
|
||||
* to un-assign for
|
||||
* @param targetTypeId
|
||||
* Target type id
|
||||
* @return the unassigned target
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
@@ -854,4 +908,5 @@ public interface TargetManagement {
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
TargetMetadata updateMetadata(@NotEmpty String controllerId, @NotNull MetaData metadata);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 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.repository.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Result object for {@link TargetType} assignments.
|
||||
*
|
||||
*/
|
||||
public class TargetTypeAssignmentResult extends AbstractAssignmentResult<Target> {
|
||||
|
||||
private final TargetType targetType;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param alreadyAssigned
|
||||
* count of already assigned (ignored) elements
|
||||
* @param assigned
|
||||
* {@link List} of assigned {@link Target}s.
|
||||
* @param unassigned
|
||||
* {@link List} of unassigned {@link Target}s.
|
||||
* @param targetType
|
||||
* the assigned or unassigned tag
|
||||
*/
|
||||
public TargetTypeAssignmentResult(final int alreadyAssigned, final List<? extends Target> assigned,
|
||||
final List<? extends Target> unassigned, final TargetType targetType) {
|
||||
super(alreadyAssigned, assigned, unassigned);
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
public TargetType getTargetType() {
|
||||
return targetType;
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetFilterQueryDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetTagDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetTypeDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TenantConfigurationDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
|
||||
@@ -53,6 +54,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.repository.event.remote.entity.TenantConfigurationCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TenantConfigurationUpdatedEvent;
|
||||
@@ -150,6 +153,11 @@ public class EventType {
|
||||
|
||||
// rollout stopped due to invalidated distribution set
|
||||
TYPES.put(43, RolloutStoppedEvent.class);
|
||||
|
||||
// target type
|
||||
TYPES.put(44, TargetTypeCreatedEvent.class);
|
||||
TYPES.put(45, TargetTypeUpdatedEvent.class);
|
||||
TYPES.put(46, TargetTypeDeletedEvent.class);
|
||||
}
|
||||
|
||||
private int value;
|
||||
|
||||
@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import static org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications.orderedByLinkedDistributionSet;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -65,6 +66,7 @@ import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTypeAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
@@ -449,11 +451,16 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByFilters(final Collection<TargetUpdateStatus> status, final Boolean overdueState,
|
||||
final String searchText, final Long installedOrAssignedDistributionSetId,
|
||||
final Boolean selectTargetWithNoTag, final String... tagNames) {
|
||||
final List<Specification<JpaTarget>> specList = buildSpecificationList(new FilterParams(status, overdueState,
|
||||
searchText, installedOrAssignedDistributionSetId, selectTargetWithNoTag, tagNames));
|
||||
public long countByFilters(Collection<TargetUpdateStatus> status, Boolean overdueState, String searchText,
|
||||
Long installedOrAssignedDistributionSetId, Boolean selectTargetWithNoTag,
|
||||
String... tagNames) {
|
||||
return countByFilters(new FilterParams(status, overdueState, searchText, installedOrAssignedDistributionSetId,
|
||||
selectTargetWithNoTag, tagNames));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByFilters(final FilterParams filterParams) {
|
||||
final List<Specification<JpaTarget>> specList = buildSpecificationList(filterParams);
|
||||
return countByCriteriaAPI(specList);
|
||||
}
|
||||
|
||||
@@ -479,6 +486,13 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
specList.add(TargetSpecifications.hasTags(filterParams.getFilterByTagNames(),
|
||||
filterParams.getSelectTargetWithNoTag()));
|
||||
}
|
||||
|
||||
if (hasTypesFilterActive(filterParams)) {
|
||||
specList.add(TargetSpecifications.hasTargetType(filterParams.getFilterByTargetType()));
|
||||
} else if (hasNoTypeFilterActive(filterParams)) {
|
||||
specList.add(TargetSpecifications.hasNoTargetType());
|
||||
}
|
||||
|
||||
return specList;
|
||||
}
|
||||
|
||||
@@ -490,6 +504,14 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
return isNoTagActive || isAtLeastOneTagActive;
|
||||
}
|
||||
|
||||
private static boolean hasTypesFilterActive(final FilterParams filterParams) {
|
||||
return filterParams.getFilterByTargetType() != null;
|
||||
}
|
||||
|
||||
private static boolean hasNoTypeFilterActive(final FilterParams filterParams) {
|
||||
return Boolean.TRUE.equals(filterParams.getSelectTargetWithNoTargetType());
|
||||
}
|
||||
|
||||
private Slice<Target> findByCriteriaAPI(final Pageable pageable, final List<Specification<JpaTarget>> specList) {
|
||||
if (CollectionUtils.isEmpty(specList)) {
|
||||
return convertPage(targetRepository.findAllWithoutCount(pageable), pageable);
|
||||
@@ -545,6 +567,59 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public TargetTypeAssignmentResult assignType(final Collection<String> controllerIds, final Long typeId) {
|
||||
final TargetType type = targetTypeRepository.findById(typeId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetType.class, typeId));
|
||||
|
||||
final List<JpaTarget> targetsWithSameType = findTargetsByInSpecification(controllerIds,
|
||||
TargetSpecifications.hasTargetType(typeId));
|
||||
|
||||
final List<JpaTarget> targetsWithoutSameType = findTargetsByInSpecification(controllerIds,
|
||||
TargetSpecifications.hasTargetTypeNot(typeId));
|
||||
|
||||
// set new target type to all targets without that type
|
||||
targetsWithoutSameType.forEach(target -> target.setTargetType(type));
|
||||
|
||||
final TargetTypeAssignmentResult result = new TargetTypeAssignmentResult(targetsWithSameType.size(),
|
||||
Collections
|
||||
.unmodifiableList(targetsWithoutSameType.stream().map(targetRepository::save).collect(Collectors.toList())),
|
||||
Collections.emptyList(), type);
|
||||
|
||||
// no reason to persist the type
|
||||
entityManager.detach(type);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public TargetTypeAssignmentResult unAssignType(final Collection<String> controllerIds) {
|
||||
final List<JpaTarget> allTargets = findTargetsByInSpecification(controllerIds, null);
|
||||
|
||||
if (allTargets.size() < controllerIds.size()) {
|
||||
throw new EntityNotFoundException(Target.class, controllerIds,
|
||||
allTargets.stream().map(Target::getControllerId).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
// set new target type to null for all targets
|
||||
allTargets.forEach(target -> target.setTargetType(null));
|
||||
|
||||
return new TargetTypeAssignmentResult(0, Collections.emptyList(), Collections
|
||||
.unmodifiableList(allTargets.stream().map(targetRepository::save).collect(Collectors.toList())), null);
|
||||
}
|
||||
|
||||
private List<JpaTarget> findTargetsByInSpecification(Collection<String> controllerIds,
|
||||
Specification<JpaTarget> specification) {
|
||||
return Lists.partition(new ArrayList<>(controllerIds), Constants.MAX_ENTRIES_IN_STATEMENT).stream()
|
||||
.map(ids -> targetRepository.findAll(TargetSpecifications.hasControllerIdIn(ids).and(specification)))
|
||||
.flatMap(List::stream).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
@@ -625,7 +700,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
/**
|
||||
* Applies orderedByLinkedDistributionSet spec for order and adds additional
|
||||
* specs based on filters
|
||||
*
|
||||
*
|
||||
* @param orderByDistributionId
|
||||
* distribution set used for order
|
||||
* @param filterParams
|
||||
|
||||
@@ -8,12 +8,6 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetTypeFields;
|
||||
import org.eclipse.hawkbit.repository.TargetTypeManagement;
|
||||
@@ -42,9 +36,14 @@ import org.springframework.orm.jpa.vendor.Database;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* JPA implementation of {@link TargetTypeManagement}.
|
||||
*
|
||||
|
||||
@@ -392,12 +392,16 @@ public final class TargetSpecifications {
|
||||
return (targetRoot, query, cb) -> {
|
||||
// Since the targetRoot is changed by joining we need to get the
|
||||
// isNull predicate first
|
||||
final Predicate targetTypeIsNull = targetRoot.get(JpaTarget_.targetType).isNull();
|
||||
final Predicate targetTypeIsNull = getTargetTypeIsNullPredicate(targetRoot);
|
||||
|
||||
return cb.or(targetTypeIsNull, cb.equal(getDsTypeIdPath(targetRoot), distributionSetTypeId));
|
||||
};
|
||||
}
|
||||
|
||||
private static Predicate getTargetTypeIsNullPredicate(Root<JpaTarget> targetRoot) {
|
||||
return targetRoot.get(JpaTarget_.targetType).isNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s that are NOT compatible
|
||||
* with given {@link DistributionSetType}. Compatibility is evaluated by
|
||||
@@ -532,13 +536,39 @@ public final class TargetSpecifications {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s that have a
|
||||
* {@link org.eclipse.hawkbit.repository.model.TargetType} assigned
|
||||
* {@link Specification} for retrieving {@link Target}s by target type id
|
||||
*
|
||||
* @param typeId
|
||||
* the id of the target type
|
||||
*
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> hasTargetType() {
|
||||
return (targetRoot, query, cb) -> cb.isNotNull(targetRoot.get(JpaTarget_.targetType));
|
||||
public static Specification<JpaTarget> hasTargetType(final long typeId) {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(JpaTarget_.targetType).get(JpaTargetType_.id),
|
||||
typeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s by target type id is equal to null
|
||||
*
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> hasNoTargetType() {
|
||||
return (targetRoot, query, cb) -> cb.isNull(targetRoot.get(JpaTarget_.targetType));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link Target}s that don't have target
|
||||
* type assigned
|
||||
*
|
||||
* @param typeId
|
||||
* the id of the target type
|
||||
*
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> hasTargetTypeNot(final Long typeId) {
|
||||
return (targetRoot, query, cb) -> cb.or(getTargetTypeIsNullPredicate(targetRoot),
|
||||
cb.notEqual(targetRoot.get(JpaTarget_.targetType).get(JpaTargetType_.id), typeId));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,6 +26,8 @@ import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTypeAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.test.TestConfiguration;
|
||||
import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.test.util.RolloutTestApprovalStrategy;
|
||||
@@ -133,4 +135,10 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
|
||||
return distributionSetManagement.toggleTagAssignment(
|
||||
sets.stream().map(DistributionSet::getId).collect(Collectors.toList()), tag.getName());
|
||||
}
|
||||
|
||||
protected TargetTypeAssignmentResult initiateTypeAssignment(final Collection<Target> targets, final TargetType type) {
|
||||
return targetManagement.assignType(
|
||||
targets.stream().map(Target::getControllerId).collect(Collectors.toList()), type.getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -58,7 +58,11 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
final TargetTag targTagZ = targetTagManagement.create(entityFactory.tag().create().name("TargTag-Z"));
|
||||
final TargetTag targTagW = targetTagManagement.create(entityFactory.tag().create().name("TargTag-W"));
|
||||
|
||||
final DistributionSet setA = testdataFactory.createDistributionSet("");
|
||||
final DistributionSet setA = testdataFactory.createDistributionSet("A");
|
||||
final DistributionSet setB = testdataFactory.createDistributionSet("B");
|
||||
|
||||
final TargetType targetTypeX = testdataFactory.createTargetType("TargetTypeX",
|
||||
Collections.singletonList(setB.getType()));
|
||||
|
||||
final DistributionSet installedSet = testdataFactory.createDistributionSet("another");
|
||||
|
||||
@@ -92,12 +96,17 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
final List<Target> targDs = testdataFactory.createTargets(100, targetDsDIdPref,
|
||||
targetDsDIdPref.concat(" description"), lastTargetNull);
|
||||
|
||||
final String targetDsEIdPref = "targ-E";
|
||||
final List<Target> targEs = testdataFactory.createTargetsWithType(100, targetDsEIdPref, targetTypeX);
|
||||
|
||||
final String assignedC = targCs.iterator().next().getControllerId();
|
||||
assignDistributionSet(setA.getId(), assignedC);
|
||||
final String assignedA = targAs.iterator().next().getControllerId();
|
||||
assignDistributionSet(setA.getId(), assignedA);
|
||||
final String assignedB = targBs.iterator().next().getControllerId();
|
||||
assignDistributionSet(setA.getId(), assignedB);
|
||||
final String assignedE = targEs.iterator().next().getControllerId();
|
||||
assignDistributionSet(setB.getId(), assignedE);
|
||||
final String installedC = targCs.iterator().next().getControllerId();
|
||||
final Long actionId = getFirstAssignedActionId(assignDistributionSet(installedSet.getId(), assignedC));
|
||||
|
||||
@@ -136,7 +145,7 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
verifyThat1TargetHasAttributeValue("%c-attribute%", targAttribute.getControllerId());
|
||||
verifyThat1TargetHasAttributeValue("%" + targAttributeId.getControllerId() + "%",
|
||||
targAttributeId.getControllerId());
|
||||
verifyThatRepositoryContains400Targets();
|
||||
verifyThatRepositoryContains500Targets();
|
||||
verifyThat200TargetsHaveTagD(targTagW, concat(targBs, targCs));
|
||||
verifyThat100TargetsContainsGivenTextAndHaveTagAssigned(targTagY, targTagW, targBs);
|
||||
verifyThat1TargetHasTagHasDescOrNameAndDs(targTagW, setA, targetManagement.getByControllerID(assignedC).get());
|
||||
@@ -147,19 +156,19 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
verifyThat1TargetWithDescOrNameHasDS(setA, targetManagement.getByControllerID(assignedA).get());
|
||||
List<Target> expected = concat(targAs, targBs, targCs, targDs);
|
||||
expected.removeAll(targetManagement.getByControllerID(Arrays.asList(assignedA, assignedB, assignedC)));
|
||||
verifyThat397TargetsAreInStatusUnknown(unknown, expected);
|
||||
verifyThat496TargetsAreInStatusUnknown(unknown, expected);
|
||||
expected = concat(targBs, targCs);
|
||||
expected.removeAll(targetManagement.getByControllerID(Arrays.asList(assignedB, assignedC)));
|
||||
verifyThat198TargetsAreInStatusUnknownAndHaveGivenTags(targTagY, targTagW, unknown, expected);
|
||||
verfyThat0TargetsAreInStatusUnknownAndHaveDSAssigned(setA, unknown);
|
||||
verifyThat0TargetsAreInStatusUnknownAndHaveDSAssigned(setA, unknown);
|
||||
expected = concat(targAs);
|
||||
expected.remove(targetManagement.getByControllerID(assignedA).get());
|
||||
verifyThat99TargetsWithNameOrDescriptionAreInGivenStatus(unknown, expected);
|
||||
expected = concat(targBs);
|
||||
expected.remove(targetManagement.getByControllerID(assignedB).get());
|
||||
verifyThat99TargetsWithGivenNameOrDescAndTagAreInStatusUnknown(targTagW, unknown, expected);
|
||||
verifyThat3TargetsAreInStatusPending(pending,
|
||||
targetManagement.getByControllerID(Arrays.asList(assignedA, assignedB, assignedC)));
|
||||
verifyThat4TargetsAreInStatusPending(pending,
|
||||
targetManagement.getByControllerID(Arrays.asList(assignedA, assignedB, assignedC, assignedE)));
|
||||
verifyThat3TargetsWithGivenDSAreInPending(setA, pending,
|
||||
targetManagement.getByControllerID(Arrays.asList(assignedA, assignedB, assignedC)));
|
||||
verifyThat1TargetWithGivenNameOrDescAndDSIsInPending(setA, pending,
|
||||
@@ -171,8 +180,13 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
verifyThat2TargetsWithGivenTagAreInPending(targTagW, pending,
|
||||
targetManagement.getByControllerID(Arrays.asList(assignedB, assignedC)));
|
||||
verifyThat200targetsWithGivenTagAreInStatusPendingorUnknown(targTagW, both, concat(targBs, targCs));
|
||||
verfiyThat1TargetAIsInStatusPendingAndHasDSInstalled(installedSet, pending,
|
||||
verifyThat1TargetAIsInStatusPendingAndHasDSInstalled(installedSet, pending,
|
||||
targetManagement.getByControllerID(installedC).get());
|
||||
verifyThat1TargetHasTypeAndDSAssigned(targetTypeX, setB, targetManagement.getByControllerID(assignedE).get());
|
||||
verifyThatTargetsHasNoTypeAndDSAssignedOrInstalled(setA, targetManagement.getByControllerID(Arrays.asList(assignedA, assignedB, assignedC)));
|
||||
verifyThatTargetsHasNoTypeAndDSAssignedOrInstalled(installedSet, targetManagement.getByControllerID(Collections.singletonList(installedC)));
|
||||
verifyThat100TargetsContainsGivenTextAndHaveTypeAssigned(targetTypeX, targEs);
|
||||
verifyThat400TargetsContainsGivenTextAndHaveNoTypeAssigned(concat(targAs, targBs, targCs, targDs));
|
||||
|
||||
expected = concat(targBs, targCs);
|
||||
expected.removeAll(targetManagement.getByControllerID(Arrays.asList(assignedB, assignedC)));
|
||||
@@ -180,354 +194,314 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verfiyThat1TargetAIsInStatusPendingAndHasDSInstalled(final DistributionSet installedSet,
|
||||
private void verifyThat1TargetAIsInStatusPendingAndHasDSInstalled(final DistributionSet installedSet,
|
||||
final List<TargetUpdateStatus> pending, final Target expected) {
|
||||
final FilterParams filterParams = new FilterParams(pending, null, null, installedSet.getId(), Boolean.FALSE);
|
||||
final String query = "updatestatus==pending and installedds.name==" + installedSet.getName();
|
||||
assertThat(targetManagement
|
||||
.findByFilters(PAGE, new FilterParams(pending, null, null, installedSet.getId(), Boolean.FALSE))
|
||||
.getContent())
|
||||
.as("has number of elements").hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(pending, null, null,
|
||||
installedSet.getId(), Boolean.FALSE)))
|
||||
.as("and contains the following elements").containsExactly(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsExactly(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat200targetsWithGivenTagAreInStatusPendingorUnknown(final TargetTag targTagW,
|
||||
final List<TargetUpdateStatus> both, final List<Target> expected) {
|
||||
final FilterParams filterParams = new FilterParams(both, null, null, null, Boolean.FALSE, targTagW.getName());
|
||||
final String query = "(updatestatus==pending or updatestatus==unknown) and tag==" + targTagW.getName();
|
||||
|
||||
assertThat(targetManagement
|
||||
.findByFilters(PAGE, new FilterParams(both, null, null, null, Boolean.FALSE, targTagW.getName()))
|
||||
.getContent()).as("has number of elements").hasSize(200)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(both, null, null, null,
|
||||
Boolean.FALSE, targTagW.getName())))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(200).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat2TargetsWithGivenTagAreInPending(final TargetTag targTagW,
|
||||
final List<TargetUpdateStatus> pending, final List<Target> expected) {
|
||||
final FilterParams filterParams = new FilterParams(pending, null, null, null, Boolean.FALSE,
|
||||
targTagW.getName());
|
||||
final String query = "updatestatus==pending and tag==" + targTagW.getName();
|
||||
|
||||
assertThat(targetManagement
|
||||
.findByFilters(PAGE, new FilterParams(pending, null, null, null, Boolean.FALSE, targTagW.getName()))
|
||||
.getContent())
|
||||
.as("has number of elements").hasSize(2).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(pending, null, null, null,
|
||||
Boolean.FALSE, targTagW.getName())))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(2).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat2TargetsWithGivenTagAndDSIsInPending(final TargetTag targTagW, final DistributionSet setA,
|
||||
final List<TargetUpdateStatus> pending, final List<Target> expected) {
|
||||
final FilterParams filterParams = new FilterParams(pending, null, null, setA.getId(), Boolean.FALSE,
|
||||
targTagW.getName());
|
||||
final String query = "updatestatus==pending and (assignedds.name==" + setA.getName() + " or installedds.name=="
|
||||
+ setA.getName() + ") and tag==" + targTagW.getName();
|
||||
|
||||
assertThat(targetManagement
|
||||
.findByFilters(PAGE,
|
||||
new FilterParams(pending, null, null, setA.getId(), Boolean.FALSE, targTagW.getName()))
|
||||
.getContent())
|
||||
.as("has number of elements").hasSize(2).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(pending, null, null, setA.getId(),
|
||||
Boolean.FALSE, targTagW.getName())))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(2).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat1TargetWithGivenNameOrDescAndTagAndDSIsInPending(final TargetTag targTagW,
|
||||
final DistributionSet setA, final List<TargetUpdateStatus> pending, final Target expected) {
|
||||
final FilterParams filterParams = new FilterParams(pending, null, "%targ-B%", setA.getId(), Boolean.FALSE,
|
||||
targTagW.getName());
|
||||
final String query = "updatestatus==pending and (assignedds.name==" + setA.getName() + " or installedds.name=="
|
||||
+ setA.getName() + ") and (name==*targ-B* or description==*targ-B*) and tag==" + targTagW.getName();
|
||||
|
||||
assertThat(targetManagement
|
||||
.findByFilters(PAGE,
|
||||
new FilterParams(pending, null, "%targ-B%", setA.getId(), Boolean.FALSE, targTagW.getName()))
|
||||
.getContent())
|
||||
.as("has number of elements").hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(pending, null, "%targ-B%",
|
||||
setA.getId(), Boolean.FALSE, targTagW.getName())))
|
||||
.as("and contains the following elements").containsExactly(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsExactly(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat1TargetWithGivenNameOrDescAndDSIsInPending(final DistributionSet setA,
|
||||
final List<TargetUpdateStatus> pending, final Target expected) {
|
||||
final FilterParams filterParams = new FilterParams(pending, null, "%targ-A%", setA.getId(), Boolean.FALSE);
|
||||
final String query = "updatestatus==pending and (assignedds.name==" + setA.getName() + " or installedds.name=="
|
||||
+ setA.getName() + ") and (name==*targ-A* or description==*targ-A*)";
|
||||
|
||||
assertThat(targetManagement
|
||||
.findByFilters(PAGE, new FilterParams(pending, null, "%targ-A%", setA.getId(), Boolean.FALSE))
|
||||
.getContent())
|
||||
.as("has number of elements").hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(pending, null, "%targ-A%",
|
||||
setA.getId(), Boolean.FALSE)))
|
||||
.as("and contains the following elements").containsExactly(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsExactly(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat3TargetsWithGivenDSAreInPending(final DistributionSet setA,
|
||||
final List<TargetUpdateStatus> pending, final List<Target> expected) {
|
||||
final FilterParams filterParams = new FilterParams(pending, null, null, setA.getId(), Boolean.FALSE);
|
||||
final String query = "updatestatus==pending and (assignedds.name==" + setA.getName() + " or installedds.name=="
|
||||
+ setA.getName() + ")";
|
||||
|
||||
assertThat(targetManagement
|
||||
.findByFilters(PAGE, new FilterParams(pending, null, null, setA.getId(), Boolean.FALSE)).getContent())
|
||||
.as("has number of elements").hasSize(3).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(
|
||||
targetManagement.countByFilters(pending, null, null, setA.getId(), Boolean.FALSE)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(3).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat3TargetsAreInStatusPending(final List<TargetUpdateStatus> pending,
|
||||
private void verifyThat4TargetsAreInStatusPending(final List<TargetUpdateStatus> pending,
|
||||
final List<Target> expected) {
|
||||
final FilterParams filterParams = new FilterParams(pending, null, null, null, Boolean.FALSE);
|
||||
final String query = "updatestatus==pending";
|
||||
|
||||
assertThat(targetManagement.findByFilters(PAGE, new FilterParams(pending, null, null, null, Boolean.FALSE))
|
||||
.getContent())
|
||||
.as("has number of elements").hasSize(3).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(pending, null, null, null,
|
||||
Boolean.FALSE, new String[0])))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(4).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat99TargetsWithGivenNameOrDescAndTagAreInStatusUnknown(final TargetTag targTagW,
|
||||
final List<TargetUpdateStatus> unknown, final List<Target> expected) {
|
||||
final FilterParams filterParams = new FilterParams(unknown, null, "%targ-B%", null, Boolean.FALSE,
|
||||
targTagW.getName());
|
||||
final String query = "updatestatus==unknown and (name==*targ-B* or description==*targ-B*) and tag=="
|
||||
+ targTagW.getName();
|
||||
|
||||
assertThat(targetManagement
|
||||
.findByFilters(PAGE,
|
||||
new FilterParams(unknown, null, "%targ-B%", null, Boolean.FALSE, targTagW.getName()))
|
||||
.getContent()).as("has number of elements").hasSize(99)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(unknown, null, "%targ-B%", null,
|
||||
Boolean.FALSE, targTagW.getName())))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(99).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat99TargetsWithNameOrDescriptionAreInGivenStatus(final List<TargetUpdateStatus> unknown,
|
||||
final List<Target> expected) {
|
||||
final FilterParams filterParams = new FilterParams(unknown, null, "%targ-A%", null, Boolean.FALSE);
|
||||
final String query = "updatestatus==unknown and (name==*targ-A* or description==*targ-A*)";
|
||||
|
||||
assertThat(targetManagement
|
||||
.findByFilters(PAGE, new FilterParams(unknown, null, "%targ-A%", null, Boolean.FALSE, new String[0]))
|
||||
.getContent()).as("has number of elements").hasSize(99)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(
|
||||
targetManagement.countByFilters(unknown, null, "%targ-A%", null, Boolean.FALSE)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(99).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verfyThat0TargetsAreInStatusUnknownAndHaveDSAssigned(final DistributionSet setA,
|
||||
private void verifyThat0TargetsAreInStatusUnknownAndHaveDSAssigned(final DistributionSet setA,
|
||||
final List<TargetUpdateStatus> unknown) {
|
||||
final FilterParams filterParams = new FilterParams(unknown, null, null, setA.getId(), Boolean.FALSE);
|
||||
final String query = "updatestatus==unknown and (assignedds.name==" + setA.getName() + " or installedds.name=="
|
||||
+ setA.getName() + ")";
|
||||
|
||||
assertThat(targetManagement
|
||||
.findByFilters(PAGE, new FilterParams(unknown, null, null, setA.getId(), Boolean.FALSE)).getContent())
|
||||
.as("has number of elements").hasSize(0).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(
|
||||
targetManagement.countByFilters(unknown, null, null, setA.getId(), Boolean.FALSE)))
|
||||
.as("and filter query returns the same result")
|
||||
.hasSize(targetManagement.findByRsql(PAGE, query).getContent().size());
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(0).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and filter query returns the same result")
|
||||
.hasSize(targetManagement.findByRsql(PAGE, query).getContent().size());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat198TargetsAreInStatusUnknownAndHaveGivenTags(final TargetTag targTagY,
|
||||
final TargetTag targTagW, final List<TargetUpdateStatus> unknown, final List<Target> expected) {
|
||||
final FilterParams filterParams = new FilterParams(unknown, null, null, null, Boolean.FALSE, targTagY.getName(),
|
||||
targTagW.getName());
|
||||
final String query = "updatestatus==unknown and (tag==" + targTagY.getName() + " or tag==" + targTagW.getName()
|
||||
+ ")";
|
||||
|
||||
assertThat(targetManagement.findByFilters(PAGE,
|
||||
new FilterParams(unknown, null, null, null, Boolean.FALSE, targTagY.getName(), targTagW.getName()))
|
||||
.getContent()).as("has number of elements").hasSize(198)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(unknown, null, null, null,
|
||||
Boolean.FALSE, targTagY.getName(), targTagW.getName())))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(198).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat397TargetsAreInStatusUnknown(final List<TargetUpdateStatus> unknown,
|
||||
private void verifyThat496TargetsAreInStatusUnknown(final List<TargetUpdateStatus> unknown,
|
||||
final List<Target> expected) {
|
||||
final FilterParams filterParams = new FilterParams(unknown, null, null, null, Boolean.FALSE);
|
||||
final String query = "updatestatus==unknown";
|
||||
|
||||
assertThat(targetManagement.findByFilters(PAGE, new FilterParams(unknown, null, null, null, Boolean.FALSE))
|
||||
.getContent()).as("has number of elements").hasSize(397)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(
|
||||
targetManagement.countByFilters(unknown, null, null, null, Boolean.FALSE)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(496).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat198TargetsAreInStatusUnknownAndOverdue(final List<TargetUpdateStatus> unknown,
|
||||
final List<Target> expected) {
|
||||
final FilterParams filterParams = new FilterParams(unknown, Boolean.TRUE, null, null, Boolean.FALSE);
|
||||
// be careful: simple filters are concatenated using AND-gating
|
||||
final String query = "lastcontrollerrequestat=le=${overdue_ts};updatestatus==UNKNOWN";
|
||||
|
||||
assertThat(targetManagement
|
||||
.findByFilters(PAGE, new FilterParams(unknown, Boolean.TRUE, null, null, Boolean.FALSE)).getContent())
|
||||
.as("has number of elements").hasSize(198).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(
|
||||
targetManagement.countByFilters(unknown, Boolean.TRUE, null, null, Boolean.FALSE)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(198).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat1TargetWithDescOrNameHasDS(final DistributionSet setA, final Target expected) {
|
||||
final FilterParams filterParams = new FilterParams(null, null, "%targ-A%", setA.getId(), Boolean.FALSE);
|
||||
final String query = "(name==*targ-A* or description==*targ-A*) and (assignedds.name==" + setA.getName()
|
||||
+ " or installedds.name==" + setA.getName() + ")";
|
||||
|
||||
assertThat(targetManagement
|
||||
.findByFilters(PAGE, new FilterParams(null, null, "%targ-A%", setA.getId(), Boolean.FALSE))
|
||||
.getContent())
|
||||
.as("has number of elements").hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(
|
||||
targetManagement.countByFilters(null, null, "%targ-A%", setA.getId(), Boolean.FALSE)))
|
||||
.as("and contains the following elements").containsExactly(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsExactly(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat3TargetsHaveDSAssigned(final DistributionSet setA, final List<Target> expected) {
|
||||
final FilterParams filterParams = new FilterParams(null, null, null, setA.getId(), Boolean.FALSE);
|
||||
final String query = "assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName();
|
||||
|
||||
assertThat(targetManagement.findByFilters(PAGE, new FilterParams(null, null, null, setA.getId(), Boolean.FALSE))
|
||||
.getContent())
|
||||
.as("has number of elements").hasSize(3).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(
|
||||
targetManagement.countByFilters(null, null, null, setA.getId(), Boolean.FALSE)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(3).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat0TargetsWithNameOrdescAndDSHaveTag(final TargetTag targTagX, final DistributionSet setA) {
|
||||
final FilterParams filterParams = new FilterParams(null, null, "%targ-C%", setA.getId(), Boolean.FALSE,
|
||||
targTagX.getName());
|
||||
final String query = "(name==*targ-C* or description==*targ-C*) and tag==" + targTagX.getName()
|
||||
+ " and (assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName() + ")";
|
||||
assertThat(targetManagement
|
||||
.findByFilters(PAGE,
|
||||
new FilterParams(null, null, "%targ-C%", setA.getId(), Boolean.FALSE, targTagX.getName()))
|
||||
.getContent())
|
||||
.as("has number of elements").hasSize(0).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(null, null, "%targ-C%",
|
||||
setA.getId(), Boolean.FALSE, targTagX.getName())))
|
||||
.as("and filter query returns the same result")
|
||||
.hasSize(targetManagement.findByRsql(PAGE, query).getContent().size());
|
||||
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(0).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and filter query returns the same result")
|
||||
.hasSize(targetManagement.findByRsql(PAGE, query).getContent().size());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat0TargetsWithTagAndDescOrNameHasDS(final TargetTag targTagW, final DistributionSet setA) {
|
||||
final FilterParams filterParams = new FilterParams(null, null, "%targ-A%", setA.getId(), Boolean.FALSE,
|
||||
targTagW.getName());
|
||||
final String query = "(name==*targ-A* or description==*targ-A*) and tag==" + targTagW.getName()
|
||||
+ " and (assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName() + ")";
|
||||
assertThat(targetManagement
|
||||
.findByFilters(PAGE,
|
||||
new FilterParams(null, null, "%targ-A%", setA.getId(), Boolean.FALSE, targTagW.getName()))
|
||||
.getContent())
|
||||
.as("has number of elements").hasSize(0).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(null, null, "%targ-A%",
|
||||
setA.getId(), Boolean.FALSE, targTagW.getName())))
|
||||
.as("and filter query returns the same result")
|
||||
.hasSize(targetManagement.findByRsql(PAGE, query).getContent().size());
|
||||
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(0).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and filter query returns the same result")
|
||||
.hasSize(targetManagement.findByRsql(PAGE, query).getContent().size());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat1TargetHasTagHasDescOrNameAndDs(final TargetTag targTagW, final DistributionSet setA,
|
||||
final Target expected) {
|
||||
final FilterParams filterParams = new FilterParams(null, null, "%targ-C%", setA.getId(), Boolean.FALSE,
|
||||
targTagW.getName());
|
||||
final String query = "(name==*targ-c* or description==*targ-C*) and tag==" + targTagW.getName()
|
||||
+ " and (assignedds.name==" + setA.getName() + " or installedds.name==" + setA.getName() + ")";
|
||||
assertThat(targetManagement
|
||||
.findByFilters(PAGE,
|
||||
new FilterParams(null, null, "%targ-C%", setA.getId(), Boolean.FALSE, targTagW.getName()))
|
||||
.getContent())
|
||||
.as("has number of elements").hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(null, null, "%targ-C%",
|
||||
setA.getId(), Boolean.FALSE, targTagW.getName())))
|
||||
.as("and contains the following elements").containsExactly(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsExactly(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat1TargetHasNameAndId(final String name, final String controllerId) {
|
||||
assertThat(targetManagement.findByFilters(PAGE, new FilterParams(null, null, name, null, Boolean.FALSE))
|
||||
.getContent()).as("has number of elements").hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints
|
||||
.saturatedCast(targetManagement.countByFilters(null, null, name, null, Boolean.FALSE)));
|
||||
final FilterParams filterParamsByName = new FilterParams(null, null, name, null, Boolean.FALSE);
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParamsByName).getContent()).as("has number of elements")
|
||||
.hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParamsByName)));
|
||||
|
||||
assertThat(targetManagement.findByFilters(PAGE, new FilterParams(null, null, controllerId, null, Boolean.FALSE))
|
||||
.getContent()).as("has number of elements").hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(
|
||||
targetManagement.countByFilters(null, null, controllerId, null, Boolean.FALSE)));
|
||||
final FilterParams filterParamsByControllerId = new FilterParams(null, null, controllerId, null, Boolean.FALSE);
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParamsByControllerId).getContent())
|
||||
.as("has number of elements").hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParamsByControllerId)));
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat1TargetHasAttributeValue(final String value, final String controllerId) {
|
||||
assertThat(targetManagement.findByFilters(PAGE, new FilterParams(null, null, value, null, Boolean.FALSE))
|
||||
.getContent()).as("has number of elements").hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(
|
||||
targetManagement.countByFilters(null, null, value, null, Boolean.FALSE)));
|
||||
final FilterParams filterParams = new FilterParams(null, null, value, null, Boolean.FALSE);
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)));
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat100TargetsContainsGivenTextAndHaveTagAssigned(final TargetTag targTagY,
|
||||
final TargetTag targTagW, final List<Target> expected) {
|
||||
final FilterParams filterParams = new FilterParams(null, null, "%targ-B%", null, Boolean.FALSE,
|
||||
targTagY.getName(), targTagW.getName());
|
||||
final String query = "(name==*targ-B* or description==*targ-B*) and (tag==" + targTagY.getName() + " or tag=="
|
||||
+ targTagW.getName() + ")";
|
||||
assertThat(targetManagement.findByFilters(PAGE,
|
||||
new FilterParams(null, null, "%targ-B%", null, Boolean.FALSE, targTagY.getName(), targTagW.getName()))
|
||||
.getContent()).as("has number of elements").hasSize(100)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(null, null, "%targ-B%", null,
|
||||
Boolean.FALSE, targTagY.getName(), targTagW.getName())))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(100).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
@@ -539,27 +513,66 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Step
|
||||
private void verifyThat200TargetsHaveTagD(final TargetTag targTagD, final List<Target> expected) {
|
||||
final FilterParams filterParams = new FilterParams(null, null, null, null, Boolean.FALSE, targTagD.getName());
|
||||
final String query = "tag==" + targTagD.getName();
|
||||
assertThat(targetManagement
|
||||
.findByFilters(PAGE, new FilterParams(null, null, null, null, Boolean.FALSE, targTagD.getName()))
|
||||
.getContent()).as("Expected number of results is").hasSize(200)
|
||||
.as("and is expected number of results is equal to ")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(null, null, null, null,
|
||||
Boolean.FALSE, targTagD.getName())))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("Expected number of results is")
|
||||
.hasSize(200).as("and is expected number of results is equal to ")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsAll(expected)
|
||||
.as("and filter query returns the same result")
|
||||
.containsAll(targetManagement.findByRsql(PAGE, query).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThatRepositoryContains400Targets() {
|
||||
assertThat(targetManagement.findByFilters(PAGE, new FilterParams(null, null, null, null, null)).getContent())
|
||||
.as("Overall we expect that many targets in the repository").hasSize(400)
|
||||
private void verifyThatRepositoryContains500Targets() {
|
||||
final FilterParams filterParams = new FilterParams(null, null, null, null, null);
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent())
|
||||
.as("Overall we expect that many targets in the repository").hasSize(500)
|
||||
.as("which is also reflected by repository count").hasSize(Ints.saturatedCast(targetManagement.count()))
|
||||
.as("which is also reflected by call without specification")
|
||||
.containsAll(targetManagement.findAll(PAGE).getContent());
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat1TargetHasTypeAndDSAssigned(final TargetType type, final DistributionSet set,
|
||||
final Target expected) {
|
||||
final FilterParams filterParams = new FilterParams(null, set.getId(), Boolean.FALSE, type.getId());
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(1).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsExactly(expected);
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThatTargetsHasNoTypeAndDSAssignedOrInstalled(final DistributionSet set, final List<Target> expected) {
|
||||
final FilterParams filterParams = new FilterParams(null, set.getId(), Boolean.TRUE, null);
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(expected.size()).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsAll(expected);
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat100TargetsContainsGivenTextAndHaveTypeAssigned(final TargetType targetType,
|
||||
final List<Target> expected) {
|
||||
final FilterParams filterParams = new FilterParams("%targ-E%", null, Boolean.FALSE, targetType.getId());
|
||||
List<Target> filteredTargets = targetManagement.findByFilters(PAGE, filterParams).getContent();
|
||||
assertThat(filteredTargets).as("has number of elements").hasSize(100)
|
||||
.as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)));
|
||||
// Comparing the controller ids, as one of the targets was modified, so a 1:1
|
||||
// comparison of the objects is not possible
|
||||
assertThat(filteredTargets.stream().map(Target::getControllerId).collect(Collectors.toList()))
|
||||
.containsAll(expected.stream().map(Target::getControllerId).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Step
|
||||
private void verifyThat400TargetsContainsGivenTextAndHaveNoTypeAssigned(final List<Target> expected) {
|
||||
final FilterParams filterParams = new FilterParams("%targ-%", null, Boolean.TRUE, null);
|
||||
assertThat(targetManagement.findByFilters(PAGE, filterParams).getContent()).as("has number of elements")
|
||||
.hasSize(400).as("that number is also returned by count query")
|
||||
.hasSize(Ints.saturatedCast(targetManagement.countByFilters(filterParams)))
|
||||
.as("and contains the following elements").containsAll(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -770,4 +783,28 @@ class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
|
||||
.type(type);
|
||||
return distributionSetManagement.create(dsCreate);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that targets with given target type are returned from repository.")
|
||||
public void findTargetByTargetType() {
|
||||
TargetType testType = testdataFactory.createTargetType("testType", Collections.singletonList(standardDsType));
|
||||
List<Target> unassigned = testdataFactory.createTargets(9, "unassigned");
|
||||
List<Target> assigned = testdataFactory.createTargetsWithType(11, "assigned", testType);
|
||||
|
||||
assertThat(targetManagement.findByFilters(PAGE,
|
||||
new FilterParams(null,null, false, testType.getId())))
|
||||
.as("Contains the targets with set type").containsAll(assigned)
|
||||
.as("and that means the following expected amount").hasSize(11);
|
||||
assertThat(targetManagement.countByFilters(new FilterParams(null,null, false, testType.getId())))
|
||||
.as("Count the targets with set type").isEqualTo(11);
|
||||
|
||||
assertThat(targetManagement.findByFilters(PAGE,
|
||||
new FilterParams(null, null, true, null)))
|
||||
.as("Contains the targets without a type").containsAll(unassigned)
|
||||
.as("and that means the following expected amount").hasSize(9);
|
||||
assertThat(targetManagement.countByFilters(new FilterParams(null, null, true, null)))
|
||||
.as("Counts the targets without a type").isEqualTo(9);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import javax.validation.ConstraintViolationException;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.repository.FilterParams;
|
||||
import org.eclipse.hawkbit.repository.Identifiable;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetUpdate;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
|
||||
@@ -39,6 +40,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreated
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
@@ -57,6 +59,7 @@ import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTypeAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.Expect;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
|
||||
@@ -752,7 +755,7 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
toggleTagAssignment(tagABCTargets, tagB);
|
||||
toggleTagAssignment(tagABCTargets, tagC);
|
||||
|
||||
assertThat(targetManagement.countByFilters(null, null, null, null, Boolean.FALSE, "X"))
|
||||
assertThat(targetManagement.countByFilters(new FilterParams(null, null, null, null, Boolean.FALSE, "X")))
|
||||
.as("Target count is wrong").isEqualTo(0);
|
||||
|
||||
// search for targets with tag tagA
|
||||
@@ -782,11 +785,11 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
checkTargetHasNotTags(tagCTargets, tagA, tagB);
|
||||
|
||||
// check again target lists refreshed from DB
|
||||
assertThat(targetManagement.countByFilters(null, null, null, null, Boolean.FALSE, "A"))
|
||||
assertThat(targetManagement.countByFilters(new FilterParams(null, null, null, null, Boolean.FALSE, "A")))
|
||||
.as("Target count is wrong").isEqualTo(targetWithTagA.size());
|
||||
assertThat(targetManagement.countByFilters(null, null, null, null, Boolean.FALSE, "B"))
|
||||
assertThat(targetManagement.countByFilters(new FilterParams(null, null, null, null, Boolean.FALSE, "B")))
|
||||
.as("Target count is wrong").isEqualTo(targetWithTagB.size());
|
||||
assertThat(targetManagement.countByFilters(null, null, null, null, Boolean.FALSE, "C"))
|
||||
assertThat(targetManagement.countByFilters(new FilterParams(null, null, null, null, Boolean.FALSE, "C")))
|
||||
.as("Target count is wrong").isEqualTo(targetWithTagC.size());
|
||||
}
|
||||
|
||||
@@ -1107,7 +1110,57 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(targetFound1.get().getOptLockRevision()).isEqualTo(2);
|
||||
assertThat(targetFound1.get().getTargetType().getId()).isEqualTo(targetType.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(allSpPermissions = true)
|
||||
@Description("Tests the assignment of types to multiple targets.")
|
||||
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 20),
|
||||
@Expect(type = TargetTypeCreatedEvent.class, count = 2),
|
||||
@Expect(type = TargetUpdatedEvent.class, count = 29), @Expect(type = TargetDeletedEvent.class, count = 1) })
|
||||
public void targetTypeBulkAssignments() {
|
||||
final List<Target> typeATargets = testdataFactory.createTargets(10, "typeATargets", "first description");
|
||||
final List<Target> typeBTargets = testdataFactory.createTargets(10, "typeBTargets", "first description");
|
||||
|
||||
// create a target type
|
||||
final TargetType typeA = testdataFactory.createTargetType("A", Collections.singletonList(standardDsType));
|
||||
final TargetType typeB = testdataFactory.createTargetType("B", Collections.singletonList(standardDsType));
|
||||
|
||||
// assign target type to target
|
||||
TargetTypeAssignmentResult resultA = initiateTypeAssignment(typeATargets, typeA);
|
||||
TargetTypeAssignmentResult resultB = initiateTypeAssignment(typeBTargets, typeB);
|
||||
assertThat(resultA.getAssigned()).isEqualTo(10);
|
||||
assertThat(resultB.getAssigned()).isEqualTo(10);
|
||||
checkTargetsHaveType(typeATargets, typeA);
|
||||
checkTargetsHaveType(typeBTargets, typeB);
|
||||
|
||||
// double assignment does not unassign
|
||||
resultA = initiateTypeAssignment(typeATargets, typeA);
|
||||
resultB = initiateTypeAssignment(typeBTargets, typeB);
|
||||
assertThat(resultA.getAssigned()).isZero();
|
||||
assertThat(resultB.getAssigned()).isZero();
|
||||
assertThat(resultA.getAlreadyAssigned()).isEqualTo(10);
|
||||
assertThat(resultB.getAlreadyAssigned()).isEqualTo(10);
|
||||
checkTargetsHaveType(typeATargets, typeA);
|
||||
checkTargetsHaveType(typeBTargets, typeB);
|
||||
|
||||
// verify that type assignment does not throw an error if target list includes an unknown id
|
||||
targetManagement.deleteByControllerID(typeATargets.get(0).getControllerId());
|
||||
final TargetTypeAssignmentResult resultC = initiateTypeAssignment(typeATargets, typeB);
|
||||
assertThat(resultC.getAssigned()).isEqualTo(9);
|
||||
assertThat(resultC.getAlreadyAssigned()).isZero();
|
||||
checkTargetsHaveType(typeATargets, typeB);
|
||||
}
|
||||
|
||||
private void checkTargetsHaveType(final List<Target> targets, final TargetType type) {
|
||||
List<JpaTarget> foundTargets = targetRepository
|
||||
.findAllById(targets.stream().map(Identifiable::getId).collect(Collectors.toList()));
|
||||
for (final Target target : foundTargets) {
|
||||
if (!type.getName().equals(type.getName())) {
|
||||
fail(String.format("Target %s is not of type %s.", target, type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Queries and loads the metadata related to a given target.")
|
||||
public void findAllTargetMetadataByControllerId() {
|
||||
|
||||
@@ -110,7 +110,7 @@ import org.springframework.test.context.TestPropertySource;
|
||||
public abstract class AbstractIntegrationTest {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractIntegrationTest.class);
|
||||
|
||||
protected static final Pageable PAGE = PageRequest.of(0, 400, Sort.by(Direction.ASC, "id"));
|
||||
protected static final Pageable PAGE = PageRequest.of(0, 500, Sort.by(Direction.ASC, "id"));
|
||||
|
||||
protected static final URI LOCALHOST = URI.create("http://127.0.0.1");
|
||||
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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%);
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user