Revert "Provide tosca function capability to complex type fields in composition view"
[sdc.git] / catalog-ui / src / app / directives / property-types / type-map / type-map-directive.ts
index 5718cdd..098b289 100644 (file)
@@ -7,9 +7,9 @@
  * 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.
  * Created by rcohen on 9/15/2016.
  */
 'use strict';
-import {ValidationUtils, PROPERTY_TYPES} from "app/utils";
-import {DataTypesService} from "app/services";
-import {SchemaProperty} from "app/models";
+import { DataTypesMap, PropertyModel, SchemaProperty } from 'app/models';
+import { InstanceFeDetails } from 'app/models/instance-fe-details';
+import { SubPropertyToscaFunction } from 'app/models/sub-property-tosca-function';
+import { ToscaGetFunction } from 'app/models/tosca-get-function';
+import { DataTypesService } from 'app/services';
+import { PROPERTY_DATA, PROPERTY_TYPES, ValidationUtils } from 'app/utils';
 
 export interface ITypeMapScope extends ng.IScope {
-    parentFormObj:ng.IFormController;
-    schemaProperty:SchemaProperty;
-    isMapKeysUnique:boolean;
-    isSchemaTypeDataType:boolean;
-    valueObjRef:any;
-    mapKeys:Array<string>;//array of map keys
-    mapKeysStatic:Array<string>;
-    MapKeyValidationPattern:RegExp;
-    fieldsPrefixName:string;
-    readOnly:boolean;
-    mapDefaultValue:any;
-    maxLength:number;
-
-    getValidationPattern(type:string):RegExp;
-    validateIntRange(value:string):boolean;
-    changeKeyOfMap(newKey:string, index:number, fieldName:string):void;
-    deleteMapItem(index:number):void;
-    addMapItemFields():void;
-    parseToCorrectType(objectOfValues:any, locationInObj:string, type:string):void;
-    getNumber(num:number):Array<any>;
-}
+    parentFormObj: ng.IFormController;
+    schemaProperty: SchemaProperty;
+    parentProperty: PropertyModel;
+    componentInstanceMap: Map<string, InstanceFeDetails>;
+    isMapKeysUnique: boolean;
+    isSchemaTypeDataType: boolean;
+    valueObjRef: any;
+    mapKeys: string[]; // array of map keys
+    mapKeysStatic: string[];
+    MapKeyValidationPattern: RegExp;
+    fieldsPrefixName: string;
+    readOnly: boolean;
+    mapDefaultValue: any;
+    maxLength: number;
+    constraints: string[];
+    showAddBtn: boolean;
+    showToscaFunction: boolean[];
+    types: DataTypesMap;
+    isService: boolean;
 
+    getValidationPattern(type: string): RegExp;
+    validateIntRange(value: string): boolean;
+    changeKeyOfMap(newKey: string, index: number, fieldName: string): void;
+    deleteMapItem(index: number): void;
+    addMapItemFields(): void;
+    parseToCorrectType(objectOfValues: any, locationInObj: string, type: string): void;
+    getNumber(num: number): any[];
+    validateSubToscaFunction(key: string): boolean;
+    onEnableTosca(toscaFlag: boolean, index: number);
+    onGetToscaFunction(toscaGetFunction: ToscaGetFunction, key: string);
+}
 
 export class TypeMapDirective implements ng.IDirective {
 
-    constructor(private DataTypesService:DataTypesService,
-                private MapKeyValidationPattern:RegExp,
-                private ValidationUtils:ValidationUtils,
-                private $timeout:ng.ITimeoutService) {
-    }
-
     scope = {
-        valueObjRef: '=',//ref to map object in the parent value object
-        schemaProperty: '=',//get the schema.property object
-        parentFormObj: '=',//ref to parent form (get angular form object)
-        fieldsPrefixName: '=',//prefix for form fields names
-        readOnly: '=',//is form read only
-        defaultValue: '@',//this map default value
-        maxLength: '='
+        valueObjRef: '=', // ref to map object in the parent value object
+        componentInstanceMap: '=',
+        schemaProperty: '=', // get the schema.property object
+        parentFormObj: '=', // ref to parent form (get angular form object)
+        fieldsPrefixName: '=', // prefix for form fields names
+        readOnly: '=', // is form read only
+        defaultValue: '@', // this map default value
+        maxLength: '=',
+        constraints: '=',
+        showAddBtn: '=?',
+        parentProperty: '=',
+        types: '=',
+        isService: '='
     };
 
     restrict = 'E';
     replace = true;
-    template = ():string => {
+
+    constructor(private DataTypesService: DataTypesService,
+                private MapKeyValidationPattern: RegExp,
+                private ValidationUtils: ValidationUtils,
+                private $timeout: ng.ITimeoutService) {
+    }
+
+    public static factory = (DataTypesService: DataTypesService,
+                             MapKeyValidationPattern: RegExp,
+                             ValidationUtils: ValidationUtils,
+                             $timeout: ng.ITimeoutService) => {
+        return new TypeMapDirective(DataTypesService, MapKeyValidationPattern, ValidationUtils, $timeout);
+    }
+    template = (): string => {
         return require('./type-map-directive.html');
-    };
+    }
 
-    link = (scope:ITypeMapScope, element:any, $attr:any) => {
+    link = (scope: ITypeMapScope, element: any, $attr: any) => {
+        scope.showAddBtn = angular.isDefined(scope.showAddBtn) ? scope.showAddBtn : true;
         scope.MapKeyValidationPattern = this.MapKeyValidationPattern;
         scope.isMapKeysUnique = true;
 
-        //reset valueObjRef and mapKeys when schema type is changed
-        scope.$watchCollection('schemaProperty.type', (newData:any):void => {
+        if (scope.mapKeys === undefined) {
+            if (scope.valueObjRef) {
+                scope.mapKeys = Object.keys(scope.valueObjRef);
+            } else if (scope.defaultValue) {
+                const defaultValue = JSON.parse(scope.defaultValue);
+                scope.valueObjRef = defaultValue;
+                scope.mapKeys = Object.keys(defaultValue);
+            } else {
+                console.warn('Missing value keys');
+            }
+        }
+
+        if (scope.mapKeys) {
+            scope.showToscaFunction = new Array(scope.mapKeys.length);
+            scope.mapKeys.forEach((key, index) => {
+                scope.showToscaFunction[index] = false;
+                if (scope.parentProperty && scope.parentProperty.subPropertyToscaFunctions != null) {
+                    scope.parentProperty.subPropertyToscaFunctions.forEach((SubPropertyToscaFunction) => {
+                        if (SubPropertyToscaFunction.subPropertyPath.indexOf(key) != -1) {
+                            scope.showToscaFunction[index] = true;
+                        }
+                    });
+                }
+            });
+        } else {
+            console.warn('Missing map keys');
+        }
+
+        // reset valueObjRef and mapKeys when schema type is changed
+        scope.$watchCollection('schemaProperty.type', (newData: any): void => {
             scope.isSchemaTypeDataType = this.DataTypesService.isDataTypeForSchemaType(scope.schemaProperty);
             if (scope.valueObjRef) {
                 scope.mapKeys = Object.keys(scope.valueObjRef);
-                //keeping another copy of the keys, as the mapKeys gets overridden sometimes
+                // keeping another copy of the keys, as the mapKeys gets overridden sometimes
                 scope.mapKeysStatic = Object.keys(scope.valueObjRef);
             }
         });
 
-        //when user brows between properties in "edit property form"
-        scope.$watchCollection('fieldsPrefixName', (newData:any):void => {
-            if (!scope.valueObjRef) {
-                scope.valueObjRef = {};
+        scope.$watchCollection('valueObjRef', (newData: any): void => {
+            if (scope.valueObjRef) {
+                scope.mapKeys = Object.keys(scope.valueObjRef);
+                scope.mapKeysStatic = Object.keys(scope.valueObjRef);
+            } else {
+                console.warn('valueObjRef missing', scope.valueObjRef);
+            }
+        });
+
+        // when user brows between properties in "edit property form"
+        scope.$watchCollection('fieldsPrefixName', (newData: any): void => {
+            if (scope.valueObjRef) {
+                scope.mapKeys = Object.keys(scope.valueObjRef);
+                // keeping another copy of the keys, as the mapKeys gets overridden sometimes
+                scope.mapKeysStatic = Object.keys(scope.valueObjRef);
             }
-            scope.mapKeys = Object.keys(scope.valueObjRef);
-            //keeping another copy of the keys, as the mapKeys gets overridden sometimes
-            scope.mapKeysStatic = Object.keys(scope.valueObjRef);
 
             if ($attr.defaultValue) {
                 scope.mapDefaultValue = JSON.parse($attr.defaultValue);
             }
         });
 
-        //return dummy array in order to prevent rendering map-keys ng-repeat again when a map key is changed
-        scope.getNumber = (num:number):Array<any> => {
+        // return dummy array in order to prevent rendering map-keys ng-repeat again when a map key is changed
+        scope.getNumber = (num: number): any[] => {
             return new Array(num);
         };
 
-        scope.getValidationPattern = (type:string):RegExp => {
+        scope.getValidationPattern = (type: string): RegExp => {
             return this.ValidationUtils.getValidationPattern(type);
         };
 
-        scope.validateIntRange = (value:string):boolean => {
+        scope.validateIntRange = (value: string): boolean => {
             return !value || this.ValidationUtils.validateIntRange(value);
         };
 
-        scope.changeKeyOfMap = (newKey:string, index:number, fieldName:string):void => {
-            let oldKey = Object.keys(scope.valueObjRef)[index];
-            let existsKeyIndex = Object.keys(scope.valueObjRef).indexOf(newKey);
-            if (existsKeyIndex > -1 && existsKeyIndex != index) {
+        scope.changeKeyOfMap = (newKey: string, index: number, fieldName: string): void => {
+            const currentKeySet = Object.keys(scope.valueObjRef);
+            const currentKey = currentKeySet[index];
+            const existingKeyIndex = currentKeySet.indexOf(newKey);
+            if (existingKeyIndex > -1 && existingKeyIndex != index) {
                 scope.parentFormObj[fieldName].$setValidity('keyExist', false);
                 scope.isMapKeysUnique = false;
-            } else {
-                scope.parentFormObj[fieldName].$setValidity('keyExist', true);
-                scope.isMapKeysUnique = true;
-                if (!scope.parentFormObj[fieldName].$invalid) {
-                    //To preserve the order of the keys, delete each one and recreate
-                    let newObj = {};
-                    angular.copy(scope.valueObjRef , newObj);
-                    angular.forEach(newObj,function(value:any,key:string){
-                        delete scope.valueObjRef[key];
-                        if(key == oldKey){
-                            scope.valueObjRef[newKey] = value;
-                        }else{
-                            scope.valueObjRef[key] = value;
-                        }
-                    });
-                }
+                return;
+            }
+
+            scope.parentFormObj[fieldName].$setValidity('keyExist', true);
+            scope.isMapKeysUnique = true;
+            if (!scope.parentFormObj[fieldName].$invalid) {
+                // To preserve the order of the keys, delete each one and recreate
+                const newObj = {};
+                angular.copy(scope.valueObjRef, newObj);
+                angular.forEach(newObj, function(value: any, key: string) {
+                    delete scope.valueObjRef[key];
+                    if (key == currentKey) {
+                        scope.valueObjRef[newKey] = value;
+                    } else {
+                        scope.valueObjRef[key] = value;
+                    }
+                });
             }
         };
 
-        scope.deleteMapItem = (index:number):void=> {
+        scope.deleteMapItem = (index: number): void => {
+            const keyToChange = scope.mapKeys[index];
             delete scope.valueObjRef[scope.mapKeys[index]];
             scope.mapKeys.splice(index, 1);
-            if (!scope.mapKeys.length) {//only when user removes all pairs of key-value fields - put the default
+            scope.showToscaFunction.splice(index, 1);
+            if (scope.parentProperty && scope.parentProperty.subPropertyToscaFunctions != null) {
+                const subToscaFunctionList: SubPropertyToscaFunction[] = [];
+                scope.parentProperty.subPropertyToscaFunctions.forEach((SubPropertyToscaFunction, index) => {
+                    if (SubPropertyToscaFunction.subPropertyPath.indexOf(keyToChange) == -1) {
+                        subToscaFunctionList.push(SubPropertyToscaFunction);
+                    }
+                });
+                scope.parentProperty.subPropertyToscaFunctions = subToscaFunctionList;
+            }
+            if (!scope.mapKeys.length) {// only when user removes all pairs of key-value fields - put the default
                 if (scope.mapDefaultValue) {
                     angular.copy(scope.mapDefaultValue, scope.valueObjRef);
                     scope.mapKeys = Object.keys(scope.valueObjRef);
@@ -151,24 +226,95 @@ export class TypeMapDirective implements ng.IDirective {
             }
         };
 
-        scope.addMapItemFields = ():void => {
+        scope.onEnableTosca = (toscaFlag: boolean, flagIndex: number): void => {
+            scope.showToscaFunction[flagIndex] = toscaFlag;
+            scope.valueObjRef[scope.mapKeys[flagIndex]] = null;
+            if (!toscaFlag) {
+                if (scope.parentProperty.subPropertyToscaFunctions != null) {
+                    const subToscaFunctionList: SubPropertyToscaFunction[] = [];
+                    scope.parentProperty.subPropertyToscaFunctions.forEach((SubPropertyToscaFunction, index) => {
+                        if (SubPropertyToscaFunction.subPropertyPath.indexOf(scope.mapKeys[flagIndex]) == -1) {
+                            subToscaFunctionList.push(SubPropertyToscaFunction);
+                        }
+                    });
+                    scope.parentProperty.subPropertyToscaFunctions = subToscaFunctionList;
+                }
+            }
+        };
+
+        scope.onGetToscaFunction = (toscaGetFunction: ToscaGetFunction, key: string): void => {
+            if (scope.parentProperty.subPropertyToscaFunctions != null) {
+                scope.parentProperty.subPropertyToscaFunctions.forEach((SubPropertyToscaFunction) => {
+                    if (SubPropertyToscaFunction.subPropertyPath.indexOf(key) != -1) {
+                        SubPropertyToscaFunction.toscaFunction = toscaGetFunction;
+                        return;
+                    }
+                });
+
+            }
+            if (scope.parentProperty.subPropertyToscaFunctions == null) {
+                scope.parentProperty.subPropertyToscaFunctions = [];
+            }
+            const subPropertyToscaFunction = new SubPropertyToscaFunction();
+            subPropertyToscaFunction.toscaFunction = toscaGetFunction;
+            subPropertyToscaFunction.subPropertyPath = [key];
+            scope.parentProperty.subPropertyToscaFunctions.push(subPropertyToscaFunction);
+        };
+
+        scope.addMapItemFields = (): void => {
+            if (!scope.valueObjRef) {
+                scope.valueObjRef = {};
+                scope.showToscaFunction = [];
+            }
+
             scope.valueObjRef[''] = null;
             scope.mapKeys = Object.keys(scope.valueObjRef);
+            scope.showToscaFunction.push(false);
         };
 
-        scope.parseToCorrectType = (objectOfValues:any, locationInObj:string, type:string):void => {
+        scope.parseToCorrectType = (objectOfValues: any, locationInObj: string, type: string): void => {
             if (objectOfValues[locationInObj] && type != PROPERTY_TYPES.STRING) {
                 objectOfValues[locationInObj] = JSON.parse(objectOfValues[locationInObj]);
             }
+        };
+
+        scope.validateSubToscaFunction = (key: string): boolean => {
+            if (scope.parentProperty.subPropertyToscaFunctions != null) {
+                scope.parentProperty.subPropertyToscaFunctions.forEach((SubPropertyToscaFunction) => {
+                    if (SubPropertyToscaFunction.subPropertyPath.indexOf(key) != -1) {
+                        return true;
+                    }
+                });
+            }
+            return false;
+        };
+    }
+
+    private isDataTypeForSchemaType = (property: SchemaProperty, types: DataTypesMap): boolean => {
+        property.simpleType = '';
+        if (property.type && PROPERTY_DATA.TYPES.indexOf(property.type) > -1) {
+            return false;
         }
-    };
+        const simpleType = this.getTypeForDataTypeDerivedFromSimple(property.type, types);
+        if (simpleType) {
+            property.simpleType = simpleType;
+            return false;
+        }
+        return true;
+    }
 
-    public static factory = (DataTypesService:DataTypesService,
-                             MapKeyValidationPattern:RegExp,
-                             ValidationUtils:ValidationUtils,
-                             $timeout:ng.ITimeoutService)=> {
-        return new TypeMapDirective(DataTypesService, MapKeyValidationPattern, ValidationUtils, $timeout);
-    };
+    private getTypeForDataTypeDerivedFromSimple = (dataTypeName: string, types: DataTypesMap): string => {
+        if (!types[dataTypeName]) {
+            return 'string';
+        }
+        if (types[dataTypeName].derivedFromName == 'tosca.datatypes.Root' || types[dataTypeName].properties) {
+            return null;
+        }
+        if (PROPERTY_DATA.SIMPLE_TYPES.indexOf(types[dataTypeName].derivedFromName) > -1) {
+            return types[dataTypeName].derivedFromName;
+        }
+        return this.getTypeForDataTypeDerivedFromSimple(types[dataTypeName].derivedFromName, types);
+    }
 }
 
 TypeMapDirective.factory.$inject = ['Sdc.Services.DataTypesService', 'MapKeyValidationPattern', 'ValidationUtils', '$timeout'];