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