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 { PropertyFEModel, InstanceFePropertiesMap, InstanceBePropertiesMap, InstancePropertiesAPIMap, Component as ComponentData, FilterPropertiesAssignmentData } from "app/models";
24 import { ResourceType } from "app/utils";
25 import property = require("lodash/property");
26 import {ComponentServiceNg2} from "../../services/component-services/component.service";
27 import {ComponentInstanceServiceNg2} from "../../services/component-instance-services/component-instance.service"
28 import { InputBEModel, InputFEModel, ComponentInstance, PropertyBEModel, DerivedFEProperty, ResourceInstance, SimpleFlatProperty } from "app/models";
29 import { KeysPipe } from 'app/ng2/pipes/keys.pipe';
30 import {WorkspaceMode, EVENTS} from "../../../utils/constants";
31 import {EventListenerService} from "app/services/event-listener-service"
32 import {HierarchyDisplayOptions} from "../../components/logic/hierarchy-navigtion/hierarchy-display-options";
33 import {FilterPropertiesAssignmentComponent} from "../../components/logic/filter-properties-assignment/filter-properties-assignment.component";
34 import {PropertyRowSelectedEvent} from "../../components/logic/properties-table/properties-table.component";
35 import {HierarchyNavService} from "./services/hierarchy-nav.service";
36 import {PropertiesUtils} from "./services/properties.utils";
37 import {ComponentModeService} from "../../services/component-services/component-mode.service";
40 templateUrl: './properties-assignment.page.component.html',
41 styleUrls: ['./properties-assignment.page.component.less']
43 export class PropertiesAssignmentComponent {
44 title = "Properties & Inputs";
46 component: ComponentData;
47 componentInstanceNamesMap: Map<string, string> = new Map<string, string>();//instanceUniqueId, name
49 propertiesNavigationData = [];
50 instancesNavigationData = [];
52 instanceFePropertiesMap:InstanceFePropertiesMap;
53 inputs: Array<InputFEModel> = [];
54 instances: Array<ComponentInstance> = [];
56 propertyStructureHeader: string;
58 selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
59 selectedInstanceType: string;
60 selectedInstanceData: ComponentInstance = new ComponentInstance();
61 checkedPropertiesCount: number = 0;
63 hierarchyPropertiesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
64 hierarchyInstancesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name');
65 displayClearSearch = false;
66 searchPropertyName:string;
67 isInpusTabSelected:boolean;
69 loadingInstances:boolean = false;
70 loadingInputs:boolean = false;
71 loadingProperties:boolean = false;
73 @ViewChild('hierarchyNavTabs') hierarchyNavTabs: ElementRef;
74 @ViewChild('propertyInputTabs') propertyInputTabs: ElementRef;
75 @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
77 constructor(private propertiesService: PropertiesService,
78 private hierarchyNavService: HierarchyNavService,
79 private propertiesUtils:PropertiesUtils,
80 private componentServiceNg2:ComponentServiceNg2,
81 private componentInstanceServiceNg2:ComponentInstanceServiceNg2,
82 @Inject("$stateParams") _stateParams,
83 private renderer: Renderer,
84 private componentModeService:ComponentModeService,
85 private EventListenerService:EventListenerService) {
87 this.instanceFePropertiesMap = new InstanceFePropertiesMap();
89 /* 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
90 than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
91 this.component = _stateParams.component;
92 this.EventListenerService.registerObserverCallback(EVENTS.ON_CHECKOUT, this.onCheckout);
93 this.updateViewMode();
97 console.log("==>" + this.constructor.name + ": ngOnInit");
98 this.loadingInputs = true;
99 this.loadingInstances = true;
100 this.loadingProperties = true;
101 this.componentServiceNg2
102 .getComponentInputs(this.component)
103 .subscribe(response => {
104 _.forEach(response.inputs, (input: InputBEModel) => {
105 this.inputs.push(new InputFEModel(input)); //only push items that were declared via SDC
107 this.loadingInputs = false;
109 }, error => {}); //ignore error
110 this.componentServiceNg2
111 .getComponentResourceInstances(this.component)
112 .subscribe(response => {
113 this.instances = response.componentInstances;
115 _.forEach(this.instances, (instance) => {
116 this.instancesNavigationData.push(instance);
117 this.componentInstanceNamesMap[instance.uniqueId] = instance.name;
119 this.loadingInstances = false;
120 if (this.instancesNavigationData[0] == undefined) {
121 this.loadingProperties = false;
123 this.selectFirstInstanceByDefault();
124 }, error => {}); //ignore error
129 this.EventListenerService.unRegisterObserver(EVENTS.ON_CHECKOUT);
132 selectFirstInstanceByDefault = () => {
133 if (this.instancesNavigationData[0] !== undefined) {
134 this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
138 updateViewMode = () => {
139 this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW;
142 onCheckout = (component:ComponentData) => {
143 this.component = component;
144 this.updateViewMode();
148 onInstanceSelectedUpdate = (resourceInstance: ResourceInstance) => {
149 console.log("==>" + this.constructor.name + ": onInstanceSelectedUpdate");
150 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
151 this.selectedInstanceData = resourceInstance;
152 this.selectedInstanceType = resourceInstance.originType;
154 this.loadingProperties = true;
155 if(this.isInput(resourceInstance.originType)) {
156 this.componentInstanceServiceNg2
157 .getComponentInstanceInputs(this.component, resourceInstance)
158 .subscribe(response => {
159 instanceBePropertiesMap[resourceInstance.uniqueId] = response;
160 this.processInstancePropertiesResponse(instanceBePropertiesMap, true);
161 this.loadingProperties = false;
163 }, error => {}); //ignore error
165 this.componentInstanceServiceNg2
166 .getComponentInstanceProperties(this.component, resourceInstance.uniqueId)
167 .subscribe(response => {
168 instanceBePropertiesMap[resourceInstance.uniqueId] = response;
169 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
170 this.loadingProperties = false;
171 }, error => {}); //ignore error
174 if(resourceInstance.componentName === "vnfConfiguration") {
175 this.isReadonly = true;
178 if( this.searchPropertyName ){
181 //clear selected property from the navigation
182 this.selectedFlatProperty = new SimpleFlatProperty();
183 this.propertiesNavigationData = [];
187 * Entry point handling response from server
189 processInstancePropertiesResponse = (instanceBePropertiesMap: InstanceBePropertiesMap, originTypeIsVF: boolean) => {
190 this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
191 this.checkedPropertiesCount = 0;
195 /*** VALUE CHANGE EVENTS ***/
196 propertyValueChanged = (event: PropertyFEModel) => {
197 console.log("==>" + this.constructor.name + ": propertyValueChanged " + event);
198 // Copying the actual value from the object ref into the value if it's from a complex type
199 event.value = event.getJSONValue();
201 if (this.isInput(this.selectedInstanceData.originType)) {
202 console.log("I want to update input value on the resource instance");
203 let inputToUpdate = new PropertyBEModel(event);
204 this.componentInstanceServiceNg2
205 .updateInstanceInput(this.component, this.selectedInstanceData.uniqueId, inputToUpdate)
206 .subscribe(response => {
207 console.log("Update resource instance input response: ", response);
208 }, error => {}); //ignore error
211 let propertyBe = new PropertyBEModel(event);
212 this.componentInstanceServiceNg2
213 .updateInstanceProperty(this.component, this.selectedInstanceData.uniqueId, propertyBe)
214 .subscribe(response => {
215 console.log("Update resource instance property response: ", response);
216 }, error => {}); //ignore error
222 inputValueChanged = (event) => {
223 console.log("==>" + this.constructor.name + ": inputValueChanged");
224 let inputToUpdate = new PropertyBEModel(event);
226 this.componentServiceNg2
227 .updateComponentInput(this.component, inputToUpdate)
228 .subscribe(response => {
229 console.log("updated the component input and got this response: ", response);
230 }, error => {}); //ignore error
234 /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
237 * Handle select node in navigation area, and select the row in table
239 onPropertySelectedUpdate = ($event) => {
240 console.log("==>" + this.constructor.name + ": onPropertySelectedUpdate");
241 this.selectedFlatProperty = $event;
242 let parentProperty:PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
243 parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
247 * When user select row in table, this will prepare the hirarchy object for the tree.
249 selectPropertyRow = (propertyRowSelectedEvent:PropertyRowSelectedEvent) => {
250 console.log("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
251 let property = propertyRowSelectedEvent.propertyModel;
252 let instanceName = propertyRowSelectedEvent.instanceName;
253 this.propertyStructureHeader = null;
255 // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
256 if(this.selectedInstanceData.originType !== ResourceType.VF) {
257 let simpleFlatProperty:Array<SimpleFlatProperty>;
258 if (property instanceof PropertyFEModel) {
259 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
260 } else if (property instanceof DerivedFEProperty) {
261 // Need to find parent PropertyFEModel
262 let parentPropertyFEModel:PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty):boolean => {
263 return property.propertiesName.indexOf(tmpFeProperty.name)===0;
265 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
267 this.propertiesNavigationData = simpleFlatProperty;
270 // Update the header in the navigation tree with property name.
271 this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
273 // Set selected property in table
274 this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
275 this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Property Structure']);
279 selectInstanceRow = ($event) => {//get instance name
280 this.selectedInstanceData = _.find(this.instancesNavigationData, (instance:ComponentInstance) => {
281 return instance.name == $event;
283 this.renderer.invokeElementMethod(
284 this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
287 tabChanged = (event) => {
288 console.log("==>" + this.constructor.name + ": tabChanged " + event);
289 this.isInpusTabSelected = event.title === "Inputs";
290 this.propertyStructureHeader = null;
291 this.searchQuery = '';
296 /*** DECLARE PROPERTIES/INPUTS ***/
297 declareProperties = (): void => {
298 console.log("==>" + this.constructor.name + ": declareProperties");
300 let selectedProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
301 let selectedInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
302 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
304 angular.forEach(instancesIds, (instanceId: string): void => {
305 let selectedInstanceData: ResourceInstance = this.instances.find(instance => instance.uniqueId == instanceId);
306 let originType: string = (selectedInstanceData) ? selectedInstanceData.originType : this.selectedInstanceType;
307 if (!this.isInput(originType)) {
308 selectedProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
310 selectedInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
314 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedInputs, selectedProperties);
316 this.componentServiceNg2
317 .createInput(this.component, inputsToCreate)
318 .subscribe(response => {
319 this.setInputTabIndication(response.length);
320 this.checkedPropertiesCount = 0;
321 _.forEach(response, (input: InputBEModel) => {
322 let newInput: InputFEModel = new InputFEModel(input);
323 this.inputs.push(newInput);
324 this.updatePropertyValueAfterDeclare(newInput);
326 }, error => {}); //ignore error
330 updatePropertyValueAfterDeclare = (input: InputFEModel) => {
331 if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
332 let propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
333 return feProperty.name == input.relatedPropertyName;
335 let inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
336 propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
337 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
338 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
342 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
343 updateCheckedPropertyCount = (increment: boolean): void => {
344 this.checkedPropertiesCount += (increment) ? 1 : -1;
345 console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount);
348 setInputTabIndication = (numInputs: number): void => {
349 this.renderer.invokeElementMethod(this.propertyInputTabs, 'setTabIndication', ['Inputs', numInputs]);
352 deleteInput = (input: InputFEModel) => {
353 console.log("==>" + this.constructor.name + ": deleteInput");
354 let inputToDelete = new PropertyBEModel(input);
356 this.componentServiceNg2
357 .deleteInput(this.component, inputToDelete)
358 .subscribe(response => {
359 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
361 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
362 this.onInstanceSelectedUpdate(this.selectedInstanceData);
363 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
365 // if (instanceFeProperties) {
366 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
367 // return prop.name == input.propertyName;
370 // if (propToEnable) {
371 // if (propToEnable.name == response.inputPath) response.inputPath = null;
372 // propToEnable.setNonDeclared(response.inputPath);
373 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
374 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
377 }, error => {}); //ignore error
382 /*** SEARCH RELATED FUNCTIONS ***/
383 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
384 let instanceBePropertiesMap:InstanceBePropertiesMap;
385 this.componentServiceNg2
386 .filterComponentInstanceProperties(this.component, filterData)
387 .subscribe(response => {
389 this.processInstancePropertiesResponse(response, false);
390 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
391 this.searchPropertyName = filterData.propertyName;//mark in table
392 this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
393 this.propertiesNavigationData = [];
394 this.displayClearSearch = true;
395 }, error => {}); //ignore error
399 clearSearch = () => {
400 this.instancesNavigationData = this.instances;
401 this.searchPropertyName = "";
402 this.hierarchyPropertiesDisplayOptions.searchText = "";
403 this.displayClearSearch = false;
404 this.advanceSearch.clearAll();
405 this.searchQuery = '';
408 clickOnClearSearch = () => {
410 this.selectFirstInstanceByDefault();
411 this.renderer.invokeElementMethod(
412 this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
415 private isInput = (instanceType:string):boolean =>{
416 return instanceType === ResourceType.VF || instanceType === ResourceType.PNF || instanceType === ResourceType.CVFC;