Support additional operands for node filters
[sdc.git] / catalog-ui / src / app / ng2 / pages / service-dependencies-editor / service-dependencies-editor.component.ts
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 {