Implicit attributes in get_attribute list
[sdc.git] / catalog-ui / src / app / ng2 / pages / properties-assignment / tosca-function / tosca-get-function / tosca-get-function.component.ts
index 46541cf..67df3e4 100644 (file)
@@ -42,9 +42,12 @@ import {ToscaGetFunctionTypeConverter} from "../../../../../models/tosca-get-fun
 export class ToscaGetFunctionComponent implements OnInit, OnChanges {
 
     @Input() property: PropertyBEModel;
+    @Input() overridingType: PROPERTY_TYPES;
     @Input() toscaGetFunction: ToscaGetFunction;
     @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
     @Input() functionType: ToscaGetFunctionType;
+    @Input() compositionMap: boolean;
+    @Input() compositionMapKey: string;
     @Output() onValidFunction: EventEmitter<ToscaGetFunction> = new EventEmitter<ToscaGetFunction>();
     @Output() onValidityChange: EventEmitter<ToscaGetFunctionValidationEvent> = new EventEmitter<ToscaGetFunctionValidationEvent>();
 
@@ -59,6 +62,8 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
     instanceNameAndIdMap: Map<string, string> = new Map<string, string>();
     dropdownValuesLabel: string;
     dropDownErrorMsg: string;
+    indexListValues:Array<ToscaIndexObject>;
+    parentListTypeFlag : boolean;
 
     private isInitialized: boolean = false;
     private componentMetadata: ComponentMetadata;
@@ -72,24 +77,19 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
 
     ngOnInit(): void {
         this.componentMetadata = this.workspaceService.metadata;
+        this.indexListValues = [];
+        if (this.property != null) {
+            this.parentListTypeFlag = (this.property.type != PROPERTY_TYPES.LIST && (!this.isComplexType(this.property.type) || (this.isComplexType(this.property.type) 
+                                    && this.property instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel> this.property).input instanceof DerivedFEProperty && this.property.input.type != PROPERTY_TYPES.LIST)));
+        }
         this.formGroup.valueChanges.subscribe(() => {
-            if (!this.isInitialized) {
-                return;
-            }
-            this.onValidityChange.emit({
-                isValid: this.formGroup.valid,
-                toscaGetFunction: this.formGroup.valid ? this.buildGetFunctionFromForm() : undefined
-            });
-            if (this.formGroup.valid) {
-                this.onValidFunction.emit(this.buildGetFunctionFromForm());
-            }
+            this.formValidation();
         });
         this.loadPropertySourceDropdown();
         this.loadPropertyDropdownLabel();
         this.initToscaGetFunction().subscribe(() => {
             this.isInitialized = true;
         });
-
     }
 
     ngOnChanges(_changes: SimpleChanges): void {
@@ -125,6 +125,34 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
                 this.loadPropertyDropdown(() => {
                     this.selectedProperty
                     .setValue(this.propertyDropdownList.find(property => property.propertyName === this.toscaGetFunction.propertyName));
+                    if (this.toscaGetFunction.toscaIndexList && this.toscaGetFunction.toscaIndexList.length > 0) {
+                        let tempSelectedProperty : PropertyDropdownValue = this.selectedProperty.value;
+                        this.toscaGetFunction.toscaIndexList.forEach((indexValue: string, index) => {
+                            let tempIndexFlag = false;
+                            let tempNestedFlag = false;
+                            let tempIndexValue = "0";
+                            let tempIndexProperty = tempSelectedProperty;
+                            let subPropertyDropdownList : Array<PropertyDropdownValue> = [];
+                            if (!isNaN(Number(indexValue)) || indexValue.toLowerCase() === 'index') {
+                                tempIndexFlag = true;
+                                tempIndexValue = indexValue;
+                                tempSelectedProperty = null;
+                                if (this.toscaGetFunction.toscaIndexList[index+1]) {
+                                    tempNestedFlag = true;
+                                    if (tempIndexProperty.schemaType != null) {
+                                        const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, tempIndexProperty.schemaType);
+                                        this.addPropertiesToDropdown(dataTypeFound.properties, subPropertyDropdownList);
+                                        tempSelectedProperty = subPropertyDropdownList.find(property => property.propertyName === this.toscaGetFunction.toscaIndexList[index+1])
+                                        if (tempSelectedProperty == null && this.toscaGetFunction.toscaIndexList[index+2]) {
+                                            tempSelectedProperty = subPropertyDropdownList.find(property => property.propertyName === this.toscaGetFunction.toscaIndexList[index+2])
+                                        }
+                                    }
+                                }
+                                let tempIndexValueMap : ToscaIndexObject = {indexFlag : tempIndexFlag, nestedFlag : tempNestedFlag, indexValue: tempIndexValue, indexProperty: tempSelectedProperty, subPropertyArray: subPropertyDropdownList};
+                                this.indexListValues.push(tempIndexValueMap);
+                            }
+                        });
+                    }
                     subscriber.next();
                 });
             } else {
@@ -152,7 +180,16 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
         toscaGetFunction.propertyUniqueId = selectedProperty.propertyId;
         toscaGetFunction.propertyName = selectedProperty.propertyName;
         toscaGetFunction.propertyPathFromSource = selectedProperty.propertyPath;
-
+        if (this.indexListValues.length > 0) {
+            let indexAndProperty : Array<string> = [];
+            this.indexListValues.forEach((indexObject : ToscaIndexObject) => {
+                indexAndProperty.push(indexObject.indexValue);
+                if(indexObject.nestedFlag && indexObject.indexProperty != null) {
+                    indexAndProperty.push(...indexObject.indexProperty.propertyPath);
+                }
+            });
+            toscaGetFunction.toscaIndexList = indexAndProperty;
+        }
         return toscaGetFunction;
     }
 
@@ -184,6 +221,33 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
         });
     }
 
+    private formValidation(): void {
+        if (!this.isInitialized) {
+            return;
+        }
+        let formGroupStatus : boolean = this.formGroup.valid;
+        const selectedProperty: PropertyDropdownValue = this.formGroup.value.selectedProperty;
+        if (selectedProperty != null && selectedProperty.isList && formGroupStatus && this.indexListValues.length > 0) {
+            this.indexListValues.forEach((indexObject : ToscaIndexObject, index) => {
+                if (indexObject.indexValue == '') {
+                    formGroupStatus = false;
+                    return;
+                }
+                if (indexObject.nestedFlag && indexObject.indexProperty == null) {
+                    formGroupStatus = false;
+                    return;
+                }
+            });
+        }
+        this.onValidityChange.emit({
+            isValid: formGroupStatus,
+            toscaGetFunction: this.formGroup.valid ? this.buildGetFunctionFromForm() : undefined
+        });
+        if (this.formGroup.valid) {
+            this.onValidFunction.emit(this.buildGetFunctionFromForm());
+        }
+    }
+
     private loadPropertyDropdown(onComplete?: () => any): void  {
         this.loadPropertyDropdownLabel();
         this.loadPropertyDropdownValues(onComplete);
@@ -217,6 +281,7 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
     private resetPropertyDropdown(): void {
         this.dropDownErrorMsg = undefined;
         this.selectedProperty.reset();
+        this.indexListValues = [];
         this.propertyDropdownList = [];
     }
 
@@ -227,13 +292,13 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
             const properties: Array<PropertyBEModel | AttributeBEModel> = this.extractProperties(response);
             if (!properties || properties.length === 0) {
                 const msgCode = this.getNotFoundMsgCode();
-                this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.propertyTypeToString()});
+                this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.overridingType != undefined ? this.overridingType : this.propertyTypeToString()});
                 return;
             }
-            this.addPropertiesToDropdown(properties);
+            this.addPropertiesToDropdown(properties, this.propertyDropdownList);
             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);
@@ -261,7 +326,26 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
     }
 
     private propertyTypeToString() {
-           if (this.isSubProperty() && this.property.type != PROPERTY_TYPES.MAP && this.property.type != PROPERTY_TYPES.LIST){
+           if (this.isSubProperty()){
+            if ((this.property instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel> this.property).input instanceof DerivedFEProperty)
+                || this.compositionMap) {
+                if(this.isComplexType(this.property.schemaType)){
+                    let mapChildProp : DerivedFEProperty = (<DerivedFEProperty> (<PropertyDeclareAPIModel> this.property).input);
+                    let propertySchemaType = mapChildProp.type;
+                    if (this.property.type == PROPERTY_TYPES.MAP || propertySchemaType == PROPERTY_TYPES.MAP) {
+                        if (mapChildProp.mapKey != '' && mapChildProp.mapKey != null && mapChildProp.schema.property.type != null) {
+                            propertySchemaType = mapChildProp.schema.property.type;
+                        }
+                    }
+                    if ((propertySchemaType == PROPERTY_TYPES.MAP || (propertySchemaType == PROPERTY_TYPES.LIST && mapChildProp.schema.property.type == PROPERTY_TYPES.MAP))
+                        && mapChildProp.isChildOfListOrMap) {
+                        propertySchemaType = PROPERTY_TYPES.STRING;
+                    }
+                    return  propertySchemaType;
+                }else{
+                    return this.property.schema.property.type;
+                }
+            }
                return this.getType((<PropertyDeclareAPIModel>this.property).propertiesName.split("#").slice(1),  this.property.type);
         }
         if (this.property.schemaType) {
@@ -324,27 +408,31 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
         );
     }
 
-    private addPropertyToDropdown(propertyDropdownValue: PropertyDropdownValue): void {
-        this.propertyDropdownList.push(propertyDropdownValue);
-        this.propertyDropdownList.sort((a, b) => a.propertyLabel.localeCompare(b.propertyLabel));
+    private addPropertyToDropdown(propertyDropdownValue: PropertyDropdownValue, propertyList: Array<PropertyDropdownValue>): void {
+        if (!propertyList.find(prop => prop.propertyName === propertyDropdownValue.propertyName)) {
+            propertyList.push(propertyDropdownValue);
+            propertyList.sort((a, b) => a.propertyLabel.localeCompare(b.propertyLabel));
+        }
     }
 
-    private addPropertiesToDropdown(properties: Array<PropertyBEModel | AttributeBEModel>): void {
+    private addPropertiesToDropdown(properties: Array<PropertyBEModel | AttributeBEModel>, propertyList: Array<PropertyDropdownValue>): void {
         for (const property of properties) {
             if (this.hasSameType(property)) {
                 this.addPropertyToDropdown({
                     propertyName: property.name,
                     propertyId: property.uniqueId,
                     propertyLabel: property.name,
-                    propertyPath: [property.name]
-                });
+                    propertyPath: [property.name],
+                    isList: property.type === PROPERTY_TYPES.LIST,
+                    schemaType: (property.type === PROPERTY_TYPES.LIST && this.isComplexType(property.schema.property.type)) ? property.schema.property.type : null
+                },propertyList);
             } else if (this.isComplexType(property.type)) {
-                this.fillPropertyDropdownWithMatchingChildProperties(property);
+                this.fillPropertyDropdownWithMatchingChildProperties(property,propertyList);
             }
         }
     }
 
-    private fillPropertyDropdownWithMatchingChildProperties(inputProperty: PropertyBEModel | AttributeBEModel,
+    private fillPropertyDropdownWithMatchingChildProperties(inputProperty: PropertyBEModel | AttributeBEModel, propertyList: Array<PropertyDropdownValue>,
                                                             parentPropertyList: Array<PropertyBEModel | AttributeBEModel> = []): void {
         const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, inputProperty.type);
         if (!dataTypeFound || !dataTypeFound.properties) {
@@ -357,30 +445,77 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
                     propertyName: dataTypeProperty.name,
                     propertyId: parentPropertyList[0].uniqueId,
                     propertyLabel: parentPropertyList.map(property => property.name).join('->') + '->' + dataTypeProperty.name,
-                    propertyPath: [...parentPropertyList.map(property => property.name), dataTypeProperty.name]
-                });
+                    propertyPath: [...parentPropertyList.map(property => property.name), dataTypeProperty.name],
+                    isList : dataTypeProperty.type === PROPERTY_TYPES.LIST,
+                    schemaType: (dataTypeProperty.type === PROPERTY_TYPES.LIST && this.isComplexType(dataTypeProperty.schema.property.type)) ? dataTypeProperty.schema.property.type : null
+                }, propertyList);
             } else if (this.isComplexType(dataTypeProperty.type)) {
-                this.fillPropertyDropdownWithMatchingChildProperties(dataTypeProperty, [...parentPropertyList])
+                this.fillPropertyDropdownWithMatchingChildProperties(dataTypeProperty, propertyList, [...parentPropertyList])
             }
         });
     }
 
     private hasSameType(property: PropertyBEModel | AttributeBEModel): boolean {
+        if (this.overridingType != undefined) {
+            return property.type === this.overridingType;
+        }
+        if (this.property.type === PROPERTY_TYPES.ANY) {
+            return true;
+        }
+        let validPropertyType = (this.parentListTypeFlag && property.type === PROPERTY_TYPES.LIST) ? property.schema.property.type : property.type;
+        if (this.parentListTypeFlag && property.type === PROPERTY_TYPES.LIST && this.isComplexType(validPropertyType)) {
+            let returnFlag : boolean = false;
+            const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, validPropertyType);
+            if (dataTypeFound && dataTypeFound.properties) {
+                dataTypeFound.properties.forEach(dataTypeProperty => {
+                    if (this.hasSameType(dataTypeProperty)) {
+                        returnFlag =  true;
+                    }
+                    if (!returnFlag && this.isComplexType(dataTypeProperty.type)) {
+                        const nestedDataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, dataTypeProperty.type);
+                        if (nestedDataTypeFound && nestedDataTypeFound.properties) {
+                            nestedDataTypeFound.properties.forEach( nestedDateTypeProperty => {
+                                if (this.hasSameType(nestedDateTypeProperty)) {
+                                    returnFlag =  true;
+                                }
+                            });
+                        }
+                    }
+                });
+            }
+            return returnFlag;
+        }
         if (this.typeHasSchema(this.property.type)) {
-            if ((this.property.type === PROPERTY_TYPES.MAP || this.property.type === PROPERTY_TYPES.LIST) && this.property instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel> this.property).input instanceof DerivedFEProperty) {
-                return property.type === this.property.schema.property.type;
+            if ((this.property instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel> this.property).input instanceof DerivedFEProperty) || this.compositionMap) {
+                let childObject : DerivedFEProperty = (<DerivedFEProperty>(<PropertyDeclareAPIModel> this.property).input);
+                let childSchemaType = (this.property != null && this.property.schemaType != null) ? this.property.schemaType : childObject.type;
+                if(this.isComplexType(childSchemaType)){
+                    if (childObject.type == PROPERTY_TYPES.MAP && childObject.isChildOfListOrMap) {
+                        return validPropertyType === PROPERTY_TYPES.STRING;
+                    }
+                    return validPropertyType === childObject.type;
+                }else{
+                    return validPropertyType === this.property.schema.property.type;
+                }
             }
             if (!property.schema || !property.schema.property) {
                 return false;
             }
-            return property.type === this.property.type && this.property.schema.property.type === property.schema.property.type;
+            return validPropertyType === this.property.type && this.property.schema.property.type === property.schema.property.type;
         }
-        if (this.property.schema.property.isDataType && this.property instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>this.property).propertiesName){
-            let typeToMatch = this.getType((<PropertyDeclareAPIModel>this.property).propertiesName.split("#").slice(1),  this.property.type);
-            return property.type === typeToMatch;
+        if ((this.property.schema.property.isDataType || this.isComplexType(this.property.type)) && this.property instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>this.property).propertiesName){
+            let typeToMatch = (<PropertyDeclareAPIModel> this.property).input.type;
+            let childObject : DerivedFEProperty = (<DerivedFEProperty>(<PropertyDeclareAPIModel> this.property).input);
+            if (childObject.type == PROPERTY_TYPES.MAP && childObject.isChildOfListOrMap) {
+                typeToMatch = PROPERTY_TYPES.STRING;
+            }
+            if ((typeToMatch === PROPERTY_TYPES.LIST || typeToMatch === PROPERTY_TYPES.MAP) && (<PropertyDeclareAPIModel> this.property).input.schema.property.type && this.compositionMap && !isNaN(Number(this.compositionMapKey))) {
+                typeToMatch = (<PropertyDeclareAPIModel> this.property).input.schema.property.type;
+            }
+            return validPropertyType === typeToMatch;
         }
 
-        return property.type === this.property.type;
+        return validPropertyType === this.property.type;
     }
 
     private getType(propertyPath:string[], type: string): string {
@@ -430,12 +565,82 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
 
     onPropertySourceChange(): void {
         this.selectedProperty.reset();
+        this.indexListValues = [];
         if (!this.functionType || !this.propertySource.valid) {
             return;
         }
         this.loadPropertyDropdown();
     }
 
+    onPropertyValueChange(): void {
+        let toscaIndexFlag = false;
+        let nestedToscaFlag = false;
+        this.indexListValues = [];
+        let subPropertyDropdownList : Array<PropertyDropdownValue> = [];
+        const selectedProperty: PropertyDropdownValue = this.selectedProperty.value;
+        if (this.parentListTypeFlag && selectedProperty.isList) {
+            toscaIndexFlag = true;
+            if (selectedProperty.schemaType != null) {
+                nestedToscaFlag = true;
+                const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, selectedProperty.schemaType);
+                this.addPropertiesToDropdown(dataTypeFound.properties, subPropertyDropdownList);
+            }
+        }
+        if (toscaIndexFlag || nestedToscaFlag) {
+            let indexValueMap : ToscaIndexObject = {indexFlag : toscaIndexFlag, nestedFlag : nestedToscaFlag, indexValue: "0", indexProperty: null, subPropertyArray: subPropertyDropdownList};
+            this.indexListValues.push(indexValueMap);
+        }
+        this.formValidation();
+    }
+
+    onSubPropertyValueChange(indexObject : ToscaIndexObject, elementIndex: number): void {
+        let toscaIndexFlag = false;
+        let nestedToscaFlag = false;
+        let subPropertyDropdownList : Array<PropertyDropdownValue> = [];
+        let selectedProperty: PropertyDropdownValue = indexObject.indexProperty;
+        if (selectedProperty.isList) {
+            toscaIndexFlag = true;
+            if (selectedProperty.schemaType != null) {
+                nestedToscaFlag = true;
+                const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, selectedProperty.schemaType);
+                this.addPropertiesToDropdown(dataTypeFound.properties, subPropertyDropdownList);
+            }
+        }
+        if (toscaIndexFlag || nestedToscaFlag) {
+            let indexValueMap : ToscaIndexObject = {indexFlag : toscaIndexFlag, nestedFlag : nestedToscaFlag, indexValue: "0", indexProperty: null, subPropertyArray: subPropertyDropdownList};
+            if(!this.indexListValues[elementIndex+1]) {
+                this.indexListValues.push(indexValueMap);
+            } else {
+                this.indexListValues[elementIndex+1] = indexValueMap;
+            }
+        } else {
+            if(this.indexListValues[elementIndex+1]) {
+                this.indexListValues.splice((elementIndex+1),1);
+            }
+        }
+        this.formValidation();
+    }
+
+    indexTokenChange(indexObject : ToscaIndexObject): void {
+        if ((indexObject.indexValue).toLowerCase() === 'index' ) {
+            this.formValidation();
+        }
+
+        const regEx = /^[0-9]*$/;
+        const error = document.getElementById('error');
+
+        if (!(regEx.test(indexObject.indexValue)) && (indexObject.indexValue).toLowerCase() !== 'index') {
+            error.textContent='Invalid value - must be an integer or INDEX';
+            this.onValidityChange.emit({
+                isValid: false,
+                toscaGetFunction: this.formGroup.valid ? this.buildGetFunctionFromForm() : undefined
+            });
+        } else {
+            error.textContent='';
+            this.formValidation();
+        }
+    }
+
     showPropertySourceDropdown(): boolean {
         return this.isGetProperty() || this.isGetAttribute();
     }
@@ -452,6 +657,9 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
         return this.formGroup.get('selectedProperty') as FormControl;
     }
 
+    onChangeIndexValue(index: ToscaIndexObject, value: any) {
+        this.indexTokenChange(index);
+    }
 }
 
 export interface PropertyDropdownValue {
@@ -459,6 +667,16 @@ export interface PropertyDropdownValue {
     propertyId: string;
     propertyLabel: string;
     propertyPath: Array<string>;
+    isList: boolean;
+    schemaType: string;
+}
+
+export interface ToscaIndexObject {
+    indexFlag: boolean;
+    nestedFlag: boolean;
+    indexValue: string;
+    indexProperty: PropertyDropdownValue;
+    subPropertyArray: Array<PropertyDropdownValue>;
 }
 
 export interface ToscaGetFunctionValidationEvent {