2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 import {Component, ViewChild, ElementRef, Renderer, Inject} from "@angular/core";
22 import { PropertiesService } from "../../services/properties.service";
23 import { HierarchyNavService } from "../../services/hierarchy-nav.service";
24 import { PropertiesUtils } from './properties.utils';
25 import { PropertyFEModel, InstanceFePropertiesMap, InstanceBePropertiesMap, InstancePropertiesAPIMap, Component as ComponentData, FilterPropertiesAssignmentData } from "app/models";
26 import { PROPERTY_TYPES, ResourceType } from "app/utils";
27 import property = require("lodash/property");
28 import {ComponentServiceNg2} from "../../services/component-services/component.service";
29 import {ComponentInstanceServiceNg2} from "../../services/component-instance-services/component-instance.service"
30 import { InputBEModel, InputFEModel, ComponentInstance, PropertyBEModel, DerivedPropertyType, DerivedFEProperty, ResourceInstance, SimpleFlatProperty } from "app/models";
31 import {HierarchyDisplayOptions} from "../../components/hierarchy-navigtion/hierarchy-display-options"
32 import {PropertyRowSelectedEvent} from "./../../components/properties-table/properties-table.component";
33 import { KeysPipe } from 'app/ng2/pipes/keys.pipe';
34 import {FilterPropertiesAssignmentComponent} from "../../components/filter-properties-assignment/filter-properties-assignment.component";
35 import { ComponentModeService } from "app/ng2/services/component-mode.service"
36 import {WorkspaceMode, EVENTS} from "../../../utils/constants";
37 import {EventListenerService} from "app/services/event-listener-service"
39 templateUrl: './properties-assignment.page.component.html',
40 styleUrls: ['./properties-assignment.page.component.less']
42 export class PropertiesAssignmentComponent {
43 title = "Properties & Inputs";
45 component: ComponentData;
46 componentInstanceNamesMap: Map<string, string> = new Map<string, string>();//instanceUniqueId, name
48 propertiesNavigationData = [];
49 instancesNavigationData = [];
51 instanceFePropertiesMap:InstanceFePropertiesMap;
52 inputs: Array<InputFEModel> = [];
53 instances: Array<ComponentInstance> = [];
55 propertyStructureHeader: string;
57 selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
58 selectedInstanceType: string;
59 selectedInstanceData: ComponentInstance = new ComponentInstance();
60 checkedPropertiesCount: number = 0;
62 hierarchyPropertiesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
63 hierarchyInstancesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name');
64 displayClearSearch = false;
65 searchPropertyName:string;
66 isInpusTabSelected:boolean;
68 loadingInstances:boolean = false;
69 loadingInputs:boolean = false;
70 loadingProperties:boolean = false;
72 @ViewChild('hierarchyNavTabs') hierarchyNavTabs: ElementRef;
73 @ViewChild('propertyInputTabs') propertyInputTabs: ElementRef;
74 @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
76 constructor(private propertiesService: PropertiesService,
77 private hierarchyNavService: HierarchyNavService,
78 private propertiesUtils:PropertiesUtils,
79 private componentServiceNg2:ComponentServiceNg2,
80 private componentInstanceServiceNg2:ComponentInstanceServiceNg2,
81 @Inject("$stateParams") _stateParams,
82 private renderer: Renderer,
83 private componentModeService:ComponentModeService,
84 private EventListenerService:EventListenerService) {
86 this.instanceFePropertiesMap = new InstanceFePropertiesMap();
88 /* 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
89 than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
90 this.component = _stateParams.component;
91 this.EventListenerService.registerObserverCallback(EVENTS.ON_CHECKOUT, this.onCheckout);
92 this.updateViewMode();
96 console.log("==>" + this.constructor.name + ": ngOnInit");
97 this.loadingInputs = true;
98 this.loadingInstances = true;
99 this.loadingProperties = true;
100 this.componentServiceNg2
101 .getComponentInputs(this.component)
102 .subscribe(response => {
103 _.forEach(response.inputs, (input: InputBEModel) => {
104 this.inputs.push(new InputFEModel(input)); //only push items that were declared via SDC
106 this.loadingInputs = false;
109 this.componentServiceNg2
110 .getComponentResourceInstances(this.component)
111 .subscribe(response => {
112 this.instances = response.componentInstances;
114 _.forEach(this.instances, (instance) => {
115 this.instancesNavigationData.push(instance);
116 this.componentInstanceNamesMap[instance.uniqueId] = instance.name;
118 this.loadingInstances = false;
119 if (this.instancesNavigationData[0] == undefined) {
120 this.loadingProperties = false;
122 this.selectFirstInstanceByDefault();
128 this.EventListenerService.unRegisterObserver(EVENTS.ON_CHECKOUT);
131 selectFirstInstanceByDefault = () => {
132 if (this.instancesNavigationData[0] !== undefined) {
133 this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
137 updateViewMode = () => {
138 this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW;
141 onCheckout = (component:ComponentData) => {
142 this.component = component;
143 this.updateViewMode();
147 onInstanceSelectedUpdate = (resourceInstance: ResourceInstance) => {
148 console.log("==>" + this.constructor.name + ": onInstanceSelectedUpdate");
149 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
150 this.selectedInstanceData = resourceInstance;
151 this.selectedInstanceType = resourceInstance.originType;
153 this.loadingProperties = true;
154 if(this.isInput(resourceInstance.originType)) {
155 this.componentInstanceServiceNg2
156 .getComponentInstanceInputs(this.component, resourceInstance)
157 .subscribe(response => {
158 instanceBePropertiesMap[resourceInstance.uniqueId] = response;
159 this.processInstancePropertiesResponse(instanceBePropertiesMap, true);
160 this.loadingProperties = false;
164 this.componentInstanceServiceNg2
165 .getComponentInstanceProperties(this.component, resourceInstance.uniqueId)
166 .subscribe(response => {
167 instanceBePropertiesMap[resourceInstance.uniqueId] = response;
168 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
169 this.loadingProperties = false;
173 if( this.searchPropertyName ){
176 //clear selected property from the navigation
177 this.selectedFlatProperty = new SimpleFlatProperty();
178 this.propertiesNavigationData = [];
182 * Entry point handling response from server
184 processInstancePropertiesResponse = (instanceBePropertiesMap: InstanceBePropertiesMap, originTypeIsVF: boolean) => {
185 this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
186 this.checkedPropertiesCount = 0;
190 /*** VALUE CHANGE EVENTS ***/
191 propertyValueChanged = (event: PropertyFEModel) => {
192 console.log("==>" + this.constructor.name + ": propertyValueChanged " + event);
193 // Copying the actual value from the object ref into the value if it's from a complex type
194 event.value = event.getJSONValue();
196 if (this.isInput(this.selectedInstanceData.originType)) {
197 console.log("I want to update input value on the resource instance");
198 let inputToUpdate = new PropertyBEModel(event);
199 this.componentInstanceServiceNg2
200 .updateInstanceInput(this.component, this.selectedInstanceData.uniqueId, inputToUpdate)
201 .subscribe(response => {
202 console.log("update resource instance input and got this response: ", response);
206 let propertyBe = new PropertyBEModel(event);
207 this.componentInstanceServiceNg2
208 .updateInstanceProperty(this.component, this.selectedInstanceData.uniqueId, propertyBe)
209 .subscribe(response => {
210 console.log("updated resource instance property and got this response: ", response);
217 inputValueChanged = (event) => {
218 console.log("==>" + this.constructor.name + ": inputValueChanged");
219 let inputToUpdate = new PropertyBEModel(event);
221 this.componentServiceNg2
222 .updateComponentInput(this.component, inputToUpdate)
223 .subscribe(response => {
224 console.log("updated the component input and got this response: ", response);
229 /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
232 * Handle select node in navigation area, and select the row in table
234 onPropertySelectedUpdate = ($event) => {
235 console.log("==>" + this.constructor.name + ": onPropertySelectedUpdate");
236 this.selectedFlatProperty = $event;
237 let parentProperty:PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
238 parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
242 * When user select row in table, this will prepare the hirarchy object for the tree.
244 selectPropertyRow = (propertyRowSelectedEvent:PropertyRowSelectedEvent) => {
245 console.log("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
246 let property = propertyRowSelectedEvent.propertyModel;
247 let instanceName = propertyRowSelectedEvent.instanceName;
248 this.propertyStructureHeader = null;
250 // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
251 if(this.selectedInstanceData.originType !== ResourceType.VF) {
252 let simpleFlatProperty:Array<SimpleFlatProperty>;
253 if (property instanceof PropertyFEModel) {
254 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
255 } else if (property instanceof DerivedFEProperty) {
256 // Need to find parent PropertyFEModel
257 let parentPropertyFEModel:PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty):boolean => {
258 return property.propertiesName.indexOf(tmpFeProperty.name)===0;
260 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
262 this.propertiesNavigationData = simpleFlatProperty;
265 // Update the header in the navigation tree with property name.
266 this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
268 // Set selected property in table
269 this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
270 this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Property Structure']);
274 selectInstanceRow = ($event) => {//get instance name
275 this.selectedInstanceData = _.find(this.instancesNavigationData, (instance:ComponentInstance) => {
276 return instance.name == $event;
278 this.renderer.invokeElementMethod(
279 this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
282 tabChanged = (event) => {
283 console.log("==>" + this.constructor.name + ": tabChanged " + event);
284 this.isInpusTabSelected = event.title === "Inputs";
285 this.propertyStructureHeader = null;
286 this.searchQuery = '';
291 /*** DECLARE PROPERTIES/INPUTS ***/
292 declareProperties = (): void => {
293 console.log("==>" + this.constructor.name + ": declareProperties");
295 let selectedProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
296 let selectedInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
297 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
299 angular.forEach(instancesIds, (instanceId: string): void => {
300 let selectedInstanceData: ResourceInstance = this.instances.find(instance => instance.uniqueId == instanceId);
301 let originType: string = (selectedInstanceData) ? selectedInstanceData.originType : this.selectedInstanceType;
302 if (!this.isInput(originType)) {
303 selectedProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
305 selectedInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
309 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedInputs, selectedProperties);
311 this.componentServiceNg2
312 .createInput(this.component, inputsToCreate)
313 .subscribe(response => {
314 this.setInputTabIndication(response.length);
315 this.checkedPropertiesCount = 0;
316 _.forEach(response, (input: InputBEModel) => {
317 let newInput: InputFEModel = new InputFEModel(input);
318 this.inputs.push(newInput);
319 this.updatePropertyValueAfterDeclare(newInput);
325 updatePropertyValueAfterDeclare = (input: InputFEModel) => {
326 if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
327 let propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
328 return feProperty.name == input.relatedPropertyName;
330 let inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
331 propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
332 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
333 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
337 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
338 updateCheckedPropertyCount = (increment: boolean): void => {
339 this.checkedPropertiesCount += (increment) ? 1 : -1;
340 console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount);
343 setInputTabIndication = (numInputs: number): void => {
344 this.renderer.invokeElementMethod(this.propertyInputTabs, 'setTabIndication', ['Inputs', numInputs]);
347 deleteInput = (input: InputFEModel) => {
348 console.log("==>" + this.constructor.name + ": deleteInput");
349 let inputToDelete = new PropertyBEModel(input);
351 this.componentServiceNg2
352 .deleteInput(this.component, inputToDelete)
353 .subscribe(response => {
354 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
356 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
357 this.onInstanceSelectedUpdate(this.selectedInstanceData);
358 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
360 // if (instanceFeProperties) {
361 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
362 // return prop.name == input.propertyName;
365 // if (propToEnable) {
366 // if (propToEnable.name == response.inputPath) response.inputPath = null;
367 // propToEnable.setNonDeclared(response.inputPath);
368 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
369 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
377 /*** SEARCH RELATED FUNCTIONS ***/
378 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
379 let instanceBePropertiesMap:InstanceBePropertiesMap;
380 this.componentServiceNg2
381 .filterComponentInstanceProperties(this.component, filterData)
382 .subscribe(response => {
384 this.processInstancePropertiesResponse(response, false);
385 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
386 this.searchPropertyName = filterData.propertyName;//mark in table
387 this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
388 this.propertiesNavigationData = [];
389 this.displayClearSearch = true;
394 clearSearch = () => {
395 this.instancesNavigationData = this.instances;
396 this.searchPropertyName = "";
397 this.hierarchyPropertiesDisplayOptions.searchText = "";
398 this.displayClearSearch = false;
399 this.advanceSearch.clearAll();
400 this.searchQuery = '';
403 clickOnClearSearch = () => {
405 this.selectFirstInstanceByDefault();
406 this.renderer.invokeElementMethod(
407 this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
410 private isInput = (instanceType:string):boolean =>{
411 return instanceType === ResourceType.VF || instanceType === ResourceType.PNF;