Fix create list input api call failure
[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() || selectedComponentInstanceData.isServiceSubstitution() && 
320                     cap.ownerId === selectedComponentInstanceData.sourceModelUid;
321                 if (cap.properties && isCapabilityOwnedByInstance) {
322                     _.forEach(cap.properties, prop => {
323                         if (!prop.origName) {
324                             prop.origName = prop.name;
325                             prop.name = cap.name + '_' + prop.name;//for display. (before save - the name returns to its orig value: prop.name)
326                         }
327                     });
328                     return result.concat(cap.properties);
329                 }
330                 return result;
331             }, []);
332         let instanceFECapabilitiesPropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(this.serviceBeCapabilitiesPropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
333         //update FECapabilitiesProperties with their origName according to BeCapabilitiesProperties
334         _.forEach(instanceFECapabilitiesPropertiesMap[currentUniqueId], prop => {
335             prop.origName = _.find(this.serviceBeCapabilitiesPropertiesMap[currentUniqueId], p => p.uniqueId === prop.uniqueId).origName;
336         });
337         //concatenate capabilitiesProps to all props list
338         this.instanceFePropertiesMap[currentUniqueId] = (this.instanceFePropertiesMap[currentUniqueId] || []).concat(instanceFECapabilitiesPropertiesMap[currentUniqueId]);
339         this.checkedPropertiesCount = 0;
340     };
341
342     isCapabilityProperty = (prop: PropertyBEModel) => {
343         return _.find(this.selectedInstance_FlattenCapabilitiesList, cap => cap.uniqueId === prop.parentUniqueId);
344     };
345
346     /*** VALUE CHANGE EVENTS ***/
347     dataChanged = (item:PropertyFEModel|InputFEModel) => {
348         let itemHasChanged;
349         if (this.isPropertiesTabSelected && item instanceof PropertyFEModel) {
350             itemHasChanged = item.hasValueObjChanged();
351         } else if (this.isInputsTabSelected && item instanceof InputFEModel) {
352             itemHasChanged = item.hasChanged();
353         } else if (this.isPoliciesTabSelected && item instanceof InputFEModel) {
354             itemHasChanged = item.hasDefaultValueChanged();
355         }
356
357         const dataChangedIdx = this.changedData.findIndex((changedItem) => changedItem === item);
358         if (itemHasChanged) {
359             if (dataChangedIdx === -1) {
360                 this.changedData.push(item);
361             }
362         } else {
363             if (dataChangedIdx !== -1) {
364                 this.changedData.splice(dataChangedIdx, 1);
365             }
366         }
367
368         if (this.isPropertiesTabSelected) {
369             this.isValidChangedData = this.changedData.every((changedItem) => (<PropertyFEModel>changedItem).valueObjIsValid);
370         } else if (this.isInputsTabSelected || this.isPoliciesTabSelected) {
371             this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid);
372         }
373         this.updateHasChangedData();
374     };
375
376
377     /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
378
379     /**
380      * Handle select node in navigation area, and select the row in table
381      */
382     onPropertySelectedUpdate = ($event) => {
383         console.log("==>" + this.constructor.name + ": onPropertySelectedUpdate");
384         this.selectedFlatProperty = $event;
385         let parentProperty:PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
386         parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
387     };
388
389     /**
390      * When user select row in table, this will prepare the hirarchy object for the tree.
391      */
392     selectPropertyRow = (propertyRowSelectedEvent:PropertyRowSelectedEvent) => {
393         console.log("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
394         let property = propertyRowSelectedEvent.propertyModel;
395         let instanceName = propertyRowSelectedEvent.instanceName;
396         this.propertyStructureHeader = null;
397
398         // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
399         if (!(this.selectedInstanceData instanceof ComponentInstance) || this.selectedInstanceData.originType !== ResourceType.VF) {
400             let simpleFlatProperty:Array<SimpleFlatProperty>;
401             if (property instanceof PropertyFEModel) {
402                 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
403             } else if (property instanceof DerivedFEProperty) {
404                 // Need to find parent PropertyFEModel
405                 let parentPropertyFEModel:PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty):boolean => {
406                     return property.propertiesName.indexOf(tmpFeProperty.name)===0;
407                 });
408                 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
409             }
410             this.propertiesNavigationData = simpleFlatProperty;
411         }
412
413         // Update the header in the navigation tree with property name.
414         this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
415
416         // Set selected property in table
417         this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
418         this.hierarchyNavTabs.triggerTabChange('Property Structure');
419     };
420
421
422     selectInstanceRow = ($event) => {//get instance name
423         this.selectedInstanceData =  _.find(this.instancesNavigationData, (instance:ComponentInstance) => {
424             return instance.name == $event;
425         });
426         this.hierarchyNavTabs.triggerTabChange('Composition');
427     };
428
429     tabChanged = (event) => {
430         // stop if has changed properties
431         if (this.hasChangedData) {
432             this.propertyInputTabs.triggerTabChange(this.currentMainTab.title);
433             this.showUnsavedChangesAlert().then((proceed) => {
434                 this.propertyInputTabs.selectTab(this.propertyInputTabs.tabs.find((tab) => tab.title === event.title));
435             }, ()=> {
436             });
437             return;
438         }
439
440         console.log("==>" + this.constructor.name + ": tabChanged " + event);
441         this.currentMainTab = this.propertyInputTabs.tabs.find((tab) => tab.title === event.title);
442         this.isPropertiesTabSelected = this.currentMainTab.title === "Properties";
443         this.isInputsTabSelected = this.currentMainTab.title === "Inputs";
444         this.isPoliciesTabSelected = this.currentMainTab.title === "Policies";
445         this.propertyStructureHeader = null;
446         this.searchQuery = '';
447     };
448
449
450
451     /*** DECLARE PROPERTIES/INPUTS ***/
452     declareProperties = (): void => {
453         console.log("==>" + this.constructor.name + ": declareProperties");
454
455         let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
456         let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
457         let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
458         let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
459         let instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
460
461         angular.forEach(instancesIds, (instanceId: string): void => {
462             let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
463             if (selectedInstanceData instanceof ComponentInstance) {
464                 if (!this.isInput(selectedInstanceData.originType)) {
465                     // convert Property FE model -> Property BE model, extract only checked
466                     selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
467                 } else {
468                     selectedComponentInstancesInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
469                 }
470             } else if (selectedInstanceData instanceof GroupInstance) {
471                 selectedGroupInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
472             } else if (selectedInstanceData instanceof PolicyInstance) {
473                 selectedPolicyInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
474             }
475         });
476
477         let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
478
479         //move changed capabilities properties from componentInstanceInputsMap obj to componentInstanceProperties
480         inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] =
481             (inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] || []).concat(
482                 _.filter(
483                     inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
484                     (prop: PropertyBEModel) => this.isCapabilityProperty(prop)
485                 )
486             );
487         inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId] = _.filter(
488             inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
489             prop => !this.isCapabilityProperty(prop)
490         );
491         if (inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId].length === 0) {
492             delete inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId];
493         }
494
495         let isCapabilityPropertyChanged = false;
496         _.forEach(
497             inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId],
498             (prop: PropertyBEModel) => {
499                 prop.name = prop.origName || prop.name;
500                 if (this.isCapabilityProperty(prop)) {
501                     isCapabilityPropertyChanged = true;
502                 }
503             }
504         );
505         this.topologyTemplateService
506             .createInput(this.component, inputsToCreate, this.isSelf())
507             .subscribe((response) => {
508                 this.setInputTabIndication(response.length);
509                 this.checkedPropertiesCount = 0;
510                 this.checkedChildPropertiesCount = 0;
511                 _.forEach(response, (input: InputBEModel) => {
512                     const newInput: InputFEModel = new InputFEModel(input);
513                     this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
514                     this.inputs.push(newInput);
515                     this.updatePropertyValueAfterDeclare(newInput);
516                 });
517                 if (isCapabilityPropertyChanged) {
518                     this.reloadInstanceCapabilities();
519                 }
520             }, error => {}); //ignore error
521     };
522
523     declareListProperties = (): void => {
524         console.log('declareListProperties() - enter');
525
526         // get selected properties
527         let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
528         let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
529         let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
530         let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
531         let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
532         let propertyNameList: Array<string> = [];
533         let insId :string;
534
535         angular.forEach(instancesIds, (instanceId: string): void => {
536             console.log("instanceId="+instanceId);
537             insId = instanceId;
538             let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
539             let checkedProperties: PropertyBEModel[] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
540
541             if (selectedInstanceData instanceof ComponentInstance) {
542                 if (!this.isInput(selectedInstanceData.originType)) {
543                     // convert Property FE model -> Property BE model, extract only checked
544                     selectedComponentInstancesProperties[instanceId] = checkedProperties;
545                 } else {
546                     selectedComponentInstancesInputs[instanceId] = checkedProperties;
547                 }
548             } else if (selectedInstanceData instanceof GroupInstance) {
549                 selectedGroupInstancesProperties[instanceId] = checkedProperties;
550             } else if (selectedInstanceData instanceof PolicyInstance) {
551                 selectedPolicyInstancesProperties[instanceId] = checkedProperties;
552             }
553
554             angular.forEach(checkedProperties, (property: PropertyBEModel) => {
555                 propertyNameList.push(property.name);
556             });
557         });
558
559         let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
560
561         let modalTitle = 'Declare Properties as List Input';
562         const modal = this.ModalService.createCustomModal(new ModalModel(
563             'sm', /* size */
564             modalTitle, /* title */
565             null, /* content */
566             [ /* buttons */
567                 new ButtonModel(
568                     'Save', /* text */
569                     'blue', /* css class */
570                     () => { /* callback */
571                         let content:any = modal.instance.dynamicContent.instance;
572
573                         /* listInput */
574                         let reglistInput: InstanceBePropertiesMap = new InstanceBePropertiesMap();
575                         let typelist: any = PROPERTY_TYPES.LIST;
576                         let uniID: any = insId;
577                         let boolfalse: any = false;
578                         let required: any = content.propertyModel.required;
579                         let schem :any = {
580                             "empty": boolfalse,
581                             "property": {
582                                 "type": content.propertyModel.simpleType,
583                                 "required": required
584                             }
585                         }
586                         let schemaProp :any = {
587                             "type": content.propertyModel.simpleType,
588                             "required": required
589                         }
590
591                         reglistInput.description = content.propertyModel.description;
592                         reglistInput.name = content.propertyModel.name;
593                         reglistInput.type = typelist;
594                         reglistInput.schemaType = content.propertyModel.simpleType;
595                         reglistInput.instanceUniqueId = uniID;
596                         reglistInput.uniqueId = uniID;
597                         reglistInput.required = required;
598                         reglistInput.schema = schem;
599                         reglistInput.schemaProperty = schemaProp;
600
601                         let input = {
602                             componentInstInputsMap: content.inputsToCreate,
603                             listInput: reglistInput
604                         };
605                         console.log("save button clicked. input=", input);
606
607                         this.topologyTemplateService
608                         .createListInput(this.component, input, this.isSelf())
609                         .subscribe(response => {
610                             this.setInputTabIndication(response.length);
611                             this.checkedPropertiesCount = 0;
612                             this.checkedChildPropertiesCount = 0;
613                             _.forEach(response, (input: InputBEModel) => {
614                                 let newInput: InputFEModel = new InputFEModel(input);
615                                 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
616                                 this.inputs.push(newInput);
617                                 // create list input does not return updated properties info, so need to reload
618                                 //this.updatePropertyValueAfterDeclare(newInput);
619                                 // Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
620                                 this.changeSelectedInstance(this.selectedInstanceData);
621
622                                 modal.instance.close();
623                             });
624                         }, error => {}); //ignore error
625             
626                     }
627                     /*, getDisabled: function */
628                 ),
629                 new ButtonModel('Cancel', 'outline grey', () => {
630                     modal.instance.close();
631                 }),
632             ],
633             null /* type */
634         ));
635         // 3rd arg is passed to DeclareListComponent instance
636         this.ModalService.addDynamicContentToModal(modal, DeclareListComponent, {properties: inputsToCreate, propertyNameList: propertyNameList});
637         modal.instance.open();
638         console.log('declareListProperties() - leave');
639     };
640
641      /*** DECLARE PROPERTIES/POLICIES ***/
642      declarePropertiesToPolicies = (): void => {
643         let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
644         let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
645
646         angular.forEach(instancesIds, (instanceId: string): void => {
647             let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
648             if (selectedInstanceData instanceof ComponentInstance) {
649                 if (!this.isInput(selectedInstanceData.originType)) {
650                     selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
651                 }
652             }
653         });
654
655         let policiesToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(null, selectedComponentInstancesProperties, null, null);
656         this.loadingPolicies = true;
657
658         this.topologyTemplateService
659             .createPolicy(this.component, policiesToCreate, this.isSelf())
660             .subscribe(response => {
661                 this.setPolicyTabIndication(response.length);
662                 this.checkedPropertiesCount = 0;
663                 this.displayPoliciesAsDeclared(response);
664                 this.loadingPolicies = false;
665             }); //ignore error
666
667     }
668
669     displayPoliciesAsDeclared = (policies) => {
670         _.forEach(policies, (policy: any) => {
671             let newPolicy: InputFEModel = new InputFEModel(policy);
672             this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
673             newPolicy.relatedPropertyName = policy.name;
674             newPolicy.relatedPropertyValue = policy.value;
675             this.updatePropertyValueAfterDeclare(newPolicy);
676             this.policies.push(policy);
677         });
678     }
679
680     saveChangedData = ():Promise<(PropertyBEModel|InputBEModel)[]> => {
681         return new Promise((resolve, reject) => {
682             if (!this.isValidChangedData) {
683                 reject('Changed data is invalid - cannot save!');
684                 return;
685             }
686             if (!this.changedData.length) {
687                 resolve([]);
688                 return;
689             }
690
691             // make request and its handlers
692             let request;
693             let handleSuccess, handleError;
694             let changedInputsProperties = [], changedCapabilitiesProperties = [];
695             if (this.isPropertiesTabSelected) {
696                 const changedProperties: PropertyBEModel[] = this.changedData.map((changedProp) => {
697                     changedProp = <PropertyFEModel>changedProp;
698                     const propBE = new PropertyBEModel(changedProp);
699                     propBE.toscaPresentation = new ToscaPresentationData();
700                     propBE.toscaPresentation.ownerId = changedProp.parentUniqueId;
701                     propBE.value = changedProp.getJSONValue();
702                     propBE.name = changedProp.origName || changedProp.name;
703                     delete propBE.origName;
704                     return propBE;
705                 });
706                 changedCapabilitiesProperties = _.filter(changedProperties, prop => this.isCapabilityProperty(prop));
707
708                 if (this.selectedInstanceData instanceof ComponentInstance) {
709                     if (this.isInput(this.selectedInstanceData.originType)) {
710                         changedInputsProperties = _.filter(changedProperties, prop => !this.isCapabilityProperty(prop));
711                         if (changedInputsProperties.length && changedCapabilitiesProperties.length) {
712                             request = Observable.forkJoin(
713                                 this.componentInstanceServiceNg2.updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties),
714                                 this.componentInstanceServiceNg2.updateInstanceProperties(this.component.componentType, this.component.uniqueId,
715                                     this.selectedInstanceData.uniqueId, changedCapabilitiesProperties)
716                             );
717                         }
718                         else if (changedInputsProperties.length) {
719                             request = this.componentInstanceServiceNg2
720                                 .updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties);
721                         }
722                         else if (changedCapabilitiesProperties.length) {
723                             request = this.componentInstanceServiceNg2
724                                 .updateInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedCapabilitiesProperties);
725                         }
726                         handleSuccess = (response) => {
727                             // reset each changed property with new value and remove it from changed properties list
728                             response.forEach((resInput) => {
729                                 const changedProp = <PropertyFEModel>this.changedData.shift();
730                                 this.propertiesUtils.resetPropertyValue(changedProp, resInput.value);
731                             });
732                             console.log('updated instance inputs:', response);
733                         };
734                     } else {
735                         if (this.isSelf()) {
736                             request = this.topologyTemplateService.updateServiceProperties(this.component.uniqueId,  _.map(changedProperties, cp => {
737                                 delete cp.constraints;
738                                 return cp;
739                             }));
740                         } else {
741                             request = this.componentInstanceServiceNg2
742                                 .updateInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
743                         }
744                         handleSuccess = (response) => {
745                             // reset each changed property with new value and remove it from changed properties list
746                             response.forEach((resProp) => {
747                                 const changedProp = <PropertyFEModel>this.changedData.shift();
748                                 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
749                             });
750                             resolve(response);
751                             console.log("updated instance properties: ", response);
752                         };
753                     }
754                 } else if (this.selectedInstanceData instanceof GroupInstance) {
755                     request = this.componentInstanceServiceNg2
756                         .updateComponentGroupInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
757                     handleSuccess = (response) => {
758                         // reset each changed property with new value and remove it from changed properties list
759                         response.forEach((resProp) => {
760                             const changedProp = <PropertyFEModel>this.changedData.shift();
761                             this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
762                         });
763                         resolve(response);
764                         console.log("updated group instance properties: ", response);
765                     };
766                 } else if (this.selectedInstanceData instanceof PolicyInstance) {
767                     request = this.componentInstanceServiceNg2
768                         .updateComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
769                     handleSuccess = (response) => {
770                         // reset each changed property with new value and remove it from changed properties list
771                         response.forEach((resProp) => {
772                             const changedProp = <PropertyFEModel>this.changedData.shift();
773                             this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
774                         });
775                         resolve(response);
776                         console.log("updated policy instance properties: ", response);
777                     };
778                 }
779             } else if (this.isInputsTabSelected) {
780             
781                 const changedInputs: InputBEModel[] = this.changedData.map((changedInput) => {
782                     changedInput = <InputFEModel>changedInput;
783                     const inputBE = new InputBEModel(changedInput);
784                     inputBE.defaultValue = changedInput.getJSONDefaultValue();
785                     return inputBE;
786                 });
787                 request = this.componentServiceNg2
788                     .updateComponentInputs(this.component, changedInputs);
789                 handleSuccess = (response) => {
790                     // reset each changed property with new value and remove it from changed properties list
791                     response.forEach((resInput) => {
792                         const changedInput = <InputFEModel>this.changedData.shift();
793                         this.inputsUtils.resetInputDefaultValue(changedInput, resInput.defaultValue);
794                         changedInput.required = resInput.required;
795                         changedInput.requiredOrig = resInput.required;
796                     });
797                     console.log("updated the component inputs and got this response: ", response);
798                 }
799             }
800
801             this.savingChangedData = true;
802             request.subscribe(
803                 (response) => {
804                     this.savingChangedData = false;
805                     if (changedCapabilitiesProperties.length) {
806                         this.reloadInstanceCapabilities();
807                     }
808                     handleSuccess && handleSuccess(response);
809                     this.updateHasChangedData();
810                     resolve(response);
811                 },
812                 (error) => {
813                     this.savingChangedData = false;
814                     handleError && handleError(error);
815                     this.updateHasChangedData();
816                     reject(error);
817                 }
818             );
819         });
820     };
821
822     reloadInstanceCapabilities = (): void => {
823         let currentInstanceIndex = _.findIndex(this.instances, instance => instance.uniqueId == this.selectedInstanceData.uniqueId);
824         this.componentServiceNg2.getComponentResourceInstances(this.component).subscribe(result => {
825             let instanceCapabilitiesData: CapabilitiesGroup = _.reduce(result.componentInstances, (res, instance) => {
826                 if (instance.uniqueId === this.selectedInstanceData.uniqueId) {
827                     return instance.capabilities;
828                 }
829                 return res;
830             }, new CapabilitiesGroup());
831             (<ComponentInstance>this.instances[currentInstanceIndex]).capabilities = instanceCapabilitiesData;
832         });
833     };
834
835     reverseChangedData = ():void => {
836         // make reverse item handler
837         let handleReverseItem;
838         if (this.isPropertiesTabSelected) {
839             handleReverseItem = (changedItem) => {
840                 changedItem = <PropertyFEModel>changedItem;
841                 this.propertiesUtils.resetPropertyValue(changedItem, changedItem.value);
842                 this.checkedPropertiesCount = 0;
843                 this.checkedChildPropertiesCount = 0;
844             };
845         } else if (this.isInputsTabSelected) {
846             handleReverseItem = (changedItem) => {
847                 changedItem = <InputFEModel>changedItem;
848                 this.inputsUtils.resetInputDefaultValue(changedItem, changedItem.defaultValue);
849                 changedItem.required = changedItem.requiredOrig;
850             };
851         }
852
853         this.changedData.forEach(handleReverseItem);
854         this.changedData = [];
855         this.updateHasChangedData();
856     };
857
858     updateHasChangedData = ():boolean => {
859         const curHasChangedData:boolean = (this.changedData.length > 0);
860         if (curHasChangedData !== this.hasChangedData) {
861             this.hasChangedData = curHasChangedData;
862             if(this.hasChangedData) {
863                 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.hasChangedData, this.showUnsavedChangesAlert);
864             } else {
865                 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
866             }
867         } 
868         return this.hasChangedData;
869     };
870
871     doSaveChangedData = (onSuccessFunction?:Function, onError?:Function):void => {
872         this.saveChangedData().then(
873             () => {
874                 this.Notification.success({
875                     message: 'Successfully saved changes',
876                     title: 'Saved'
877                 });
878                 if(onSuccessFunction) onSuccessFunction();
879                 if(this.isPropertiesTabSelected){
880                     this.checkedPropertiesCount = 0;
881                     this.checkedChildPropertiesCount = 0;
882                 }
883             },
884             () => {
885                 this.Notification.error({
886                     message: 'Failed to save changes!',
887                     title: 'Failure'
888                 });
889                 if(onError) onError();
890             }
891         );
892     };
893
894     showUnsavedChangesAlert = ():Promise<any> => {
895         let modalTitle:string;
896         if (this.isPropertiesTabSelected) {
897             modalTitle = `Unsaved properties for ${this.selectedInstanceData.name}`;
898         } else if (this.isInputsTabSelected) {
899             modalTitle = `Unsaved inputs for ${this.component.name}`;
900         }
901
902         return new Promise<any>((resolve, reject) => {
903             const modal = this.ModalServiceSdcUI.openCustomModal(
904                 {
905                     title: modalTitle,
906                     size: 'sm',
907                     type: SdcUiCommon.ModalType.custom,
908                     testId: "navigate-modal",
909
910                     buttons: [
911                         {id: 'cancelButton', text: 'Cancel', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => reject()},
912                         {id: 'discardButton', text: 'Discard', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => { this.reverseChangedData(); resolve()}},
913                         {id: 'saveButton', text: 'Save', type: SdcUiCommon.ButtonType.primary, size: 'xsm', closeModal: true, disabled: !this.isValidChangedData, callback: () => this.doSaveChangedData(resolve, reject)}
914                     ] as SdcUiCommon.IModalButtonComponent[]
915                 } as SdcUiCommon.IModalConfig, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
916         });
917
918     }
919
920     updatePropertyValueAfterDeclare = (input: InputFEModel) => {
921         if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
922             const instanceName = input.instanceUniqueId.slice(input.instanceUniqueId.lastIndexOf('.') + 1);
923             const propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
924                 return feProperty.name == input.relatedPropertyName &&
925                     (feProperty.name == input.relatedPropertyName || input.name === instanceName.concat('_').concat(feProperty.name.replace(/[.]/g, '_')));
926             });
927             const inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
928             propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
929             this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
930             this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
931         }
932     }
933
934     //used for declare button, to keep count of newly checked properties (and ignore declared properties)
935     updateCheckedPropertyCount = (increment: boolean): void => {
936         this.checkedPropertiesCount += (increment) ? 1 : -1;
937         console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount);
938     };
939
940     updateCheckedChildPropertyCount = (increment: boolean): void => {
941         this.checkedChildPropertiesCount += (increment) ? 1 : -1;
942     };
943
944     setInputTabIndication = (numInputs: number): void => {
945         this.propertyInputTabs.setTabIndication('Inputs', numInputs);
946     };
947
948     setPolicyTabIndication = (numPolicies: number): void => {
949         this.propertyInputTabs.setTabIndication('Policies', numPolicies);
950     }
951
952     resetUnsavedChangesForInput = (input:InputFEModel) => {
953         this.inputsUtils.resetInputDefaultValue(input, input.defaultValue);
954         this.changedData = this.changedData.filter((changedItem) => changedItem.uniqueId !== input.uniqueId);
955         this.updateHasChangedData();
956     }
957
958     deleteInput = (input: InputFEModel) => {
959         //reset any unsaved changes to the input before deleting it
960         this.resetUnsavedChangesForInput(input);
961
962         console.log("==>" + this.constructor.name + ": deleteInput");
963         let inputToDelete = new InputBEModel(input);
964
965         this.componentServiceNg2
966             .deleteInput(this.component, inputToDelete)
967             .subscribe(response => {
968                 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
969
970                 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
971                 this.changeSelectedInstance(this.selectedInstanceData);
972                 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
973
974                 // if (instanceFeProperties) {
975                 //     let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
976                 //         return prop.name == input.propertyName;
977                 //     });
978
979                 //     if (propToEnable) {
980                 //         if (propToEnable.name == response.inputPath) response.inputPath = null;
981                 //         propToEnable.setNonDeclared(response.inputPath);
982                 //         //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
983                 //         this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
984                 //     }
985                 // }
986             }, error => {}); //ignore error
987     };
988
989     deletePolicy = (policy: PolicyInstance) => {
990         this.loadingPolicies = true;
991         this.topologyTemplateService
992             .deletePolicy(this.component, policy)
993             .subscribe((response) => {
994                 this.policies = this.policies.filter(policy => policy.uniqueId !== response.uniqueId);
995                 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
996                 this.changeSelectedInstance(this.selectedInstanceData);
997                 this.loadingPolicies = false;
998             });
999     };
1000
1001     deleteProperty = (property: PropertyFEModel) => {
1002         const propertyToDelete = new PropertyFEModel(property);
1003         this.loadingProperties = true;
1004         const feMap = this.instanceFePropertiesMap;
1005         this.topologyTemplateService
1006             .deleteServiceProperty(this.component.uniqueId, propertyToDelete)
1007             .subscribe((response) => {
1008                 const props = feMap[this.component.uniqueId];
1009                 props.splice(props.findIndex(p => p.uniqueId === response),1);
1010                 this.loadingProperties = false;
1011             }, (error) => {
1012                 this.loadingProperties = false;
1013                 console.error(error);
1014             });
1015     }
1016
1017     /*** addProperty ***/
1018     addProperty = () => {
1019         let modalTitle = 'Add Property';
1020         let modal = this.ModalService.createCustomModal(new ModalModel(
1021             'sm',
1022             modalTitle,
1023             null,
1024             [
1025                 new ButtonModel('Save', 'blue', () => {
1026                     modal.instance.dynamicContent.instance.isLoading = true;
1027                     const newProperty: PropertyBEModel = modal.instance.dynamicContent.instance.propertyModel;
1028                     this.topologyTemplateService.createServiceProperty(this.component.uniqueId, newProperty)
1029                         .subscribe((response) => {
1030                             modal.instance.dynamicContent.instance.isLoading = false;
1031                             const newProp: PropertyFEModel = this.propertiesUtils.convertAddPropertyBAToPropertyFE(response);
1032                             this.instanceFePropertiesMap[this.component.uniqueId].push(newProp);
1033                             modal.instance.close();
1034                         }, (error) => {
1035                             modal.instance.dynamicContent.instance.isLoading = false;
1036                             this.Notification.error({
1037                                 message: 'Failed to add property:' + error,
1038                                 title: 'Failure'
1039                             });
1040                         });
1041                 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
1042                 new ButtonModel('Cancel', 'outline grey', () => {
1043                     modal.instance.close();
1044                 }),
1045             ],
1046             null
1047         ));
1048         this.ModalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
1049         modal.instance.open();
1050     }
1051
1052     /*** SEARCH RELATED FUNCTIONS ***/
1053     searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
1054         let instanceBePropertiesMap:InstanceBePropertiesMap;
1055         this.componentServiceNg2
1056             .filterComponentInstanceProperties(this.component, filterData)
1057             .subscribe((response) => {
1058                 this.processInstancePropertiesResponse(response, false);
1059                 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
1060                 this.searchPropertyName = filterData.propertyName;//mark in table
1061                 this.hierarchyNavTabs.triggerTabChange('Composition');
1062                 this.propertiesNavigationData = [];
1063                 this.displayClearSearch = true;
1064             }, (error) => {}); //ignore error
1065
1066     }
1067
1068     clearSearch = () => {
1069         this.instancesNavigationData = this.instances;
1070         this.searchPropertyName = "";
1071         this.hierarchyPropertiesDisplayOptions.searchText = "";
1072         this.displayClearSearch = false;
1073         this.advanceSearch.clearAll();
1074         this.searchQuery = '';
1075     };
1076
1077     clickOnClearSearch = () => {
1078         this.clearSearch();
1079         this.selectFirstInstanceByDefault();
1080         this.hierarchyNavTabs.triggerTabChange('Composition');
1081     };
1082
1083     private isInput = (instanceType:string):boolean =>{
1084         return instanceType === ResourceType.VF || instanceType === ResourceType.PNF || instanceType === ResourceType.CVFC || instanceType === ResourceType.CR;
1085     }
1086     
1087
1088 }