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