Support additional operands for node filters 65/133365/27
authorfranciscovila <javier.paradela.vila@est.tech>
Wed, 15 Feb 2023 17:14:59 +0000 (17:14 +0000)
committerMichael Morris <michael.morris@est.tech>
Tue, 16 May 2023 15:05:13 +0000 (15:05 +0000)
Issue-ID: SDC-4395
Signed-off-by: franciscovila <javier.paradela.vila@est.tech>
Change-Id: I66b172d100ffd2757de88bc7640761f31fd20c28

32 files changed:
catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/NodeFilterValidator.java
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/dto/FilterConstraintDto.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/validators/ListValidator.java
catalog-model/src/main/java/org/openecomp/sdc/be/ui/mapper/FilterConstraintMapper.java
catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UIConstraint.java
catalog-ui/src/app/models/filter-constraint.ts
catalog-ui/src/app/models/ui-models/property-filter-constraint-ui.ts
catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html
catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.ts
catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.ts
catalog-ui/src/app/ng2/components/ui/dynamic-element/dynamic-element.component.ts
catalog-ui/src/app/ng2/components/ui/form-components/form-elements.module.ts
catalog-ui/src/app/ng2/components/ui/form-components/integer-input/ui-element-integer-input.component.html
catalog-ui/src/app/ng2/components/ui/form-components/range-input/ui-element-range-input.component.html [new file with mode: 0644]
catalog-ui/src/app/ng2/components/ui/form-components/range-input/ui-element-range-input.component.less [new file with mode: 0644]
catalog-ui/src/app/ng2/components/ui/form-components/range-input/ui-element-range-input.component.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/components/ui/form-components/valid-values-input/ui-element-valid-values-input.component.html [new file with mode: 0644]
catalog-ui/src/app/ng2/components/ui/form-components/valid-values-input/ui-element-valid-values-input.component.less [new file with mode: 0644]
catalog-ui/src/app/ng2/components/ui/form-components/valid-values-input/ui-element-valid-values-input.component.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/properties-assignment/services/properties.utils.ts
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.html
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.ts
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.ts
catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.html
catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.ts
catalog-ui/src/app/utils/constants.ts
catalog-ui/src/app/utils/filter-constraint-helper.ts
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyFilterConstraintDataDefinition.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyFilterConstraintDataDefinitionJsonDeserializer.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/ConstraintType.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/FilterValueType.java

index 86cedf2..30fe3dc 100644 (file)
@@ -21,6 +21,7 @@ package org.openecomp.sdc.be.components.validation;
 
 import com.google.gson.Gson;
 import fj.data.Either;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -32,6 +33,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.openecomp.sdc.be.dao.api.ActionStatus;
 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
 import org.openecomp.sdc.be.datatypes.elements.ToscaGetFunctionDataDefinition;
+import org.openecomp.sdc.be.datatypes.enums.ConstraintType;
 import org.openecomp.sdc.be.datatypes.enums.PropertyFilterTargetType;
 import org.openecomp.sdc.be.datatypes.enums.PropertySource;
 import org.openecomp.sdc.be.impl.ComponentsUtils;
@@ -139,26 +141,64 @@ public class NodeFilterValidator {
     private Either<Boolean, ResponseFormat> validatePropertyConstraint(final Component parentComponent, final String componentInstanceId,
                                                                        final FilterConstraintDto filterConstraint, final String capabilityName) {
         String source = SOURCE;
+        ResponseFormat responseFormat = null;
+        List<ToscaGetFunctionDataDefinition> toscaGetFunctionDataDefinitionList = new ArrayList<>();
         final ToscaGetFunctionDataDefinition toscaGetFunction = filterConstraint.getAsToscaGetFunction().orElse(null);
         if (toscaGetFunction == null || !(filterConstraint.getValue() instanceof ToscaGetFunctionDataDefinition)) {
-            return Either.right(componentsUtils.getResponseFormat(ActionStatus.TOSCA_FUNCTION_EXPECTED_ERROR));
+            final List<ToscaGetFunctionDataDefinition> toscaGetFunctionList = filterConstraint.getAsListToscaGetFunction().orElse(null);
+            if (toscaGetFunctionList == null || toscaGetFunctionList.isEmpty() || !(filterConstraint.getValue() instanceof List)) {
+                return Either.right(componentsUtils.getResponseFormat(ActionStatus.TOSCA_FUNCTION_EXPECTED_ERROR));
+            }
+            else {
+                toscaGetFunctionDataDefinitionList = toscaGetFunctionList;
+            }
         }
-        final Optional<? extends ToscaPropertyData> sourceSelectedProperty = findPropertyFromGetFunction(parentComponent, toscaGetFunction);
-        if (sourceSelectedProperty.isPresent()) {
-            Optional<? extends PropertyDefinition> targetComponentInstanceProperty =
-                getInstanceProperties(parentComponent, componentInstanceId, capabilityName, filterConstraint.getPropertyName());
+        else{
+            toscaGetFunctionDataDefinitionList.add(toscaGetFunction);
+        }
+        Boolean allGood = true;
+        for (ToscaGetFunctionDataDefinition _toscaGetFunction: toscaGetFunctionDataDefinitionList) {
+
+            final Optional<? extends ToscaPropertyData> sourceSelectedProperty =
+                findPropertyFromGetFunction(parentComponent, _toscaGetFunction);
+            if (sourceSelectedProperty.isPresent()) {
+                Optional<? extends PropertyDefinition> targetComponentInstanceProperty =
+                    getInstanceProperties(parentComponent, componentInstanceId, capabilityName,
+                        filterConstraint.getPropertyName());
+
+                source = targetComponentInstanceProperty.isEmpty() ? TARGET : SOURCE;
+                if (targetComponentInstanceProperty.isPresent()) {
+                    responseFormat =
+                        validatePropertyData(sourceSelectedProperty.get(), targetComponentInstanceProperty.get(),
+                            filterConstraint.getOperator().isLengthConstraint());
+                    if (responseFormat != null) {
+                        allGood = false;
+                        break;
+                    }
 
-            source = targetComponentInstanceProperty.isEmpty() ? TARGET : SOURCE;
-            if (targetComponentInstanceProperty.isPresent()) {
-                final ResponseFormat responseFormat = validatePropertyData(sourceSelectedProperty.get(), targetComponentInstanceProperty.get());
-                if (responseFormat != null) {
-                    return Either.right(responseFormat);
                 }
-                return Either.left(true);
+                else {
+                    allGood = false;
+                    final String missingProperty =
+                        SOURCE.equals(source) ? filterConstraint.getValue().toString() : filterConstraint.getPropertyName();
+                    responseFormat =
+                        componentsUtils.getResponseFormat(ActionStatus.FILTER_PROPERTY_NOT_FOUND, source, missingProperty);
+                    break;
+                }
+            }
+            else {
+                allGood = false;
+                final String missingProperty =
+                    SOURCE.equals(source) ? filterConstraint.getValue().toString() : filterConstraint.getPropertyName();
+                responseFormat =
+                    componentsUtils.getResponseFormat(ActionStatus.FILTER_PROPERTY_NOT_FOUND, source, missingProperty);
+                break;
             }
         }
-        final String missingProperty = SOURCE.equals(source) ? filterConstraint.getValue().toString() : filterConstraint.getPropertyName();
-        return Either.right(componentsUtils.getResponseFormat(ActionStatus.FILTER_PROPERTY_NOT_FOUND, source, missingProperty));
+        if (allGood) {
+            return Either.left(true);
+        }
+        return Either.right(responseFormat);
     }
 
     private Optional<? extends ToscaPropertyData> findPropertyFromGetFunction(final Component parentComponent,
@@ -276,80 +316,118 @@ public class NodeFilterValidator {
             return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_DOES_NOT_HAVE_INPUTS, parentComponent.getName()));
         }
         if (!(filterConstraint.getValue() instanceof ToscaGetFunctionDataDefinition)) {
-            return Either.right(componentsUtils.getResponseFormat(ActionStatus.TOSCA_FUNCTION_EXPECTED_ERROR));
-        }
-        final ToscaGetFunctionDataDefinition getFunction = (ToscaGetFunctionDataDefinition) filterConstraint.getValue();
-        final List<String> propertyPathFromSource = getFunction.getPropertyPathFromSource();
-        Optional<? extends PropertyDefinition> sourceSelectedProperty =
-            sourceInputDefinition.stream().filter(input -> input.getName().equals(propertyPathFromSource.get(0))).findFirst();
-        if (sourceSelectedProperty.isEmpty()) {
-            LOGGER.debug(INPUT_NOT_FOUND_LOG,
-                propertyPathFromSource.get(0), parentComponent.getName(), parentComponent.getUniqueId());
-            return Either.right(
-                componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INPUT_NOT_FOUND, propertyPathFromSource.get(0), parentComponent.getName())
-            );
-        }
-        if (propertyPathFromSource.size() > 1) {
-            final Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> allDataTypesEither =
-                applicationDataTypeCache.getAll(parentComponent.getModel());
-            if (allDataTypesEither.isRight()) {
-                LOGGER.error("Could not load data types for model {}", parentComponent.getModel());
-                return Either.right(componentsUtils.getResponseFormat(ActionStatus.DATA_TYPES_NOT_LOADED, parentComponent.getModel()));
+            if (filterConstraint.getValue() instanceof List) {
+                Optional optValid = ((List<?>) filterConstraint.getValue()).stream().filter(filterConstraintValue ->
+                    !(filterConstraintValue instanceof ToscaGetFunctionDataDefinition)).findAny();
+                if (optValid.isPresent()) {
+                    return Either.right(componentsUtils.getResponseFormat(ActionStatus.TOSCA_FUNCTION_EXPECTED_ERROR));
+                }
+            }
+            else {
+                return Either.right(componentsUtils.getResponseFormat(ActionStatus.TOSCA_FUNCTION_EXPECTED_ERROR));
             }
-            sourceSelectedProperty =
-                findSubProperty(propertyPathFromSource.subList(1, propertyPathFromSource.size()), sourceSelectedProperty.get().getType(),
-                    allDataTypesEither.left().value());
-        }
-        final Optional<? extends PropertyDefinition> targetComponentInstanceProperty;
-        if (PropertyFilterTargetType.CAPABILITY.equals(filterConstraint.getTargetType())) {
-            final CapabilityDefinition capability = parentComponent.getComponentInstances().stream()
-                .filter(componentInstance -> componentInstance.getUniqueId().equals(componentInstanceId))
-                .map(componentInstance -> componentInstance.getCapabilities().values())
-                .flatMap(Collection::stream)
-                .flatMap(Collection::stream)
-                .filter(capabilityDefinition -> capabilityDefinition.getName().equals(filterConstraint.getCapabilityName()))
-                .findFirst().orElse(null);
-            if (capability == null) {
+        }
+        if (filterConstraint.getValue() instanceof ToscaGetFunctionDataDefinition) {
+            final ToscaGetFunctionDataDefinition getFunction =
+                (ToscaGetFunctionDataDefinition) filterConstraint.getValue();
+            final List<String> propertyPathFromSource = getFunction.getPropertyPathFromSource();
+            Optional<? extends PropertyDefinition> sourceSelectedProperty =
+                sourceInputDefinition.stream().filter(input -> input.getName().equals(propertyPathFromSource.get(0)))
+                    .findFirst();
+            if (sourceSelectedProperty.isEmpty()) {
+                LOGGER.debug(INPUT_NOT_FOUND_LOG,
+                    propertyPathFromSource.get(0), parentComponent.getName(), parentComponent.getUniqueId());
                 return Either.right(
-                    componentsUtils.getResponseFormat(ActionStatus.CAPABILITY_NOT_FOUND_IN_COMPONENT,
-                        filterConstraint.getCapabilityName(), parentComponent.getComponentType().getValue(), parentComponent.getName())
+                    componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INPUT_NOT_FOUND,
+                        propertyPathFromSource.get(0), parentComponent.getName())
                 );
             }
-            targetComponentInstanceProperty = capability.getProperties().stream()
-                .filter(property -> filterConstraint.getPropertyName().equals(property.getName()))
-                .findFirst();
-        } else {
-            targetComponentInstanceProperty =
-                parentComponent.getComponentInstancesProperties()
-                    .get(componentInstanceId).stream()
+            if (propertyPathFromSource.size() > 1) {
+                final Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> allDataTypesEither =
+                    applicationDataTypeCache.getAll(parentComponent.getModel());
+                if (allDataTypesEither.isRight()) {
+                    LOGGER.error("Could not load data types for model {}", parentComponent.getModel());
+                    return Either.right(componentsUtils.getResponseFormat(ActionStatus.DATA_TYPES_NOT_LOADED,
+                        parentComponent.getModel()));
+                }
+                sourceSelectedProperty =
+                    findSubProperty(propertyPathFromSource.subList(1, propertyPathFromSource.size()),
+                        sourceSelectedProperty.get().getType(),
+                        allDataTypesEither.left().value());
+            }
+            final Optional<? extends PropertyDefinition> targetComponentInstanceProperty;
+            if (PropertyFilterTargetType.CAPABILITY.equals(filterConstraint.getTargetType())) {
+                final CapabilityDefinition capability = parentComponent.getComponentInstances().stream()
+                    .filter(componentInstance -> componentInstance.getUniqueId().equals(componentInstanceId))
+                    .map(componentInstance -> componentInstance.getCapabilities().values())
+                    .flatMap(Collection::stream)
+                    .flatMap(Collection::stream)
+                    .filter(capabilityDefinition -> capabilityDefinition.getName()
+                        .equals(filterConstraint.getCapabilityName()))
+                    .findFirst().orElse(null);
+                if (capability == null) {
+                    return Either.right(
+                        componentsUtils.getResponseFormat(ActionStatus.CAPABILITY_NOT_FOUND_IN_COMPONENT,
+                            filterConstraint.getCapabilityName(), parentComponent.getComponentType().getValue(),
+                            parentComponent.getName())
+                    );
+                }
+                targetComponentInstanceProperty = capability.getProperties().stream()
                     .filter(property -> filterConstraint.getPropertyName().equals(property.getName()))
                     .findFirst();
-        }
-        if (sourceSelectedProperty.isPresent() && targetComponentInstanceProperty.isPresent()) {
-            final ResponseFormat responseFormat = validatePropertyData(sourceSelectedProperty.get(), targetComponentInstanceProperty.get());
-            if (responseFormat != null) {
-                return Either.right(responseFormat);
+            } else {
+                targetComponentInstanceProperty =
+                    parentComponent.getComponentInstancesProperties()
+                        .get(componentInstanceId).stream()
+                        .filter(property -> filterConstraint.getPropertyName().equals(property.getName()))
+                        .findFirst();
+            }
+            if (sourceSelectedProperty.isPresent() && targetComponentInstanceProperty.isPresent()) {
+                final ResponseFormat responseFormat =
+                    validatePropertyData(sourceSelectedProperty.get(), targetComponentInstanceProperty.get(),
+                        filterConstraint.getOperator().isLengthConstraint());
+                if (responseFormat != null) {
+                    return Either.right(responseFormat);
+                }
+                return Either.left(true);
             }
-            return Either.left(true);
-        }
 
-        return Either.right(componentsUtils.getResponseFormat(ActionStatus.INPUTS_NOT_FOUND));
+            return Either.right(componentsUtils.getResponseFormat(ActionStatus.INPUTS_NOT_FOUND));
+        }
+        return Either.left(true);
     }
 
     private <T extends ToscaPropertyData> ResponseFormat validatePropertyData(final T sourcePropDefinition,
-                                                                              final T targetPropDefinition) {
+                                                                              final T targetPropDefinition,
+                                                                              final boolean isLengthConstraint) {
         final String sourceType = sourcePropDefinition.getType();
         final String targetType = targetPropDefinition.getType();
-        if (sourceType.equals(targetType)) {
-            if (TYPES_WITH_SCHEMA.contains(sourceType)) {
-                final String sourceSchemaType = sourcePropDefinition.getSchemaType();
-                final String targetSchemaType = targetPropDefinition.getSchemaType();
-                if (sourceSchemaType != null && !sourceSchemaType.equals(targetSchemaType)) {
-                    return componentsUtils.getResponseFormat(ActionStatus.SOURCE_TARGET_SCHEMA_MISMATCH,
-                        targetPropDefinition.getName(), targetSchemaType, sourcePropDefinition.getName(), sourceSchemaType);
+        if (!isLengthConstraint) {
+            if (sourceType.equals(targetType)) {
+                if (TYPES_WITH_SCHEMA.contains(sourceType)) {
+                    final String sourceSchemaType = sourcePropDefinition.getSchemaType();
+                    final String targetSchemaType = targetPropDefinition.getSchemaType();
+                    if (sourceSchemaType != null && !sourceSchemaType.equals(targetSchemaType)) {
+                        return componentsUtils.getResponseFormat(ActionStatus.SOURCE_TARGET_SCHEMA_MISMATCH,
+                            targetPropDefinition.getName(), targetSchemaType, sourcePropDefinition.getName(),
+                            sourceSchemaType);
+                    }
                 }
+                return null;
+            }
+        }
+        else {
+            if (sourceType.equalsIgnoreCase("integer")) {
+                if (TYPES_WITH_SCHEMA.contains(sourceType)) {
+                    final String sourceSchemaType = sourcePropDefinition.getSchemaType();
+                    if (sourceSchemaType != null && !sourceSchemaType.equalsIgnoreCase("integer")) {
+                        return componentsUtils.getResponseFormat(ActionStatus.SOURCE_TARGET_SCHEMA_MISMATCH,
+                            targetPropDefinition.getName(), "integer", sourcePropDefinition.getName(),
+                            sourceSchemaType);
+                    }
+                }
+                return null;
             }
-            return null;
         }
         return componentsUtils.getResponseFormat(ActionStatus.SOURCE_TARGET_PROPERTY_TYPE_MISMATCH,
             sourcePropDefinition.getName(), sourcePropDefinition.getType(), targetPropDefinition.getName(), targetPropDefinition.getType());
@@ -369,6 +447,13 @@ public class NodeFilterValidator {
             return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_OPERATOR_PROVIDED, filterConstraint.getPropertyName(),
                 filterConstraint.getOperator().getType()));
         }
+        if (filterConstraint.getOperator().equals(ConstraintType.VALID_VALUES) || filterConstraint.getOperator().equals(ConstraintType.IN_RANGE)) {
+            return isValidValueCheck("list", componentInstanceProperty.getType(), parentComponent.getModel(),
+                filterConstraint.getValue(), filterConstraint.getPropertyName());
+        }
+        if (filterConstraint.getOperator().isLengthConstraint() && componentInstanceProperty.getType().equals("list")) {
+            return Either.left(true);
+        }
         return isValidValueCheck(componentInstanceProperty.getType(), componentInstanceProperty.getSchemaType(), parentComponent.getModel(),
             filterConstraint.getValue(), filterConstraint.getPropertyName());
     }
@@ -386,6 +471,10 @@ public class NodeFilterValidator {
             return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_OPERATOR_PROVIDED, filterConstraint.getPropertyName(),
                 filterConstraint.getOperator().getType()));
         }
+        if (filterConstraint.getOperator().equals(ConstraintType.VALID_VALUES) || filterConstraint.getOperator().equals(ConstraintType.IN_RANGE)) {
+            return isValidValueCheck("list", componentProperty.getType(), component.getModel(),
+                filterConstraint.getValue(), filterConstraint.getPropertyName());
+        }
         return isValidValueCheck(componentProperty.getType(), componentProperty.getSchemaType(), component.getModel(),
             filterConstraint.getValue(), filterConstraint.getPropertyName());
     }
@@ -517,7 +606,9 @@ public class NodeFilterValidator {
                 String.join("->", toscaGetFunction.getPropertyPathFromSource())));
         }
 
-        final ResponseFormat responseFormat = validatePropertyData(sourceSelectedProperty.get(), targetComponentProperty.get());
+        final ResponseFormat responseFormat =
+            validatePropertyData(sourceSelectedProperty.get(), targetComponentProperty.get(),
+                filterConstraint.getOperator().isLengthConstraint());
         if (responseFormat != null) {
             return Either.right(responseFormat);
         }
index 6c1f4e3..4b82498 100644 (file)
@@ -82,6 +82,7 @@ import org.openecomp.sdc.be.datatypes.elements.SubstitutionFilterPropertyDataDef
 import org.openecomp.sdc.be.datatypes.elements.ToscaArtifactDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.ToscaFunction;
 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
+import org.openecomp.sdc.be.datatypes.enums.ConstraintType;
 import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
@@ -114,6 +115,7 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
 import org.openecomp.sdc.be.model.operations.impl.ModelOperation;
+import org.openecomp.sdc.be.model.tosca.ToscaType;
 import org.openecomp.sdc.be.model.tosca.converters.ToscaMapValueConverter;
 import org.openecomp.sdc.be.tosca.PropertyConvertor.PropertyType;
 import org.openecomp.sdc.be.tosca.builder.ToscaRelationshipBuilder;
@@ -225,14 +227,6 @@ public class ToscaExportHandler {
                 .forEach(operations -> operations.values().forEach(operation -> operation.setImplementation(null)));
     }
 
-    private static Object buildNodeFilterValue(final PropertyFilterConstraintDataDefinition filterConstraint) {
-        if (filterConstraint.getValue() instanceof ToscaFunction) {
-            return Map.of(filterConstraint.getOperator().getType(), ((ToscaFunction) filterConstraint.getValue()).getJsonObjectValue());
-        } else {
-            return Map.of(filterConstraint.getOperator().getType(), filterConstraint.getValue());
-        }
-    }
-
     public Either<ToscaRepresentation, ToscaError> exportComponent(Component component) {
         return convertToToscaTemplate(component).left().map(this::createToscaRepresentation);
     }
@@ -1776,6 +1770,38 @@ public class ToscaExportHandler {
         return propertiesCopy;
     }
 
+    private static Object buildNodeFilterValue(final PropertyFilterConstraintDataDefinition filterConstraint) {
+        if (filterConstraint.getValue() instanceof ToscaFunction) {
+            return Map.of(filterConstraint.getOperator().getType(), ((ToscaFunction) filterConstraint.getValue()).getJsonObjectValue());
+        }
+        if (filterConstraint.getValue() instanceof List) {
+            if (((List<?>) filterConstraint.getValue()).get(0) instanceof ToscaFunction) {
+                List<Object> toscaFunctionList = new ArrayList<>();
+                ((List<?>) filterConstraint.getValue()).forEach(toscaFunctionValue -> toscaFunctionList.add(
+                    ((ToscaFunction) toscaFunctionValue).getJsonObjectValue()));
+                return Map.of(filterConstraint.getOperator().getType(), toscaFunctionList);
+            }
+        }
+        if (doesTypeNeedConvertingToIntOrFloat(filterConstraint.getOriginalType(), filterConstraint.getValue())) {
+            ToscaType toscaType = ToscaType.getToscaType(
+                filterConstraint.getValue() instanceof List ? ToscaType.LIST.getType() : filterConstraint.getOriginalType());
+            filterConstraint.setValue(toscaType.convert(String.valueOf(filterConstraint.getValue())));
+        }
+        else if (ConstraintType.LENGTH.getType().equals(filterConstraint.getOperator().getType()) ||
+            ConstraintType.MIN_LENGTH.getType().equals(filterConstraint.getOperator().getType()) ||
+            ConstraintType.MAX_LENGTH.getType().equals(filterConstraint.getOperator().getType())) {
+                filterConstraint.setValue(Integer.valueOf(String.valueOf(filterConstraint.getValue())));
+        }
+        return Map.of(filterConstraint.getOperator().getType(), filterConstraint.getValue());
+    }
+
+    private static boolean doesTypeNeedConvertingToIntOrFloat(String propertyType, Object value) {
+        if (value instanceof List && ((List<?>) value).get(0) instanceof LinkedHashMap && ((LinkedHashMap) ((List<?>) value).get(0)).get("type") != null ) {
+            return false;
+        }
+        return ToscaType.INTEGER.getType().equals(propertyType) || ToscaType.FLOAT.getType().equals(propertyType);
+    }
+
     private Map<String, String[]> buildSubstitutionMappingPropertyMapping(final Component component) {
         if (component == null || CollectionUtils.isEmpty(component.getInputs())) {
             return Collections.emptyMap();
index b9ceb11..4800c02 100644 (file)
@@ -22,6 +22,8 @@
 package org.openecomp.sdc.be.model.dto;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Optional;
 import lombok.Data;
 import org.openecomp.sdc.be.datatypes.elements.ToscaGetFunctionDataDefinition;
@@ -38,6 +40,7 @@ public class FilterConstraintDto {
     private ConstraintType operator;
     private FilterValueType valueType;
     private Object value;
+    private String originalType;
 
     public boolean isCapabilityPropertyFilter() {
         return capabilityName != null;
@@ -53,6 +56,18 @@ public class FilterConstraintDto {
             return Optional.empty();
         }
     }
+    public Optional<List<ToscaGetFunctionDataDefinition>> getAsListToscaGetFunction() {
+        List<ToscaGetFunctionDataDefinition> toscaGetFunctionDataDefinitionList = new ArrayList<>();
+        if (value instanceof List) {
+            try {
+                ((List<?>) value).forEach(toscaValue -> toscaGetFunctionDataDefinitionList.add(new ObjectMapper().convertValue(toscaValue, ToscaGetFunctionDataDefinition.class)));
+                return Optional.of(toscaGetFunctionDataDefinitionList);
+            } catch (final Exception ignored) {
+                return Optional.empty();
+            }
+        }
+        return Optional.empty();
+    }
 
 }
 
index 20d927f..46fd44d 100644 (file)
@@ -72,6 +72,27 @@ public class ListValidator implements PropertyTypeValidator {
                 case MAP:
                        innerValidator = ToscaPropertyType.MAP.getValidator();
                        break;
+                case RANGE:
+                    innerValidator = ToscaPropertyType.RANGE.getValidator();
+                    break;
+                case SCALAR_UNIT_BITRATE:
+                    innerValidator = ToscaPropertyType.SCALAR_UNIT_BITRATE.getValidator();
+                    break;
+                case SCALAR_UNIT_FREQUENCY:
+                    innerValidator = ToscaPropertyType.SCALAR_UNIT_FREQUENCY.getValidator();
+                    break;
+                case SCALAR_UNIT_TIME:
+                    innerValidator = ToscaPropertyType.SCALAR_UNIT_TIME.getValidator();
+                    break;
+                case SCALAR_UNIT_SIZE:
+                    innerValidator = ToscaPropertyType.SCALAR_UNIT_SIZE.getValidator();
+                    break;
+                case SCALAR_UNIT:
+                    innerValidator = ToscaPropertyType.SCALAR_UNIT.getValidator();
+                    break;
+                case TIMESTAMP:
+                    innerValidator = ToscaPropertyType.TIMESTAMP.getValidator();
+                    break;
                 default:
                     log.debug("inner Tosca Type is unknown. {}", innerToscaType);
                     return false;
index 9c1b6c9..59d7ef0 100644 (file)
@@ -23,6 +23,7 @@ package org.openecomp.sdc.be.ui.mapper;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.gson.Gson;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -49,6 +50,7 @@ public class FilterConstraintMapper {
         filterConstraint.setTargetType(StringUtils.isEmpty(uiConstraint.getCapabilityName()) ? PropertyFilterTargetType.PROPERTY : PropertyFilterTargetType.CAPABILITY);
         FilterValueType.findByName(uiConstraint.getSourceType()).ifPresent(filterConstraint::setValueType);
         filterConstraint.setValue(mapValueFrom(uiConstraint));
+        filterConstraint.setOriginalType(uiConstraint.getOriginalType());
         return filterConstraint;
     }
 
@@ -95,6 +97,7 @@ public class FilterConstraintMapper {
         propertyFilterConstraint.setOperator(filterConstraintDto.getOperator());
         propertyFilterConstraint.setValueType(filterConstraintDto.getValueType());
         propertyFilterConstraint.setValue(filterConstraintDto.getValue());
+        propertyFilterConstraint.setOriginalType(filterConstraintDto.getOriginalType());
         return propertyFilterConstraint;
     }
 
@@ -106,13 +109,32 @@ public class FilterConstraintMapper {
         uiConstraint.setServicePropertyName(filterConstraintDto.getPropertyName());
         uiConstraint.setSourceType(filterConstraintDto.getValueType().getName());
         uiConstraint.setSourceName(uiConstraint.getSourceType());
+        uiConstraint.setOriginalType(uiConstraint.getOriginalType());
         return uiConstraint;
     }
 
     private Object parseValueFromUiConstraint(final Object value) {
-        if (!(value instanceof Map || value instanceof String)) {
+        if (!(value instanceof Map || value instanceof List || value instanceof String)) {
             return value;
         }
+        if (value instanceof List) {
+            List<ToscaFunction> listValue = new ArrayList<>();
+            ToscaFunction valueObject;
+            for (Object obj: (List)value) {
+                try {
+                    valueObject = (ToscaFunction) getValueObject(obj);
+                }
+                catch (Exception e) {
+                    return value;
+                }
+                listValue.add(valueObject);
+            }
+            return listValue;
+        }
+        return getValueObject(value);
+    }
+
+    private Object getValueObject(Object value) {
         final Map<?, ?> valueAsMap;
         if (value instanceof String) {
             try {
index 401de95..acb0c81 100644 (file)
@@ -35,6 +35,7 @@ public class UIConstraint implements Serializable {
     private String sourceType;
     private String sourceName;
     private Object value;
+    private String originalType;
 
     public UIConstraint() {
     }
index 69ad90c..5f4a943 100644 (file)
@@ -26,6 +26,7 @@ export class FilterConstraint {
     sourceType: string;
     sourceName: string;
     value: any;
+    originalType: string;
 
     constructor(input?: any) {
         if (input) {
@@ -35,6 +36,7 @@ export class FilterConstraint {
             this.sourceType = input.sourceType;
             this.sourceName = input.sourceName;
             this.value = input.value;
+            this.originalType = input.originalType;
         }
     }
 }
index f47677b..c1acbee 100644 (file)
@@ -20,6 +20,9 @@
  */
 
 import {FilterConstraint} from "../filter-constraint";
+import {ConstraintOperatorType} from "../../utils/filter-constraint-helper";
+import {ToscaGetFunction} from "../tosca-get-function";
+import {ToscaFunction} from "../tosca-function";
 
 export class PropertyFilterConstraintUi extends FilterConstraint {
     isValidValue: boolean;
index 58303a9..c4a3893 100644 (file)
@@ -44,7 +44,7 @@
     <!-- RIGHT CELL OR FULL WIDTH CELL-->
     <ng-container *ngIf="propType == derivedPropertyTypes.SIMPLE || property.isDeclared || (property.isToscaFunction() && !property.isChildOfListOrMap) || (property.isChildOfListOrMap && propType == derivedPropertyTypes.MAP && property.schema.property.isSimpleType)">
         <div class="table-cell">
-            <checkbox class="{{propType == derivedPropertyTypes.MAP ? 'inline-checkBox' : 'inline-checkBox-List'}}" *ngIf="(property.isChildOfListOrMap && property.schema.property.isSimpleType)" [(checked)]="property.isSelected" [disabled]="property.isDisabled || readonly || property.mapKey == '' || checkboxDisabled" (checkedChange)="toggleTosca.emit(property)" ></checkbox>
+            <checkbox class="{{propType == derivedPropertyTypes.MAP ? 'inline-checkBox' : 'inline-checkBox-List'}}" *ngIf="hideCheckBox === false && (property.isChildOfListOrMap && property.schema.property.isSimpleType)" [(checked)]="property.isSelected" [disabled]="property.isDisabled || readonly || property.mapKey == '' || checkboxDisabled" (checkedChange)="toggleTosca.emit(property)" ></checkbox>
             <dynamic-element class="value-input"
                 pattern="validationUtils.getValidationPattern(property.type)"
                 [value]="(property.isDeclared || property.isToscaFunction()) ? property.value : property.valueObj"
index b632ddd..82c5af4 100644 (file)
@@ -55,6 +55,7 @@ export class DynamicPropertyComponent {
     @Input() hasChildren: boolean;
     @Input() hasDeclareOption:boolean;
     @Input() disablePropertyValue: boolean;
+    @Input() hideCheckBox: boolean;
     @Input() rootProperty: PropertyFEModel;
 
     @Output('propertyChanged') emitter: EventEmitter<void> = new EventEmitter<void>();
index 50ea60e..9a63dff 100644 (file)
@@ -33,7 +33,8 @@ import {ConstraintOperatorType, FilterConstraintHelper} from "../../../../utils/
 
 export enum SourceType {
     STATIC = 'static',
-    TOSCA_FUNCTION = 'tosca_function'
+    TOSCA_FUNCTION = 'tosca_function',
+    TOSCA_FUNCTION_LIST = 'tosca_function_list'
 }
 
 class I18nTexts {
@@ -125,7 +126,12 @@ export class ServiceDependenciesComponent implements OnInit, OnChanges {
             {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.LESS_THAN), value: ConstraintOperatorType.LESS_THAN},
             {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.EQUAL), value: ConstraintOperatorType.EQUAL},
             {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.GREATER_OR_EQUAL), value: ConstraintOperatorType.GREATER_OR_EQUAL},
-            {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.LESS_OR_EQUAL), value: ConstraintOperatorType.LESS_OR_EQUAL}
+            {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.LESS_OR_EQUAL), value: ConstraintOperatorType.LESS_OR_EQUAL},
+            {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.LENGTH), value: ConstraintOperatorType.LENGTH},
+            {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.IN_RANGE), value: ConstraintOperatorType.IN_RANGE},
+            {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.MIN_LENGTH), value: ConstraintOperatorType.MIN_LENGTH},
+            {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.MAX_LENGTH), value: ConstraintOperatorType.MAX_LENGTH},
+            {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.PATTERN), value: ConstraintOperatorType.PATTERN}
         ];
         this.topologyTemplateService.getComponentInputsWithProperties(this.compositeService.componentType, this.compositeService.uniqueId)
         .subscribe((result: ComponentGenericResponse) => {
index 50c77d3..2cf3c79 100644 (file)
 
 import * as _ from "lodash";
 import { Component, Compiler, EventEmitter, ViewContainerRef, ViewChild, Input, Output, ElementRef, ComponentRef, ComponentFactoryResolver } from '@angular/core'
-import {ValidationConfiguration, PropertyFEModel} from "app/models";
+import {ValidationConfiguration} from "app/models";
 import {IUiElementChangeEvent} from "../form-components/ui-element-base.component";
 import {UiElementInputComponent} from "../form-components/input/ui-element-input.component";
 import {UiElementPopoverInputComponent} from "../form-components/popover-input/ui-element-popover-input.component";
 import {UiElementIntegerInputComponent} from "../form-components/integer-input/ui-element-integer-input.component";
 import {UiElementDropDownComponent, DropdownValue} from "../form-components/dropdown/ui-element-dropdown.component";
 import {PROPERTY_DATA, PROPERTY_TYPES} from "../../../../utils/constants";
+import {UiElementValidValuesInputComponent} from "../form-components/valid-values-input/ui-element-valid-values-input.component";
+import {UiElementRangeInputComponent} from "../form-components/range-input/ui-element-range-input.component";
 
 enum DynamicElementComponentCreatorIdentifier {
     STRING,
@@ -39,7 +41,9 @@ enum DynamicElementComponentCreatorIdentifier {
     ENUM,
     LIST,
     DEFAULT,
-    TIMESTAMP
+    TIMESTAMP,
+    RANGE,
+    VALID_VALUES
 }
 
 @Component({
@@ -51,13 +55,16 @@ enum DynamicElementComponentCreatorIdentifier {
         UiElementInputComponent,
         UiElementDropDownComponent,
         UiElementPopoverInputComponent,
-        UiElementIntegerInputComponent
+        UiElementIntegerInputComponent,
+        UiElementRangeInputComponent,
+        UiElementValidValuesInputComponent
     ]
 })
 export class DynamicElementComponent {
 
     @ViewChild('target', { read: ViewContainerRef }) target: any;
     @Input() type: any;
+    @Input() operator: any;
     @Input() childType: any;
     @Input() name: string;
     @Input() testId: string;
@@ -92,28 +99,37 @@ export class DynamicElementComponent {
         // Factory to create component based on type or other property attributes.
         const prevElementCreatorIdentifier: DynamicElementComponentCreatorIdentifier = this.elementCreatorIdentifier;
         switch(true) {
-            case this.path && this.path.toUpperCase().indexOf("SUBNETPOOLID") !== -1:
+            case this.path && this.path.toUpperCase().indexOf("SUBNETPOOLID") !== -1 && this.operator != 'valid_values':
                 this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.SUBNETPOOLID;
                 break;
             case this.getValidValues() !== undefined && this.getValidValues() !== null:
                 this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.ENUM;
                 break;
-            case this.type === 'integer':
+            case this.operator === 'length' || this.operator === 'min_length' || this.operator === 'max_length':
                 this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.INTEGER;
                 break;
-            case this.type === 'float':
+            case this.type === 'integer' && this.operator != 'valid_values' && this.operator != 'in_range':
+                this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.INTEGER;
+                break;
+            case this.type === 'float' && this.operator != 'valid_values' && this.operator != 'in_range':
                 this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.FLOAT;
                 break;
-            case PROPERTY_DATA.SCALAR_TYPES.indexOf(this.type) > -1:
-            case this.type === 'string':
+            case PROPERTY_DATA.SCALAR_TYPES.indexOf(this.type) > -1 && this.operator != 'valid_values' && this.operator != 'in_range':
+            case this.type === 'string' && this.operator != 'valid_values' && this.operator != 'in_range' && this.operator != 'length' && this.operator != 'min_length' && this.operator != 'max_length':
                 this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.STRING;
                 break;
-            case this.type === PROPERTY_TYPES.TIMESTAMP:
+            case this.type === PROPERTY_TYPES.TIMESTAMP && this.operator != 'valid_values' && this.operator != 'in_range':
                 this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.TIMESTAMP;
                 break;
-            case this.type === 'boolean':
+            case this.type === 'boolean' && this.operator != 'valid_values':
                 this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.BOOLEAN;
                 break;
+            case this.type === 'range' || this.operator === 'in_range':
+                this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.RANGE;
+                break;
+            case this.operator === 'valid_values':
+                this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.VALID_VALUES;
+                break;
           case this.type === 'map':
                 this.createElementCreatorIdentifierForChild();
                 break;
@@ -156,6 +172,12 @@ export class DynamicElementComponent {
         case 'boolean':
           this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.BOOLEAN;
           break;
+        case 'range':
+          this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.RANGE;
+          break;
+          case 'valid-values':
+              this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.VALID_VALUES;
+              break;
         default:
           this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.DEFAULT;
       }
@@ -201,6 +223,15 @@ export class DynamicElementComponent {
                     this.createComponent(UiElementInputComponent);
                     break;
 
+                case DynamicElementComponentCreatorIdentifier.RANGE:
+                    this.createComponent(UiElementRangeInputComponent);
+                    break;
+
+                case DynamicElementComponentCreatorIdentifier.VALID_VALUES:
+                    this.createComponent(UiElementValidValuesInputComponent);
+                    this.cmpRef.instance.type = this.type;
+                    break;
+
                 case DynamicElementComponentCreatorIdentifier.BOOLEAN:
                     this.createComponent(UiElementDropDownComponent);
 
index b35d3ae..d7f134b 100644 (file)
@@ -14,6 +14,8 @@ import { UiElementIntegerInputComponent } from './integer-input/ui-element-integ
 import { UiElementPopoverInputComponent } from './popover-input/ui-element-popover-input.component';
 import { RadioButtonComponent } from './radio-buttons/radio-buttons.component';
 import { UiElementBase } from './ui-element-base.component';
+import {UiElementRangeInputComponent} from "./range-input/ui-element-range-input.component";
+import {UiElementValidValuesInputComponent} from "./valid-values-input/ui-element-valid-values-input.component";
 
 @NgModule({
     imports: [
@@ -29,12 +31,16 @@ import { UiElementBase } from './ui-element-base.component';
         UiElementInputComponent,
         UiElementIntegerInputComponent,
         UiElementPopoverInputComponent,
+        UiElementRangeInputComponent,
+        UiElementValidValuesInputComponent,
         UiElementBase,
         RadioButtonComponent],
 
     exports: [UiElementDropDownComponent,
         UiElementInputComponent,
         UiElementIntegerInputComponent,
+        UiElementRangeInputComponent,
+        UiElementValidValuesInputComponent,
         UiElementPopoverInputComponent,
         RadioButtonComponent,
         TooltipModule,
index d5ef08b..4ab0a68 100644 (file)
@@ -17,7 +17,7 @@
 <input
     class="value-input"
     [ngClass]="{'error': control.invalid, 'disabled':readonly}"
-    type="text"
+    type="{{type === 'integer' ? 'number' : 'text' }}"
     [name]="name"
     [(ngModel)]="value"
     (input)="onChange()"
diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/range-input/ui-element-range-input.component.html b/catalog-ui/src/app/ng2/components/ui/form-components/range-input/ui-element-range-input.component.html
new file mode 100644 (file)
index 0000000..970492e
--- /dev/null
@@ -0,0 +1,81 @@
+<!--
+*  ============LICENSE_START=======================================================
+*  Copyright (C) 2023 Nordix Foundation.
+*  ================================================================================
+*  Licensed under the Apache License, Version 2.0 (the "License");
+*  you may not use this file except in compliance with the License.
+*  You may obtain a copy of the License at
+*
+*       http://www.apache.org/licenses/LICENSE-2.0
+*
+*  Unless required by applicable law or agreed to in writing, software
+*  distributed under the License is distributed on an "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*  See the License for the specific language governing permissions and
+*  limitations under the License.
+*
+*  SPDX-License-Identifier: Apache-2.0
+*  ============LICENSE_END=========================================================
+ -->
+<div class="w-sdc-form-columns-wrapper">
+    <div class="w-sdc-form-column">
+
+            <input *ngIf="isFloatType()"
+                class="value-input"
+                [ngClass]="{'error': control.invalid, 'disabled':readonly}"
+                type="number"
+                step="0.01"
+                [name]="name"
+                [(ngModel)]="lowerBound"
+                [value]="getInRangeValue(0)"
+                (input)="onChangeMin()"
+                [attr.maxlength]="validation.propertyValue.max"
+                [attr.minlength]="validation.propertyValue.min"
+                [formControl]="control"
+                [attr.data-tests-id]="'valueMin-' + testId"
+                />
+        <input *ngIf="isIntegerType()"
+               class="value-input"
+               [ngClass]="{'error': control.invalid, 'disabled':readonly}"
+               type="number"
+               [name]="name"
+               [(ngModel)]="lowerBound"
+               [value]="getInRangeValue(0)"
+               (input)="onChangeMin()"
+               [attr.maxlength]="validation.propertyValue.max"
+               [attr.minlength]="validation.propertyValue.min"
+               [formControl]="control"
+               [attr.data-tests-id]="'valueMin-' + testId"
+        />
+        <input *ngIf="isStringType()"
+               class="value-input"
+               [ngClass]="{'error': control.invalid, 'disabled':readonly}"
+               type="text"
+               [name]="name"
+               [(ngModel)]="lowerBound"
+               [value]="getInRangeValue(0)"
+               (input)="onChangeMin()"
+               [attr.maxlength]="validation.propertyValue.max"
+               [attr.minlength]="validation.propertyValue.min"
+               [formControl]="control"
+               [attr.data-tests-id]="'valueMin-' + testId"
+        />
+    </div>
+    <div class="w-sdc-form-column">
+            <input
+                    class="value-input"
+                    [ngClass]="{'error': control.invalid, 'disabled':readonly}"
+                    [type]="isIntegerType() || isFloatType() ? 'number' : 'text'"
+                    [name]="name"
+                    [(ngModel)]="upperBound"
+                    [value]="getInRangeValue(1)"
+                    (input)="onChangeMax()"
+                    [attr.maxlength]="validation.propertyValue.max"
+                    [attr.minlength]="validation.propertyValue.min"
+
+                    [formControl]="control"
+                    [attr.data-tests-id]="'valueMax-' + testId"
+            />
+
+    </div>
+</div>
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/range-input/ui-element-range-input.component.less b/catalog-ui/src/app/ng2/components/ui/form-components/range-input/ui-element-range-input.component.less
new file mode 100644 (file)
index 0000000..c393024
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+@import '../../../../../../assets/styles/variables';
+
+/deep/ ui-element-range-input {
+
+    input {
+        text-indent: 6px;
+        border: solid 1px @main_color_o;
+    }
+
+    .error {
+        border: solid 1px @func_color_q;
+        color: @func_color_q;
+        outline: none;
+        box-sizing: border-box;
+    }
+
+}
diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/range-input/ui-element-range-input.component.ts b/catalog-ui/src/app/ng2/components/ui/form-components/range-input/ui-element-range-input.component.ts
new file mode 100644 (file)
index 0000000..65c5bd7
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+import {Component, Input} from '@angular/core';
+import { UiElementBase, UiElementBaseInterface } from './../ui-element-base.component';
+import {PROPERTY_DATA} from "../../../../../utils/constants";
+
+@Component({
+    selector: 'ui-element-range-input',
+    templateUrl: './ui-element-range-input.component.html',
+    styleUrls: ['./ui-element-range-input.component.less'],
+})
+export class UiElementRangeInputComponent extends UiElementBase implements UiElementBaseInterface {
+    @Input() lowerBound: any;
+    @Input() upperBound: any;
+    step: number;
+    constructor() {
+        super();
+        this.pattern = this.validation.validationPatterns.comment;
+        this.value = new Array(2);
+        this.value[0] = this.lowerBound;
+        this.value[1] = this.upperBound;
+    }
+
+    ngOnInit(){
+        this.step = 0;
+        if (this.type === 'float') {
+            this.step = 0.01;
+        }
+        if (this.type === 'integer') {
+            this.step = 0;
+        }
+    }
+
+    isFloatType(): boolean {
+        return this.type === 'float';
+    }
+
+    isIntegerType(): boolean {
+        return this.type === 'integer' || this.type === 'range' || this.type === 'timestamp';
+    }
+
+    isStringType(): boolean {
+        return this.type === 'string' || PROPERTY_DATA.SCALAR_TYPES.indexOf(this.type) > -1;
+    }
+
+    onChangeMin() {
+        if (!this.value) {
+            this.value = new Array(2);
+        }
+        this.value.splice(0, 1, this.lowerBound);
+        this.baseEmitter.emit({
+            value: this.value ,
+            isValid: this.isValidRange()
+        });
+    }
+
+    onChangeMax() {
+        if (!this.value) {
+            this.value = new Array(2);
+        }
+        this.value.splice(1, 1, this.upperBound);
+        this.baseEmitter.emit({
+            value: this.value,
+            isValid: this.isValidRange()
+        });
+    }
+
+    getInRangeValue(valueIndex: number): string {
+        if(!this.value || !this.value[valueIndex]) {
+            return "";
+        }
+        return this.value[valueIndex];
+    }
+
+    isNumber(value: string | number): boolean
+    {
+        return ((value != undefined) &&
+            (value != null) &&
+            (value !== '') &&
+            !isNaN(Number(value.toString())));
+    }
+
+    isValidRange(): boolean
+    {
+        if (this.isStringType()) {
+            return this.getInRangeValue(0) <= this.getInRangeValue(1);
+        }
+        return this.isNumber(this.value[0])
+        && (this.getInRangeValue(1) === "UNBOUNDED"
+                || (this.isNumber(this.value[1])
+                    && this.getInRangeValue(0) <= this.getInRangeValue(1)));
+    }
+}
diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/valid-values-input/ui-element-valid-values-input.component.html b/catalog-ui/src/app/ng2/components/ui/form-components/valid-values-input/ui-element-valid-values-input.component.html
new file mode 100644 (file)
index 0000000..ff4d6d1
--- /dev/null
@@ -0,0 +1,39 @@
+<!--
+*  ============LICENSE_START=======================================================
+*  Copyright (C) 2023 Nordix Foundation.
+*  ================================================================================
+*  Licensed under the Apache License, Version 2.0 (the "License");
+*  you may not use this file except in compliance with the License.
+*  You may obtain a copy of the License at
+*
+*       http://www.apache.org/licenses/LICENSE-2.0
+*
+*  Unless required by applicable law or agreed to in writing, software
+*  distributed under the License is distributed on an "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*  See the License for the specific language governing permissions and
+*  limitations under the License.
+*
+*  SPDX-License-Identifier: Apache-2.0
+*  ============LICENSE_END=========================================================
+ -->
+
+    <div class="add-btn"
+             (click)="addToList()">Add to List
+    </div>
+    <div class="w-sdc-form-columns-wrapper" *ngFor="let val of value; let valueIndex = index; trackBy:trackByFn">
+        <div class="w-sdc-form-column">
+            <input type="text" class="i-sdc-form-input" *ngIf="showStringField()"
+                   [value]="val"
+                   (input)="onChangeConstrainValueIndex($event.target.value, valueIndex)"/>
+            <input type="number" class="i-sdc-form-input" *ngIf="showIntegerField()"
+                   [value]="val"
+                   (input)="onChangeConstrainValueIndex($event.target.value, valueIndex)"/>
+            <input type="number" class="i-sdc-form-input" step="0.01" *ngIf="type == 'float'"
+                   [value]="val"
+                   (input)="onChangeConstrainValueIndex($event.target.value, valueIndex)"/>
+        </div>
+        <div class="w-sdc-form-column">
+            <span class="sprite-new delete-btn" (click)="removeFromList(valueIndex)"></span>
+        </div>
+    </div>
diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/valid-values-input/ui-element-valid-values-input.component.less b/catalog-ui/src/app/ng2/components/ui/form-components/valid-values-input/ui-element-valid-values-input.component.less
new file mode 100644 (file)
index 0000000..c393024
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+@import '../../../../../../assets/styles/variables';
+
+/deep/ ui-element-range-input {
+
+    input {
+        text-indent: 6px;
+        border: solid 1px @main_color_o;
+    }
+
+    .error {
+        border: solid 1px @func_color_q;
+        color: @func_color_q;
+        outline: none;
+        box-sizing: border-box;
+    }
+
+}
diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/valid-values-input/ui-element-valid-values-input.component.ts b/catalog-ui/src/app/ng2/components/ui/form-components/valid-values-input/ui-element-valid-values-input.component.ts
new file mode 100644 (file)
index 0000000..079fdeb
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+import {Component, Output, EventEmitter} from '@angular/core';
+import { UiElementBase, UiElementBaseInterface } from './../ui-element-base.component';
+import {ConstraintTypes} from "../../../../pages/properties-assignment/constraints/constraints.component";
+import {PROPERTY_DATA, PROPERTY_TYPES} from "../../../../../utils/constants";
+
+@Component({
+    selector: 'ui-element-valid-values-input',
+    templateUrl: './ui-element-valid-values-input.component.html',
+    styleUrls: ['./ui-element-valid-values-input.component.less'],
+})
+export class UiElementValidValuesInputComponent extends UiElementBase implements UiElementBaseInterface {
+    @Output() onConstraintChange: EventEmitter<any> = new EventEmitter<any>();
+    constructor() {
+        super();
+        this.pattern = this.validation.validationPatterns.comment;
+    }
+
+    showStringField(): boolean {
+        return this.type === PROPERTY_TYPES.STRING || PROPERTY_DATA.SCALAR_TYPES.indexOf(this.type) > -1;
+    }
+
+    showIntegerField(): boolean {
+        return this.type === PROPERTY_TYPES.INTEGER || this.type === PROPERTY_TYPES.TIMESTAMP;
+    }
+
+    addToList(){
+        if (!this.value) {
+            this.value = new Array();
+        }
+        this.value.push("");
+        this.baseEmitter.emit({
+            value: this.value,
+            isValid: false
+        });
+        this.emitOnConstraintChange()
+    }
+
+    onChangeConstrainValueIndex(newValue: any, valueIndex: number) {
+        if(!this.value) {
+            this.value = new Array();
+        }
+        this.value[valueIndex] = newValue;
+        this.baseEmitter.emit({
+            value: this.value,
+            isValid: newValue != "" && !this.doesArrayContaintEmptyValues(this.value)
+        });
+        this.emitOnConstraintChange();
+    }
+
+    private emitOnConstraintChange(): void {
+        this.onConstraintChange.emit({
+            valid: this.validateConstraints()
+        });
+    }
+    private validateConstraints(): boolean {
+        if (Array.isArray(this.value)) {
+            return !(this.value.length == 0 || this.doesArrayContaintEmptyValues(this.value));
+        }
+        return this.value && this.type != ConstraintTypes.null
+    }
+
+    removeFromList(valueIndex: number){
+        this.value.splice(valueIndex, 1);
+        this.baseEmitter.emit({
+            value: this.value,
+            isValid: !this.doesArrayContaintEmptyValues(this.value)
+        });
+        this.emitOnConstraintChange()
+    }
+
+    trackByFn(index) {
+        return index;
+    }
+
+    private doesArrayContaintEmptyValues(arr) {
+        for(const element of arr) {
+            if(element === "") return true;
+        }
+        return false;
+    }
+}
index 8dd4ca9..6a27622 100644 (file)
@@ -181,6 +181,8 @@ export class PropertiesUtils {
                     property.childPropUpdated(childProp);
                 });
 
+            } else if (property.derivedDataType === DerivedPropertyType.RANGE) {
+                property.valueObj = JSON.stringify(property.getValueObj());
             }
         }
         property.updateValueObjOrig();
index 898b189..65a024c 100644 (file)
@@ -43,6 +43,7 @@
     </div>
     <div *ngIf="isGetFunctionSelected()">
       <app-tosca-get-function [property]="property" [toscaGetFunction]="toscaFunction"
+                              [overridingType] = "overridingType"
                               [componentInstanceMap]="componentInstanceMap"
                               [functionType]="toscaFunctionTypeForm.value"
                               [compositionMap]="compositionMap"
index 8169694..ecaff25 100644 (file)
@@ -30,7 +30,7 @@ import {ToscaGetFunctionValidationEvent} from "./tosca-get-function/tosca-get-fu
 import {ToscaFunction} from "../../../../models/tosca-function";
 import {ToscaConcatFunctionValidationEvent} from "./tosca-concat-function/tosca-concat-function.component";
 import {ToscaCustomFunctionValidationEvent} from "./tosca-custom-function/tosca-custom-function.component";
-import {PROPERTY_TYPES, PROPERTY_DATA} from "../../../../utils/constants";
+import {PROPERTY_TYPES} from "../../../../utils/constants";
 import {YamlFunctionValidationEvent} from "./yaml-function/yaml-function.component";
 import {ToscaConcatFunction} from "../../../../models/tosca-concat-function";
 import {ToscaCustomFunction} from "../../../../models/tosca-custom-function";
@@ -45,6 +45,8 @@ import {CustomToscaFunction} from "../../../../models/default-custom-functions";
 export class ToscaFunctionComponent implements OnInit, OnChanges {
 
     @Input() property: PropertyBEModel;
+    @Input() overridingType: PROPERTY_TYPES;
+    @Input() inToscaFunction: ToscaFunction;
     @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
     @Input() customToscaFunctions: Array<CustomToscaFunction> = [];
     @Input() allowClear: boolean = true;
@@ -74,7 +76,7 @@ export class ToscaFunctionComponent implements OnInit, OnChanges {
 
     ngOnInit(): void {
         this.componentMetadata = this.workspaceService.metadata;
-        this.toscaFunction = this.property.toscaFunction ? this.property.toscaFunction : undefined;
+        this.toscaFunction = this.inToscaFunction ? this.inToscaFunction : this.property.toscaFunction ? this.property.toscaFunction : undefined;
         this.loadToscaFunctions();
         this.formGroup.valueChanges.subscribe(() => {
             if (!this.isInitialized) {
@@ -93,7 +95,7 @@ export class ToscaFunctionComponent implements OnInit, OnChanges {
     ngOnChanges(changes: SimpleChanges): void {
         if (changes.property) {
             this.resetForm();
-            this.toscaFunction = this.property.toscaFunction ? this.property.toscaFunction : undefined;
+            this.toscaFunction = this.inToscaFunction ? this.inToscaFunction : this.property.toscaFunction ? this.property.toscaFunction : undefined;
             this.initToscaFunction();
             this.loadToscaFunctions();
             this.emitValidityChange();
@@ -130,11 +132,11 @@ export class ToscaFunctionComponent implements OnInit, OnChanges {
                 return;
             }
         }
-
         if (!this.property.isToscaFunction()) {
             return;
         }
-        this.toscaFunctionForm.setValue(this.property.toscaFunction);
+
+        this.toscaFunctionForm.setValue(this.inToscaFunction ? this.inToscaFunction : this.property.toscaFunction);
         let type = this.property.toscaFunction.type;
         if (type == ToscaFunctionType.CUSTOM) {
             let name = (this.property.toscaFunction as ToscaCustomFunction).name;
@@ -145,7 +147,7 @@ export class ToscaFunctionComponent implements OnInit, OnChanges {
                 this.toscaFunctionTypeForm.setValue("other");
             }
         } else {
-            this.toscaFunctionTypeForm.setValue(type);
+            this.toscaFunctionTypeForm.setValue(this.inToscaFunction ? this.inToscaFunction.type : type);
         }
     }
 
@@ -159,6 +161,9 @@ export class ToscaFunctionComponent implements OnInit, OnChanges {
         this.toscaFunctions.push(ToscaFunctionType.GET_INPUT);
         this.toscaFunctions.push(ToscaFunctionType.GET_PROPERTY);
         if (this.property.type === PROPERTY_TYPES.STRING || this.property.type === PROPERTY_TYPES.ANY) {
+            this.toscaFunctions.push(ToscaFunctionType.CUSTOM);
+        }
+        if ((this.property.type === PROPERTY_TYPES.STRING || this.property.type === PROPERTY_TYPES.ANY) && this.overridingType === undefined) {
             this.toscaFunctions.push(ToscaFunctionType.CONCAT);
         }
         this.loadCustomToscaFunctions();
index fe6f2f1..284c559 100644 (file)
@@ -42,6 +42,7 @@ import {ToscaGetFunctionTypeConverter} from "../../../../../models/tosca-get-fun
 export class ToscaGetFunctionComponent implements OnInit, OnChanges {
 
     @Input() property: PropertyBEModel;
+    @Input() overridingType: PROPERTY_TYPES;
     @Input() toscaGetFunction: ToscaGetFunction;
     @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
     @Input() functionType: ToscaGetFunctionType;
@@ -243,13 +244,13 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
             const properties: Array<PropertyBEModel | AttributeBEModel> = this.extractProperties(response);
             if (!properties || properties.length === 0) {
                 const msgCode = this.getNotFoundMsgCode();
-                this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.propertyTypeToString()});
+                this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.overridingType != undefined ? this.overridingType : this.propertyTypeToString()});
                 return;
             }
             this.addPropertiesToDropdown(properties);
             if (this.propertyDropdownList.length == 0) {
                 const msgCode = this.getNotFoundMsgCode();
-                this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.propertyTypeToString()});
+                this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.overridingType != undefined ? this.overridingType : this.propertyTypeToString()});
             }
         }, (error) => {
             console.error('An error occurred while loading properties.', error);
@@ -403,6 +404,9 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
     }
 
     private hasSameType(property: PropertyBEModel | AttributeBEModel): boolean {
+        if (this.overridingType != undefined) {
+            return property.type === this.overridingType;
+        }
         if (this.property.type === PROPERTY_TYPES.ANY) {
             return true;
         }
index 8024eb1..c90cfd8 100644 (file)
                     <label class="i-sdc-form-label required">{{"OPERATOR_LABEL" | translate}}</label>
                     <ui-element-dropdown class="i-sdc-form-select" data-tests-id="constraintOperator"
                                          [testId]="'constraintOperator'"
-                                         [values]="operatorTypes" [(value)]="currentRule.constraintOperator"></ui-element-dropdown>
+                                         (change)="onSourceTypeChange()"
+                                         [values]="operatorTypes" [(value)]="currentRule.constraintOperator"
+                                         >
+                    </ui-element-dropdown>
                 </div>
             </div>
             <div class="rule-builder-content">
                            data-tests-id="value-type-static"
                            [(ngModel)]="selectedSourceType"
                            [value]="SOURCE_TYPES.STATIC.value"
-                           (ngModelChange)="onSourceTypeChange()"/> {{"VALUE_LABEL" | translate}}
+                           (ngModelChange)="onSourceTypeChange($event)"/> {{"VALUE_LABEL" | translate}}
                     <input type="radio" name="sourceType"
                            data-tests-id="value-type-tosca-function"
                            [(ngModel)]="selectedSourceType"
-                           [value]="SOURCE_TYPES.TOSCA_FUNCTION.value"
-                           (ngModelChange)="onSourceTypeChange()"/> {{"VALUE_EXPRESSION_LABEL" | translate}}
+                           [value]="isValidValuesOperator() || isRangeType() || isInRangeOperator() ? SOURCE_TYPES.TOSCA_FUNCTION_LIST.value: SOURCE_TYPES.TOSCA_FUNCTION.value"
+                           (ngModelChange)="onSourceTypeChange($event)"/> {{"VALUE_EXPRESSION_LABEL" | translate}}
                 </div>
             </div>
             <div class="rule-builder-content" *ngIf="isToscaFunctionSource() && selectedProperty">
+                <div class="i-sdc-form-item rule-input-field">
+                    <tosca-function [property]="selectedProperty"
+                                    [overridingType] = "isLengthOperator() ? overridingType : undefined"
+                                    [componentInstanceMap]="componentInstanceMap"
+                                    [allowClear]="false"
+                                    (onValidityChange)="onToscaFunctionValidityChange($event)"
+                    >
+                    </tosca-function>
+                </div>
+            </div>
+            <div class="rule-builder-content" *ngIf="isToscaFunctionSource() && selectedProperty && (isRangeType() || isInRangeOperator())">
                 <div class="i-sdc-form-item rule-input-field">
                     <tosca-function [property]="selectedProperty"
                                     [componentInstanceMap]="componentInstanceMap"
                     </tosca-function>
                 </div>
             </div>
+
+            <div class="rule-builder-content" *ngIf="isToscaFunctionListSource() && selectedProperty && (isRangeType() || isInRangeOperator())">
+
+                <div class="i-sdc-form-item rule-input-field">
+                    <div class="w-sdc-form-columns-wrapper" *ngFor="let val of rangeToscaFunctionList; let valueIndex = index; trackBy:trackByFn">
+                        <div class="w-sdc-form-column" style="border-width:3px; border-style:solid; border-color:#009fdb; padding: 1em;">
+                            <tosca-function [property]="selectedProperty"
+                                            [inToscaFunction]="val"
+                                            [componentInstanceMap]="componentInstanceMap"
+                                            [allowClear]="false"
+                                            (onValidityChange)="onToscaRangeFunctionListValidityChange($event, valueIndex)"
+                            >
+                            </tosca-function>
+                        </div>
+                    </div>
+                </div>
+            </div>
+
+            <div class="rule-builder-content" *ngIf="isToscaFunctionListSource() && selectedProperty && isValidValuesOperator()">
+
+                <div class="i-sdc-form-item rule-input-field">
+                    <div class="add-btn"
+                         (click)="addToList()">Add to List
+                    </div>
+                    <div class="w-sdc-form-columns-wrapper" *ngFor="let val of this.validValuesToscaFunctionList; let valueIndex = index; trackBy:trackByFn">
+                        <div class="w-sdc-form-column" style="border-width:3px; border-style:solid; border-color:#009fdb; padding: 1em;">
+                            <tosca-function [property]="selectedProperty"
+                                            [inToscaFunction]="val"
+                                            [componentInstanceMap]="componentInstanceMap"
+                                            [allowClear]="false"
+                                            (onValidityChange)="onToscaFunctionListValidityChange($event, valueIndex)"
+                            >
+                            </tosca-function>
+                        </div>
+                        <div class="w-sdc-form-column">
+                            <span class="sprite-new delete-btn" (click)="removeFromList(valueIndex)"></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
             <div *ngIf="isToscaFunctionSource() && !selectedProperty">
                 {{"NODE_FILTER_SELECT_PROPERTY" | translate}}
             </div>
             <div class="rule-builder-content" *ngIf="isStaticSource()">
                 <div class="i-sdc-form-item rule-input-field complex-input-field">
                     <dynamic-property
-                        *ngIf="isComplexListMapType()"
+                            *ngIf="isComplexListMapType() && !isRangeType() && !isValidValuesOperator() && !isLengthOperator()"
                         [selectedPropertyId]="selectedProperty.uniqueId"
                         [property]="selectedProperty"
                         [expandedChildId]="selectedProperty.expandedChildPropertyId ?
                                 selectedProperty.expandedChildPropertyId : selectedProperty.name"
                         [canBeDeclared]="true"
+                        [hideCheckBox]="true"
                         (propertyChanged)="updateComplexListMapTypeRuleValue()"
                         [rootProperty]="selectedProperty"
                         (expandChild)="selectedProperty.updateExpandedChildPropertyId($event)">
                     </dynamic-property>
                     <dynamic-element
-                        *ngIf="!isComplexListMapType()"
+                        *ngIf="!isComplexListMapType() && !isValidValuesOperator()"
                         [(value)]="currentRule.value"
                         class="rule-assigned-value"
                         data-tests-id="ruleAssignedValue"
                         (elementChanged)="onValueChange($event.isValid)"
-                        [type]="selectedProperty ? selectedProperty.type : 'string'">
+                        [type]="isLengthOperator() ? 'integer' : selectedProperty ? selectedProperty.type : 'string'"
+                        [operator]="currentRule.constraintOperator">
+                    </dynamic-element>
+                    <dynamic-element
+                            *ngIf="isComplexListMapType() && isLengthOperator()"
+                            [(value)]="currentRule.value"
+                            class="rule-assigned-value"
+                            data-tests-id="ruleAssignedValue"
+                            (elementChanged)="onValueChange($event.isValid)"
+                            [type]="isLengthOperator() ? 'integer' : selectedProperty ? selectedProperty.type : 'string'"
+                            [operator]="currentRule.constraintOperator">
+                    </dynamic-element>
+                    <dynamic-element
+                            *ngIf="isRangeType()"
+                            [(value)]="currentRule.value"
+                            class="rule-assigned-value"
+                            data-tests-id="ruleAssignedValue"
+                            (elementChanged)="onValueChange($event.isValid)"
+                            [type]="selectedProperty ? selectedProperty.type : 'string'">
+                    </dynamic-element>
+                    <dynamic-element
+                            *ngIf="isValidValuesOperator()"
+                            [(value)]="currentRule.value"
+                            class="rule-assigned-value"
+                            data-tests-id="ruleAssignedValue"
+                            (elementChanged)="onValueChange($event.isValid)"
+                            [type]="selectedProperty ? selectedProperty.type : 'string'"
+                            [operator]="currentRule.constraintOperator">
                     </dynamic-element>
                 </div>
             </div>
index 39609a5..5897f27 100644 (file)
@@ -19,7 +19,7 @@ import {InputBEModel, PropertyBEModel, PropertyFEModel, PropertyModel} from 'app
 import {SourceType} from 'app/ng2/components/logic/service-dependencies/service-dependencies.component';
 import {DropdownValue} from 'app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component';
 import {ServiceServiceNg2} from 'app/ng2/services/component-services/service.service';
-import {PROPERTY_DATA} from 'app/utils';
+import {PROPERTY_DATA, PROPERTY_TYPES} from 'app/utils';
 import {PropertiesUtils} from '../properties-assignment/services/properties.utils';
 import {ToscaFunctionValidationEvent} from "../properties-assignment/tosca-function/tosca-function.component";
 import {InstanceFeDetails} from "../../../models/instance-fe-details";
@@ -30,7 +30,7 @@ import {ConstraintOperatorType, FilterConstraintHelper} from "../../../utils/fil
 import {ToscaFunctionHelper} from "../../../utils/tosca-function-helper";
 import {TopologyTemplateService} from "app/ng2/services/component-services/topology-template.service";
 import {CustomToscaFunction} from "../../../models/default-custom-functions";
-import {ToscaFunctionType} from "../../../models/tosca-function-type.enum";
+import {ToscaFunction} from "../../../models/tosca-function";
 
 @Component({
   selector: 'service-dependencies-editor',
@@ -52,8 +52,23 @@ export class ServiceDependenciesEditorComponent implements OnInit {
       ConstraintOperatorType.LESS_THAN,
       ConstraintOperatorType.EQUAL,
       ConstraintOperatorType.GREATER_OR_EQUAL,
-      ConstraintOperatorType.LESS_OR_EQUAL
+      ConstraintOperatorType.LESS_OR_EQUAL,
+      ConstraintOperatorType.IN_RANGE,
+      ConstraintOperatorType.VALID_VALUES,
+      ConstraintOperatorType.LENGTH,
+      ConstraintOperatorType.MIN_LENGTH,
+      ConstraintOperatorType.MAX_LENGTH,
+      ConstraintOperatorType.PATTERN
   ];
+    @Input() comparableAllowedOperators: ConstraintOperatorType[] = [
+        ConstraintOperatorType.GREATER_THAN,
+        ConstraintOperatorType.LESS_THAN,
+        ConstraintOperatorType.EQUAL,
+        ConstraintOperatorType.GREATER_OR_EQUAL,
+        ConstraintOperatorType.LESS_OR_EQUAL,
+        ConstraintOperatorType.IN_RANGE,
+        ConstraintOperatorType.VALID_VALUES,
+    ];
   @Input() capabilityNameAndPropertiesMap: Map<string, PropertyModel[]>;
   @Input() filterType: FilterType;
   @Input() filterConstraint: PropertyFilterConstraintUi;
@@ -62,6 +77,13 @@ export class ServiceDependenciesEditorComponent implements OnInit {
 
   FILTER_TYPE_CAPABILITY: FilterType = FilterType.CAPABILITY
 
+  listAllowedOperators: ConstraintOperatorType[] = [
+        ConstraintOperatorType.EQUAL,
+        ConstraintOperatorType.LENGTH,
+        ConstraintOperatorType.MIN_LENGTH,
+        ConstraintOperatorType.MAX_LENGTH
+    ];
+
   operatorTypes: DropdownValue[] = [
     {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.GREATER_THAN), value: ConstraintOperatorType.GREATER_THAN},
     {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.LESS_THAN), value: ConstraintOperatorType.LESS_THAN},
@@ -69,6 +91,9 @@ export class ServiceDependenciesEditorComponent implements OnInit {
     {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.GREATER_OR_EQUAL), value: ConstraintOperatorType.GREATER_OR_EQUAL},
     {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.LESS_OR_EQUAL), value: ConstraintOperatorType.LESS_OR_EQUAL}
   ];
+  lengthArray: string[] = [ConstraintOperatorType.LENGTH,
+      ConstraintOperatorType.MIN_LENGTH,
+      ConstraintOperatorType.MAX_LENGTH];
 
   servicePropertyDropdownList: DropdownValue[];
   isLoading: false;
@@ -77,10 +102,14 @@ export class ServiceDependenciesEditorComponent implements OnInit {
   componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
   customToscaFunctions: Array<CustomToscaFunction>;
   capabilityDropdownList: DropdownValue[] = [];
+  validValuesToscaFunctionList: ToscaFunction[];
+  rangeToscaFunctionList: ToscaFunction[];
+  overridingType = PROPERTY_TYPES.INTEGER;
 
   SOURCE_TYPES = {
     STATIC: {label: 'Static', value: SourceType.STATIC},
-    TOSCA_FUNCTION: {label: 'Tosca Function', value: SourceType.TOSCA_FUNCTION}
+    TOSCA_FUNCTION: {label: 'Tosca Function', value: SourceType.TOSCA_FUNCTION},
+    TOSCA_FUNCTION_LIST: {label: 'Tosca Function List', value: SourceType.TOSCA_FUNCTION_LIST}
   };
 
   constructor(private propertiesUtils: PropertiesUtils, private compositionService: CompositionService, private topologyTemplateService: TopologyTemplateService) {}
@@ -100,6 +129,7 @@ export class ServiceDependenciesEditorComponent implements OnInit {
     this.initSelectedSourceType();
     this.initPropertyDropdown();
     this.syncRuleData();
+    this.generateRangeToscaFunctionList();
   }
 
   private initCustomToscaFunctions() {
@@ -138,43 +168,87 @@ export class ServiceDependenciesEditorComponent implements OnInit {
     this.servicePropertyDropdownList = [new DropdownValue(undefined, selectLabel), ...propertyList.map(prop => new DropdownValue(prop.name, prop.name)).sort((prop1, prop2) => prop1.value.localeCompare(prop2.value))];
   }
 
-  private initConstraintOperatorOptions(): void {
-    if (!this.selectedProperty) {
-      this.operatorTypes = [new DropdownValue(undefined, 'Select a Property')];
-      return;
+    private initConstraintOperatorOptions(): void {
+        if (!this.selectedProperty) {
+            this.operatorTypes = [this.setOperatorDropdownValue(undefined)];
+            return;
+        }
+        const operatorList: DropdownValue[] = [];
+        switch (true) {
+            case this.selectedProperty.type === PROPERTY_TYPES.RANGE:
+                if (this.currentRule.constraintOperator !== ConstraintOperatorType.IN_RANGE) {
+                    this.currentRule.constraintOperator = ConstraintOperatorType.IN_RANGE;
+                }
+                this.operatorTypes = [this.setOperatorDropdownValue(ConstraintOperatorType.IN_RANGE)];
+                break;
+            case this.selectedProperty.type === PROPERTY_TYPES.STRING:
+                this.allowedOperators.forEach(constraintOperatorType =>
+                    operatorList.push(this.setOperatorDropdownValue(constraintOperatorType))
+                );
+                this.operatorTypes = operatorList;
+                break;
+            case  this.selectedProperty.type != PROPERTY_TYPES.STRING &&
+            ((PROPERTY_DATA.SIMPLE_TYPES_COMPARABLE.indexOf(this.selectedProperty.type) > -1) ||
+            (PROPERTY_DATA.COMPARABLE_TYPES.indexOf(this.selectedProperty.type) > -1)):
+                this.comparableAllowedOperators.forEach(constraintOperatorType =>
+                    operatorList.push(this.setOperatorDropdownValue(constraintOperatorType))
+                );
+                this.operatorTypes = operatorList;
+                break;
+            case this.selectedProperty.type === PROPERTY_TYPES.LIST:
+                this.listAllowedOperators.forEach(constraintOperatorType =>
+                    operatorList.push(this.setOperatorDropdownValue(constraintOperatorType))
+                );
+                this.operatorTypes = operatorList;
+                break;
+            default:
+                if (this.currentRule.constraintOperator !== ConstraintOperatorType.EQUAL) {
+                    this.currentRule.constraintOperator = ConstraintOperatorType.EQUAL;
+                }
+                this.operatorTypes = [this.setOperatorDropdownValue(ConstraintOperatorType.EQUAL)];
+                break;
+        }
     }
 
-    if (PROPERTY_DATA.SIMPLE_TYPES_COMPARABLE.indexOf(this.selectedProperty.type) === -1) {
-      if (this.currentRule.constraintOperator !== ConstraintOperatorType.EQUAL) {
-        this.currentRule.constraintOperator = ConstraintOperatorType.EQUAL;
-      }
-      this.operatorTypes = [new DropdownValue(ConstraintOperatorType.EQUAL, FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.EQUAL))];
-    } else {
-      const operatorList: DropdownValue[] = [];
-      this.allowedOperators.forEach(constraintOperatorType =>
-        operatorList.push(new DropdownValue(constraintOperatorType, FilterConstraintHelper.convertToSymbol(constraintOperatorType)))
-      );
-      this.operatorTypes = operatorList;
+    private setOperatorDropdownValue(constraintOperatorType: ConstraintOperatorType) {
+        if (constraintOperatorType === undefined) {
+            return new DropdownValue(undefined, 'Select a Property');
+        }
+        return new DropdownValue(constraintOperatorType, FilterConstraintHelper.convertToSymbol(constraintOperatorType));
     }
-  }
 
-  private initSelectedSourceType(): void {
+    private initSelectedSourceType(): void {
     if (!this.currentRule.sourceType || this.currentRule.sourceType === SourceType.STATIC) {
       this.selectedSourceType = SourceType.STATIC;
     } else {
-      this.selectedSourceType = SourceType.TOSCA_FUNCTION;
+        if (!this.isValidValuesOperator() && !this.isRangeType() && !this.isInRangeOperator()){
+          this.selectedSourceType = SourceType.TOSCA_FUNCTION;
+        }
+        else {
+          this.selectedSourceType = SourceType.TOSCA_FUNCTION_LIST;
+        }
     }
   }
 
   private initCurrentRule(): void {
+      let propertyList: PropertyBEModel[] = [];
+      if (this.filterType == FilterType.CAPABILITY) {
+          if (this.currentRule.capabilityName) {
+              propertyList = this.capabilityNameAndPropertiesMap.get(this.currentRule.capabilityName);
+          }
+      } else {
+          propertyList = this.selectedInstanceProperties;
+      }
     if (this.filterConstraint) {
+        this.filterConstraint.originalType = propertyList.find(prop=>prop.name==this.filterConstraint.servicePropertyName).type;
       this.currentRule = new PropertyFilterConstraintUi(this.filterConstraint);
     } else {
       this.currentRule = new PropertyFilterConstraintUi({
         sourceName: SourceType.STATIC,
         sourceType: SourceType.STATIC,
         constraintOperator: ConstraintOperatorType.EQUAL,
-        value: undefined
+        value: undefined,
+        originalType: undefined
       });
     }
   }
@@ -223,18 +297,26 @@ export class ServiceDependenciesEditorComponent implements OnInit {
     }
     newProperty.value = undefined;
     newProperty.toscaFunction = undefined;
+
     if (typeof this.currentRule.value === 'string') {
       newProperty.value = this.currentRule.value;
       this.propertiesUtils.initValueObjectRef(newProperty);
     } else if (ToscaFunctionHelper.isValueToscaFunction(this.currentRule.value)) {
       newProperty.toscaFunction = ToscaFunctionHelper.convertObjectToToscaFunction(this.currentRule.value);
       newProperty.value = newProperty.toscaFunction.buildValueString();
+    } else if (Array.isArray(this.currentRule.value) &&
+        typeof this.currentRule.value[0] === "object" &&
+        this.currentRule.value[0]['propertySource'] != undefined) {
+            this.validValuesToscaFunctionList = this.currentRule.value;
+            this.rangeToscaFunctionList = this.currentRule.value;
+            newProperty.toscaFunction = this.currentRule.value;
     } else {
       newProperty.value = JSON.stringify(this.currentRule.value);
       this.propertiesUtils.initValueObjectRef(newProperty);
     }
 
     this.selectedProperty = newProperty;
+      this.currentRule.originalType = this.selectedProperty.type;
   }
 
   updateSelectedProperty(): void {
@@ -256,6 +338,7 @@ export class ServiceDependenciesEditorComponent implements OnInit {
 
     this.propertiesUtils.initValueObjectRef(newProperty);
     this.selectedProperty = newProperty;
+    this.currentRule.originalType = this.selectedProperty.type;
   }
 
   isStaticSource(): boolean {
@@ -266,10 +349,30 @@ export class ServiceDependenciesEditorComponent implements OnInit {
     return this.selectedSourceType === SourceType.TOSCA_FUNCTION
   }
 
+  isToscaFunctionListSource(): boolean {
+    return this.selectedSourceType === SourceType.TOSCA_FUNCTION_LIST
+  }
+
   isComplexListMapType(): boolean {
     return this.selectedProperty && this.selectedProperty.derivedDataType > 0;
   }
 
+  isRangeType(): boolean {
+    return this.selectedProperty && this.selectedProperty.derivedDataType == 4;
+  }
+
+  isLengthOperator(): boolean {
+      return this.lengthArray.indexOf(this.currentRule.constraintOperator) > -1;
+  }
+
+  isInRangeOperator(): boolean {
+    return this.currentRule.constraintOperator && this.currentRule.constraintOperator === ConstraintOperatorType.IN_RANGE;
+  }
+
+  isValidValuesOperator(): boolean {
+    return this.currentRule.constraintOperator && this.currentRule.constraintOperator === ConstraintOperatorType.VALID_VALUES;
+  }
+
   updateComplexListMapTypeRuleValue(): void {
     this.currentRule.value = PropertyFEModel.cleanValueObj(this.selectedProperty.valueObj);
     this.onValueChange(this.selectedProperty.valueObjIsValid);
@@ -277,11 +380,23 @@ export class ServiceDependenciesEditorComponent implements OnInit {
 
   onToscaFunctionValidityChange(validationEvent: ToscaFunctionValidationEvent): void {
     if (validationEvent.isValid && validationEvent.toscaFunction) {
-      this.currentRule.value = validationEvent.toscaFunction;
-      this.currentRule.sourceType = validationEvent.toscaFunction.type
-      if (validationEvent.toscaFunction instanceof ToscaGetFunction) {
-        this.currentRule.sourceName = validationEvent.toscaFunction.sourceName;
-      }
+        if (this.isValidValuesOperator()) {
+            this.currentRule.value = this.validValuesToscaFunctionList;
+            this.currentRule.sourceType = SourceType.TOSCA_FUNCTION_LIST;
+            if (validationEvent.toscaFunction instanceof ToscaGetFunction) {
+                this.currentRule.sourceName = SourceType.TOSCA_FUNCTION_LIST;
+            }
+        }
+        else {
+            if (this.isLengthOperator()) {
+                this.overridingType = PROPERTY_TYPES.INTEGER;
+            }
+            this.currentRule.value = validationEvent.toscaFunction;
+            this.currentRule.sourceType = validationEvent.toscaFunction.type
+            if (validationEvent.toscaFunction instanceof ToscaGetFunction) {
+                this.currentRule.sourceName = validationEvent.toscaFunction.sourceName;
+            }
+        }
     } else {
       this.currentRule.updateValidity(false);
       this.currentRule.value = undefined;
@@ -290,12 +405,50 @@ export class ServiceDependenciesEditorComponent implements OnInit {
     }
   }
 
+    onToscaFunctionListValidityChange(validationEvent: ToscaFunctionValidationEvent, valueIndex: number): void {
+        if (validationEvent.isValid && validationEvent.toscaFunction) {
+            this.validValuesToscaFunctionList.splice(this.validValuesToscaFunctionList.length -1, 1, validationEvent.toscaFunction);
+            this.currentRule.value = this.validValuesToscaFunctionList;
+            this.currentRule.sourceType = 'SEVERAL';
+            if (validationEvent.toscaFunction instanceof ToscaGetFunction) {
+                this.currentRule.sourceName = validationEvent.toscaFunction.sourceName;
+            }
+        } else {
+            this.currentRule.updateValidity(false);
+            this.currentRule.value = undefined;
+            this.currentRule.sourceType = undefined;
+            this.currentRule.sourceName = undefined;
+        }
+    }
+
+    onToscaRangeFunctionListValidityChange(validationEvent: ToscaFunctionValidationEvent, valueIndex: number): void {
+        if (validationEvent.isValid && validationEvent.toscaFunction) {
+            this.rangeToscaFunctionList.splice(valueIndex, 1, validationEvent.toscaFunction);
+            this.currentRule.value = this.rangeToscaFunctionList;
+            this.currentRule.sourceType = 'SEVERAL';
+            if (validationEvent.toscaFunction instanceof ToscaGetFunction) {
+                this.currentRule.sourceName = validationEvent.toscaFunction.sourceName;
+            }
+        } else {
+            this.currentRule.updateValidity(false);
+            this.currentRule.value = undefined;
+            this.currentRule.sourceType = undefined;
+            this.currentRule.sourceName = undefined;
+        }
+    }
+
   onSourceTypeChange(): void {
     this.currentRule.value = undefined;
+    if (!this.isStaticSource() && (this.isValidValuesOperator() || this.isRangeType() || this.isInRangeOperator())) {
+        this.selectedSourceType = SourceType.TOSCA_FUNCTION_LIST;
+    }
     this.currentRule.sourceType = this.selectedSourceType;
     if (this.isStaticSource()) {
       this.currentRule.sourceName = SourceType.STATIC;
     }
+    if (this.isToscaFunctionListSource()) {
+      this.currentRule.sourceName = SourceType.TOSCA_FUNCTION_LIST;
+    }
     this.updateSelectedProperty();
   }
 
@@ -305,6 +458,41 @@ export class ServiceDependenciesEditorComponent implements OnInit {
     this.onPropertyChange();
   }
 
+  addToList(){
+      if (!this.validValuesToscaFunctionList) {
+          this.validValuesToscaFunctionList = new Array();
+      }
+      this.validValuesToscaFunctionList.push(ToscaFunctionHelper.convertObjectToToscaFunction(undefined));
+  }
+
+  generateRangeToscaFunctionList() {
+      if (!this.rangeToscaFunctionList) {
+          this.rangeToscaFunctionList = new Array();
+          this.rangeToscaFunctionList.push(ToscaFunctionHelper.convertObjectToToscaFunction(undefined));
+          this.rangeToscaFunctionList.push(ToscaFunctionHelper.convertObjectToToscaFunction(undefined));
+      }
+  }
+
+  trackByFn(index) {
+    return index;
+  }
+
+  removeFromList(valueIndex: number){
+    this.validValuesToscaFunctionList.splice(valueIndex, 1);
+      this.currentRule.updateValidity(!this.doesArrayContainsEmptyValues(this.validValuesToscaFunctionList) && !(this.validValuesToscaFunctionList.length === 0));
+      if (this.doesArrayContainsEmptyValues(this.validValuesToscaFunctionList) || (this.validValuesToscaFunctionList.length === 0)) {
+          this.currentRule.value = undefined;
+          this.currentRule.sourceType = undefined;
+          this.currentRule.sourceName = undefined;
+      }
+  }
+
+  private doesArrayContainsEmptyValues(arr) {
+    for(const element of arr) {
+      if(element === undefined) return true;
+    }
+      return false;
+  }
 }
 
 export enum FilterType {
index 927c778..8c62cec 100644 (file)
@@ -164,6 +164,7 @@ export class PROPERTY_TYPES {
     public static SCALAR_FREQUENCY = 'scalar-unit.frequency';
     public static SCALAR_SIZE = 'scalar-unit.size';
     public static SCALAR_TIME = 'scalar-unit.time';
+    public static SCALAR_UNIT = 'scalar-unit';
 }
 
 export class SOURCES {
@@ -177,12 +178,12 @@ export class PROPERTY_DATA {
     public static SIMPLE_TYPES = [PROPERTY_TYPES.STRING, PROPERTY_TYPES.INTEGER, PROPERTY_TYPES.TIMESTAMP, PROPERTY_TYPES.FLOAT, PROPERTY_TYPES.BOOLEAN, PROPERTY_TYPES.JSON, PROPERTY_TYPES.SCALAR_BITRATE, PROPERTY_TYPES.SCALAR_FREQUENCY, PROPERTY_TYPES.SCALAR_SIZE, PROPERTY_TYPES.SCALAR_TIME];
     public static SIMPLE_TYPES_COMPARABLE = [PROPERTY_TYPES.STRING, PROPERTY_TYPES.INTEGER, PROPERTY_TYPES.FLOAT];
     public static SCHEMA_TYPES = [PROPERTY_TYPES.LIST, PROPERTY_TYPES.MAP];
-    public static SCALAR_TYPES = [PROPERTY_TYPES.SCALAR_BITRATE, PROPERTY_TYPES.SCALAR_FREQUENCY, PROPERTY_TYPES.SCALAR_SIZE, PROPERTY_TYPES.SCALAR_TIME];
+    public static SCALAR_TYPES = [PROPERTY_TYPES.SCALAR_BITRATE, PROPERTY_TYPES.SCALAR_FREQUENCY, PROPERTY_TYPES.SCALAR_SIZE, PROPERTY_TYPES.SCALAR_TIME, PROPERTY_TYPES.SCALAR_UNIT];
     public static ROOT_DATA_TYPE = "tosca.datatypes.Root";
     public static OPENECOMP_ROOT = "org.openecomp.datatypes.Root";
     public static SUPPLEMENTAL_DATA = "supplemental_data";
     public static SOURCES = [SOURCES.A_AND_AI, SOURCES.ORDER, SOURCES.RUNTIME];
-    public static COMPARABLE_TYPES = [PROPERTY_TYPES.STRING, PROPERTY_TYPES.INTEGER, PROPERTY_TYPES.FLOAT, PROPERTY_TYPES.TIMESTAMP, PROPERTY_TYPES.SCALAR_BITRATE, PROPERTY_TYPES.SCALAR_FREQUENCY, PROPERTY_TYPES.SCALAR_SIZE, PROPERTY_TYPES.SCALAR_TIME];
+    public static COMPARABLE_TYPES = [PROPERTY_TYPES.STRING, PROPERTY_TYPES.INTEGER, PROPERTY_TYPES.FLOAT, PROPERTY_TYPES.TIMESTAMP, PROPERTY_TYPES.SCALAR_BITRATE, PROPERTY_TYPES.SCALAR_FREQUENCY, PROPERTY_TYPES.SCALAR_SIZE, PROPERTY_TYPES.SCALAR_TIME, PROPERTY_TYPES.SCALAR_UNIT];
 }
 
 export class PROPERTY_VALUE_CONSTRAINTS {
index f120708..7ee9d27 100644 (file)
@@ -50,9 +50,14 @@ export class FilterConstraintHelper {
             case ConstraintOperatorType.GREATER_THAN: return '>';
             case ConstraintOperatorType.GREATER_OR_EQUAL: return '>=';
             case ConstraintOperatorType.LESS_OR_EQUAL: return '<=';
+            case ConstraintOperatorType.IN_RANGE: return 'in range';
+            case ConstraintOperatorType.VALID_VALUES: return 'valid values';
+            case ConstraintOperatorType.LENGTH: return 'length';
+            case ConstraintOperatorType.MIN_LENGTH: return 'minimum length';
+            case ConstraintOperatorType.MAX_LENGTH: return 'maximum length';
+            case ConstraintOperatorType.PATTERN: return 'pattern';
         }
     }
-
 }
 
 export enum ConstraintOperatorType {
@@ -60,6 +65,12 @@ export enum ConstraintOperatorType {
     GREATER_THAN = 'greater_than',
     LESS_THAN = 'less_than',
     GREATER_OR_EQUAL = 'greater_or_equal',
-    LESS_OR_EQUAL = 'less_or_equal'
+    LESS_OR_EQUAL = 'less_or_equal',
+    IN_RANGE = 'in_range',
+    VALID_VALUES = 'valid_values',
+    LENGTH = 'length',
+    MIN_LENGTH = 'min_length',
+    MAX_LENGTH = 'max_length',
+    PATTERN = 'pattern'
 }
 
index a767133..894b54b 100644 (file)
 package org.openecomp.sdc.be.datatypes.elements;
 
 import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.DeserializationContext;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import org.openecomp.sdc.be.datatypes.enums.ConstraintType;
@@ -73,6 +75,9 @@ public class PropertyFilterConstraintDataDefinitionJsonDeserializer extends StdD
         if (node.get("valueType") != null) {
             propertyFilterConstraint.setValueType(FilterValueType.valueOf(node.get("valueType").asText()));
         }
+        if (node.get("originalType") != null) {
+            propertyFilterConstraint.setOriginalType(node.get("originalType").asText());
+        }
         propertyFilterConstraint.setValue(deserializeValue(node.get("value")));
 
         return propertyFilterConstraint;
@@ -91,7 +96,25 @@ public class PropertyFilterConstraintDataDefinitionJsonDeserializer extends StdD
             LOGGER.debug(COULD_NOT_PARSE_CLASS, PropertyFilterConstraintDataDefinition.class.getName(), Map.class.getName(), e);
         }
         try {
-            return objectMapper.treeToValue(value, List.class);
+            if (value.isArray()) {
+                try {
+                    objectMapper.treeToValue(value.get(0), ToscaFunction.class);
+                } catch (JsonProcessingException e) {
+                    return objectMapper.treeToValue(value, List.class);
+                }
+                List<ToscaFunction> listToscaFunction = new ArrayList<>();
+                value.forEach(nodeListValue -> {
+                    try {
+                        listToscaFunction.add(objectMapper.treeToValue(nodeListValue, ToscaFunction.class));
+                    } catch (JsonProcessingException e) {
+                        LOGGER.debug(COULD_NOT_PARSE_CLASS, PropertyFilterConstraintDataDefinition.class.getName(), List.class.getName(), e);
+                    }
+                });
+                return listToscaFunction;
+            }
+            else {
+                return objectMapper.treeToValue(value, List.class);
+            }
         } catch (final Exception e) {
             LOGGER.debug(COULD_NOT_PARSE_CLASS, PropertyFilterConstraintDataDefinition.class.getName(), List.class.getName(), e);
         }
index 2963b6b..263bd70 100644 (file)
@@ -48,6 +48,10 @@ public enum ConstraintType {
         ConstraintType.GREATER_OR_EQUAL,
         ConstraintType.LESS_OR_EQUAL,
         ConstraintType.LESS_THAN);
+    private static final Set<ConstraintType> lengthConstraints = Set.of(
+        ConstraintType.LENGTH,
+        ConstraintType.MIN_LENGTH,
+        ConstraintType.MAX_LENGTH);
     private final String type;
     private final List<String> typeAlias;
 
@@ -74,4 +78,8 @@ public enum ConstraintType {
         return comparableConstraints.contains(this);
     }
 
+    public boolean isLengthConstraint() {
+        return lengthConstraints.contains(this);
+    }
+
 }
index cacc4b1..62a19b8 100644 (file)
@@ -35,7 +35,8 @@ public enum FilterValueType {
     GET_INPUT("get_input", "service_input"),
     GET_ATTRIBUTE("get_attribute", null),
     YAML("yaml", null),
-    CONCAT("concat", null);
+    CONCAT("concat", null),
+    SEVERAL("several", null);
 
     private final String name;
     private final String legacyName;