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;
108 }, error => {}); //ignore error
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();
123 }, error => {}); //ignore error
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;
162 }, error => {}); //ignore error
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;
170 }, error => {}); //ignore error
173 if(resourceInstance.componentName === "vnfConfiguration") {
174 this.isReadonly = true;
177 if( this.searchPropertyName ){
180 //clear selected property from the navigation
181 this.selectedFlatProperty = new SimpleFlatProperty();
182 this.propertiesNavigationData = [];
186 * Entry point handling response from server
188 processInstancePropertiesResponse = (instanceBePropertiesMap: InstanceBePropertiesMap, originTypeIsVF: boolean) => {
189 this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
190 this.checkedPropertiesCount = 0;
194 /*** VALUE CHANGE EVENTS ***/
195 propertyValueChanged = (event: PropertyFEModel) => {
196 console.log("==>" + this.constructor.name + ": propertyValueChanged " + event);
197 // Copying the actual value from the object ref into the value if it's from a complex type
198 event.value = event.getJSONValue();
200 if (this.isInput(this.selectedInstanceData.originType)) {
201 console.log("I want to update input value on the resource instance");
202 let inputToUpdate = new PropertyBEModel(event);
203 this.componentInstanceServiceNg2
204 .updateInstanceInput(this.component, this.selectedInstanceData.uniqueId, inputToUpdate)
205 .subscribe(response => {
206 console.log("Update resource instance input response: ", response);
207 }, error => {}); //ignore error
210 let propertyBe = new PropertyBEModel(event);
211 this.componentInstanceServiceNg2
212 .updateInstanceProperty(this.component, this.selectedInstanceData.uniqueId, propertyBe)
213 .subscribe(response => {
214 console.log("Update resource instance property response: ", response);
215 }, error => {}); //ignore error
221 inputValueChanged = (event) => {
222 console.log("==>" + this.constructor.name + ": inputValueChanged");
223 let inputToUpdate = new PropertyBEModel(event);
225 this.componentServiceNg2
226 .updateComponentInput(this.component, inputToUpdate)
227 .subscribe(response => {
228 console.log("updated the component input and got this response: ", response);
229 }, error => {}); //ignore error
233 /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
236 * Handle select node in navigation area, and select the row in table
238 onPropertySelectedUpdate = ($event) => {
239 console.log("==>" + this.constructor.name + ": onPropertySelectedUpdate");
240 this.selectedFlatProperty = $event;
241 let parentProperty:PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
242 parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
246 * When user select row in table, this will prepare the hirarchy object for the tree.
248 selectPropertyRow = (propertyRowSelectedEvent:PropertyRowSelectedEvent) => {
249 console.log("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
250 let property = propertyRowSelectedEvent.propertyModel;
251 let instanceName = propertyRowSelectedEvent.instanceName;
252 this.propertyStructureHeader = null;
254 // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
255 if(this.selectedInstanceData.originType !== ResourceType.VF) {
256 let simpleFlatProperty:Array<SimpleFlatProperty>;
257 if (property instanceof PropertyFEModel) {
258 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
259 } else if (property instanceof DerivedFEProperty) {
260 // Need to find parent PropertyFEModel
261 let parentPropertyFEModel:PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty):boolean => {
262 return property.propertiesName.indexOf(tmpFeProperty.name)===0;
264 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
266 this.propertiesNavigationData = simpleFlatProperty;
269 // Update the header in the navigation tree with property name.
270 this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
272 // Set selected property in table
273 this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
274 this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Property Structure']);
278 selectInstanceRow = ($event) => {//get instance name
279 this.selectedInstanceData = _.find(this.instancesNavigationData, (instance:ComponentInstance) => {
280 return instance.name == $event;
282 this.renderer.invokeElementMethod(
283 this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
286 tabChanged = (event) => {
287 console.log("==>" + this.constructor.name + ": tabChanged " + event);
288 this.isInpusTabSelected = event.title === "Inputs";
289 this.propertyStructureHeader = null;
290 this.searchQuery = '';
295 /*** DECLARE PROPERTIES/INPUTS ***/
296 declareProperties = (): void => {
297 console.log("==>" + this.constructor.name + ": declareProperties");
299 let selectedProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
300 let selectedInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
301 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
303 angular.forEach(instancesIds, (instanceId: string): void => {
304 let selectedInstanceData: ResourceInstance = this.instances.find(instance => instance.uniqueId == instanceId);
305 let originType: string = (selectedInstanceData) ? selectedInstanceData.originType : this.selectedInstanceType;
306 if (!this.isInput(originType)) {
307 selectedProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
309 selectedInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
313 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedInputs, selectedProperties);
315 this.componentServiceNg2
316 .createInput(this.component, inputsToCreate)
317 .subscribe(response => {
318 this.setInputTabIndication(response.length);
319 this.checkedPropertiesCount = 0;
320 _.forEach(response, (input: InputBEModel) => {
321 let newInput: InputFEModel = new InputFEModel(input);
322 this.inputs.push(newInput);
323 this.updatePropertyValueAfterDeclare(newInput);
325 }, error => {}); //ignore error
329 updatePropertyValueAfterDeclare = (input: InputFEModel) => {
330 if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
331 let propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
332 return feProperty.name == input.relatedPropertyName;
334 let inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
335 propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
336 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
337 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
341 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
342 updateCheckedPropertyCount = (increment: boolean): void => {
343 this.checkedPropertiesCount += (increment) ? 1 : -1;
344 console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount);
347 setInputTabIndication = (numInputs: number): void => {
348 this.renderer.invokeElementMethod(this.propertyInputTabs, 'setTabIndication', ['Inputs', numInputs]);
351 deleteInput = (input: InputFEModel) => {
352 console.log("==>" + this.constructor.name + ": deleteInput");
353 let inputToDelete = new PropertyBEModel(input);
355 this.componentServiceNg2
356 .deleteInput(this.component, inputToDelete)
357 .subscribe(response => {
358 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
360 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
361 this.onInstanceSelectedUpdate(this.selectedInstanceData);
362 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
364 // if (instanceFeProperties) {
365 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
366 // return prop.name == input.propertyName;
369 // if (propToEnable) {
370 // if (propToEnable.name == response.inputPath) response.inputPath = null;
371 // propToEnable.setNonDeclared(response.inputPath);
372 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
373 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
376 }, error => {}); //ignore error
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, false);
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;
394 }, error => {}); //ignore error
398 clearSearch = () => {
399 this.instancesNavigationData = this.instances;
400 this.searchPropertyName = "";
401 this.hierarchyPropertiesDisplayOptions.searchText = "";
402 this.displayClearSearch = false;
403 this.advanceSearch.clearAll();
404 this.searchQuery = '';
407 clickOnClearSearch = () => {
409 this.selectFirstInstanceByDefault();
410 this.renderer.invokeElementMethod(
411 this.hierarchyNavTabs, 'triggerTabChange', ['Composition']);
414 private isInput = (instanceType:string):boolean =>{
415 return instanceType === ResourceType.VF || instanceType === ResourceType.PNF || instanceType === ResourceType.CVFC;