Catalog alignment
[sdc.git] / catalog-ui / src / app / ng2 / pages / properties-assignment / properties-assignment.page.component.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 import * as _ from "lodash";
22 import { Component, ViewChild, Inject, TemplateRef } from "@angular/core";
23 import { PropertiesService } from "../../services/properties.service";
24 import { PropertyFEModel, InstanceFePropertiesMap, InstanceBePropertiesMap, InstancePropertiesAPIMap, Component as ComponentData, FilterPropertiesAssignmentData, ModalModel, ButtonModel } from "app/models";
25 import { ResourceType } from "app/utils";
26 import { ComponentServiceNg2 } from "../../services/component-services/component.service";
27 import { TopologyTemplateService } from "../../services/component-services/topology-template.service";
28 import { ComponentInstanceServiceNg2 } from "../../services/component-instance-services/component-instance.service"
29 import { InputBEModel, InputFEModel, ComponentInstance, GroupInstance, PolicyInstance, PropertyBEModel, DerivedFEProperty, SimpleFlatProperty } from "app/models";
30 import { KeysPipe } from 'app/ng2/pipes/keys.pipe';
31 import { WorkspaceMode, EVENTS, PROPERTY_TYPES } from "../../../utils/constants";
32 import { EventListenerService } from "app/services/event-listener-service"
33 import { HierarchyDisplayOptions } from "../../components/logic/hierarchy-navigtion/hierarchy-display-options";
34 import { FilterPropertiesAssignmentComponent } from "../../components/logic/filter-properties-assignment/filter-properties-assignment.component";
35 import { PropertyRowSelectedEvent } from "../../components/logic/properties-table/properties-table.component";
36 import { HierarchyNavService } from "./services/hierarchy-nav.service";
37 import { PropertiesUtils } from "./services/properties.utils";
38 import { ComponentModeService } from "../../services/component-services/component-mode.service";
39 import { Tabs, Tab } from "../../components/ui/tabs/tabs.component";
40 import { InputsUtils } from "./services/inputs.utils";
41 import { InstanceFeDetails } from "../../../models/instance-fe-details";
42 import { SdcUiServices, SdcUiCommon } from "onap-ui-angular";
43 import { UnsavedChangesComponent } from "app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component";
44 import {PropertyCreatorComponent} from "./property-creator/property-creator.component";
45 import {ModalService} from "../../services/modal.service";
46 import { DeclareListComponent } from "./declare-list/declare-list.component";
47 import { CapabilitiesGroup, Capability } from "../../../models/capability";
48 import { ToscaPresentationData } from "../../../models/tosca-presentation";
49 import { Observable } from "rxjs";
50
51 const SERVICE_SELF_TITLE = "SELF";
52 @Component({
53     templateUrl: './properties-assignment.page.component.html',
54     styleUrls: ['./properties-assignment.page.component.less']
55 })
56 export class PropertiesAssignmentComponent {
57     title = "Properties & Inputs";
58
59     component: ComponentData;
60     componentInstanceNamesMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();//instanceUniqueId, {name, iconClass}
61
62     propertiesNavigationData = [];
63     instancesNavigationData = [];
64
65     instanceFePropertiesMap:InstanceFePropertiesMap;
66     inputs: Array<InputFEModel> = [];
67     policies: Array<PolicyInstance> = [];
68     instances: Array<ComponentInstance|GroupInstance|PolicyInstance> = [];
69     searchQuery: string;
70     propertyStructureHeader: string;
71
72     selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
73     selectedInstanceData: ComponentInstance|GroupInstance|PolicyInstance = null;
74     checkedPropertiesCount: number = 0;
75     checkedChildPropertiesCount: number = 0;
76
77     hierarchyPropertiesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
78     hierarchyInstancesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name', 'archived', null, 'iconClass');
79     displayClearSearch = false;
80     searchPropertyName:string;
81     currentMainTab:Tab;
82     isInputsTabSelected:boolean;
83     isPropertiesTabSelected:boolean;
84     isPoliciesTabSelected:boolean;
85     isReadonly:boolean;
86     resourceIsReadonly:boolean;
87     loadingInstances:boolean = false;
88     loadingInputs:boolean = false;
89     loadingPolicies:boolean = false;
90     loadingProperties:boolean = false;
91     changedData:Array<PropertyFEModel|InputFEModel>;
92     hasChangedData:boolean;
93     isValidChangedData:boolean;
94     savingChangedData:boolean;
95     stateChangeStartUnregister:Function;
96     serviceBePropertiesMap: InstanceBePropertiesMap;
97     serviceBeCapabilitiesPropertiesMap: InstanceBePropertiesMap;
98     selectedInstance_FlattenCapabilitiesList: Capability[];
99
100     @ViewChild('hierarchyNavTabs') hierarchyNavTabs: Tabs;
101     @ViewChild('propertyInputTabs') propertyInputTabs: Tabs;
102     @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
103    
104     constructor(private propertiesService: PropertiesService,
105                 private hierarchyNavService: HierarchyNavService,
106                 private propertiesUtils:PropertiesUtils,
107                 private inputsUtils:InputsUtils,
108                 private componentServiceNg2:ComponentServiceNg2,
109                 private componentInstanceServiceNg2:ComponentInstanceServiceNg2,
110                 @Inject("$stateParams") _stateParams,
111                 @Inject("$scope") private $scope:ng.IScope,
112                 @Inject("$state") private $state:ng.ui.IStateService,
113                 @Inject("Notification") private Notification:any,
114                 private componentModeService:ComponentModeService,
115                 private EventListenerService:EventListenerService,
116                 private ModalServiceSdcUI: SdcUiServices.ModalService,
117                 private ModalService: ModalService,
118                 private keysPipe:KeysPipe,
119                 private topologyTemplateService: TopologyTemplateService) {
120
121         this.instanceFePropertiesMap = new InstanceFePropertiesMap();
122         /* This is the way you can access the component data, please do not use any data except metadata, all other data should be received from the new api calls on the first time
123         than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
124         this.component = _stateParams.component;
125         this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.onCheckout);
126         this.updateViewMode();
127
128         this.changedData = [];
129         this.updateHasChangedData();
130         this.isValidChangedData = true;
131     }
132
133     ngOnInit() {
134         console.log("==>" + this.constructor.name + ": ngOnInit");
135         this.loadingInputs = true;
136         this.loadingPolicies = true;
137         this.loadingInstances = true;
138         this.loadingProperties = true;
139         this.topologyTemplateService
140             .getComponentInputsWithProperties(this.component.componentType, this.component.uniqueId)
141             .subscribe(response => {
142                 _.forEach(response.inputs, (input: InputBEModel) => {
143                     const newInput: InputFEModel = new InputFEModel(input);
144                     this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
145                     this.inputs.push(newInput); //only push items that were declared via SDC
146                 });
147                 this.loadingInputs = false;
148
149             }, error => {}); //ignore error
150         this.componentServiceNg2
151             .getComponentResourcePropertiesData(this.component)
152             .subscribe(response => {
153                 this.loadingPolicies = false;
154                 this.instances = [];
155                 this.instances.push(...response.componentInstances);
156                 this.instances.push(...response.groupInstances);
157                 this.instances.push(...response.policies);
158
159                 _.forEach(response.policies, (policy: any) => {
160                     const newPolicy: InputFEModel = new InputFEModel(policy);
161                     this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
162                     this.policies.push(policy);
163                 });
164
165                 // add the service self instance to the top of the list.
166                 const serviceInstance = new ComponentInstance();
167                 serviceInstance.name = SERVICE_SELF_TITLE;
168                 serviceInstance.uniqueId = this.component.uniqueId;
169                 this.instances.unshift(serviceInstance);
170
171                 _.forEach(this.instances, (instance) => {
172                     this.instancesNavigationData.push(instance);
173                     this.componentInstanceNamesMap[instance.uniqueId] = <InstanceFeDetails>{name: instance.name, iconClass:instance.iconClass, originArchived:instance.originArchived};
174                 });
175                 this.loadingInstances = false;
176                 if (this.instancesNavigationData[0] == undefined) {
177                     this.loadingProperties = false;
178                 }
179                 this.selectFirstInstanceByDefault();
180             }, error => { this.loadingInstances = false; }); //ignore error
181
182         this.stateChangeStartUnregister = this.$scope.$on('$stateChangeStart', (event, toState, toParams) => {
183             // stop if has changed properties
184             if (this.hasChangedData) {
185                 event.preventDefault();
186                 this.showUnsavedChangesAlert().then(() => {
187                     this.$state.go(toState, toParams);
188                 }, () => {});
189             }
190         });
191     };
192
193     ngOnDestroy() {
194         this.EventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE);
195         this.stateChangeStartUnregister();
196     }
197
198     selectFirstInstanceByDefault = () => {
199         if (this.instancesNavigationData[0] !== undefined) {
200             this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
201         }
202     };
203
204     updateViewMode = () => {
205         this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW;
206     }
207
208     onCheckout = (component:ComponentData) => {
209         this.component = component;
210         this.updateViewMode();
211     }
212
213     isSelf = ():boolean => {
214         return this.selectedInstanceData && this.selectedInstanceData.uniqueId == this.component.uniqueId;
215     }
216
217     getServiceProperties(){
218         this.loadingProperties = false;
219         this.topologyTemplateService
220             .getServiceProperties(this.component.uniqueId)
221             .subscribe((response) => {
222                 this.serviceBePropertiesMap = new InstanceBePropertiesMap();
223                 this.serviceBePropertiesMap[this.component.uniqueId] = response;
224                 this.processInstancePropertiesResponse(this.serviceBePropertiesMap, false);
225                 this.loadingProperties = false;
226             }, (error) => {
227                 this.loadingProperties = false;
228             });
229     }
230
231     onInstanceSelectedUpdate = (instance: ComponentInstance|GroupInstance|PolicyInstance) => {
232         // stop if has changed properties
233         if (this.hasChangedData) {
234             this.showUnsavedChangesAlert().then((resolve)=> {
235                 this.changeSelectedInstance(instance)
236             }, (reject) => {
237             });
238             return;
239         }
240         this.changeSelectedInstance(instance);
241     };
242
243     changeSelectedInstance =  (instance: ComponentInstance|GroupInstance|PolicyInstance) => {
244         this.selectedInstanceData = instance;
245         this.loadingProperties = true;
246         if (instance instanceof ComponentInstance) {
247             let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
248             if (this.isInput(instance.originType)) {
249                 this.componentInstanceServiceNg2
250                     .getComponentInstanceInputs(this.component, instance)
251                     .subscribe(response => {
252                         instanceBePropertiesMap[instance.uniqueId] = response;
253                         this.processInstancePropertiesResponse(instanceBePropertiesMap, true);
254                         this.loadingProperties = false;
255                     }, error => {
256                     }); //ignore error
257             } else if (this.isSelf()) {
258                 this.getServiceProperties();
259             } else {
260                 this.componentInstanceServiceNg2
261                     .getComponentInstanceProperties(this.component, instance.uniqueId)
262                     .subscribe(response => {
263                         instanceBePropertiesMap[instance.uniqueId] = response;
264                         this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
265                         this.loadingProperties = false;
266                     }, error => {
267                     }); //ignore error
268             }
269
270             this.resourceIsReadonly = (instance.componentName === "vnfConfiguration");
271         } else if (instance instanceof GroupInstance) {
272             let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
273             this.componentInstanceServiceNg2
274                 .getComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
275                 .subscribe((response) => {
276                     instanceBePropertiesMap[instance.uniqueId] = response;
277                     this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
278                     this.loadingProperties = false;
279                 });
280         } else if (instance instanceof PolicyInstance) {
281             let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
282             this.componentInstanceServiceNg2
283                 .getComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId)
284                 .subscribe((response) => {
285                     instanceBePropertiesMap[instance.uniqueId] = response;
286                     this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
287                     this.loadingProperties = false;
288                 });
289         } else {
290             this.loadingProperties = false;
291         }
292
293         if (this.searchPropertyName) {
294             this.clearSearch();
295         }
296         //clear selected property from the navigation
297         this.selectedFlatProperty = new SimpleFlatProperty();
298         this.propertiesNavigationData = [];
299     };
300
301     /**
302      * Entry point handling response from server
303      */
304     processInstancePropertiesResponse = (instanceBePropertiesMap: InstanceBePropertiesMap, originTypeIsVF: boolean) => {
305         this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
306         this.checkedPropertiesCount = 0;
307         this.checkedChildPropertiesCount = 0;
308     };
309
310     processInstanceCapabilitiesPropertiesResponse = (originTypeIsVF: boolean) => {
311         let selectedComponentInstanceData = <ComponentInstance>(this.selectedInstanceData);
312         let currentUniqueId = this.selectedInstanceData.uniqueId;
313         this.serviceBeCapabilitiesPropertiesMap = new InstanceBePropertiesMap();
314         let isCapabilityOwnedByInstance: boolean;
315         this.serviceBeCapabilitiesPropertiesMap[currentUniqueId] = _.reduce(
316             this.selectedInstance_FlattenCapabilitiesList,
317             (result, cap: Capability) => {
318                 isCapabilityOwnedByInstance = cap.ownerId === currentUniqueId ||
319                     selectedComponentInstanceData.isServiceProxy() && cap.ownerId === selectedComponentInstanceData.sourceModelUid;
320                 if (cap.properties && isCapabilityOwnedByInstance) {
321                     _.forEach(cap.properties, prop => {
322                         if (!prop.origName) {
323                             prop.origName = prop.name;
324                             prop.name = cap.name + '_' + prop.name;//for display. (before save - the name returns to its orig value: prop.name)
325                         }
326                     });
327                     return result.concat(cap.properties);
328                 }
329                 return result;
330             }, []);
331         let instanceFECapabilitiesPropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(this.serviceBeCapabilitiesPropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
332         //update FECapabilitiesProperties with their origName according to BeCapabilitiesProperties
333         _.forEach(instanceFECapabilitiesPropertiesMap[currentUniqueId], prop => {
334             prop.origName = _.find(this.serviceBeCapabilitiesPropertiesMap[currentUniqueId], p => p.uniqueId === prop.uniqueId).origName;
335         });
336         //concatenate capabilitiesProps to all props list
337         this.instanceFePropertiesMap[currentUniqueId] = (this.instanceFePropertiesMap[currentUniqueId] || []).concat(instanceFECapabilitiesPropertiesMap[currentUniqueId]);
338         this.checkedPropertiesCount = 0;
339     };
340
341     isCapabilityProperty = (prop: PropertyBEModel) => {
342         return _.find(this.selectedInstance_FlattenCapabilitiesList, cap => cap.uniqueId === prop.parentUniqueId);
343     };
344
345     /*** VALUE CHANGE EVENTS ***/
346     dataChanged = (item:PropertyFEModel|InputFEModel) => {
347         let itemHasChanged;
348         if (this.isPropertiesTabSelected && item instanceof PropertyFEModel) {
349             itemHasChanged = item.hasValueObjChanged();
350         } else if (this.isInputsTabSelected && item instanceof InputFEModel) {
351             itemHasChanged = item.hasDefaultValueChanged();
352         } else if (this.isPoliciesTabSelected && item instanceof InputFEModel) {
353             itemHasChanged = item.hasDefaultValueChanged();
354         }
355
356         const dataChangedIdx = this.changedData.findIndex((changedItem) => changedItem === item);
357         if (itemHasChanged) {
358             if (dataChangedIdx === -1) {
359                 this.changedData.push(item);
360             }
361         } else {
362             if (dataChangedIdx !== -1) {
363                 this.changedData.splice(dataChangedIdx, 1);
364             }
365         }
366
367         if (this.isPropertiesTabSelected) {
368             this.isValidChangedData = this.changedData.every((changedItem) => (<PropertyFEModel>changedItem).valueObjIsValid);
369         } else if (this.isInputsTabSelected || this.isPoliciesTabSelected) {
370             this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid);
371         }
372         this.updateHasChangedData();
373     };
374
375
376     /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
377
378     /**
379      * Handle select node in navigation area, and select the row in table
380      */
381     onPropertySelectedUpdate = ($event) => {
382         console.log("==>" + this.constructor.name + ": onPropertySelectedUpdate");
383         this.selectedFlatProperty = $event;
384         let parentProperty:PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
385         parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
386     };
387
388     /**
389      * When user select row in table, this will prepare the hirarchy object for the tree.
390      */
391     selectPropertyRow = (propertyRowSelectedEvent:PropertyRowSelectedEvent) => {
392         console.log("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
393         let property = propertyRowSelectedEvent.propertyModel;
394         let instanceName = propertyRowSelectedEvent.instanceName;
395         this.propertyStructureHeader = null;
396
397         // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
398         if (!(this.selectedInstanceData instanceof ComponentInstance) || this.selectedInstanceData.originType !== ResourceType.VF) {
399             let simpleFlatProperty:Array<SimpleFlatProperty>;
400             if (property instanceof PropertyFEModel) {
401                 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
402             } else if (property instanceof DerivedFEProperty) {
403                 // Need to find parent PropertyFEModel
404                 let parentPropertyFEModel:PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty):boolean => {
405                     return property.propertiesName.indexOf(tmpFeProperty.name)===0;
406                 });
407                 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
408             }
409             this.propertiesNavigationData = simpleFlatProperty;
410         }
411
412         // Update the header in the navigation tree with property name.
413         this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
414
415         // Set selected property in table
416         this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
417         this.hierarchyNavTabs.triggerTabChange('Property Structure');
418     };
419
420
421     selectInstanceRow = ($event) => {//get instance name
422         this.selectedInstanceData =  _.find(this.instancesNavigationData, (instance:ComponentInstance) => {
423             return instance.name == $event;
424         });
425         this.hierarchyNavTabs.triggerTabChange('Composition');
426     };
427
428     tabChanged = (event) => {
429         // stop if has changed properties
430         if (this.hasChangedData) {
431             this.propertyInputTabs.triggerTabChange(this.currentMainTab.title);
432             this.showUnsavedChangesAlert().then((proceed) => {
433                 this.propertyInputTabs.selectTab(this.propertyInputTabs.tabs.find((tab) => tab.title === event.title));
434             }, ()=> {
435             });
436             return;
437         }
438
439         console.log("==>" + this.constructor.name + ": tabChanged " + event);
440         this.currentMainTab = this.propertyInputTabs.tabs.find((tab) => tab.title === event.title);
441         this.isPropertiesTabSelected = this.currentMainTab.title === "Properties";
442         this.isInputsTabSelected = this.currentMainTab.title === "Inputs";
443         this.isPoliciesTabSelected = this.currentMainTab.title === "Policies";
444         this.propertyStructureHeader = null;
445         this.searchQuery = '';
446     };
447
448
449
450     /*** DECLARE PROPERTIES/INPUTS ***/
451     declareProperties = (): void => {
452         console.log("==>" + this.constructor.name + ": declareProperties");
453
454         let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
455         let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
456         let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
457         let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
458         let instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
459
460         angular.forEach(instancesIds, (instanceId: string): void => {
461             let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
462             if (selectedInstanceData instanceof ComponentInstance) {
463                 if (!this.isInput(selectedInstanceData.originType)) {
464                     // convert Property FE model -> Property BE model, extract only checked
465                     selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
466                 } else {
467                     selectedComponentInstancesInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
468                 }
469             } else if (selectedInstanceData instanceof GroupInstance) {
470                 selectedGroupInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
471             } else if (selectedInstanceData instanceof PolicyInstance) {
472                 selectedPolicyInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
473             }
474         });
475
476         let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
477
478         //move changed capabilities properties from componentInstanceInputsMap obj to componentInstanceProperties
479         inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] =
480             (inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] || []).concat(
481                 _.filter(
482                     inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
483                     (prop: PropertyBEModel) => this.isCapabilityProperty(prop)
484                 )
485             );
486         inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId] = _.filter(
487             inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
488             prop => !this.isCapabilityProperty(prop)
489         );
490         if (inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId].length === 0) {
491             delete inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId];
492         }
493
494         let isCapabilityPropertyChanged = false;
495         _.forEach(
496             inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId],
497             (prop: PropertyBEModel) => {
498                 prop.name = prop.origName || prop.name;
499                 if (this.isCapabilityProperty(prop)) {
500                     isCapabilityPropertyChanged = true;
501                 }
502             }
503         );
504         this.topologyTemplateService
505             .createInput(this.component, inputsToCreate, this.isSelf())
506             .subscribe((response) => {
507                 this.setInputTabIndication(response.length);
508                 this.checkedPropertiesCount = 0;
509                 this.checkedChildPropertiesCount = 0;
510                 _.forEach(response, (input: InputBEModel) => {
511                     const newInput: InputFEModel = new InputFEModel(input);
512                     this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
513                     this.inputs.push(newInput);
514                     this.updatePropertyValueAfterDeclare(newInput);
515                 });
516                 if (isCapabilityPropertyChanged) {
517                     this.reloadInstanceCapabilities();
518                 }
519             }, error => {}); //ignore error
520     };
521
522     declareListProperties = (): void => {
523         console.log('declareListProperties() - enter');
524
525         // get selected properties
526         let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
527         let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
528         let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
529         let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
530         let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
531         let propertyNameList: Array<string> = [];
532         let insId :string;
533
534         angular.forEach(instancesIds, (instanceId: string): void => {
535             console.log("instanceId="+instanceId);
536             insId = instanceId;
537             let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
538             let checkedProperties: PropertyBEModel[] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
539
540             if (selectedInstanceData instanceof ComponentInstance) {
541                 if (!this.isInput(selectedInstanceData.originType)) {
542                     // convert Property FE model -> Property BE model, extract only checked
543                     selectedComponentInstancesProperties[instanceId] = checkedProperties;
544                 } else {
545                     selectedComponentInstancesInputs[instanceId] = checkedProperties;
546                 }
547             } else if (selectedInstanceData instanceof GroupInstance) {
548                 selectedGroupInstancesProperties[instanceId] = checkedProperties;
549             } else if (selectedInstanceData instanceof PolicyInstance) {
550                 selectedPolicyInstancesProperties[instanceId] = checkedProperties;
551             }
552
553             angular.forEach(checkedProperties, (property: PropertyBEModel) => {
554                 propertyNameList.push(property.name);
555             });
556         });
557
558         let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
559
560         let modalTitle = 'Declare Properties as List Input';
561         const modal = this.ModalService.createCustomModal(new ModalModel(
562             'sm', /* size */
563             modalTitle, /* title */
564             null, /* content */
565             [ /* buttons */
566                 new ButtonModel(
567                     'Save', /* text */
568                     'blue', /* css class */
569                     () => { /* callback */
570                         let content:any = modal.instance.dynamicContent.instance;
571
572                         /* listInput */
573                         let reglistInput: InstanceBePropertiesMap = new InstanceBePropertiesMap();
574                         let typelist: any = PROPERTY_TYPES.LIST;
575                         let uniID: any = insId;
576                         let boolfalse: any = false;
577                         let schem :any = {
578                             "empty": boolfalse,
579                             "property": {
580                                 "type": content.propertyModel.simpleType,
581                                 "required": boolfalse
582                             }
583                         }
584                         let schemaProp :any = {
585                             "type": content.propertyModel.simpleType,
586                             "required": boolfalse
587                         }
588
589                         reglistInput.description = content.propertyModel.description;
590                         reglistInput.name = content.propertyModel.name;
591                         reglistInput.type = typelist;
592                         reglistInput.schemaType = content.propertyModel.simpleType;
593                         reglistInput.instanceUniqueId = uniID;
594                         reglistInput.uniqueId = uniID;
595                         reglistInput.required =boolfalse;
596                         reglistInput.schema = schem;
597                         reglistInput.schemaProperty = schemaProp;
598
599                         let input = {
600                             componentInstInputsMap: content.inputsToCreate,
601                             listInput: reglistInput
602                         };
603                         console.log("save button clicked. input=", input);
604
605                         this.topologyTemplateService
606                         .createListInput(this.component.uniqueId, input, this.isSelf())
607                         .subscribe(response => {
608                             this.setInputTabIndication(response.length);
609                             this.checkedPropertiesCount = 0;
610                             this.checkedChildPropertiesCount = 0;
611                             _.forEach(response, (input: InputBEModel) => {
612                                 let newInput: InputFEModel = new InputFEModel(input);
613                                 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
614                                 this.inputs.push(newInput);
615                                 // create list input does not return updated properties info, so need to reload
616                                 //this.updatePropertyValueAfterDeclare(newInput);
617                                 // Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
618                                 this.changeSelectedInstance(this.selectedInstanceData);
619
620                                 modal.instance.close();
621                             });
622                         }, error => {}); //ignore error
623             
624                     }
625                     /*, getDisabled: function */
626                 ),
627                 new ButtonModel('Cancel', 'outline grey', () => {
628                     modal.instance.close();
629                 }),
630             ],
631             null /* type */
632         ));
633         // 3rd arg is passed to DeclareListComponent instance
634         this.ModalService.addDynamicContentToModal(modal, DeclareListComponent, {properties: inputsToCreate, propertyNameList: propertyNameList});
635         modal.instance.open();
636         console.log('declareListProperties() - leave');
637     };
638
639      /*** DECLARE PROPERTIES/POLICIES ***/
640      declarePropertiesToPolicies = (): void => {
641         let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
642         let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
643
644         angular.forEach(instancesIds, (instanceId: string): void => {
645             let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
646             if (selectedInstanceData instanceof ComponentInstance) {
647                 if (!this.isInput(selectedInstanceData.originType)) {
648                     selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
649                 }
650             }
651         });
652
653         let policiesToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(null, selectedComponentInstancesProperties, null, null);
654         this.loadingPolicies = true;
655
656         this.topologyTemplateService
657             .createPolicy(this.component, policiesToCreate, this.isSelf())
658             .subscribe(response => {
659                 this.setPolicyTabIndication(response.length);
660                 this.checkedPropertiesCount = 0;
661                 this.displayPoliciesAsDeclared(response);
662                 this.loadingPolicies = false;
663             }); //ignore error
664
665     }
666
667     displayPoliciesAsDeclared = (policies) => {
668         _.forEach(policies, (policy: any) => {
669             let newPolicy: InputFEModel = new InputFEModel(policy);
670             this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
671             newPolicy.relatedPropertyName = policy.name;
672             newPolicy.relatedPropertyValue = policy.value;
673             this.updatePropertyValueAfterDeclare(newPolicy);
674             this.policies.push(policy);
675         });
676     }
677
678     saveChangedData = ():Promise<(PropertyBEModel|InputBEModel)[]> => {
679         return new Promise((resolve, reject) => {
680             if (!this.isValidChangedData) {
681                 reject('Changed data is invalid - cannot save!');
682                 return;
683             }
684             if (!this.changedData.length) {
685                 resolve([]);
686                 return;
687             }
688
689             // make request and its handlers
690             let request;
691             let handleSuccess, handleError;
692             let changedInputsProperties = [], changedCapabilitiesProperties = [];
693             if (this.isPropertiesTabSelected) {
694                 const changedProperties: PropertyBEModel[] = this.changedData.map((changedProp) => {
695                     changedProp = <PropertyFEModel>changedProp;
696                     const propBE = new PropertyBEModel(changedProp);
697                     propBE.toscaPresentation = new ToscaPresentationData();
698                     propBE.toscaPresentation.ownerId = changedProp.parentUniqueId;
699                     propBE.value = changedProp.getJSONValue();
700                     propBE.name = changedProp.origName || changedProp.name;
701                     delete propBE.origName;
702                     return propBE;
703                 });
704                 changedCapabilitiesProperties = _.filter(changedProperties, prop => this.isCapabilityProperty(prop));
705
706                 if (this.selectedInstanceData instanceof ComponentInstance) {
707                     if (this.isInput(this.selectedInstanceData.originType)) {
708                         changedInputsProperties = _.filter(changedProperties, prop => !this.isCapabilityProperty(prop));
709                         if (changedInputsProperties.length && changedCapabilitiesProperties.length) {
710                             request = Observable.forkJoin(
711                                 this.componentInstanceServiceNg2.updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties),
712                                 this.componentInstanceServiceNg2.updateInstanceProperties(this.component.componentType, this.component.uniqueId,
713                                     this.selectedInstanceData.uniqueId, changedCapabilitiesProperties)
714                             );
715                         }
716                         else if (changedInputsProperties.length) {
717                             request = this.componentInstanceServiceNg2
718                                 .updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties);
719                         }
720                         else if (changedCapabilitiesProperties.length) {
721                             request = this.componentInstanceServiceNg2
722                                 .updateInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedCapabilitiesProperties);
723                         }
724                         handleSuccess = (response) => {
725                             // reset each changed property with new value and remove it from changed properties list
726                             response.forEach((resInput) => {
727                                 const changedProp = <PropertyFEModel>this.changedData.shift();
728                                 this.propertiesUtils.resetPropertyValue(changedProp, resInput.value);
729                             });
730                             console.log('updated instance inputs:', response);
731                         };
732                     } else {
733                         if (this.isSelf()) {
734                             request = this.topologyTemplateService.updateServiceProperties(this.component.uniqueId,  _.map(changedProperties, cp => {
735                                 delete cp.constraints;
736                                 return cp;
737                             }));
738                         } else {
739                             request = this.componentInstanceServiceNg2
740                                 .updateInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
741                         }
742                         handleSuccess = (response) => {
743                             // reset each changed property with new value and remove it from changed properties list
744                             response.forEach((resProp) => {
745                                 const changedProp = <PropertyFEModel>this.changedData.shift();
746                                 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
747                             });
748                             resolve(response);
749                             console.log("updated instance properties: ", response);
750                         };
751                     }
752                 } else if (this.selectedInstanceData instanceof GroupInstance) {
753                     request = this.componentInstanceServiceNg2
754                         .updateComponentGroupInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
755                     handleSuccess = (response) => {
756                         // reset each changed property with new value and remove it from changed properties list
757                         response.forEach((resProp) => {
758                             const changedProp = <PropertyFEModel>this.changedData.shift();
759                             this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
760                         });
761                         resolve(response);
762                         console.log("updated group instance properties: ", response);
763                     };
764                 } else if (this.selectedInstanceData instanceof PolicyInstance) {
765                     request = this.componentInstanceServiceNg2
766                         .updateComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
767                     handleSuccess = (response) => {
768                         // reset each changed property with new value and remove it from changed properties list
769                         response.forEach((resProp) => {
770                             const changedProp = <PropertyFEModel>this.changedData.shift();
771                             this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
772                         });
773                         resolve(response);
774                         console.log("updated policy instance properties: ", response);
775                     };
776                 }
777             } else if (this.isInputsTabSelected) {
778             
779                 const changedInputs: InputBEModel[] = this.changedData.map((changedInput) => {
780                     changedInput = <InputFEModel>changedInput;
781                     const inputBE = new InputBEModel(changedInput);
782                     inputBE.defaultValue = changedInput.getJSONDefaultValue();
783                     return inputBE;
784                 });
785                 request = this.componentServiceNg2
786                     .updateComponentInputs(this.component, changedInputs);
787                 handleSuccess = (response) => {
788                     // reset each changed property with new value and remove it from changed properties list
789                     response.forEach((resInput) => {
790                         const changedInput = <InputFEModel>this.changedData.shift();
791                         this.inputsUtils.resetInputDefaultValue(changedInput, resInput.defaultValue);
792                     });
793                     console.log("updated the component inputs and got this response: ", response);
794                 }
795             }
796
797             this.savingChangedData = true;
798             request.subscribe(
799                 (response) => {
800                     this.savingChangedData = false;
801                     if (changedCapabilitiesProperties.length) {
802                         this.reloadInstanceCapabilities();
803                     }
804                     handleSuccess && handleSuccess(response);
805                     this.updateHasChangedData();
806                     resolve(response);
807                 },
808                 (error) => {
809                     this.savingChangedData = false;
810                     handleError && handleError(error);
811                     this.updateHasChangedData();
812                     reject(error);
813                 }
814             );
815         });
816     };
817
818     reloadInstanceCapabilities = (): void => {
819         let currentInstanceIndex = _.findIndex(this.instances, instance => instance.uniqueId == this.selectedInstanceData.uniqueId);
820         this.componentServiceNg2.getComponentResourceInstances(this.component).subscribe(result => {
821             let instanceCapabilitiesData: CapabilitiesGroup = _.reduce(result.componentInstances, (res, instance) => {
822                 if (instance.uniqueId === this.selectedInstanceData.uniqueId) {
823                     return instance.capabilities;
824                 }
825                 return res;
826             }, new CapabilitiesGroup());
827             (<ComponentInstance>this.instances[currentInstanceIndex]).capabilities = instanceCapabilitiesData;
828         });
829     };
830
831     reverseChangedData = ():void => {
832         // make reverse item handler
833         let handleReverseItem;
834         if (this.isPropertiesTabSelected) {
835             handleReverseItem = (changedItem) => {
836                 changedItem = <PropertyFEModel>changedItem;
837                 this.propertiesUtils.resetPropertyValue(changedItem, changedItem.value);
838                 this.checkedPropertiesCount = 0;
839                 this.checkedChildPropertiesCount = 0;
840             };
841         } else if (this.isInputsTabSelected) {
842             handleReverseItem = (changedItem) => {
843                 changedItem = <InputFEModel>changedItem;
844                 this.inputsUtils.resetInputDefaultValue(changedItem, changedItem.defaultValue);
845             };
846         }
847
848         this.changedData.forEach(handleReverseItem);
849         this.changedData = [];
850         this.updateHasChangedData();
851     };
852
853     updateHasChangedData = ():boolean => {
854         const curHasChangedData:boolean = (this.changedData.length > 0);
855         if (curHasChangedData !== this.hasChangedData) {
856             this.hasChangedData = curHasChangedData;
857             if(this.hasChangedData) {
858                 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.hasChangedData, this.showUnsavedChangesAlert);
859             } else {
860                 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
861             }
862         } 
863         return this.hasChangedData;
864     };
865
866     doSaveChangedData = (onSuccessFunction?:Function, onError?:Function):void => {
867         this.saveChangedData().then(
868             () => {
869                 this.Notification.success({
870                     message: 'Successfully saved changes',
871                     title: 'Saved'
872                 });
873                 if(onSuccessFunction) onSuccessFunction();
874                 if(this.isPropertiesTabSelected){
875                     this.checkedPropertiesCount = 0;
876                     this.checkedChildPropertiesCount = 0;
877                 }
878             },
879             () => {
880                 this.Notification.error({
881                     message: 'Failed to save changes!',
882                     title: 'Failure'
883                 });
884                 if(onError) onError();
885             }
886         );
887     };
888
889     showUnsavedChangesAlert = ():Promise<any> => {
890         let modalTitle:string;
891         if (this.isPropertiesTabSelected) {
892             modalTitle = `Unsaved properties for ${this.selectedInstanceData.name}`;
893         } else if (this.isInputsTabSelected) {
894             modalTitle = `Unsaved inputs for ${this.component.name}`;
895         }
896
897         return new Promise<any>((resolve, reject) => {
898             const modal = this.ModalServiceSdcUI.openCustomModal(
899                 {
900                     title: modalTitle,
901                     size: 'sm',
902                     type: SdcUiCommon.ModalType.custom,
903                     testId: "navigate-modal",
904
905                     buttons: [
906                         {id: 'cancelButton', text: 'Cancel', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => reject()},
907                         {id: 'discardButton', text: 'Discard', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => { this.reverseChangedData(); resolve()}},
908                         {id: 'saveButton', text: 'Save', type: SdcUiCommon.ButtonType.primary, size: 'xsm', closeModal: true, disabled: !this.isValidChangedData, callback: () => this.doSaveChangedData(resolve, reject)}
909                 ] as SdcUiCommon.IModalButtonComponent[]
910             } as SdcUiCommon.IModalConfig, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
911         });
912
913     }
914
915     updatePropertyValueAfterDeclare = (input: InputFEModel) => {
916         if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
917             const instanceName = input.instanceUniqueId.slice(input.instanceUniqueId.lastIndexOf('.') + 1);
918             const propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
919                 return feProperty.name == input.relatedPropertyName &&
920                     (feProperty.name == input.relatedPropertyName || input.name === instanceName.concat('_').concat(feProperty.name.replace(/[.]/g, '_')));
921             });
922             const inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
923             propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
924             this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
925             this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
926         }
927     }
928
929     //used for declare button, to keep count of newly checked properties (and ignore declared properties)
930     updateCheckedPropertyCount = (increment: boolean): void => {
931         this.checkedPropertiesCount += (increment) ? 1 : -1;
932         console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount);
933     };
934
935     updateCheckedChildPropertyCount = (increment: boolean): void => {
936         this.checkedChildPropertiesCount += (increment) ? 1 : -1;
937     };
938
939     setInputTabIndication = (numInputs: number): void => {
940         this.propertyInputTabs.setTabIndication('Inputs', numInputs);
941     };
942
943     setPolicyTabIndication = (numPolicies: number): void => {
944         this.propertyInputTabs.setTabIndication('Policies', numPolicies);
945     }
946
947     resetUnsavedChangesForInput = (input:InputFEModel) => {
948         this.inputsUtils.resetInputDefaultValue(input, input.defaultValue);
949         this.changedData = this.changedData.filter((changedItem) => changedItem.uniqueId !== input.uniqueId);
950         this.updateHasChangedData();
951     }
952
953     deleteInput = (input: InputFEModel) => {
954         //reset any unsaved changes to the input before deleting it
955         this.resetUnsavedChangesForInput(input);
956
957         console.log("==>" + this.constructor.name + ": deleteInput");
958         let inputToDelete = new InputBEModel(input);
959
960         this.componentServiceNg2
961             .deleteInput(this.component, inputToDelete)
962             .subscribe(response => {
963                 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
964
965                 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
966                 this.changeSelectedInstance(this.selectedInstanceData);
967                 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
968
969                 // if (instanceFeProperties) {
970                 //     let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
971                 //         return prop.name == input.propertyName;
972                 //     });
973
974                 //     if (propToEnable) {
975                 //         if (propToEnable.name == response.inputPath) response.inputPath = null;
976                 //         propToEnable.setNonDeclared(response.inputPath);
977                 //         //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
978                 //         this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
979                 //     }
980                 // }
981             }, error => {}); //ignore error
982     };
983
984     deletePolicy = (policy: PolicyInstance) => {
985         this.loadingPolicies = true;
986         this.topologyTemplateService
987             .deletePolicy(this.component, policy)
988             .subscribe((response) => {
989                 this.policies = this.policies.filter(policy => policy.uniqueId !== response.uniqueId);
990                 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
991                 this.changeSelectedInstance(this.selectedInstanceData);
992                 this.loadingPolicies = false;
993             });
994     };
995
996     deleteProperty = (property: PropertyFEModel) => {
997         const propertyToDelete = new PropertyFEModel(property);
998         this.loadingProperties = true;
999         const feMap = this.instanceFePropertiesMap;
1000         this.topologyTemplateService
1001             .deleteServiceProperty(this.component.uniqueId, propertyToDelete)
1002             .subscribe((response) => {
1003                 const props = feMap[this.component.uniqueId];
1004                 props.splice(props.findIndex(p => p.uniqueId === response),1);
1005                 this.loadingProperties = false;
1006             }, (error) => {
1007                 this.loadingProperties = false;
1008                 console.error(error);
1009             });
1010     }
1011
1012     /*** addProperty ***/
1013     addProperty = () => {
1014         let modalTitle = 'Add Property';
1015         let modal = this.ModalService.createCustomModal(new ModalModel(
1016             'sm',
1017             modalTitle,
1018             null,
1019             [
1020                 new ButtonModel('Save', 'blue', () => {
1021                     modal.instance.dynamicContent.instance.isLoading = true;
1022                     const newProperty: PropertyBEModel = modal.instance.dynamicContent.instance.propertyModel;
1023                     this.topologyTemplateService.createServiceProperty(this.component.uniqueId, newProperty)
1024                         .subscribe((response) => {
1025                             modal.instance.dynamicContent.instance.isLoading = false;
1026                             const newProp: PropertyFEModel = this.propertiesUtils.convertAddPropertyBAToPropertyFE(response);
1027                             this.instanceFePropertiesMap[this.component.uniqueId].push(newProp);
1028                             modal.instance.close();
1029                         }, (error) => {
1030                             modal.instance.dynamicContent.instance.isLoading = false;
1031                             this.Notification.error({
1032                                 message: 'Failed to add property:' + error,
1033                                 title: 'Failure'
1034                             });
1035                         });
1036                 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
1037                 new ButtonModel('Cancel', 'outline grey', () => {
1038                     modal.instance.close();
1039                 }),
1040             ],
1041             null
1042         ));
1043         this.ModalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
1044         modal.instance.open();
1045     }
1046
1047     /*** SEARCH RELATED FUNCTIONS ***/
1048     searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
1049         let instanceBePropertiesMap:InstanceBePropertiesMap;
1050         this.componentServiceNg2
1051             .filterComponentInstanceProperties(this.component, filterData)
1052             .subscribe((response) => {
1053                 this.processInstancePropertiesResponse(response, false);
1054                 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
1055                 this.searchPropertyName = filterData.propertyName;//mark in table
1056                 this.hierarchyNavTabs.triggerTabChange('Composition');
1057                 this.propertiesNavigationData = [];
1058                 this.displayClearSearch = true;
1059             }, (error) => {}); //ignore error
1060
1061     }
1062
1063     clearSearch = () => {
1064         this.instancesNavigationData = this.instances;
1065         this.searchPropertyName = "";
1066         this.hierarchyPropertiesDisplayOptions.searchText = "";
1067         this.displayClearSearch = false;
1068         this.advanceSearch.clearAll();
1069         this.searchQuery = '';
1070     };
1071
1072     clickOnClearSearch = () => {
1073         this.clearSearch();
1074         this.selectFirstInstanceByDefault();
1075         this.hierarchyNavTabs.triggerTabChange('Composition');
1076     };
1077
1078     private isInput = (instanceType:string):boolean =>{
1079         return instanceType === ResourceType.VF || instanceType === ResourceType.PNF || instanceType === ResourceType.CVFC || instanceType === ResourceType.CR;
1080     }
1081     
1082
1083 }