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"
19 templateUrl: './properties-assignment.page.component.html',
20 styleUrls: ['./properties-assignment.page.component.less']
22 export class PropertiesAssignmentComponent {
23 title = "Properties & Inputs";
25 component: ComponentData;
26 componentInstanceNamesMap: Map<string, string> = new Map<string, string>();//instanceUniqueId, name
28 propertiesNavigationData = [];
29 instancesNavigationData = [];
31 instanceFePropertiesMap:InstanceFePropertiesMap;
32 inputs: Array<InputFEModel> = [];
33 instances: Array<ComponentInstance> = [];
35 propertyStructureHeader: string;
37 selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
38 selectedInstanceType: string;
39 selectedInstanceData: ComponentInstance = new ComponentInstance();
40 checkedPropertiesCount: number = 0;
42 hierarchyPropertiesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
43 hierarchyInstancesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name');
44 displayClearSearch = false;
45 searchPropertyName:string;
46 isInpusTabSelected:boolean;
48 loadingInstances:boolean = false;
49 loadingInputs:boolean = false;
50 loadingProperties:boolean = false;
52 @ViewChild('hierarchyNavTabs') hierarchyNavTabs: ElementRef;
53 @ViewChild('propertyInputTabs') propertyInputTabs: ElementRef;
54 @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
56 constructor(private propertiesService: PropertiesService,
57 private hierarchyNavService: HierarchyNavService,
58 private propertiesUtils:PropertiesUtils,
59 private componentServiceNg2:ComponentServiceNg2,
60 private componentInstanceServiceNg2:ComponentInstanceServiceNg2,
61 @Inject("$stateParams") _stateParams,
62 private renderer: Renderer,
63 private componentModeService:ComponentModeService,
64 private EventListenerService:EventListenerService) {
66 this.instanceFePropertiesMap = new InstanceFePropertiesMap();
68 /* 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
69 than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
70 this.component = _stateParams.component;
71 this.EventListenerService.registerObserverCallback(EVENTS.ON_CHECKOUT, this.onCheckout);
72 this.updateViewMode();
76 console.log("==>" + this.constructor.name + ": ngOnInit");
77 this.loadingInputs = true;
78 this.loadingInstances = true;
79 this.loadingProperties = true;
80 this.componentServiceNg2
81 .getComponentInputs(this.component)
82 .subscribe(response => {
83 _.forEach(response.inputs, (input: InputBEModel) => {
84 this.inputs.push(new InputFEModel(input)); //only push items that were declared via SDC
86 this.loadingInputs = false;
89 this.componentServiceNg2
90 .getComponentResourceInstances(this.component)
91 .subscribe(response => {
92 this.instances = response.componentInstances;
94 _.forEach(this.instances, (instance) => {
95 this.instancesNavigationData.push(instance);
96 this.componentInstanceNamesMap[instance.uniqueId] = instance.name;
98 this.loadingInstances = false;
99 if (this.instancesNavigationData[0] == undefined) {
100 this.loadingProperties = false;
102 this.selectFirstInstanceByDefault();
108 this.EventListenerService.unRegisterObserver(EVENTS.ON_CHECKOUT);
111 selectFirstInstanceByDefault = () => {
112 if (this.instancesNavigationData[0] !== undefined) {
113 this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
117 updateViewMode = () => {
118 this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW;
121 onCheckout = (component:ComponentData) => {
122 this.component = component;
123 this.updateViewMode();
127 onInstanceSelectedUpdate = (resourceInstance: ResourceInstance) => {
128 console.log("==>" + this.constructor.name + ": onInstanceSelectedUpdate");
129 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
130 this.selectedInstanceData = resourceInstance;
131 this.selectedInstanceType = resourceInstance.originType;
133 this.loadingProperties = true;
134 if(this.isInput(resourceInstance.originType)) {
135 this.componentInstanceServiceNg2
136 .getComponentInstanceInputs(this.component, resourceInstance)
137 .subscribe(response => {
138 instanceBePropertiesMap[resourceInstance.uniqueId] = response;
139 this.processInstancePropertiesResponse(instanceBePropertiesMap, true);
140 this.loadingProperties = false;
144 this.componentInstanceServiceNg2
145 .getComponentInstanceProperties(this.component, resourceInstance.uniqueId)
146 .subscribe(response => {
147 instanceBePropertiesMap[resourceInstance.uniqueId] = response;
148 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
149 this.loadingProperties = false;
153 if( this.searchPropertyName ){
156 //clear selected property from the navigation
157 this.selectedFlatProperty = new SimpleFlatProperty();
158 this.propertiesNavigationData = [];
162 * Entry point handling response from server
164 processInstancePropertiesResponse = (instanceBePropertiesMap: InstanceBePropertiesMap, originTypeIsVF: boolean) => {
165 this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
166 this.checkedPropertiesCount = 0;
170 /*** VALUE CHANGE EVENTS ***/
171 propertyValueChanged = (event: PropertyFEModel) => {
172 console.log("==>" + this.constructor.name + ": propertyValueChanged " + event);
173 // Copying the actual value from the object ref into the value if it's from a complex type
174 event.value = event.getJSONValue();
176 if (this.isInput(this.selectedInstanceData.originType)) {
177 console.log("I want to update input value on the resource instance");
178 let inputToUpdate = new PropertyBEModel(event);
179 this.componentInstanceServiceNg2
180 .updateInstanceInput(this.component, this.selectedInstanceData.uniqueId, inputToUpdate)
181 .subscribe(response => {
182 console.log("update resource instance input and got this response: ", response);
186 let propertyBe = new PropertyBEModel(event);
187 this.componentInstanceServiceNg2
188 .updateInstanceProperty(this.component, this.selectedInstanceData.uniqueId, propertyBe)
189 .subscribe(response => {
190 console.log("updated resource instance property and got this response: ", response);
197 inputValueChanged = (event) => {
198 console.log("==>" + this.constructor.name + ": inputValueChanged");
199 let inputToUpdate = new PropertyBEModel(event);
201 this.componentServiceNg2
202 .updateComponentInput(this.component, inputToUpdate)
203 .subscribe(response => {
204 console.log("updated the component input and got this response: ", response);
209 /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
212 * Handle select node in navigation area, and select the row in table
214 onPropertySelectedUpdate = ($event) => {
215 console.log("==>" + this.constructor.name + ": onPropertySelectedUpdate");
216 this.selectedFlatProperty = $event;
217 let parentProperty:PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
218 parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
222 * When user select row in table, this will prepare the hirarchy object for the tree.
224 selectPropertyRow = (propertyRowSelectedEvent:PropertyRowSelectedEvent) => {
225 console.log("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
226 let property = propertyRowSelectedEvent.propertyModel;
227 let instanceName = propertyRowSelectedEvent.instanceName;
228 this.propertyStructureHeader = null;
230 // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
231 if(this.selectedInstanceData.originType !== ResourceType.VF) {
232 let simpleFlatProperty:Array<SimpleFlatProperty>;
233 if (property instanceof PropertyFEModel) {
234 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
235 } else if (property instanceof DerivedFEProperty) {
236 // Need to find parent PropertyFEModel
237 let parentPropertyFEModel:PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty):boolean => {
238 return property.propertiesName.indexOf(tmpFeProperty.name)===0;
240 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
242 this.propertiesNavigationData = simpleFlatProperty;
245 // Update the header in the navigation tree with property name.
246 this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
248 // Set selected property in table
249 this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
250 this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Property Structure']);
254 selectInstanceRow = ($event) => {//get instance name
255 this.selectedInstanceData = _.find(this.instancesNavigationData, (instance:ComponentInstance) => {
256 return instance.name == $event;
258 this.renderer.invokeElementMethod(
259 this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
262 tabChanged = (event) => {
263 console.log("==>" + this.constructor.name + ": tabChanged " + event);
264 this.isInpusTabSelected = event.title === "Inputs";
265 this.propertyStructureHeader = null;
266 this.searchQuery = '';
271 /*** DECLARE PROPERTIES/INPUTS ***/
272 declareProperties = (): void => {
273 console.log("==>" + this.constructor.name + ": declareProperties");
275 let selectedProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
277 let instancesNames = new KeysPipe().transform(this.instanceFePropertiesMap, []);
278 angular.forEach(instancesNames, (instanceName: string): void => {
279 selectedProperties[instanceName] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceName]);
280 //selectedProperties[this.selectedInstanceData.uniqueId] = this.propertiesService.getCheckedProperties(this.properties);
283 let inputsToCreate: InstancePropertiesAPIMap;
284 if (!this.isInput(this.selectedInstanceType)) {
285 inputsToCreate = new InstancePropertiesAPIMap(null, selectedProperties);
287 inputsToCreate = new InstancePropertiesAPIMap(selectedProperties, null);
289 this.componentServiceNg2
290 .createInput(this.component, inputsToCreate)
291 .subscribe(response => {
292 this.setInputTabIndication(response.length);
293 this.checkedPropertiesCount = 0;
294 _.forEach(response, (input: InputBEModel) => {
295 let newInput: InputFEModel = new InputFEModel(input);
296 this.inputs.push(newInput);
297 this.updatePropertyValueAfterDeclare(newInput);
303 updatePropertyValueAfterDeclare = (input: InputFEModel) => {
304 if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
305 let propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
306 return feProperty.name == input.relatedPropertyName;
308 let inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
309 propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
310 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
311 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
315 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
316 updateCheckedPropertyCount = (increment: boolean): void => {
317 this.checkedPropertiesCount += (increment) ? 1 : -1;
318 console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount);
321 setInputTabIndication = (numInputs: number): void => {
322 this.renderer.invokeElementMethod(this.propertyInputTabs, 'setTabIndication', ['Inputs', numInputs]);
325 deleteInput = (input: InputFEModel) => {
326 console.log("==>" + this.constructor.name + ": deleteInput");
327 let inputToDelete = new PropertyBEModel(input);
329 this.componentServiceNg2
330 .deleteInput(this.component, inputToDelete)
331 .subscribe(response => {
332 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
334 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
335 this.onInstanceSelectedUpdate(this.selectedInstanceData);
336 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
338 // if (instanceFeProperties) {
339 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
340 // return prop.name == input.propertyName;
343 // if (propToEnable) {
344 // if (propToEnable.name == response.inputPath) response.inputPath = null;
345 // propToEnable.setNonDeclared(response.inputPath);
346 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
347 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
355 /*** SEARCH RELATED FUNCTIONS ***/
356 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
357 let instanceBePropertiesMap:InstanceBePropertiesMap;
358 this.componentServiceNg2
359 .filterComponentInstanceProperties(this.component, filterData)
360 .subscribe(response => {
362 this.processInstancePropertiesResponse(response, false);
363 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
364 this.searchPropertyName = filterData.propertyName;//mark in table
365 this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
366 this.propertiesNavigationData = [];
367 this.displayClearSearch = true;
372 clearSearch = () => {
373 this.instancesNavigationData = this.instances;
374 this.searchPropertyName = "";
375 this.hierarchyPropertiesDisplayOptions.searchText = "";
376 this.displayClearSearch = false;
377 this.advanceSearch.clearAll();
378 this.searchQuery = '';
381 clickOnClearSearch = () => {
383 this.selectFirstInstanceByDefault();
384 this.renderer.invokeElementMethod(
385 this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
388 private isInput = (instanceType:string):boolean =>{
389 return instanceType === ResourceType.VF || instanceType === ResourceType.PNF;