[SDC] rebase code
[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 { PropertiesService } from "../../services/properties.service";
3 import { HierarchyNavService } from "../../services/hierarchy-nav.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 { InputBEModel, InputFEModel, ComponentInstance, PropertyBEModel, DerivedPropertyType, DerivedFEProperty, ResourceInstance, SimpleFlatProperty } 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 import { ComponentModeService } from "app/ng2/services/component-mode.service"
16 import {WorkspaceMode, EVENTS} from "../../../utils/constants";
17 import {EventListenerService} from "app/services/event-listener-service"
18 @Component({
19     templateUrl: './properties-assignment.page.component.html',
20     styleUrls: ['./properties-assignment.page.component.less']
21 })
22 export class PropertiesAssignmentComponent {
23     title = "Properties & Inputs";
24
25     component:ComponentData;
26
27     propertiesNavigationData = [];
28     instancesNavigationData = [];
29
30     instanceFePropertiesMap:InstanceFePropertiesMap;
31     inputs: Array<InputFEModel> = [];
32     instances: Array<ComponentInstance> = [];
33     searchQuery: string;
34     propertyStructureHeader: string;
35
36     selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
37     selectedInstanceType: string;
38     selectedInstanceData: ComponentInstance = new ComponentInstance();
39     checkedPropertiesCount: number = 0;
40
41     hierarchyPropertiesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
42     hierarchyInstancesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name');
43     displayClearSearch = false;
44     searchPropertyName:string;
45     isInpusTabSelected:boolean;
46     isReadonly:boolean;
47     loadingInstances:boolean = false;
48     loadingInputs:boolean = false;
49     loadingProperties:boolean = false;
50
51     @ViewChild('hierarchyNavTabs') hierarchyNavTabs: ElementRef;
52     @ViewChild('propertyInputTabs') propertyInputTabs: ElementRef;
53     @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
54
55     constructor(private propertiesService: PropertiesService,
56                 private hierarchyNavService: HierarchyNavService,
57                 private propertiesUtils:PropertiesUtils,
58                 private componentServiceNg2:ComponentServiceNg2,
59                 private componentInstanceServiceNg2:ComponentInstanceServiceNg2,
60                 @Inject("$stateParams") _stateParams,
61                 private renderer: Renderer,
62                 private componentModeService:ComponentModeService,
63                 private EventListenerService:EventListenerService) {
64
65         this.instanceFePropertiesMap = new InstanceFePropertiesMap();
66
67         /* 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
68         than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
69         this.component = _stateParams.component;
70         this.EventListenerService.registerObserverCallback(EVENTS.ON_CHECKOUT, this.onCheckout);
71         this.updateViewMode();
72     }
73
74     ngOnInit() {
75         console.log("==>" + this.constructor.name + ": ngOnInit");
76         this.loadingInputs = true;
77         this.loadingInstances = true;
78         this.loadingProperties = true;
79         this.componentServiceNg2
80             .getComponentInputs(this.component)
81             .subscribe(response => {
82                 _.forEach(response.inputs, (input: InputBEModel) => {
83                     this.inputs.push(new InputFEModel(input));
84                 });
85                 this.loadingInputs = false;
86
87             });
88         this.componentServiceNg2
89             .getComponentResourceInstances(this.component)
90             .subscribe(response => {
91                 this.instances = response.componentInstances;
92
93                 _.forEach(this.instances, (instance) => {
94                     this.instancesNavigationData.push(instance);
95                 });
96                 this.loadingInstances = false;
97                 if (this.instancesNavigationData[0] == undefined) {
98                     this.loadingProperties = false;
99                 }
100                 this.selectFirstInstanceByDefault();
101             });
102
103     };
104
105     ngOnDestroy() {
106         this.EventListenerService.unRegisterObserver(EVENTS.ON_CHECKOUT);
107     }
108
109     selectFirstInstanceByDefault = () => {
110         if (this.instancesNavigationData[0] !== undefined) {
111             this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
112         }
113     };
114
115     updateViewMode = () => {
116         this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW;
117     }
118
119     onCheckout = (component:ComponentData) => {
120         this.component = component;
121         this.updateViewMode();
122     }
123
124
125     onInstanceSelectedUpdate = (resourceInstance: ResourceInstance) => {
126         console.log("==>" + this.constructor.name + ": onInstanceSelectedUpdate");
127         let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
128         this.selectedInstanceData = resourceInstance;
129         this.selectedInstanceType = resourceInstance.originType;
130
131         this.loadingProperties = true;
132         if(resourceInstance.originType === ResourceType.VF) {
133             this.componentInstanceServiceNg2
134                 .getComponentInstanceInputs(this.component, resourceInstance)
135                 .subscribe(response => {
136                     instanceBePropertiesMap[resourceInstance.uniqueId] = response;
137                     this.processInstancePropertiesResponse(instanceBePropertiesMap);
138                     this.loadingProperties = false;
139
140                 });
141         } else {
142             this.componentInstanceServiceNg2
143                 .getComponentInstanceProperties(this.component, resourceInstance.uniqueId)
144                 .subscribe(response => {
145                     instanceBePropertiesMap[resourceInstance.uniqueId] = response;
146                     this.processInstancePropertiesResponse(instanceBePropertiesMap);
147                     this.loadingProperties = false;
148                 });
149         }
150
151         if( this.searchPropertyName ){
152             this.clearSearch();
153         }
154         //clear selected property from the navigation
155         this.selectedFlatProperty = new SimpleFlatProperty();
156         this.propertiesNavigationData = [];
157     };
158
159     /**
160      * Entry point handling response from server
161      */
162     processInstancePropertiesResponse = (instanceBePropertiesMap:InstanceBePropertiesMap) => {
163         this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, this.inputs); //create flattened children, disable declared props, and init values
164         this.checkedPropertiesCount = 0;
165     };
166
167
168     /*** VALUE CHANGE EVENTS ***/
169     propertyValueChanged = (event: PropertyFEModel) => {
170         console.log("==>" + this.constructor.name + ": propertyValueChanged " + event);
171         // Copying the actual value from the object ref into the value if it's from a complex type
172         event.value = event.getJSONValue();
173
174         if (this.selectedInstanceData.originType === ResourceType.VF) {
175             console.log("I want to update input value on the resource instance");
176             let inputToUpdate = new PropertyBEModel(event);
177             this.componentInstanceServiceNg2
178                 .updateInstanceInput(this.component, this.selectedInstanceData.uniqueId, inputToUpdate)
179                 .subscribe(response => {
180                     console.log("update resource instance input and got this response: ", response);
181                 })
182         }
183         else {
184             let propertyBe = new PropertyBEModel(event);
185             this.componentInstanceServiceNg2
186                 .updateInstanceProperty(this.component, this.selectedInstanceData.uniqueId, propertyBe)
187                 .subscribe(response => {
188                     console.log("updated resource instance property and got this response: ", response);
189                 });
190             console.log(event);
191         }
192
193     };
194
195     inputValueChanged = (event) => {
196         console.log("==>" + this.constructor.name + ": inputValueChanged");
197         let inputToUpdate = new PropertyBEModel(event);
198
199         this.componentServiceNg2
200             .updateComponentInput(this.component, inputToUpdate)
201             .subscribe(response => {
202                 console.log("updated the component input and got this response: ", response);
203             })
204     };
205
206
207     /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
208
209     /**
210      * Handle select node in navigation area, and select the row in table
211      */
212     onPropertySelectedUpdate = ($event) => {
213         console.log("==>" + this.constructor.name + ": onPropertySelectedUpdate");
214         this.selectedFlatProperty = $event;
215         let parentProperty:PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
216         parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
217     };
218
219     /**
220      * When user select row in table, this will prepare the hirarchy object for the tree.
221      */
222     selectPropertyRow = (propertyRowSelectedEvent:PropertyRowSelectedEvent) => {
223         console.log("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
224         let property = propertyRowSelectedEvent.propertyModel;
225         let instanceName = propertyRowSelectedEvent.instanceName;
226         this.propertyStructureHeader = null;
227
228         // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
229         if(this.selectedInstanceData.originType !== ResourceType.VF) {
230             let simpleFlatProperty:Array<SimpleFlatProperty>;
231             if (property instanceof PropertyFEModel) {
232                 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
233             } else if (property instanceof DerivedFEProperty) {
234                 // Need to find parent PropertyFEModel
235                 let parentPropertyFEModel:PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty):boolean => {
236                     return property.propertiesName.indexOf(tmpFeProperty.name)===0;
237                 });
238                 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
239             }
240             this.propertiesNavigationData = simpleFlatProperty;
241         }
242
243         // Update the header in the navigation tree with property name.
244         this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
245
246         // Set selected property in table
247         this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
248         this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Property Structure']);
249     };
250
251
252     selectInstanceRow = ($event) => {//get instance name
253         this.selectedInstanceData =  _.find(this.instancesNavigationData, (instance:ComponentInstance) => {
254             return instance.name == $event;
255         });
256         this.renderer.invokeElementMethod(
257             this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
258     };
259
260     tabChanged = (event) => {
261         console.log("==>" + this.constructor.name + ": tabChanged " + event);
262         this.isInpusTabSelected = event.title === "Inputs";
263         this.propertyStructureHeader = null;
264         this.searchQuery = '';
265     };
266
267
268
269     /*** DECLARE PROPERTIES/INPUTS ***/
270     declareProperties = (): void => {
271         console.log("==>" + this.constructor.name + ": declareProperties");
272
273         let selectedProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
274
275         let instancesNames = new KeysPipe().transform(this.instanceFePropertiesMap, []);
276         angular.forEach(instancesNames, (instanceName: string): void => {
277             selectedProperties[instanceName] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceName]);
278             //selectedProperties[this.selectedInstanceData.uniqueId] = this.propertiesService.getCheckedProperties(this.properties);
279         });
280
281         let inputsToCreate: InstancePropertiesAPIMap;
282         if (this.selectedInstanceType !== ResourceType.VF) {
283             inputsToCreate = new InstancePropertiesAPIMap(null, selectedProperties);
284         } else {
285             inputsToCreate = new InstancePropertiesAPIMap(selectedProperties, null);
286         }
287         this.componentServiceNg2
288             .createInput(this.component, inputsToCreate)
289             .subscribe(response => {
290                 this.setInputTabIndication(response.length);
291                 this.checkedPropertiesCount = 0;
292                 _.forEach(response, (input: InputBEModel) => {
293                     let newInput: InputFEModel = new InputFEModel(input);
294                     this.inputs.push(newInput);
295                     this.updatePropertyValueAfterDeclare(newInput);
296                 });
297             });
298     };
299
300
301     updatePropertyValueAfterDeclare = (input: InputFEModel) => {
302         if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
303             let propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
304                 return feProperty.name == input.relatedProperty.name;
305             });
306
307             propertyForUpdatindVal.setAsDeclared(input.relatedProperty.nestedPath); //set prop as declared before assigning value
308             this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, input.relatedProperty.nestedPath);
309             this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedProperty.value, input.relatedProperty.nestedPath);
310         }
311     }
312
313     //used for declare button, to keep count of newly checked properties (and ignore declared properties)
314     updateCheckedPropertyCount = (increment: boolean): void => {
315         this.checkedPropertiesCount += (increment) ? 1 : -1;
316         console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount);
317     };
318
319     setInputTabIndication = (numInputs: number): void => {
320         this.renderer.invokeElementMethod(this.propertyInputTabs, 'setTabIndication', ['Inputs', numInputs]);
321     };
322
323     deleteInput = (input: InputFEModel) => {
324         console.log("==>" + this.constructor.name + ": deleteInput");
325         let inputToDelete = new PropertyBEModel(input);
326
327         this.componentServiceNg2
328             .deleteInput(this.component, inputToDelete)
329             .subscribe(response => {
330                 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
331
332                 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
333                 this.onInstanceSelectedUpdate(this.selectedInstanceData);
334                 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
335
336                 // if (instanceFeProperties) {
337                 //     let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
338                 //         return prop.name == input.propertyName;
339                 //     });
340
341                 //     if (propToEnable) {
342                 //         if (propToEnable.name == response.inputPath) response.inputPath = null;
343                 //         propToEnable.setNonDeclared(response.inputPath);
344                 //         //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
345                 //         this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
346                 //     }
347                 // }
348             });
349     };
350
351
352
353     /*** SEARCH RELATED FUNCTIONS ***/
354     searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
355         let instanceBePropertiesMap:InstanceBePropertiesMap;
356         this.componentServiceNg2
357             .filterComponentInstanceProperties(this.component, filterData)
358             .subscribe(response => {
359
360                 this.processInstancePropertiesResponse(response);
361                 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
362                 this.searchPropertyName = filterData.propertyName;//mark in table
363                 this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
364                 this.propertiesNavigationData = [];
365                 this.displayClearSearch = true;
366             });
367
368     };
369
370     clearSearch = () => {
371         this.instancesNavigationData = this.instances;
372         this.searchPropertyName = "";
373         this.hierarchyPropertiesDisplayOptions.searchText = "";
374         this.displayClearSearch = false;
375         this.advanceSearch.clearAll();
376     };
377
378     clickOnClearSearch = () => {
379         this.clearSearch();
380         this.selectFirstInstanceByDefault();
381         this.renderer.invokeElementMethod(
382             this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
383     };
384
385 }