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;
27 propertiesNavigationData = [];
28 instancesNavigationData = [];
30 instanceFePropertiesMap:InstanceFePropertiesMap;
31 inputs: Array<InputFEModel> = [];
32 instances: Array<ComponentInstance> = [];
34 propertyStructureHeader: string;
36 selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
37 selectedInstanceType: string;
38 selectedInstanceData: ComponentInstance = new ComponentInstance();
39 checkedPropertiesCount: number = 0;
41 hierarchyPropertiesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
42 hierarchyInstancesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name');
43 displayClearSearch = false;
44 searchPropertyName:string;
45 isInpusTabSelected:boolean;
47 loadingInstances:boolean = false;
48 loadingInputs:boolean = false;
49 loadingProperties:boolean = false;
51 @ViewChild('hierarchyNavTabs') hierarchyNavTabs: ElementRef;
52 @ViewChild('propertyInputTabs') propertyInputTabs: ElementRef;
53 @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
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) {
65 this.instanceFePropertiesMap = new InstanceFePropertiesMap();
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();
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));
85 this.loadingInputs = false;
88 this.componentServiceNg2
89 .getComponentResourceInstances(this.component)
90 .subscribe(response => {
91 this.instances = response.componentInstances;
93 _.forEach(this.instances, (instance) => {
94 this.instancesNavigationData.push(instance);
96 this.loadingInstances = false;
97 if (this.instancesNavigationData[0] == undefined) {
98 this.loadingProperties = false;
100 this.selectFirstInstanceByDefault();
106 this.EventListenerService.unRegisterObserver(EVENTS.ON_CHECKOUT);
109 selectFirstInstanceByDefault = () => {
110 if (this.instancesNavigationData[0] !== undefined) {
111 this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
115 updateViewMode = () => {
116 this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW;
119 onCheckout = (component:ComponentData) => {
120 this.component = component;
121 this.updateViewMode();
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;
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;
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;
151 if( this.searchPropertyName ){
154 //clear selected property from the navigation
155 this.selectedFlatProperty = new SimpleFlatProperty();
156 this.propertiesNavigationData = [];
160 * Entry point handling response from server
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;
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();
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);
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);
195 inputValueChanged = (event) => {
196 console.log("==>" + this.constructor.name + ": inputValueChanged");
197 let inputToUpdate = new PropertyBEModel(event);
199 this.componentServiceNg2
200 .updateComponentInput(this.component, inputToUpdate)
201 .subscribe(response => {
202 console.log("updated the component input and got this response: ", response);
207 /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
210 * Handle select node in navigation area, and select the row in table
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;
220 * When user select row in table, this will prepare the hirarchy object for the tree.
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;
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;
238 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
240 this.propertiesNavigationData = simpleFlatProperty;
243 // Update the header in the navigation tree with property name.
244 this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
246 // Set selected property in table
247 this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
248 this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Property Structure']);
252 selectInstanceRow = ($event) => {//get instance name
253 this.selectedInstanceData = _.find(this.instancesNavigationData, (instance:ComponentInstance) => {
254 return instance.name == $event;
256 this.renderer.invokeElementMethod(
257 this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
260 tabChanged = (event) => {
261 console.log("==>" + this.constructor.name + ": tabChanged " + event);
262 this.isInpusTabSelected = event.title === "Inputs";
263 this.propertyStructureHeader = null;
264 this.searchQuery = '';
269 /*** DECLARE PROPERTIES/INPUTS ***/
270 declareProperties = (): void => {
271 console.log("==>" + this.constructor.name + ": declareProperties");
273 let selectedProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
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);
281 let inputsToCreate: InstancePropertiesAPIMap;
282 if (this.selectedInstanceType !== ResourceType.VF) {
283 inputsToCreate = new InstancePropertiesAPIMap(null, selectedProperties);
285 inputsToCreate = new InstancePropertiesAPIMap(selectedProperties, null);
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);
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;
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);
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);
319 setInputTabIndication = (numInputs: number): void => {
320 this.renderer.invokeElementMethod(this.propertyInputTabs, 'setTabIndication', ['Inputs', numInputs]);
323 deleteInput = (input: InputFEModel) => {
324 console.log("==>" + this.constructor.name + ": deleteInput");
325 let inputToDelete = new PropertyBEModel(input);
327 this.componentServiceNg2
328 .deleteInput(this.component, inputToDelete)
329 .subscribe(response => {
330 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
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)];
336 // if (instanceFeProperties) {
337 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
338 // return prop.name == input.propertyName;
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);
353 /*** SEARCH RELATED FUNCTIONS ***/
354 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
355 let instanceBePropertiesMap:InstanceBePropertiesMap;
356 this.componentServiceNg2
357 .filterComponentInstanceProperties(this.component, filterData)
358 .subscribe(response => {
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;
370 clearSearch = () => {
371 this.instancesNavigationData = this.instances;
372 this.searchPropertyName = "";
373 this.hierarchyPropertiesDisplayOptions.searchText = "";
374 this.displayClearSearch = false;
375 this.advanceSearch.clearAll();
378 clickOnClearSearch = () => {
380 this.selectFirstInstanceByDefault();
381 this.renderer.invokeElementMethod(
382 this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);