From 8183ade590e367f28e13484201d2c9526be221dc Mon Sep 17 00:00:00 2001 From: franciscovila Date: Wed, 15 Feb 2023 17:14:59 +0000 Subject: Support additional operands for node filters Issue-ID: SDC-4395 Signed-off-by: franciscovila Change-Id: I66b172d100ffd2757de88bc7640761f31fd20c28 --- .../components/validation/NodeFilterValidator.java | 237 ++++++++++++++------ .../openecomp/sdc/be/tosca/ToscaExportHandler.java | 42 +++- .../sdc/be/model/dto/FilterConstraintDto.java | 15 ++ .../be/model/tosca/validators/ListValidator.java | 21 ++ .../sdc/be/ui/mapper/FilterConstraintMapper.java | 24 +- .../openecomp/sdc/be/ui/model/UIConstraint.java | 1 + catalog-ui/src/app/models/filter-constraint.ts | 2 + .../ui-models/property-filter-constraint-ui.ts | 3 + .../dynamic-property.component.html | 2 +- .../dynamic-property/dynamic-property.component.ts | 1 + .../service-dependencies.component.ts | 10 +- .../dynamic-element/dynamic-element.component.ts | 51 ++++- .../ui/form-components/form-elements.module.ts | 6 + .../ui-element-integer-input.component.html | 2 +- .../ui-element-range-input.component.html | 81 +++++++ .../ui-element-range-input.component.less | 37 ++++ .../ui-element-range-input.component.ts | 112 ++++++++++ .../ui-element-valid-values-input.component.html | 39 ++++ .../ui-element-valid-values-input.component.less | 37 ++++ .../ui-element-valid-values-input.component.ts | 102 +++++++++ .../services/properties.utils.ts | 2 + .../tosca-function/tosca-function.component.html | 1 + .../tosca-function/tosca-function.component.ts | 17 +- .../tosca-get-function.component.ts | 8 +- .../service-dependencies-editor.component.html | 96 +++++++- .../service-dependencies-editor.component.ts | 244 ++++++++++++++++++--- catalog-ui/src/app/utils/constants.ts | 5 +- .../src/app/utils/filter-constraint-helper.ts | 15 +- .../PropertyFilterConstraintDataDefinition.java | 1 + ...erConstraintDataDefinitionJsonDeserializer.java | 25 ++- .../sdc/be/datatypes/enums/ConstraintType.java | 8 + .../sdc/be/datatypes/enums/FilterValueType.java | 3 +- 32 files changed, 1105 insertions(+), 145 deletions(-) create mode 100644 catalog-ui/src/app/ng2/components/ui/form-components/range-input/ui-element-range-input.component.html create mode 100644 catalog-ui/src/app/ng2/components/ui/form-components/range-input/ui-element-range-input.component.less create mode 100644 catalog-ui/src/app/ng2/components/ui/form-components/range-input/ui-element-range-input.component.ts create mode 100644 catalog-ui/src/app/ng2/components/ui/form-components/valid-values-input/ui-element-valid-values-input.component.html create mode 100644 catalog-ui/src/app/ng2/components/ui/form-components/valid-values-input/ui-element-valid-values-input.component.less create mode 100644 catalog-ui/src/app/ng2/components/ui/form-components/valid-values-input/ui-element-valid-values-input.component.ts diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/NodeFilterValidator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/NodeFilterValidator.java index 86cedf26d7..30fe3dcad1 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/NodeFilterValidator.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/NodeFilterValidator.java @@ -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 validatePropertyConstraint(final Component parentComponent, final String componentInstanceId, final FilterConstraintDto filterConstraint, final String capabilityName) { String source = SOURCE; + ResponseFormat responseFormat = null; + List 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 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 sourceSelectedProperty = findPropertyFromGetFunction(parentComponent, toscaGetFunction); - if (sourceSelectedProperty.isPresent()) { - Optional targetComponentInstanceProperty = - getInstanceProperties(parentComponent, componentInstanceId, capabilityName, filterConstraint.getPropertyName()); + else{ + toscaGetFunctionDataDefinitionList.add(toscaGetFunction); + } + Boolean allGood = true; + for (ToscaGetFunctionDataDefinition _toscaGetFunction: toscaGetFunctionDataDefinitionList) { + + final Optional sourceSelectedProperty = + findPropertyFromGetFunction(parentComponent, _toscaGetFunction); + if (sourceSelectedProperty.isPresent()) { + Optional 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 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 propertyPathFromSource = getFunction.getPropertyPathFromSource(); - Optional 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, 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 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 propertyPathFromSource = getFunction.getPropertyPathFromSource(); + Optional 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, 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 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 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); } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java index 6c1f4e3211..4b8249823e 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java @@ -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 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 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 buildSubstitutionMappingPropertyMapping(final Component component) { if (component == null || CollectionUtils.isEmpty(component.getInputs())) { return Collections.emptyMap(); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/dto/FilterConstraintDto.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/dto/FilterConstraintDto.java index b9ceb11276..4800c020d2 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/dto/FilterConstraintDto.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/dto/FilterConstraintDto.java @@ -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> getAsListToscaGetFunction() { + List 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(); + } } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/validators/ListValidator.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/validators/ListValidator.java index 20d927f483..46fd44d786 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/validators/ListValidator.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/validators/ListValidator.java @@ -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; diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/mapper/FilterConstraintMapper.java b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/mapper/FilterConstraintMapper.java index 9c1b6c9f48..59d7ef074f 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/mapper/FilterConstraintMapper.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/mapper/FilterConstraintMapper.java @@ -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 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 { diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UIConstraint.java b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UIConstraint.java index 401de95e71..acb0c81d35 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UIConstraint.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UIConstraint.java @@ -35,6 +35,7 @@ public class UIConstraint implements Serializable { private String sourceType; private String sourceName; private Object value; + private String originalType; public UIConstraint() { } diff --git a/catalog-ui/src/app/models/filter-constraint.ts b/catalog-ui/src/app/models/filter-constraint.ts index 69ad90cb90..5f4a9432cf 100644 --- a/catalog-ui/src/app/models/filter-constraint.ts +++ b/catalog-ui/src/app/models/filter-constraint.ts @@ -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; } } } diff --git a/catalog-ui/src/app/models/ui-models/property-filter-constraint-ui.ts b/catalog-ui/src/app/models/ui-models/property-filter-constraint-ui.ts index f47677bf5a..c1acbee07e 100644 --- a/catalog-ui/src/app/models/ui-models/property-filter-constraint-ui.ts +++ b/catalog-ui/src/app/models/ui-models/property-filter-constraint-ui.ts @@ -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; diff --git a/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html b/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html index 58303a9319..c4a3893423 100644 --- a/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html +++ b/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html @@ -44,7 +44,7 @@
- + = new EventEmitter(); diff --git a/catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.ts b/catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.ts index 50ea60e4ea..9a63dff739 100644 --- a/catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.ts +++ b/catalog-ui/src/app/ng2/components/logic/service-dependencies/service-dependencies.component.ts @@ -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) => { diff --git a/catalog-ui/src/app/ng2/components/ui/dynamic-element/dynamic-element.component.ts b/catalog-ui/src/app/ng2/components/ui/dynamic-element/dynamic-element.component.ts index 50c77d3f53..2cf3c79e11 100644 --- a/catalog-ui/src/app/ng2/components/ui/dynamic-element/dynamic-element.component.ts +++ b/catalog-ui/src/app/ng2/components/ui/dynamic-element/dynamic-element.component.ts @@ -22,13 +22,15 @@ 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); diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/form-elements.module.ts b/catalog-ui/src/app/ng2/components/ui/form-components/form-elements.module.ts index b35d3ae3f4..d7f134b008 100644 --- a/catalog-ui/src/app/ng2/components/ui/form-components/form-elements.module.ts +++ b/catalog-ui/src/app/ng2/components/ui/form-components/form-elements.module.ts @@ -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, diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/integer-input/ui-element-integer-input.component.html b/catalog-ui/src/app/ng2/components/ui/form-components/integer-input/ui-element-integer-input.component.html index d5ef08b126..4ab0a689a8 100644 --- a/catalog-ui/src/app/ng2/components/ui/form-components/integer-input/ui-element-integer-input.component.html +++ b/catalog-ui/src/app/ng2/components/ui/form-components/integer-input/ui-element-integer-input.component.html @@ -17,7 +17,7 @@ +
+
+ + + + +
+
+ + +
+
\ 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 index 0000000000..c393024899 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/form-components/range-input/ui-element-range-input.component.less @@ -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 index 0000000000..65c5bd72e3 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/form-components/range-input/ui-element-range-input.component.ts @@ -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 index 0000000000..ff4d6d1353 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/form-components/valid-values-input/ui-element-valid-values-input.component.html @@ -0,0 +1,39 @@ + + +
Add to List +
+
+
+ + + +
+
+ +
+
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 index 0000000000..c393024899 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/form-components/valid-values-input/ui-element-valid-values-input.component.less @@ -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 index 0000000000..079fdeba1c --- /dev/null +++ b/catalog-ui/src/app/ng2/components/ui/form-components/valid-values-input/ui-element-valid-values-input.component.ts @@ -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 = new EventEmitter(); + 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; + } +} diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/services/properties.utils.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/services/properties.utils.ts index 8dd4ca96ec..6a27622638 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/services/properties.utils.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/services/properties.utils.ts @@ -181,6 +181,8 @@ export class PropertiesUtils { property.childPropUpdated(childProp); }); + } else if (property.derivedDataType === DerivedPropertyType.RANGE) { + property.valueObj = JSON.stringify(property.getValueObj()); } } property.updateValueObjOrig(); diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.html b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.html index 898b189746..65a024cde4 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.html +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.html @@ -43,6 +43,7 @@
= new Map(); @Input() customToscaFunctions: Array = []; @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(); diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.ts index fe6f2f143c..284c559c55 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.ts @@ -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 = new Map(); @Input() functionType: ToscaGetFunctionType; @@ -243,13 +244,13 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges { const properties: Array = 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; } diff --git a/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.html b/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.html index 8024eb1615..c90cfd8210 100644 --- a/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.html +++ b/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.html @@ -51,7 +51,10 @@ + (change)="onSourceTypeChange()" + [values]="operatorTypes" [(value)]="currentRule.constraintOperator" + > +
@@ -61,15 +64,26 @@ data-tests-id="value-type-static" [(ngModel)]="selectedSourceType" [value]="SOURCE_TYPES.STATIC.value" - (ngModelChange)="onSourceTypeChange()"/> {{"VALUE_LABEL" | translate}} + (ngModelChange)="onSourceTypeChange($event)"/> {{"VALUE_LABEL" | translate}} {{"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}}
+
+ + +
+
+
+ +
+ +
+
+
+ + +
+
+
+
+ +
+ +
+
Add to List +
+
+
+ + +
+
+ +
+
+
+
{{"NODE_FILTER_SELECT_PROPERTY" | translate}}
+ [type]="isLengthOperator() ? 'integer' : selectedProperty ? selectedProperty.type : 'string'" + [operator]="currentRule.constraintOperator"> + + + + + +
diff --git a/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.ts b/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.ts index 39609a5fbd..5897f272b3 100644 --- a/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.ts +++ b/catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.ts @@ -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; @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 = new Map(); customToscaFunctions: Array; 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 { diff --git a/catalog-ui/src/app/utils/constants.ts b/catalog-ui/src/app/utils/constants.ts index 927c778df6..8c62cec739 100644 --- a/catalog-ui/src/app/utils/constants.ts +++ b/catalog-ui/src/app/utils/constants.ts @@ -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 { diff --git a/catalog-ui/src/app/utils/filter-constraint-helper.ts b/catalog-ui/src/app/utils/filter-constraint-helper.ts index f1207084a7..7ee9d27efe 100644 --- a/catalog-ui/src/app/utils/filter-constraint-helper.ts +++ b/catalog-ui/src/app/utils/filter-constraint-helper.ts @@ -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' } diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyFilterConstraintDataDefinition.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyFilterConstraintDataDefinition.java index 9284b530eb..3dc11248f2 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyFilterConstraintDataDefinition.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyFilterConstraintDataDefinition.java @@ -38,4 +38,5 @@ public class PropertyFilterConstraintDataDefinition { private ConstraintType operator; private FilterValueType valueType; private Object value; + private String originalType; } diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyFilterConstraintDataDefinitionJsonDeserializer.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyFilterConstraintDataDefinitionJsonDeserializer.java index a767133a4c..894b54b291 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyFilterConstraintDataDefinitionJsonDeserializer.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyFilterConstraintDataDefinitionJsonDeserializer.java @@ -22,11 +22,13 @@ 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 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); } diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/ConstraintType.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/ConstraintType.java index 2963b6bcd1..263bd70ab7 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/ConstraintType.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/ConstraintType.java @@ -48,6 +48,10 @@ public enum ConstraintType { ConstraintType.GREATER_OR_EQUAL, ConstraintType.LESS_OR_EQUAL, ConstraintType.LESS_THAN); + private static final Set lengthConstraints = Set.of( + ConstraintType.LENGTH, + ConstraintType.MIN_LENGTH, + ConstraintType.MAX_LENGTH); private final String type; private final List typeAlias; @@ -74,4 +78,8 @@ public enum ConstraintType { return comparableConstraints.contains(this); } + public boolean isLengthConstraint() { + return lengthConstraints.contains(this); + } + } diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/FilterValueType.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/FilterValueType.java index cacc4b1bac..62a19b8041 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/FilterValueType.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/FilterValueType.java @@ -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; -- cgit 1.2.3-korg