[SDC-29] catalog 1707 rebase commit.
[sdc.git] / catalog-ui / src / app / ng2 / pages / properties-assignment / properties-assignment.page.component.ts
1 import {Component, ViewChild, ElementRef, Renderer, Inject} from "@angular/core";
2 import {PostsService} from "../../services/posts.service";
3 import {PropertiesService, SimpleFlatProperty} from "../../services/properties.service";
4 import { PropertiesUtils } from './properties.utils';
5 import { PropertyFEModel, InstanceFePropertiesMap, InstanceBePropertiesMap, InstancePropertiesAPIMap, Component as ComponentData, FilterPropertiesAssignmentData } from "app/models";
6 import { PROPERTY_TYPES, ResourceType } from "app/utils";
7 import property = require("lodash/property");
8 import {ComponentServiceNg2} from "../../services/component-services/component.service";
9 import {ComponentInstanceServiceNg2} from "../../services/component-instance-services/component-instance.service"
10 import {InputFEModel, ComponentInstance, PropertyBEModel, DerivedFEProperty, ResourceInstance} from "app/models";
11 import {HierarchyDisplayOptions} from "../../components/hierarchy-navigtion/hierarchy-display-options"
12 import {PropertyRowSelectedEvent} from "./../../components/properties-table/properties-table.component";
13 import { KeysPipe } from 'app/ng2/pipes/keys.pipe';
14 import {FilterPropertiesAssignmentComponent} from "../../components/filter-properties-assignment/filter-properties-assignment.component";
15
16 @Component({
17     templateUrl: './properties-assignment.page.component.html',
18     styleUrls: ['./properties-assignment.page.component.less']
19 })
20 export class PropertiesAssignmentComponent {
21     title = "Properties & Inputs";
22
23     component:ComponentData;
24
25     propertiesNavigationData = [];
26     instancesNavigationData = [];
27
28     instanceFePropertiesMap:InstanceFePropertiesMap;
29     inputs: Array<InputFEModel> = [];
30     instances: Array<ComponentInstance> = [];
31     searchQuery: string;
32     propertyStructureHeader: string
33
34     selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
35     selectedInstanceType: string;
36     selectedInstanceData: ComponentInstance = new ComponentInstance();
37     checkedPropertiesCount: number = 0;
38
39     hierarchyPropertiesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name', 'childrens');
40     hierarchyInstancesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name');
41     displayClearSearch = false;
42     searchPropertyName:string;
43     hideAdvanceSearch:boolean;
44
45     @ViewChild('hierarchyNavTabs') hierarchyNavTabs: ElementRef;
46     @ViewChild('propertyInputTabs') propertyInputTabs: ElementRef;
47     @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
48
49     constructor(private propertiesService:PropertiesService,
50                 private propertiesUtils:PropertiesUtils,
51                 private componentServiceNg2:ComponentServiceNg2,
52                 private componentInstanceServiceNg2:ComponentInstanceServiceNg2,
53                 @Inject("$stateParams") _stateParams,
54                 private renderer: Renderer) {
55
56         this.instanceFePropertiesMap = new InstanceFePropertiesMap();
57
58         /* 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
59         than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
60         this.component = _stateParams.component;
61     }
62
63     ngOnInit() {
64         console.log("==>" + this.constructor.name + ": ngOnInit");
65         this.componentServiceNg2
66             .getComponentResourceInstances(this.component)
67             .subscribe(response => {
68                 this.instances = response.componentInstances;
69
70                 _.forEach(this.instances, (instance) => {
71                     this.instancesNavigationData.push(instance);
72                 });
73
74                 this.selectFirstInstanceByDefault();
75             });
76
77         this.componentServiceNg2
78             .getComponentInputs(this.component)
79             .subscribe(response => {
80                 _.forEach(response.inputs, (input: PropertyBEModel) => {
81                     this.inputs.push(new InputFEModel(input));
82                 });
83             })
84     }
85
86     selectFirstInstanceByDefault = () => {
87         if (this.instancesNavigationData[0] !== undefined) {
88             this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
89         }
90     }
91
92     propertyValueChanged = (event) => {
93         console.log("==>" + this.constructor.name + ": propertyValueChanged " + event);
94
95         if(this.selectedInstanceData.originType === ResourceType.VF) {
96             console.log("I want to update input value on the resource instance");
97             let inputToUpdate = new PropertyBEModel(event);
98             this.componentInstanceServiceNg2
99                 .updateInstanceInput(this.component, this.selectedInstanceData.uniqueId, inputToUpdate)
100                 .subscribe(response => {
101                     console.log("update resource instance input and got this response: ",response);
102                 })
103         }
104         else {
105             // Copying the actual value from the object ref into the value if it's from a complex type
106             if(event.isDataType) {
107                 event.value = JSON.stringify(event.valueObjectRef);
108             }
109             let propertyBe = new PropertyBEModel(event);
110             this.componentInstanceServiceNg2
111                 .updateInstanceProperty(this.component, this.selectedInstanceData.uniqueId, propertyBe)
112                 .subscribe(response => {
113                     console.log("updated resource instance property and got this response: ",response);
114                 });
115             console.log(event);
116         }
117
118     };
119
120     inputValueChanged = (event) => {
121         console.log("==>" + this.constructor.name + ": inputValueChanged");
122         let inputToUpdate = new PropertyBEModel(event);
123
124         this.componentServiceNg2
125             .updateComponentInput(this.component, inputToUpdate)
126             .subscribe(response => {
127                 console.log("updated the component input and got this response: ", response);
128             })
129     };
130
131     declareProperties = ():void => {
132         console.log("==>" + this.constructor.name + ": declareProperties");
133
134         let selectedProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
135
136         let instancesNames = new KeysPipe().transform(this.instanceFePropertiesMap,[]);
137         angular.forEach(instancesNames, (instanceName:string):void=>{
138             selectedProperties[instanceName] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceName]);
139             //selectedProperties[this.selectedInstanceData.uniqueId] = this.propertiesService.getCheckedProperties(this.properties);
140         });
141
142         let inputsToCreate: InstancePropertiesAPIMap;
143         if (this.selectedInstanceType !== ResourceType.VF) {
144             inputsToCreate = new InstancePropertiesAPIMap(null, selectedProperties);
145         } else {
146             inputsToCreate = new InstancePropertiesAPIMap(selectedProperties, null);
147         }
148         this.componentServiceNg2
149             .createInput(this.component, inputsToCreate)
150             .subscribe(response => {
151                 this.setInputTabIndication(response.length);
152                 this.checkedPropertiesCount = 0;
153                 _.forEach(response, (input: PropertyBEModel) => { this.inputs.push(new InputFEModel(input)); });
154                 this.findAndDisableDeclaredProperties();
155             });
156     }
157
158     //TODO: Can remove? no one use it
159     // getSelectedFEProps = (): Array<PropertyFEModel> => {
160     //     return this.properties.filter(prop => prop.isSelected && !prop.isDeclared);
161     // }
162
163     onInstanceSelectedUpdate = (resourceInstance: ResourceInstance) => {
164         console.log("==>" + this.constructor.name + ": onInstanceSelectedUpdate");
165         let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
166         this.selectedInstanceData = resourceInstance;
167         this.selectedInstanceType = resourceInstance.originType;
168
169         if(resourceInstance.originType === ResourceType.VF) {
170             this.componentInstanceServiceNg2
171                 .getComponentInstanceInputs(this.component, resourceInstance)
172                 .subscribe(response => {
173                     instanceBePropertiesMap[resourceInstance.uniqueId] = response;
174                     this.processInstancePropertiesResponse(instanceBePropertiesMap);
175                 });
176         } else {
177             this.componentInstanceServiceNg2
178                 .getComponentInstanceProperties(this.component, resourceInstance.uniqueId)
179                 .subscribe(response => {
180                     instanceBePropertiesMap[resourceInstance.uniqueId] = response;
181                     this.processInstancePropertiesResponse(instanceBePropertiesMap);
182                 });
183         }
184
185         if( this.searchPropertyName ){
186             this.clearSearch();
187         }
188     };
189
190     /**
191      * Entry point handling response from server
192      */
193     processInstancePropertiesResponse = (instanceBePropertiesMap:InstanceBePropertiesMap) => {
194         this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap); //create flattened children
195         this.findAndDisableDeclaredProperties(); //disable properties or flattened children that are declared
196         this.checkedPropertiesCount = 0;
197     };
198
199     /**
200      * Handle select node in navigation area, and select the row in table
201      */
202     onPropertySelectedUpdate = ($event) => {
203         console.log("==>" + this.constructor.name + ": onPropertySelectedUpdate");
204         this.selectedFlatProperty = $event;
205         let parentProperty:PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
206         parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
207     };
208
209     /**
210      * When user select row in table, this will prepare the hirarchy object for the tree.
211      */
212     selectPropertyRow = (propertyRowSelectedEvent:PropertyRowSelectedEvent) => {
213         console.log("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
214         let property = propertyRowSelectedEvent.propertyModel;
215         let instanceName = propertyRowSelectedEvent.instanceName;
216         this.propertyStructureHeader = null;
217
218         // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
219         if(this.selectedInstanceData.originType !== ResourceType.VF) {
220             let simpleFlatProperty:Array<SimpleFlatProperty>;
221             if (property instanceof PropertyFEModel) {
222                 simpleFlatProperty = this.propertiesService.getSimplePropertiesTree(property, instanceName);
223             } else if (property instanceof DerivedFEProperty) {
224                 // Need to find parent PropertyFEModel
225                 let parentPropertyFEModel:PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty):boolean => {
226                     return property.propertiesName.indexOf(tmpFeProperty.name)===0;
227                 });
228                 simpleFlatProperty = this.propertiesService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
229             }
230             this.propertiesNavigationData = simpleFlatProperty;
231         }
232
233         // Updatet the header in the navigation tree with property name.
234         if(property instanceof DerivedFEProperty) {
235             this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
236         }
237
238         // Set selected property in table
239         this.selectedFlatProperty = new SimpleFlatProperty(property.uniqueId, null, property.name, null);
240         this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Property Structure']);
241     };
242
243     //TODO: Can remove? no one use it
244     // findParentProperty = (childProp: DerivedFEProperty): PropertyFEModel => {
245     //     return this.properties.find(prop => prop.name == childProp.propertiesName.substring(0, childProp.propertiesName.indexOf("#")));
246     // }
247
248     //used for declare button, to keep count of newly checked properties (and ignore declared properties)
249     updateCheckedPropertyCount = (increment: boolean):void => {
250         this.checkedPropertiesCount += (increment) ? 1 : -1;
251         console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount);
252     }
253
254     selectInstanceRow = ($event) => {//get instance name
255         this.selectedInstanceData =  _.find(this.instancesNavigationData, (instance:ComponentInstance) => {
256             return instance.name == $event;
257         });
258         this.renderer.invokeElementMethod(
259             this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
260     }
261
262     tabChanged = (event) => {
263         console.log("==>" + this.constructor.name + ": tabChanged " + event);
264         this.hideAdvanceSearch = event.title !== "Properties";
265         this.searchQuery = '';
266     };
267
268     deleteInput = (input:InputFEModel) => {
269         console.log("==>" + this.constructor.name + ": deleteInput");
270         let inputToDelete = new PropertyBEModel(input);
271
272         this.componentServiceNg2
273             .deleteInput(this.component, inputToDelete)
274             .subscribe(response => {
275                 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
276                 let propToEnable: PropertyFEModel = this.instanceFePropertiesMap[input.instanceName].find(prop => prop.name == input.propertyName);
277                 propToEnable.setNonDeclared(response.inputPath);
278                 this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
279                 //this.propertiesService.initValueObjectRef(propToEnable); //TODO:speak to BE about value returned by server
280             });
281     }
282
283     setInputTabIndication = (numInputs: number): void => {
284         this.renderer.invokeElementMethod( this.propertyInputTabs, 'setTabIndication', ['Inputs', numInputs]);
285     }
286
287     findAndDisableDeclaredProperties = () => {
288         this.inputs.filter(input => input.instanceName === this.selectedInstanceData.normalizedName).forEach(input => {
289             let prop: PropertyFEModel = this.instanceFePropertiesMap[this.selectedInstanceData.uniqueId].find(prop => prop.name === input.propertyName);
290             if (prop) {
291                 prop.setAsDeclared(input.inputPath); //if a path was sent, its a child prop. this param is optional
292                 this.propertiesService.disableRelatedProperties(prop, input.inputPath)
293                 //this.propertiesService.initValueObjectRef(prop);
294             }
295         });
296     };
297
298     searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
299         //let filteredProperties = this.componentServiceNg2.filterComponentInstanceProperties(this.component, filterData);
300         let instanceBePropertiesMap:InstanceBePropertiesMap;
301         this.componentServiceNg2
302             .filterComponentInstanceProperties(this.component, filterData)
303             .subscribe(response => {
304                 //instanceBePropertiesMap=response;
305                 //console.log("================filter results=============");
306                 //console.table(instanceBePropertiesMap);
307                 this.processInstancePropertiesResponse(response);
308
309
310                 //this.properties = [];
311                 // _.forEach(instanceBePropertiesMap, (InstanceProperties:Array<PropertyBEModel>, instanceName:string) => {
312                 //     this.properties = this.properties.concat(this.propertiesService.convertPropertiesToFEAndCreateChildren(InstanceProperties, instanceName));
313                 // });
314
315
316                 // this.instancesNavigationData = _.filter(this.instancesNavigationData, (instance:ComponentInstance) => {
317                 //     return instanceBePropertiesMap[instance.name];
318                 // });
319
320                 // this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
321                 this.searchPropertyName = filterData.propertyName;//mark in table
322                 this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
323                 this.propertiesNavigationData = [];
324                 this.displayClearSearch = true;
325             });
326
327     };
328
329     clearSearch = () => {
330         this.instancesNavigationData = this.instances;
331         this.searchPropertyName = "";
332         this.hierarchyPropertiesDisplayOptions.searchText = "";
333         this.displayClearSearch = false;
334         this.advanceSearch.clearAll();
335     }
336
337     clickOnClearSearch = () => {
338         this.clearSearch();
339         this.selectFirstInstanceByDefault();
340         this.renderer.invokeElementMethod(
341             this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
342     }
343
344 }