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 // Updatet the header in the navigation tree with property name.
246 if(property instanceof DerivedFEProperty) {
247 this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
250 // Set selected property in table
251 this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
252 this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Property Structure']);
256 selectInstanceRow = ($event) => {//get instance name
257 this.selectedInstanceData = _.find(this.instancesNavigationData, (instance:ComponentInstance) => {
258 return instance.name == $event;
260 this.renderer.invokeElementMethod(
261 this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
264 tabChanged = (event) => {
265 console.log("==>" + this.constructor.name + ": tabChanged " + event);
266 this.isInpusTabSelected = event.title === "Inputs";
267 this.propertyStructureHeader = null;
268 this.searchQuery = '';
273 /*** DECLARE PROPERTIES/INPUTS ***/
274 declareProperties = (): void => {
275 console.log("==>" + this.constructor.name + ": declareProperties");
277 let selectedProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
279 let instancesNames = new KeysPipe().transform(this.instanceFePropertiesMap, []);
280 angular.forEach(instancesNames, (instanceName: string): void => {
281 selectedProperties[instanceName] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceName]);
282 //selectedProperties[this.selectedInstanceData.uniqueId] = this.propertiesService.getCheckedProperties(this.properties);
285 let inputsToCreate: InstancePropertiesAPIMap;
286 if (this.selectedInstanceType !== ResourceType.VF) {
287 inputsToCreate = new InstancePropertiesAPIMap(null, selectedProperties);
289 inputsToCreate = new InstancePropertiesAPIMap(selectedProperties, null);
291 this.componentServiceNg2
292 .createInput(this.component, inputsToCreate)
293 .subscribe(response => {
294 this.setInputTabIndication(response.length);
295 this.checkedPropertiesCount = 0;
296 _.forEach(response, (input: InputBEModel) => {
297 this.inputs.push(new InputFEModel(input));
298 this.updatePropertyValueAfterDeclare(input);
303 updatePropertyValueAfterDeclare = (input: InputBEModel) => {
304 _.forEach(input.properties, (property: ComponentInstanceProperty) => {
305 this.updatePropertyOrInputValueAfterDeclare(property, input);
308 _.forEach(input.inputs, (inputInstance: ComponentInstanceInput) => {
309 this.updatePropertyOrInputValueAfterDeclare(inputInstance, input);
313 updatePropertyOrInputValueAfterDeclare = (inputSource: ComponentInstanceProperty | ComponentInstanceInput, input: InputBEModel) => {
314 if (this.instanceFePropertiesMap[inputSource.componentInstanceId]) {
315 let propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[inputSource.componentInstanceId], (feProperty: PropertyFEModel) => {
316 return feProperty.name == inputSource.name;
319 if (input.inputPath == propertyForUpdatindVal.name) input.inputPath = null; //Fix - if inputPath is sent for parent props, remove it
321 propertyForUpdatindVal.setAsDeclared(input.inputPath); //set prop as declared before assigning value
322 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, input.inputPath);
323 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, inputSource.value, input.inputPath);
324 // if (input.inputPath) {
325 // let childProp = _.find(propertyForUpdatindVal.flattenedChildren, (child: DerivedFEProperty) => {
326 // return child.propertiesName == input.inputPath;
328 // this.propertiesUtils.assignFlattenedChildrenValues(JSON.parse(inputSource.value), [childProp], inputSource.name);
330 // propertyForUpdatindVal.valueObj = inputSource.value;
335 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
336 updateCheckedPropertyCount = (increment: boolean): void => {
337 this.checkedPropertiesCount += (increment) ? 1 : -1;
338 console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount);
341 setInputTabIndication = (numInputs: number): void => {
342 this.renderer.invokeElementMethod(this.propertyInputTabs, 'setTabIndication', ['Inputs', numInputs]);
345 deleteInput = (input: InputFEModel) => {
346 console.log("==>" + this.constructor.name + ": deleteInput");
347 let inputToDelete = new PropertyBEModel(input);
349 this.componentServiceNg2
350 .deleteInput(this.component, inputToDelete)
351 .subscribe(response => {
352 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
354 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
355 this.onInstanceSelectedUpdate(this.selectedInstanceData);
356 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
358 // if (instanceFeProperties) {
359 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
360 // return prop.name == input.propertyName;
363 // if (propToEnable) {
364 // if (propToEnable.name == response.inputPath) response.inputPath = null;
365 // propToEnable.setNonDeclared(response.inputPath);
366 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
367 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
373 getInstanceUniqueId = (instanceName: string): string => {
374 let wantedInstance: ComponentInstance = this.instances.find((instance) => {
375 return instance.normalizedName === instanceName;
378 return wantedInstance.uniqueId;
383 /*** SEARCH RELATED FUNCTIONS ***/
384 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
385 let instanceBePropertiesMap:InstanceBePropertiesMap;
386 this.componentServiceNg2
387 .filterComponentInstanceProperties(this.component, filterData)
388 .subscribe(response => {
390 this.processInstancePropertiesResponse(response);
391 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
392 this.searchPropertyName = filterData.propertyName;//mark in table
393 this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
394 this.propertiesNavigationData = [];
395 this.displayClearSearch = true;
400 clearSearch = () => {
401 this.instancesNavigationData = this.instances;
402 this.searchPropertyName = "";
403 this.hierarchyPropertiesDisplayOptions.searchText = "";
404 this.displayClearSearch = false;
405 this.advanceSearch.clearAll();
408 clickOnClearSearch = () => {
410 this.selectFirstInstanceByDefault();
411 this.renderer.invokeElementMethod(
412 this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);