Provide tosca function capability to complex type fields in composition view
[sdc.git] / catalog-ui / src / app / directives / property-types / type-list / type-list-directive.ts
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 /**
22  * Created by rcohen on 9/15/2016.
23  */
24 'use strict';
25 import {SchemaProperty, PropertyModel, DataTypesMap} from "app/models";
26 import {ValidationUtils, PROPERTY_TYPES, PROPERTY_DATA} from "app/utils";
27 import {DataTypesService} from "app/services";
28 import {InstanceFeDetails} from "app/models/instance-fe-details";
29 import {ToscaGetFunction} from "app/models/tosca-get-function";
30 import {SubPropertyToscaFunction} from "app/models/sub-property-tosca-function";
31
32 export interface ITypeListScope extends ng.IScope {
33     parentFormObj:ng.IFormController;
34     schemaProperty:SchemaProperty;
35     parentProperty:PropertyModel;
36     componentInstanceMap: Map<string, InstanceFeDetails>;
37     isSchemaTypeDataType:boolean;
38     valueObjRef:any;
39     propertyNameValidationPattern:RegExp;
40     fieldsPrefixName:string;
41     readOnly:boolean;
42     listDefaultValue:any;
43     listNewItem:any;
44     maxLength:number;
45     stringSchema: SchemaProperty;
46     showToscaFunction: Array<boolean>;
47     constraints:string[];
48     types:DataTypesMap;
49     isService:boolean;
50     complexToscapath: string;
51
52     getValidationPattern(type:string):RegExp;
53     validateIntRange(value:string):boolean;
54     addListItem():void;
55     addValueToList(value:string,index:number);
56     deleteListItem(listItemIndex:number):void;
57     getStringSchemaProperty():SchemaProperty;
58     getNumber(num:number):Array<any>;
59     onEnableTosca(toscaFlag:boolean,index:number);
60     onGetToscaFunction(toscaGetFunction: ToscaGetFunction, index:number);
61 }
62
63
64 export class TypeListDirective implements ng.IDirective {
65
66     private readonly stringSchema: SchemaProperty;
67
68     constructor(private DataTypesService:DataTypesService,
69                 private PropertyNameValidationPattern:RegExp,
70                 private ValidationUtils:ValidationUtils) {
71         this.stringSchema = new SchemaProperty();
72         this.stringSchema.type = PROPERTY_TYPES.STRING;
73         this.stringSchema.isSimpleType = true;
74         this.stringSchema.isDataType = false;
75     }
76
77     scope = {
78         valueObjRef: '=',//ref to list object in the parent value object
79         schemaProperty: '=',//get the schema.property object
80         componentInstanceMap: '=',
81         parentProperty: '=',
82         parentFormObj: '=',//ref to parent form (get angular form object)
83         fieldsPrefixName: '=',//prefix for form fields names
84         readOnly: '=',//is form read only
85         defaultValue: '@',//this list default value
86         maxLength: '=',
87         constraints: '=',
88         types: '=',
89         isService: '=',
90         complexToscapath: '='
91     };
92
93     restrict = 'E';
94     replace = true;
95     template = ():string => {
96         return require('./type-list-directive.html');
97     };
98     
99     private isDataTypeForSchemaType = (property:SchemaProperty, types:DataTypesMap):boolean=> {
100         property.simpleType = "";
101         if (property.type && PROPERTY_DATA.TYPES.indexOf(property.type) > -1) {
102             return false;
103         }
104         let simpleType = this.getTypeForDataTypeDerivedFromSimple(property.type, types);
105         if (simpleType) {
106             property.simpleType = simpleType;
107             return false;
108         }
109         return true;
110     };
111     
112     private getTypeForDataTypeDerivedFromSimple = (dataTypeName:string, types:DataTypesMap):string => {
113         if (!types[dataTypeName]) {
114             return 'string';
115         }
116         if (types[dataTypeName].derivedFromName == "tosca.datatypes.Root" || types[dataTypeName].properties) {
117             return null;
118         }
119         if (PROPERTY_DATA.SIMPLE_TYPES.indexOf(types[dataTypeName].derivedFromName) > -1) {
120             return types[dataTypeName].derivedFromName
121         }
122         return this.getTypeForDataTypeDerivedFromSimple(types[dataTypeName].derivedFromName, types);
123     };
124
125     link = (scope:ITypeListScope, element:any, $attr:any) => {
126         scope.propertyNameValidationPattern = this.PropertyNameValidationPattern;
127         scope.stringSchema = this.stringSchema;
128         if ((scope.valueObjRef == null || scope.valueObjRef.length == 0) && scope.complexToscapath == null) {
129             scope.valueObjRef = [];
130             scope.valueObjRef.push("");
131         }
132         if (scope.valueObjRef != null && scope.valueObjRef.length > 0) {
133             scope.showToscaFunction = new Array(scope.valueObjRef.length);
134             scope.valueObjRef.forEach((value, index) => {
135                 scope.showToscaFunction[index] = false;
136                 if (scope.parentProperty.subPropertyToscaFunctions != null) {
137                     let key : string = index.toString();
138                     scope.parentProperty.subPropertyToscaFunctions.forEach(SubPropertyToscaFunction => {
139                         if (SubPropertyToscaFunction.subPropertyPath.toString() == key) {
140                             scope.showToscaFunction[index] = true;
141                             return;
142                         }
143                     });
144                 }
145             });
146         }
147         
148         //reset valueObjRef when schema type is changed
149         scope.$watchCollection('schemaProperty.type', (newData:any):void => {
150             scope.isSchemaTypeDataType = this.DataTypesService.isDataTypeForSchemaType(scope.schemaProperty);
151         });
152
153         //when user brows between properties in "edit property form"
154         scope.$watchCollection('fieldsPrefixName', (newData:any):void => {
155             scope.listNewItem = {value: ''};
156
157             if ($attr.defaultValue) {
158                 scope.listDefaultValue = JSON.parse($attr.defaultValue);
159             }
160         });
161
162         scope.getValidationPattern = (type:string):RegExp => {
163             return this.ValidationUtils.getValidationPattern(type);
164         };
165
166         scope.validateIntRange = (value:string):boolean => {
167             return !value || this.ValidationUtils.validateIntRange(value);
168         };
169
170         scope.addListItem = ():void => {
171             scope.valueObjRef = scope.valueObjRef || [];
172             let newVal;
173             if (scope.schemaProperty.type === PROPERTY_TYPES.MAP) {
174                 newVal = {"": ""};
175             } else if ((scope.schemaProperty.simpleType || scope.schemaProperty.type) == PROPERTY_TYPES.STRING) {
176                 newVal = scope.listNewItem.value;
177             } else {
178                 if (scope.listNewItem.value != "") {
179                     newVal = JSON.parse(scope.listNewItem.value);
180                 }
181             }
182             scope.valueObjRef.push(newVal);
183             scope.showToscaFunction = scope.showToscaFunction || [];
184             scope.showToscaFunction.push(false);
185             scope.listNewItem.value = "";
186         };
187
188         //return dummy array in order to prevent rendering map-keys ng-repeat again when a map key is changed
189         scope.getNumber = (num:number):Array<any> => {
190             return new Array(num);
191         };
192
193         scope.addValueToList = (value:string,index:number):void => {
194             console.log("value : "+value+" , index : "+index);
195             scope.valueObjRef[index] = value;
196             scope.parentProperty.value = scope.valueObjRef;
197         }
198
199         scope.deleteListItem = (listItemIndex: number): void => {
200             scope.valueObjRef.splice(listItemIndex, 1);
201             let key : string = listItemIndex.toString();
202             if (scope.parentProperty.subPropertyToscaFunctions != null) {
203                 let subToscaFunctionList : Array<SubPropertyToscaFunction> = [];
204                 scope.parentProperty.subPropertyToscaFunctions.forEach((SubPropertyToscaFunction, index) => {
205                     if (SubPropertyToscaFunction.subPropertyPath.indexOf(key) == -1) {
206                         subToscaFunctionList.push(SubPropertyToscaFunction);
207                     }
208                 });
209                 scope.parentProperty.subPropertyToscaFunctions = subToscaFunctionList;
210             }
211             if (!scope.valueObjRef.length && scope.listDefaultValue) {
212                 angular.copy(scope.listDefaultValue, scope.valueObjRef);
213             }
214         };
215
216         scope.onEnableTosca = (toscaFlag:boolean,flagIndex:number):void => {
217             scope.showToscaFunction[flagIndex] = toscaFlag;
218             scope.valueObjRef[flagIndex] = "";
219             let key:string = flagIndex.toString();
220             if (!toscaFlag) {
221                 if (scope.parentProperty.subPropertyToscaFunctions != null) {
222                     let subToscaFunctionList : Array<SubPropertyToscaFunction> = [];
223                     scope.parentProperty.subPropertyToscaFunctions.forEach((SubPropertyToscaFunction, index) => {
224                         if (SubPropertyToscaFunction.subPropertyPath.toString() != key) {
225                             subToscaFunctionList.push(SubPropertyToscaFunction);
226                         }
227                     });
228                     scope.parentProperty.subPropertyToscaFunctions = subToscaFunctionList;
229                 }
230             }
231         };
232
233         scope.onGetToscaFunction = (toscaGetFunction: ToscaGetFunction, index:number): void => {
234             let key:string = index.toString();
235             if (scope.parentProperty.subPropertyToscaFunctions != null) {
236                 let toscaFlag : boolean = true;
237                 scope.parentProperty.subPropertyToscaFunctions.forEach(SubPropertyToscaFunction => {
238                     if (SubPropertyToscaFunction.subPropertyPath.toString() == key) {
239                         SubPropertyToscaFunction.toscaFunction = toscaGetFunction;
240                         toscaFlag = false;
241                         return;
242                     }
243                 });
244                 if (toscaFlag) {
245                     let subPropertyToscaFunction = new SubPropertyToscaFunction();
246                     subPropertyToscaFunction.toscaFunction = toscaGetFunction;
247                     subPropertyToscaFunction.subPropertyPath = [key];
248                     scope.parentProperty.subPropertyToscaFunctions.push(subPropertyToscaFunction);
249                 }
250             } else {  
251                 let subPropertyToscaFunction = new SubPropertyToscaFunction();
252                 subPropertyToscaFunction.toscaFunction = toscaGetFunction;
253                 subPropertyToscaFunction.subPropertyPath = [key];
254                 scope.parentProperty.subPropertyToscaFunctions = [subPropertyToscaFunction];
255             }
256         }
257
258     };
259
260     public static factory = (DataTypesService:DataTypesService,
261                              PropertyNameValidationPattern:RegExp,
262                              ValidationUtils:ValidationUtils)=> {
263         return new TypeListDirective(DataTypesService, PropertyNameValidationPattern, ValidationUtils);
264     };
265 }
266
267 TypeListDirective.factory.$inject = ['Sdc.Services.DataTypesService', 'PropertyNameValidationPattern', 'ValidationUtils'];
268