faf2a0fb883e94c41b7173e535ca59fb545007a5
[sdc.git] / catalog-ui / src / app / view-models / forms / property-forms / component-property-form / property-form-view-model.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 'use strict';
22 import * as _ from "lodash";
23 import {FormState, PROPERTY_DATA, PROPERTY_TYPES, PROPERTY_VALUE_CONSTRAINTS, ValidationUtils} from "app/utils";
24 import {DataTypesService} from "app/services";
25 import {DataTypesMap, PropertyModel, InputBEModel, Component, InputFEModel} from "app/models";
26 import {ComponentInstance} from "../../../../models/componentsInstances/componentInstance";
27 import {ComponentInstanceServiceNg2} from "app/ng2/services/component-instance-services/component-instance.service";
28 import {ComponentServiceNg2} from "app/ng2/services/component-services/component.service";
29 import {SdcUiCommon, SdcUiComponents, SdcUiServices} from "onap-ui-angular";
30 import {CompositionService} from "app/ng2/pages/composition/composition.service";
31 import {WorkspaceService} from "app/ng2/pages/workspace/workspace.service";
32 import {Observable} from "rxjs";
33 import {TopologyTemplateService} from "app/ng2/services/component-services/topology-template.service";
34 import {InstanceFeDetails} from "../../../../models/instance-fe-details";
35 import {ToscaGetFunction} from "../../../../models/tosca-get-function";
36 import {ToscaFunctionValidationEvent} from "../../../../ng2/pages/properties-assignment/tosca-function/tosca-function.component";
37 import {CustomToscaFunction} from "../../../../models/default-custom-functions";
38 import {ToscaFunctionType} from "../../../../models/tosca-function-type.enum";
39
40 export interface IEditPropertyModel {
41     property:PropertyModel;
42     types:Array<string>;
43     simpleTypes:Array<string>;
44     hasGetFunctionValue: boolean;
45     isGetFunctionValid: boolean;
46 }
47
48 interface IPropertyFormViewModelScope extends ng.IScope {
49     forms: any;
50     editForm: ng.IFormController;
51     footerButtons: Array<any>;
52     isNew: boolean;
53     nameMaxLength: number;
54     isLoading: boolean;
55     componentMetadata: { isService: boolean, isVfc: boolean };
56     validationPattern: RegExp;
57     propertyNameValidationPattern: RegExp;
58     commentValidationPattern: RegExp;
59     editPropertyModel: IEditPropertyModel;
60     componentInstanceMap: Map<string, InstanceFeDetails>;
61     customToscaFunctions: Array<CustomToscaFunction>;
62     modalInstanceProperty:ng.ui.bootstrap.IModalServiceInstance;
63     currentPropertyIndex:number;
64     isLastProperty:boolean;
65     myValue:any;
66     nonPrimitiveTypes:Array<string>;
67     dataTypes:DataTypesMap;
68     isTypeDataType:boolean;
69     maxLength:number;
70     isViewOnly:boolean;
71     isPropertyValueOwner:boolean;
72     isVnfConfiguration:boolean;
73     constraints:string[];
74     modelNameFilter:string;
75     isGetFunctionValueType: boolean;
76     invalidMandatoryFields: boolean;
77
78     validateJson(json: string): boolean;
79     save(doNotCloseModal?: boolean): void;
80     getValidationPattern(type: string): RegExp;
81     validateIntRange(value: string): boolean;
82     close(): void;
83     onSchemaTypeChange(): void;
84     onTypeChange(resetSchema: boolean): void;
85     showSchema(): boolean;
86     delete(property: PropertyModel): void;
87     getPrev(): void;
88     getNext(): void;
89     isSimpleType(typeName: string): boolean;
90     getDefaultValue(): any;
91     onValueTypeChange(): void;
92 }
93
94 export class PropertyFormViewModel {
95
96     static '$inject' = [
97         '$scope',
98         'Sdc.Services.DataTypesService',
99         '$uibModalInstance',
100         'property',
101         'ValidationPattern',
102         'PropertyNameValidationPattern',
103         'CommentValidationPattern',
104         'ValidationUtils',
105         'component',
106         '$filter',
107         'ModalServiceSdcUI',
108         'filteredProperties',
109         '$timeout',
110         'isViewOnly',
111         'isPropertyValueOwner',
112         'propertyOwnerType',
113         'propertyOwnerId',
114         'ComponentInstanceServiceNg2',
115         'ComponentServiceNg2',
116         'TopologyTemplateService',
117         'CompositionService',
118         'workspaceService',
119         'inputProperty'
120     ];
121
122     private formState:FormState;
123
124     constructor(private $scope:IPropertyFormViewModelScope,
125                 private DataTypesService:DataTypesService,
126                 private $uibModalInstance:ng.ui.bootstrap.IModalServiceInstance,
127                 private property:PropertyModel,
128                 private ValidationPattern:RegExp,
129                 private PropertyNameValidationPattern:RegExp,
130                 private CommentValidationPattern:RegExp,
131                 private ValidationUtils:ValidationUtils,
132                 private component:Component,
133                 private $filter:ng.IFilterService,
134                 private modalService:SdcUiServices.ModalService,
135                 private filteredProperties:Array<PropertyModel>,
136                 private $timeout:ng.ITimeoutService,
137                 private isViewOnly:boolean,
138                 private isPropertyValueOwner:boolean,
139                 private propertyOwnerType:string,
140                 private propertyOwnerId:string,
141                 private ComponentInstanceServiceNg2: ComponentInstanceServiceNg2,
142                 private ComponentServiceNg2: ComponentServiceNg2,
143                 private topologyTemplateService: TopologyTemplateService,
144                 private compositionService: CompositionService,
145                 private workspaceService: WorkspaceService,
146                 private inputProperty : InputFEModel) {
147
148         this.formState = angular.isDefined(property.name) ? FormState.UPDATE : FormState.CREATE;
149         this.initScope();
150     }
151
152     private initResource = ():void => {
153         this.$scope.editPropertyModel.property = new PropertyModel(this.property);
154         this.$scope.editPropertyModel.property.type = this.property.type ? this.property.type : null;
155         this.$scope.editPropertyModel.property.value = this.property.value ? this.property.value : this.property.defaultValue;
156         this.$scope.constraints = this.property.constraints && this.property.constraints[0] ? this.property.constraints[0]["validValues"] : null;
157         this.initToscaGetFunction();
158         this.setMaxLength();
159     };
160
161     private initToscaGetFunction() {
162         this.$scope.editPropertyModel.hasGetFunctionValue = this.$scope.editPropertyModel.property.isToscaFunction();
163         this.$scope.editPropertyModel.isGetFunctionValid = true;
164     }
165
166     private isDataTypeForPropertyType = (property:PropertyModel):boolean=> {
167         property.simpleType = "";
168         if (property.type && PROPERTY_DATA.TYPES.indexOf(property.type) > -1) {
169             return false;
170         }
171         let simpleType = this.getTypeForDataTypeDerivedFromSimple(property.type);
172         if (simpleType) {
173             property.simpleType = simpleType;
174             return false;
175         }
176         return true;
177     };
178
179     private getTypeForDataTypeDerivedFromSimple = (dataTypeName:string):string => {
180         if (!this.$scope.dataTypes[dataTypeName]) {
181             return 'string';
182         }
183         if (this.$scope.dataTypes[dataTypeName].derivedFromName == "tosca.datatypes.Root" || this.$scope.dataTypes[dataTypeName].properties) {
184             return null;
185         }
186         if (PROPERTY_DATA.SIMPLE_TYPES.indexOf(this.$scope.dataTypes[dataTypeName].derivedFromName) > -1) {
187             return this.$scope.dataTypes[dataTypeName].derivedFromName
188         }
189         return this.getTypeForDataTypeDerivedFromSimple(this.$scope.dataTypes[dataTypeName].derivedFromName);
190     };
191
192     private initForNotSimpleType = ():void => {
193         const property = this.$scope.editPropertyModel.property;
194         this.$scope.isTypeDataType = this.DataTypesService.isDataTypeForPropertyType(this.$scope.editPropertyModel.property);
195         if (property.isToscaFunction()) {
196             this.initValueForGetFunction();
197             return;
198         }
199
200         if (this.isComplexType(property.type)) {
201             if (property.value || property.defaultValue) {
202                 this.$scope.myValue = JSON.parse(property.value || property.defaultValue);
203             } else {
204                 this.initEmptyComplexValue(property.type);
205             }
206         }
207     };
208
209     private initValueForGetFunction(): void {
210         const property = this.$scope.editPropertyModel.property;
211         if (property.defaultValue) {
212             this.$scope.myValue = JSON.parse(property.defaultValue);
213             return;
214         }
215         if (this.isComplexType(property.type)) {
216             this.initEmptyComplexValue(property.type);
217             return;
218         }
219
220         this.$scope.myValue = undefined;
221     }
222
223     private initComponentInstanceMap() {
224         this.$scope.componentInstanceMap = new Map<string, InstanceFeDetails>();
225         if (this.compositionService.componentInstances) {
226             this.compositionService.componentInstances.forEach(value => {
227                 this.$scope.componentInstanceMap.set(value.uniqueId, <InstanceFeDetails>{
228                     name: value.name
229                 });
230             });
231         }
232     }
233
234     private initCustomToscaFunctions() {
235         this.$scope.customToscaFunctions = [];
236         this.topologyTemplateService.getDefaultCustomFunction().toPromise().then((data) => {
237             for (let customFunction of data) {
238                 this.$scope.customToscaFunctions.push(new CustomToscaFunction(customFunction));
239             }
240         });
241     }
242
243     private initEmptyComplexValue(type: string): any {
244         switch (type) {
245             case PROPERTY_TYPES.MAP:
246                 this.$scope.myValue = {'': null};
247                 break;
248             case PROPERTY_TYPES.LIST:
249                 this.$scope.myValue = [''];
250                 break;
251             default:
252                 this.$scope.myValue = {};
253         }
254     }
255
256     private isComplexType(type: string): boolean {
257         if (!type) {
258             return false;
259         }
260         return PROPERTY_DATA.SIMPLE_TYPES.indexOf(type) == -1;
261     }
262
263     private setMaxLength = ():void => {
264         switch (this.$scope.editPropertyModel.property.type) {
265             case PROPERTY_TYPES.MAP:
266             case PROPERTY_TYPES.LIST:
267                 this.$scope.maxLength = this.$scope.editPropertyModel.property.schema.property.type == PROPERTY_TYPES.JSON ?
268                     PROPERTY_VALUE_CONSTRAINTS.JSON_MAX_LENGTH :
269                     PROPERTY_VALUE_CONSTRAINTS.MAX_LENGTH;
270                 break;
271             case PROPERTY_TYPES.JSON:
272                 this.$scope.maxLength = PROPERTY_VALUE_CONSTRAINTS.JSON_MAX_LENGTH;
273                 break;
274             default:
275                 this.$scope.maxLength =PROPERTY_VALUE_CONSTRAINTS.MAX_LENGTH;
276         }
277     };
278
279
280     private initScope = ():void => {
281
282         //scope properties
283         this.$scope.isViewOnly = this.isViewOnly;
284         this.$scope.isLoading = true;
285         this.$scope.forms = {};
286         this.$scope.validationPattern = this.ValidationPattern;
287         this.$scope.propertyNameValidationPattern = this.PropertyNameValidationPattern;
288         this.$scope.commentValidationPattern = this.CommentValidationPattern;
289         this.$scope.nameMaxLength = PROPERTY_VALUE_CONSTRAINTS.NAME_MAX_LENGTH;
290         this.$scope.isNew = (this.formState === FormState.CREATE);
291         this.$scope.componentMetadata = {
292             isService: this.workspaceService.metadata.isService(),
293             isVfc: this.workspaceService.metadata.isVfc()
294         }
295         this.$scope.modalInstanceProperty = this.$uibModalInstance;
296         this.$scope.currentPropertyIndex = _.findIndex(this.filteredProperties, i=> i.name == this.property.name);
297         this.$scope.isLastProperty = this.$scope.currentPropertyIndex == (this.filteredProperties.length - 1);
298         const property = new PropertyModel(this.property);
299         this.$scope.editPropertyModel = {
300             'property': property,
301             types: PROPERTY_DATA.TYPES,
302             simpleTypes: PROPERTY_DATA.SIMPLE_TYPES,
303             hasGetFunctionValue: property.isToscaFunction(),
304             isGetFunctionValid: true,
305         };
306         this.$scope.editPropertyModel.types.sort((a,b) => a.localeCompare(b));
307         this.$scope.isPropertyValueOwner = this.isPropertyValueOwner;
308         this.$scope.propertyOwnerType = this.propertyOwnerType;
309         this.$scope.modelNameFilter = this.workspaceService.metadata.model;
310         //check if property of VnfConfiguration
311         this.$scope.isVnfConfiguration = false;
312         if(this.propertyOwnerType == "component" && angular.isArray(this.compositionService.componentInstances)) {
313             const componentPropertyOwner:ComponentInstance = this.compositionService.componentInstances.find((ci:ComponentInstance) => {
314                 return ci.uniqueId === this.property.resourceInstanceUniqueId;
315             });
316             if (componentPropertyOwner && componentPropertyOwner.componentName === 'vnfConfiguration') {
317                 this.$scope.isVnfConfiguration = true;
318             }
319         }
320         this.initResource();
321         this.initForNotSimpleType();
322         this.initComponentInstanceMap();
323         this.initCustomToscaFunctions();
324
325         this.$scope.validateJson = (json:string):boolean => {
326             if (!json) {
327                 return true;
328             }
329             return this.ValidationUtils.validateJson(json);
330         };
331
332         this.DataTypesService.fetchDataTypesByModel(this.workspaceService.metadata.model).then(response => {
333             this.$scope.dataTypes = response.data as DataTypesMap;
334                 this.$scope.nonPrimitiveTypes = _.filter(Object.keys(this.$scope.dataTypes), (type: string) => {
335                     return this.$scope.editPropertyModel.types.indexOf(type) == -1 ;
336                 }).sort((a, b) => a.localeCompare(b));
337                 this.$scope.isLoading = false;
338         });
339
340         //scope methods
341         this.$scope.save = (doNotCloseModal?:boolean):void => {
342             let property:PropertyModel = this.$scope.editPropertyModel.property;
343             this.$scope.isLoading = true;
344             if (property.propertyView){
345                 if (property.constraints.length == 0) {
346                     return;
347                 }
348                 let input : InputBEModel = this.inputProperty;
349                 input.constraints = property.constraints;
350                 this.ComponentServiceNg2.updateComponentInputs(this.component, [input]).subscribe(
351                     (response) => {
352                         console.debug("Input property updated");
353                         this.$uibModalInstance.close();
354                     },
355                     (error) => {
356                         console.debug("Failed to update input property");
357                         this.$uibModalInstance.close();
358                     }
359                 );
360                 return;
361             }
362             this.$scope.editPropertyModel.property.description = this.ValidationUtils.stripAndSanitize(this.$scope.editPropertyModel.property.description);
363             //if read only - or no changes made - just closes the modal
364             //need to check for property.value changes manually to detect if map properties deleted
365             if ((this.$scope.editPropertyModel.property.readonly && !this.$scope.isPropertyValueOwner)
366                 || (!this.$scope.forms.editForm.$dirty && angular.equals(JSON.stringify(this.$scope.myValue), this.$scope.editPropertyModel.property.value))) {
367                 this.$uibModalInstance.close();
368                 return;
369             }
370
371             this.$scope.isLoading = true;
372
373             let onPropertyFailure = (response):void => {
374                 console.error('Failed to update property', response);
375                 this.$scope.isLoading = false;
376             };
377
378             let onPropertySuccess = (propertyFromBE:PropertyModel):void => {
379                 this.$scope.isLoading = false;
380                 this.filteredProperties[this.$scope.currentPropertyIndex] = propertyFromBE;
381                 if (!doNotCloseModal) {
382                     this.$uibModalInstance.close(propertyFromBE);
383                 } else {
384                     this.$scope.forms.editForm.$setPristine();
385                     this.$scope.editPropertyModel.property = new PropertyModel();
386                 }
387             };
388
389             //Not clean, but doing this as a temporary fix until we update the property right panel modals
390             if (this.propertyOwnerType === "group"){
391                 this.ComponentInstanceServiceNg2.updateComponentGroupInstanceProperties(this.workspaceService.metadata.componentType, this.workspaceService.metadata.uniqueId, this.propertyOwnerId, [property])
392                     .subscribe((propertiesFromBE) => { onPropertySuccess(<PropertyModel>propertiesFromBE[0])}, error => onPropertyFailure(error));
393             } else if (this.propertyOwnerType === "policy"){
394                 if (!this.$scope.editPropertyModel.property.simpleType &&
395                     !this.$scope.isSimpleType(this.$scope.editPropertyModel.property.type) &&
396                     !_.isNil(this.$scope.myValue)) {
397                     property.value = JSON.stringify(this.$scope.myValue);
398                 }
399                 this.ComponentInstanceServiceNg2.updateComponentPolicyInstanceProperties(this.workspaceService.metadata.componentType, this.workspaceService.metadata.uniqueId, this.propertyOwnerId, [property])
400                     .subscribe((propertiesFromBE) => { onPropertySuccess(<PropertyModel>propertiesFromBE[0])}, error => onPropertyFailure(error));
401             } else {
402                 //in case we have uniqueId we call update method
403                 if (this.$scope.isPropertyValueOwner) {
404                     if (!this.$scope.editPropertyModel.property.simpleType && !this.$scope.isSimpleType(property.type)) {
405                         property.value = JSON.stringify(this.$scope.myValue);
406                     }
407                     this.updateInstanceProperties(property.resourceInstanceUniqueId, [property]).subscribe((propertiesFromBE) => onPropertySuccess(propertiesFromBE[0]),
408                         error => onPropertyFailure(error));
409                 } else {
410                     if (!this.$scope.editPropertyModel.property.simpleType && !this.$scope.isSimpleType(property.type)) {
411                         property.defaultValue = JSON.stringify(this.$scope.myValue);
412                         property.value = JSON.stringify(this.$scope.myValue);
413                     } else {
414                         this.$scope.editPropertyModel.property.defaultValue = this.$scope.editPropertyModel.property.value;
415                     }
416                     this.addOrUpdateProperty(property).subscribe(onPropertySuccess, error => onPropertyFailure(error));
417                 }
418             }
419         };
420
421         this.$scope.getPrev = ():void=> {
422             this.property = this.filteredProperties[--this.$scope.currentPropertyIndex];
423             this.initResource();
424             this.initForNotSimpleType();
425             this.$scope.isLastProperty = false;
426         };
427
428         this.$scope.getNext = ():void=> {
429             this.property = this.filteredProperties[++this.$scope.currentPropertyIndex];
430             this.initResource();
431             this.initForNotSimpleType();
432             this.$scope.isLastProperty = this.$scope.currentPropertyIndex == (this.filteredProperties.length - 1);
433         };
434
435         this.$scope.isSimpleType = (typeName:string):boolean=> {
436             return typeName && this.$scope.editPropertyModel.simpleTypes.indexOf(typeName) != -1;
437         };
438
439         this.$scope.showSchema = (): boolean => {
440             return [PROPERTY_TYPES.LIST, PROPERTY_TYPES.MAP].indexOf(this.$scope.editPropertyModel.property.type) > -1;
441         };
442
443         this.$scope.getValidationPattern = (type: string): RegExp => {
444             return this.ValidationUtils.getValidationPattern(type);
445         };
446
447         this.$scope.validateIntRange = (value: string): boolean => {
448             return !value || this.ValidationUtils.validateIntRange(value);
449         };
450
451         this.$scope.close = (): void => {
452             this.$uibModalInstance.close();
453         };
454
455         // Add the done button at the footer.
456         this.$scope.footerButtons = [
457             {'name': 'Save', 'css': 'blue', 'callback': this.$scope.save},
458             {'name': 'Cancel', 'css': 'grey', 'callback': this.$scope.close}
459         ];
460
461         this.$scope.$watch("forms.editForm.$invalid", (newVal) => {
462             if (this.$scope.editPropertyModel.hasGetFunctionValue) {
463                 this.$scope.invalidMandatoryFields = !newVal || !this.$scope.editPropertyModel.property.toscaFunction || this.isViewOnly;
464                 this.$scope.footerButtons[0].disabled = this.$scope.invalidMandatoryFields;
465             } else {
466                 this.$scope.invalidMandatoryFields = !newVal || this.isViewOnly;
467                 this.$scope.footerButtons[0].disabled = this.$scope.invalidMandatoryFields;
468             }
469         });
470
471         this.$scope.$watch("forms.editForm.$valid", (newVal) => {
472             if (this.$scope.editPropertyModel.hasGetFunctionValue) {
473                 this.$scope.invalidMandatoryFields = !newVal || !this.$scope.editPropertyModel.property.toscaFunction || this.isViewOnly;
474                 this.$scope.footerButtons[0].disabled = this.$scope.invalidMandatoryFields;
475             } else {
476                 this.$scope.invalidMandatoryFields = !newVal || this.isViewOnly;
477                 this.$scope.footerButtons[0].disabled = this.$scope.invalidMandatoryFields;
478             }
479         });
480
481         this.$scope.getDefaultValue = ():any => {
482             return this.$scope.isPropertyValueOwner ? this.$scope.editPropertyModel.property.defaultValue : null;
483         };
484
485         this.$scope.onTypeChange = ():void => {
486             this.$scope.editPropertyModel.property.value = '';
487             this.$scope.editPropertyModel.property.defaultValue = '';
488             this.setMaxLength();
489             this.initForNotSimpleType();
490         };
491
492         this.$scope.onSchemaTypeChange = ():void => {
493             if (this.$scope.editPropertyModel.property.type == PROPERTY_TYPES.MAP) {
494                 this.$scope.myValue = {};
495             } else if (this.$scope.editPropertyModel.property.type == PROPERTY_TYPES.LIST) {
496                 this.$scope.myValue = [];
497             }
498             this.setMaxLength();
499         };
500
501         this.$scope.delete = (property:PropertyModel):void => {
502             let onOk: Function = ():void => {
503                 this.deleteProperty(property.uniqueId).subscribe(
504                     this.$scope.close
505                 );
506             };
507             let title:string = this.$filter('translate')("PROPERTY_VIEW_DELETE_MODAL_TITLE");
508             let message:string = this.$filter('translate')("PROPERTY_VIEW_DELETE_MODAL_TEXT", "{'name': '" + property.name + "'}");
509             const okButton = {testId: "OK", text: "OK", type: SdcUiCommon.ButtonType.info, callback: onOk, closeModal: true} as SdcUiComponents.ModalButtonComponent;
510             this.modalService.openInfoModal(title, message, 'delete-modal', [okButton]);
511         };
512
513         this.$scope.onValueTypeChange = (): void => {
514             this.setEmptyValue();
515             if (this.$scope.editPropertyModel.hasGetFunctionValue) {
516                 this.$scope.editPropertyModel.isGetFunctionValid = undefined;
517             } else {
518                 this.$scope.editPropertyModel.property.toscaFunction = undefined;
519                 this.$scope.editPropertyModel.isGetFunctionValid = true;
520             }
521         }
522
523         this.$scope.onConstraintChange = (constraints: any): void => {
524             console.log('$scope.onConstraintChange', constraints);
525
526             if (!this.$scope.invalidMandatoryFields) {
527                 this.$scope.footerButtons[0].disabled = !constraints.valid;
528             } else {
529                 this.$scope.footerButtons[0].disabled = this.$scope.invalidMandatoryFields;
530             }
531             if (!constraints.constraints || constraints.constraints.length == 0) {
532                 this.$scope.editPropertyModel.property.propertyConstraints = null;
533                 this.$scope.editPropertyModel.property.constraints = null;
534                 return;
535             }
536             this.$scope.editPropertyModel.property.propertyConstraints = this.serializePropertyConstraints(constraints.constraints);
537             this.$scope.editPropertyModel.property.constraints = constraints.constraints;
538         }
539
540         this.$scope.onPropertyMetadataChange = (metadata: any): void => {
541             if (!this.$scope.invalidMandatoryFields) {
542                 this.$scope.footerButtons[0].disabled = !metadata.valid;
543             } else {
544                 this.$scope.footerButtons[0].disabled = this.$scope.invalidMandatoryFields;
545             }
546             if (!metadata.metadata || metadata.metadata.length == 0) {
547                 this.$scope.editPropertyModel.property.metadata = null;
548                 return;
549             }
550             this.$scope.editPropertyModel.property.metadata = metadata.metadata;
551         }
552
553         this.$scope.onGetFunctionValidFunction = (toscaGetFunction: ToscaGetFunction): void => {
554             this.$scope.editPropertyModel.property.toscaFunction = toscaGetFunction;
555         }
556
557         this.$scope.onToscaFunctionValidityChange = (validationEvent: ToscaFunctionValidationEvent): void => {
558             if (validationEvent.isValid) {
559                 this.$scope.editPropertyModel.isGetFunctionValid = true;
560                 return;
561             }
562             this.$scope.editPropertyModel.isGetFunctionValid = undefined;
563         }
564     };
565
566     private serializePropertyConstraints(constraints: any[]): string[] {
567         if (constraints) {
568             let stringConstrsints = new Array();
569             constraints.forEach((constraint) => {
570                 stringConstrsints.push(JSON.stringify(constraint));
571             })
572             return stringConstrsints;
573         }
574         return null;
575     }
576
577     private setEmptyValue() {
578         const property1 = this.$scope.editPropertyModel.property;
579         property1.value = undefined;
580         if (this.isComplexType(property1.type)) {
581             this.initEmptyComplexValue(property1.type);
582             return;
583         }
584         this.$scope.myValue = '';
585     }
586
587     private updateInstanceProperties = (componentInstanceId:string, properties:PropertyModel[]):Observable<PropertyModel[]> => {
588
589         return this.ComponentInstanceServiceNg2.updateInstanceProperties(this.workspaceService.metadata.componentType, this.workspaceService.metadata.uniqueId, componentInstanceId, properties)
590             .map(newProperties => {
591                 newProperties.forEach((newProperty) => {
592                     if (!_.isNil(newProperty.path)) {
593                         if (newProperty.path[0] === newProperty.resourceInstanceUniqueId) newProperty.path.shift();
594                         // find exist instance property in parent component for update the new value ( find bu uniqueId & path)
595                         let existProperty: PropertyModel = <PropertyModel>_.find(this.compositionService.componentInstancesProperties[newProperty.resourceInstanceUniqueId], {
596                             uniqueId: newProperty.uniqueId,
597                             path: newProperty.path
598                         });
599                         let index = this.compositionService.componentInstancesProperties[newProperty.resourceInstanceUniqueId].indexOf(existProperty);
600                         this.compositionService.componentInstancesProperties[newProperty.resourceInstanceUniqueId][index] = newProperty;
601                     }
602                 });
603                 return newProperties;
604             });
605     };
606
607     private addOrUpdateProperty = (property: PropertyModel): Observable<PropertyModel> => {
608         if (!property.uniqueId) {
609             let onSuccess = (newProperty: PropertyModel): PropertyModel => {
610                 this.filteredProperties.push(newProperty);
611                 return newProperty;
612             };
613             return this.topologyTemplateService.addProperty(this.workspaceService.metadata.componentType, this.workspaceService.metadata.uniqueId, property)
614                 .map(onSuccess);
615         } else {
616             let onSuccess = (newProperty: PropertyModel): PropertyModel => {
617                 // find exist instance property in parent component for update the new value ( find bu uniqueId )
618                 let existProperty: PropertyModel = <PropertyModel>_.find(this.filteredProperties, {uniqueId: newProperty.uniqueId});
619                 let propertyIndex = this.filteredProperties.indexOf(existProperty);
620                 this.filteredProperties[propertyIndex] = newProperty;
621                 return newProperty;
622             };
623             return this.topologyTemplateService.updateProperty(this.workspaceService.metadata.componentType, this.workspaceService.metadata.uniqueId, property).map(onSuccess);
624         }
625     };
626
627     public deleteProperty = (propertyId:string):Observable<void> => {
628         let onSuccess = ():void => {
629             console.debug("Property deleted");
630             delete _.remove(this.filteredProperties, {uniqueId: propertyId})[0];
631         };
632         let onFailed = ():void => {
633             console.debug("Failed to delete property");
634         };
635         return this.topologyTemplateService.deleteProperty(this.workspaceService.metadata.componentType, this.workspaceService.metadata.uniqueId, propertyId).map(onSuccess, onFailed);
636     };
637
638 }