1 import {Component, ViewChild, ElementRef, Renderer, Inject} from "@angular/core";
2 import {PostsService} from "../../services/posts.service";
3 import { PropertiesService } from "../../services/properties.service";
4 import { HierarchyNavService } from "../../services/hierarchy-nav.service";
5 import { PropertiesUtils } from './properties.utils';
6 import { PropertyFEModel, InstanceFePropertiesMap, InstanceBePropertiesMap, InstancePropertiesAPIMap, Component as ComponentData, FilterPropertiesAssignmentData } from "app/models";
7 import { PROPERTY_TYPES, ResourceType } from "app/utils";
8 import property = require("lodash/property");
9 import {ComponentServiceNg2} from "../../services/component-services/component.service";
10 import {ComponentInstanceServiceNg2} from "../../services/component-instance-services/component-instance.service"
11 import { InputFEModel, ComponentInstance, PropertyBEModel, DerivedPropertyType, DerivedFEProperty, ResourceInstance, SimpleFlatProperty } from "app/models";
12 import {HierarchyDisplayOptions} from "../../components/hierarchy-navigtion/hierarchy-display-options"
13 import {PropertyRowSelectedEvent} from "./../../components/properties-table/properties-table.component";
14 import { KeysPipe } from 'app/ng2/pipes/keys.pipe';
15 import {FilterPropertiesAssignmentComponent} from "../../components/filter-properties-assignment/filter-properties-assignment.component";
16 import { ComponentModeService } from "app/ng2/services/component-mode.service"
17 import {WorkspaceMode, EVENTS} from "../../../utils/constants";
18 import {ComponentInstanceProperty, InputBEModel} from "app/models"
19 import {ComponentInstanceInput} from "../../../models/properties-inputs/input-be-model";
20 import {EventListenerService} from "app/services/event-listener-service"
22 templateUrl: './properties-assignment.page.component.html',
23 styleUrls: ['./properties-assignment.page.component.less']
25 export class PropertiesAssignmentComponent {
26 title = "Properties & Inputs";
28 component:ComponentData;
30 propertiesNavigationData = [];
31 instancesNavigationData = [];
33 instanceFePropertiesMap:InstanceFePropertiesMap;
34 inputs: Array<InputFEModel> = [];
35 instances: Array<ComponentInstance> = [];
37 propertyStructureHeader: string;
39 selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
40 selectedInstanceType: string;
41 selectedInstanceData: ComponentInstance = new ComponentInstance();
42 checkedPropertiesCount: number = 0;
44 hierarchyPropertiesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
45 hierarchyInstancesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name');
46 displayClearSearch = false;
47 searchPropertyName:string;
48 isInpusTabSelected:boolean;
50 loadingInstances:boolean = false;
51 loadingInputs:boolean = false;
52 loadingProperties:boolean = false;
54 @ViewChild('hierarchyNavTabs') hierarchyNavTabs: ElementRef;
55 @ViewChild('propertyInputTabs') propertyInputTabs: ElementRef;
56 @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
58 constructor(private propertiesService: PropertiesService,
59 private hierarchyNavService: HierarchyNavService,
60 private propertiesUtils:PropertiesUtils,
61 private componentServiceNg2:ComponentServiceNg2,
62 private componentInstanceServiceNg2:ComponentInstanceServiceNg2,
63 @Inject("$stateParams") _stateParams,
64 private renderer: Renderer,
65 private componentModeService:ComponentModeService,
66 private EventListenerService:EventListenerService) {
68 this.instanceFePropertiesMap = new InstanceFePropertiesMap();
70 /* 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
71 than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
72 this.component = _stateParams.component;
73 this.EventListenerService.registerObserverCallback(EVENTS.ON_CHECKOUT, this.onCheckout);
74 this.updateViewMode();
78 console.log("==>" + this.constructor.name + ": ngOnInit");
79 this.loadingInputs = true;
80 this.loadingInstances = true;
81 this.loadingProperties = true;
82 this.componentServiceNg2
83 .getComponentInputs(this.component)
84 .subscribe(response => {
85 _.forEach(response.inputs, (input: InputBEModel) => {
86 this.inputs.push(new InputFEModel(input));
88 this.loadingInputs = false;
91 this.componentServiceNg2
92 .getComponentResourceInstances(this.component)
93 .subscribe(response => {
94 this.instances = response.componentInstances;
96 _.forEach(this.instances, (instance) => {
97 this.instancesNavigationData.push(instance);
99 this.loadingInstances = false;
100 if (this.instancesNavigationData[0] == undefined) {
101 this.loadingProperties = false;
103 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(resourceInstance.originType === ResourceType.VF) {
135 this.componentInstanceServiceNg2
136 .getComponentInstanceInputs(this.component, resourceInstance)
137 .subscribe(response => {
138 instanceBePropertiesMap[resourceInstance.uniqueId] = response;
139 this.processInstancePropertiesResponse(instanceBePropertiesMap);
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);
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) => {
165 this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, 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.selectedInstanceData.originType === ResourceType.VF) {
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.selectedInstanceType !== ResourceType.VF) {
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 this.inputs.push(new InputFEModel(input));
296 this.updatePropertyValueAfterDeclare(input);
301 updatePropertyValueAfterDeclare = (input: InputBEModel) => {
302 _.forEach(input.properties, (property: ComponentInstanceProperty) => {
303 this.updatePropertyOrInputValueAfterDeclare(property, input);
306 _.forEach(input.inputs, (inputInstance: ComponentInstanceInput) => {
307 this.updatePropertyOrInputValueAfterDeclare(inputInstance, input);
311 updatePropertyOrInputValueAfterDeclare = (inputSource: ComponentInstanceProperty | ComponentInstanceInput, input: InputBEModel) => {
312 if (this.instanceFePropertiesMap[inputSource.componentInstanceId]) {
313 let propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[inputSource.componentInstanceId], (feProperty: PropertyFEModel) => {
314 return feProperty.name == inputSource.name;
317 if (input.inputPath == propertyForUpdatindVal.name) input.inputPath = null; //Fix - if inputPath is sent for parent props, remove it
319 propertyForUpdatindVal.setAsDeclared(input.inputPath); //set prop as declared before assigning value
320 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, input.inputPath);
321 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, inputSource.value, input.inputPath);
322 // if (input.inputPath) {
323 // let childProp = _.find(propertyForUpdatindVal.flattenedChildren, (child: DerivedFEProperty) => {
324 // return child.propertiesName == input.inputPath;
326 // this.propertiesUtils.assignFlattenedChildrenValues(JSON.parse(inputSource.value), [childProp], inputSource.name);
328 // propertyForUpdatindVal.valueObj = inputSource.value;
333 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
334 updateCheckedPropertyCount = (increment: boolean): void => {
335 this.checkedPropertiesCount += (increment) ? 1 : -1;
336 console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount);
339 setInputTabIndication = (numInputs: number): void => {
340 this.renderer.invokeElementMethod(this.propertyInputTabs, 'setTabIndication', ['Inputs', numInputs]);
343 deleteInput = (input: InputFEModel) => {
344 console.log("==>" + this.constructor.name + ": deleteInput");
345 let inputToDelete = new PropertyBEModel(input);
347 this.componentServiceNg2
348 .deleteInput(this.component, inputToDelete)
349 .subscribe(response => {
350 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
352 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
353 this.onInstanceSelectedUpdate(this.selectedInstanceData);
354 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
356 // if (instanceFeProperties) {
357 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
358 // return prop.name == input.propertyName;
361 // if (propToEnable) {
362 // if (propToEnable.name == response.inputPath) response.inputPath = null;
363 // propToEnable.setNonDeclared(response.inputPath);
364 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
365 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
371 getInstanceUniqueId = (instanceName: string): string => {
372 let wantedInstance: ComponentInstance = this.instances.find((instance) => {
373 return instance.normalizedName === instanceName;
376 return wantedInstance.uniqueId;
381 /*** SEARCH RELATED FUNCTIONS ***/
382 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
383 let instanceBePropertiesMap:InstanceBePropertiesMap;
384 this.componentServiceNg2
385 .filterComponentInstanceProperties(this.component, filterData)
386 .subscribe(response => {
388 this.processInstancePropertiesResponse(response);
389 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
390 this.searchPropertyName = filterData.propertyName;//mark in table
391 this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
392 this.propertiesNavigationData = [];
393 this.displayClearSearch = true;
398 clearSearch = () => {
399 this.instancesNavigationData = this.instances;
400 this.searchPropertyName = "";
401 this.hierarchyPropertiesDisplayOptions.searchText = "";
402 this.displayClearSearch = false;
403 this.advanceSearch.clearAll();
406 clickOnClearSearch = () => {
408 this.selectFirstInstanceByDefault();
409 this.renderer.invokeElementMethod(
410 this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);