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 * as _ from "lodash";
22 import {Component, ViewChild, Inject, TemplateRef} from "@angular/core";
23 import { PropertiesService } from "../../services/properties.service";
24 import { PropertyFEModel, InstanceFePropertiesMap, InstanceBePropertiesMap, InstancePropertiesAPIMap, Component as ComponentData, FilterPropertiesAssignmentData, ModalModel, ButtonModel } from "app/models";
25 import { ResourceType } from "app/utils";
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, GroupInstance, PolicyInstance, PropertyBEModel, DerivedFEProperty, 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";
38 import {ModalService} from "../../services/modal.service";
39 import {Tabs, Tab} from "../../components/ui/tabs/tabs.component";
40 import {InputsUtils} from "./services/inputs.utils";
41 import {PropertyCreatorComponent} from "./property-creator/property-creator.component";
42 import { InstanceFeDetails } from "../../../models/instance-fe-details";
43 import { SdcUiComponents } from "sdc-ui/lib/angular";
44 //import { ModalService as ModalServiceSdcUI} from "sdc-ui/lib/angular/modals/modal.service";
45 import { IModalButtonComponent } from "sdc-ui/lib/angular/modals/models/modal-config";
46 import { UnsavedChangesComponent } from "app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component";
48 const SERVICE_SELF_TITLE = "SELF";
50 templateUrl: './properties-assignment.page.component.html',
51 styleUrls: ['./properties-assignment.page.component.less']
53 export class PropertiesAssignmentComponent {
54 title = "Properties & Inputs";
56 component: ComponentData;
57 componentInstanceNamesMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();//instanceUniqueId, {name, iconClass}
59 propertiesNavigationData = [];
60 instancesNavigationData = [];
62 instanceFePropertiesMap:InstanceFePropertiesMap;
63 inputs: Array<InputFEModel> = [];
64 policies: Array<PolicyInstance> = [];
65 instances: Array<ComponentInstance|GroupInstance|PolicyInstance> = [];
67 propertyStructureHeader: string;
69 selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
70 selectedInstanceData: ComponentInstance|GroupInstance|PolicyInstance = null;
71 checkedPropertiesCount: number = 0;
73 hierarchyPropertiesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
74 hierarchyInstancesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name', 'archived', null, 'iconClass');
75 displayClearSearch = false;
76 searchPropertyName:string;
78 isInputsTabSelected:boolean;
79 isPropertiesTabSelected:boolean;
80 isPoliciesTabSelected:boolean;
82 resourceIsReadonly:boolean;
83 loadingInstances:boolean = false;
84 loadingInputs:boolean = false;
85 loadingPolicies:boolean = false;
86 loadingProperties:boolean = false;
87 changedData:Array<PropertyFEModel|InputFEModel>;
88 hasChangedData:boolean;
89 isValidChangedData:boolean;
90 savingChangedData:boolean;
91 stateChangeStartUnregister:Function;
92 serviceBePropertiesMap: InstanceBePropertiesMap;
94 @ViewChild('hierarchyNavTabs') hierarchyNavTabs: Tabs;
95 @ViewChild('propertyInputTabs') propertyInputTabs: Tabs;
96 @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
98 constructor(private propertiesService: PropertiesService,
99 private hierarchyNavService: HierarchyNavService,
100 private propertiesUtils:PropertiesUtils,
101 private inputsUtils:InputsUtils,
102 private componentServiceNg2:ComponentServiceNg2,
103 private componentInstanceServiceNg2:ComponentInstanceServiceNg2,
104 @Inject("$stateParams") _stateParams,
105 @Inject("$scope") private $scope:ng.IScope,
106 @Inject("$state") private $state:ng.ui.IStateService,
107 @Inject("Notification") private Notification:any,
108 private componentModeService:ComponentModeService,
109 private ModalService:ModalService,
110 private EventListenerService:EventListenerService,
111 private ModalServiceSdcUI: SdcUiComponents.ModalService) {
113 this.instanceFePropertiesMap = new InstanceFePropertiesMap();
115 /* 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
116 than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
117 this.component = _stateParams.component;
118 this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.onCheckout);
119 this.updateViewMode();
121 this.changedData = [];
122 this.updateHasChangedData();
123 this.isValidChangedData = true;
127 console.log("==>" + this.constructor.name + ": ngOnInit");
128 this.loadingInputs = true;
129 this.loadingPolicies = true;
130 this.loadingInstances = true;
131 this.loadingProperties = true;
132 this.componentServiceNg2
133 .getComponentInputsWithProperties(this.component)
134 .subscribe(response => {
135 _.forEach(response.inputs, (input: InputBEModel) => {
136 const newInput: InputFEModel = new InputFEModel(input);
137 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
138 this.inputs.push(newInput); //only push items that were declared via SDC
140 this.loadingInputs = false;
143 this.componentServiceNg2
144 .getComponentResourcePropertiesData(this.component)
145 .subscribe(response => {
146 this.loadingPolicies = false;
148 this.instances.push(...response.componentInstances);
149 this.instances.push(...response.groupInstances);
151 _.forEach(response.policies, (policy: any) => {
152 const newPolicy: InputFEModel = new InputFEModel(policy);
153 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
154 this.policies.push(policy);
157 // add the service self instance to the top of the list.
158 const serviceInstance = new ComponentInstance();
159 serviceInstance.name = SERVICE_SELF_TITLE;
160 serviceInstance.uniqueId = this.component.uniqueId;
161 this.instances.unshift(serviceInstance);
163 _.forEach(this.instances, (instance) => {
164 this.instancesNavigationData.push(instance);
165 this.componentInstanceNamesMap[instance.uniqueId] = <InstanceFeDetails>{name: instance.name, iconClass:instance.iconClass, originArchived:instance.originArchived};
167 this.loadingInstances = false;
168 if (this.instancesNavigationData[0] == undefined) {
169 this.loadingProperties = false;
171 this.selectFirstInstanceByDefault();
174 this.stateChangeStartUnregister = this.$scope.$on('$stateChangeStart', (event, toState, toParams) => {
175 // stop if has changed properties
176 if (this.hasChangedData) {
177 event.preventDefault();
178 this.showUnsavedChangesAlert().then(() => {
179 this.$state.go(toState, toParams);
186 this.EventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE);
187 this.stateChangeStartUnregister();
190 selectFirstInstanceByDefault = () => {
191 if (this.instancesNavigationData[0] !== undefined) {
192 this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
196 updateViewMode = () => {
197 this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW;
200 onCheckout = (component:ComponentData) => {
201 this.component = component;
202 this.updateViewMode();
205 isSelf = ():boolean => {
206 return this.selectedInstanceData && this.selectedInstanceData.uniqueId == this.component.uniqueId;
209 getServiceProperties(){
210 this.loadingProperties = false;
211 this.componentServiceNg2
212 .getServiceProperties(this.component)
213 .subscribe(response => {
214 this.serviceBePropertiesMap = new InstanceBePropertiesMap();
215 this.serviceBePropertiesMap[this.component.uniqueId] = response;
216 this.processInstancePropertiesResponse(this.serviceBePropertiesMap, false);
217 this.loadingProperties = false;
219 this.loadingProperties = false;
223 onInstanceSelectedUpdate = (instance: ComponentInstance|GroupInstance|PolicyInstance) => {
224 // stop if has changed properties
225 if (this.hasChangedData) {
226 this.showUnsavedChangesAlert().then((resolve)=> {
227 this.changeSelectedInstance(instance)
232 this.changeSelectedInstance(instance);
235 changeSelectedInstance = (instance: ComponentInstance|GroupInstance|PolicyInstance) => {
236 this.selectedInstanceData = instance;
237 this.loadingProperties = true;
238 if (instance instanceof ComponentInstance) {
239 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
240 if (this.isInput(instance.originType)) {
241 this.componentInstanceServiceNg2
242 .getComponentInstanceInputs(this.component, instance)
243 .subscribe(response => {
244 instanceBePropertiesMap[instance.uniqueId] = response;
245 this.processInstancePropertiesResponse(instanceBePropertiesMap, true);
246 this.loadingProperties = false;
249 } else if (this.isSelf()) {
250 this.getServiceProperties();
252 this.componentInstanceServiceNg2
253 .getComponentInstanceProperties(this.component, instance.uniqueId)
254 .subscribe(response => {
255 instanceBePropertiesMap[instance.uniqueId] = response;
256 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
257 this.loadingProperties = false;
262 this.resourceIsReadonly = (instance.componentName === "vnfConfiguration");
263 } else if (instance instanceof GroupInstance) {
264 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
265 this.componentInstanceServiceNg2
266 .getComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
267 .subscribe((response) => {
268 instanceBePropertiesMap[instance.uniqueId] = response;
269 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
270 this.loadingProperties = false;
272 } else if (instance instanceof PolicyInstance) {
273 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
274 this.componentInstanceServiceNg2
275 .getComponentPolicyInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
276 .subscribe((response) => {
277 instanceBePropertiesMap[instance.uniqueId] = response;
278 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
279 this.loadingProperties = false;
282 this.loadingProperties = false;
285 if (this.searchPropertyName) {
288 //clear selected property from the navigation
289 this.selectedFlatProperty = new SimpleFlatProperty();
290 this.propertiesNavigationData = [];
294 * Entry point handling response from server
296 processInstancePropertiesResponse = (instanceBePropertiesMap: InstanceBePropertiesMap, originTypeIsVF: boolean) => {
297 this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
298 this.checkedPropertiesCount = 0;
302 /*** VALUE CHANGE EVENTS ***/
303 dataChanged = (item:PropertyFEModel|InputFEModel) => {
305 if (this.isPropertiesTabSelected && item instanceof PropertyFEModel) {
306 itemHasChanged = item.hasValueObjChanged();
307 } else if (this.isInputsTabSelected && item instanceof InputFEModel) {
308 itemHasChanged = item.hasDefaultValueChanged();
309 } else if (this.isPoliciesTabSelected && item instanceof InputFEModel) {
310 itemHasChanged = item.hasDefaultValueChanged();
313 const dataChangedIdx = this.changedData.findIndex((changedItem) => changedItem === item);
314 if (itemHasChanged) {
315 if (dataChangedIdx === -1) {
316 this.changedData.push(item);
319 if (dataChangedIdx !== -1) {
320 this.changedData.splice(dataChangedIdx, 1);
324 if (this.isPropertiesTabSelected) {
325 this.isValidChangedData = this.changedData.every((changedItem) => (<PropertyFEModel>changedItem).valueObjIsValid);
326 } else if (this.isInputsTabSelected || this.isPoliciesTabSelected) {
327 this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid);
329 this.updateHasChangedData();
333 /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
336 * Handle select node in navigation area, and select the row in table
338 onPropertySelectedUpdate = ($event) => {
339 console.log("==>" + this.constructor.name + ": onPropertySelectedUpdate");
340 this.selectedFlatProperty = $event;
341 let parentProperty:PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
342 parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
346 * When user select row in table, this will prepare the hirarchy object for the tree.
348 selectPropertyRow = (propertyRowSelectedEvent:PropertyRowSelectedEvent) => {
349 console.log("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
350 let property = propertyRowSelectedEvent.propertyModel;
351 let instanceName = propertyRowSelectedEvent.instanceName;
352 this.propertyStructureHeader = null;
354 // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
355 if (!(this.selectedInstanceData instanceof ComponentInstance) || this.selectedInstanceData.originType !== ResourceType.VF) {
356 let simpleFlatProperty:Array<SimpleFlatProperty>;
357 if (property instanceof PropertyFEModel) {
358 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
359 } else if (property instanceof DerivedFEProperty) {
360 // Need to find parent PropertyFEModel
361 let parentPropertyFEModel:PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty):boolean => {
362 return property.propertiesName.indexOf(tmpFeProperty.name)===0;
364 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
366 this.propertiesNavigationData = simpleFlatProperty;
369 // Update the header in the navigation tree with property name.
370 this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
372 // Set selected property in table
373 this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
374 this.hierarchyNavTabs.triggerTabChange('Property Structure');
378 selectInstanceRow = ($event) => {//get instance name
379 this.selectedInstanceData = _.find(this.instancesNavigationData, (instance:ComponentInstance) => {
380 return instance.name == $event;
382 this.hierarchyNavTabs.triggerTabChange('Composition');
385 tabChanged = (event) => {
386 // stop if has changed properties
387 if (this.hasChangedData) {
388 this.propertyInputTabs.triggerTabChange(this.currentMainTab.title);
389 this.showUnsavedChangesAlert().then((proceed) => {
390 this.propertyInputTabs.selectTab(this.propertyInputTabs.tabs.find((tab) => tab.title === event.title));
396 console.log("==>" + this.constructor.name + ": tabChanged " + event);
397 this.currentMainTab = this.propertyInputTabs.tabs.find((tab) => tab.title === event.title);
398 this.isPropertiesTabSelected = this.currentMainTab.title === "Properties";
399 this.isInputsTabSelected = this.currentMainTab.title === "Inputs";
400 this.isPoliciesTabSelected = this.currentMainTab.title === "Policies";
401 this.propertyStructureHeader = null;
402 this.searchQuery = '';
407 /*** DECLARE PROPERTIES/INPUTS ***/
408 declareProperties = (): void => {
409 console.log("==>" + this.constructor.name + ": declareProperties");
411 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
412 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
413 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
414 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
415 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
417 angular.forEach(instancesIds, (instanceId: string): void => {
418 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
419 if (selectedInstanceData instanceof ComponentInstance) {
420 if (!this.isInput(selectedInstanceData.originType)) {
421 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
423 selectedComponentInstancesInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
425 } else if (selectedInstanceData instanceof GroupInstance) {
426 selectedGroupInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
427 } else if (selectedInstanceData instanceof PolicyInstance) {
428 selectedPolicyInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
432 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
434 this.componentServiceNg2
435 .createInput(this.component, inputsToCreate, this.isSelf())
436 .subscribe(response => {
437 this.setInputTabIndication(response.length);
438 this.checkedPropertiesCount = 0;
439 _.forEach(response, (input: InputBEModel) => {
440 let newInput: InputFEModel = new InputFEModel(input);
441 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
442 this.inputs.push(newInput);
443 this.updatePropertyValueAfterDeclare(newInput);
445 }, error => {}); //ignore error
448 /*** DECLARE PROPERTIES/POLICIES ***/
449 declarePropertiesToPolicies = (): void => {
450 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
451 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
453 angular.forEach(instancesIds, (instanceId: string): void => {
454 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
455 if (selectedInstanceData instanceof ComponentInstance) {
456 if (!this.isInput(selectedInstanceData.originType)) {
457 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
462 let policiesToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(null, selectedComponentInstancesProperties, null, null);
463 this.loadingPolicies = true;
465 this.componentServiceNg2
466 .createPolicy(this.component, policiesToCreate, this.isSelf())
467 .subscribe(response => {
468 this.setPolicyTabIndication(response.length);
469 this.checkedPropertiesCount = 0;
470 this.displayPoliciesAsDeclared(response);
471 this.loadingPolicies = false;
476 displayPoliciesAsDeclared = (policies) => {
477 _.forEach(policies, (policy: any) => {
478 let newPolicy: InputFEModel = new InputFEModel(policy);
479 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
480 newPolicy.relatedPropertyName = policy.name;
481 newPolicy.relatedPropertyValue = policy.value;
482 this.updatePropertyValueAfterDeclare(newPolicy);
483 this.policies.push(policy);
488 saveChangedData = ():Promise<(PropertyBEModel|InputBEModel)[]> => {
489 return new Promise((resolve, reject) => {
490 if (!this.isValidChangedData) {
491 reject('Changed data is invalid - cannot save!');
494 if (!this.changedData.length) {
499 // make request and its handlers
501 let handleSuccess, handleError;
502 if (this.isPropertiesTabSelected) {
503 const changedProperties: PropertyBEModel[] = this.changedData.map((changedProp) => {
504 changedProp = <PropertyFEModel>changedProp;
505 const propBE = new PropertyBEModel(changedProp);
506 propBE.value = changedProp.getJSONValue();
510 if (this.selectedInstanceData instanceof ComponentInstance) {
511 if (this.isInput(this.selectedInstanceData.originType)) {
512 request = this.componentInstanceServiceNg2
513 .updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedProperties);
514 handleSuccess = (response) => {
515 // reset each changed property with new value and remove it from changed properties list
516 response.forEach((resInput) => {
517 const changedProp = <PropertyFEModel>this.changedData.shift();
518 this.propertiesUtils.resetPropertyValue(changedProp, resInput.value);
520 console.log('updated instance inputs:', response);
524 request = this.componentServiceNg2.updateServiceProperties(this.component, _.map(changedProperties, cp => {
525 delete cp.constraints;
529 request = this.componentInstanceServiceNg2
530 .updateInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
532 handleSuccess = (response) => {
533 // reset each changed property with new value and remove it from changed properties list
534 response.forEach((resProp) => {
535 const changedProp = <PropertyFEModel>this.changedData.shift();
536 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
539 console.log("updated instance properties: ", response);
542 } else if (this.selectedInstanceData instanceof GroupInstance) {
543 request = this.componentInstanceServiceNg2
544 .updateComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
545 handleSuccess = (response) => {
546 // reset each changed property with new value and remove it from changed properties list
547 response.forEach((resProp) => {
548 const changedProp = <PropertyFEModel>this.changedData.shift();
549 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
552 console.log("updated group instance properties: ", response);
554 } else if (this.selectedInstanceData instanceof PolicyInstance) {
555 request = this.componentInstanceServiceNg2
556 .updateComponentPolicyInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
557 handleSuccess = (response) => {
558 // reset each changed property with new value and remove it from changed properties list
559 response.forEach((resProp) => {
560 const changedProp = <PropertyFEModel>this.changedData.shift();
561 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
564 console.log("updated policy instance properties: ", response);
567 } else if (this.isInputsTabSelected) {
568 const changedInputs: InputBEModel[] = this.changedData.map((changedInput) => {
569 changedInput = <InputFEModel>changedInput;
570 const inputBE = new InputBEModel(changedInput);
571 inputBE.defaultValue = changedInput.getJSONDefaultValue();
574 request = this.componentServiceNg2
575 .updateComponentInputs(this.component, changedInputs);
576 handleSuccess = (response) => {
577 // reset each changed property with new value and remove it from changed properties list
578 response.forEach((resInput) => {
579 const changedInput = <InputFEModel>this.changedData.shift();
580 this.inputsUtils.resetInputDefaultValue(changedInput, resInput.defaultValue);
582 console.log("updated the component inputs and got this response: ", response);
586 this.savingChangedData = true;
589 this.savingChangedData = false;
590 handleSuccess && handleSuccess(response);
591 this.updateHasChangedData();
595 this.savingChangedData = false;
596 handleError && handleError(error);
597 this.updateHasChangedData();
604 reverseChangedData = ():void => {
605 // make reverse item handler
606 let handleReverseItem;
607 if (this.isPropertiesTabSelected) {
608 handleReverseItem = (changedItem) => {
609 changedItem = <PropertyFEModel>changedItem;
610 this.propertiesUtils.resetPropertyValue(changedItem, changedItem.value);
612 } else if (this.isInputsTabSelected) {
613 handleReverseItem = (changedItem) => {
614 changedItem = <InputFEModel>changedItem;
615 this.inputsUtils.resetInputDefaultValue(changedItem, changedItem.defaultValue);
619 this.changedData.forEach(handleReverseItem);
620 this.changedData = [];
621 this.updateHasChangedData();
624 updateHasChangedData = ():boolean => {
625 const curHasChangedData:boolean = (this.changedData.length > 0);
626 if (curHasChangedData !== this.hasChangedData) {
627 this.hasChangedData = curHasChangedData;
628 if(this.hasChangedData) {
629 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.hasChangedData, this.showUnsavedChangesAlert);
631 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
634 return this.hasChangedData;
637 doSaveChangedData = (onSuccessFunction?:Function, onError?:Function):void => {
638 this.saveChangedData().then(
640 this.Notification.success({
641 message: 'Successfully saved changes',
644 if(onSuccessFunction) onSuccessFunction();
647 this.Notification.error({
648 message: 'Failed to save changes!',
651 if(onError) onError();
656 showUnsavedChangesAlert = ():Promise<any> => {
657 let modalTitle:string;
658 if (this.isPropertiesTabSelected) {
659 modalTitle = `Unsaved properties for ${this.selectedInstanceData.name}`;
660 } else if (this.isInputsTabSelected) {
661 modalTitle = `Unsaved inputs for ${this.component.name}`;
664 return new Promise<any>((resolve, reject) => {
665 const modal = this.ModalServiceSdcUI.openCustomModal(
673 {id: 'cancelButton', text: 'Cancel', type: 'secondary', size: 'xsm', closeModal: true, callback: () => reject()},
674 {id: 'discardButton', text: 'Discard', type: 'secondary', size: 'xsm', closeModal: true, callback: () => { this.reverseChangedData(); resolve()}},
675 {id: 'saveButton', text: 'Save', type: 'primary', size: 'xsm', closeModal: true, disabled: !this.isValidChangedData, callback: () => this.doSaveChangedData(resolve, reject)}
676 ] as IModalButtonComponent[]
677 }, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
682 updatePropertyValueAfterDeclare = (input: InputFEModel) => {
683 if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
684 let propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
685 return feProperty.name == input.relatedPropertyName;
687 let inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
688 propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
689 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
690 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
694 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
695 updateCheckedPropertyCount = (increment: boolean): void => {
696 this.checkedPropertiesCount += (increment) ? 1 : -1;
697 console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount);
700 setInputTabIndication = (numInputs: number): void => {
701 this.propertyInputTabs.setTabIndication('Inputs', numInputs);
704 setPolicyTabIndication = (numPolicies: number): void => {
705 this.propertyInputTabs.setTabIndication('Policies', numPolicies);
708 resetUnsavedChangesForInput = (input:InputFEModel) => {
709 this.inputsUtils.resetInputDefaultValue(input, input.defaultValue);
710 this.changedData = this.changedData.filter((changedItem) => changedItem.uniqueId !== input.uniqueId);
711 this.updateHasChangedData();
714 deleteInput = (input: InputFEModel) => {
715 //reset any unsaved changes to the input before deleting it
716 this.resetUnsavedChangesForInput(input);
718 console.log("==>" + this.constructor.name + ": deleteInput");
719 let inputToDelete = new InputBEModel(input);
721 this.componentServiceNg2
722 .deleteInput(this.component, inputToDelete)
723 .subscribe(response => {
724 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
726 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
727 this.changeSelectedInstance(this.selectedInstanceData);
728 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
730 // if (instanceFeProperties) {
731 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
732 // return prop.name == input.propertyName;
735 // if (propToEnable) {
736 // if (propToEnable.name == response.inputPath) response.inputPath = null;
737 // propToEnable.setNonDeclared(response.inputPath);
738 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
739 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
742 }, error => {}); //ignore error
745 deletePolicy = (policy: PolicyInstance) => {
746 this.loadingPolicies = true;
747 this.componentServiceNg2
748 .deletePolicy(this.component, policy)
749 .subscribe(response => {
750 this.policies = this.policies.filter(policy => policy.uniqueId !== response.uniqueId);
751 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
752 this.changeSelectedInstance(this.selectedInstanceData);
753 this.loadingPolicies = false;
757 deleteProperty = (property: PropertyFEModel) => {
758 let propertyToDelete = new PropertyFEModel(property);
759 this.loadingProperties = true;
760 let feMap = this.instanceFePropertiesMap;
761 this.componentServiceNg2
762 .deleteServiceProperty(this.component, propertyToDelete)
763 .subscribe(response => {
764 const props = feMap[this.component.uniqueId];
765 props.splice(props.findIndex(p => p.uniqueId === response),1);
766 this.loadingProperties = false;
768 this.loadingProperties = false;
769 console.error(error);
773 /*** addProperty ***/
774 addProperty = () => {
775 let modalTitle = 'Add Property';
776 const modal = this.ModalService.createCustomModal(new ModalModel(
781 new ButtonModel('Save', 'blue', () => {
782 modal.instance.dynamicContent.instance.isLoading = true;
783 const newProperty: PropertyBEModel = modal.instance.dynamicContent.instance.propertyModel;
784 this.componentServiceNg2.createServiceProperty(this.component, newProperty)
785 .subscribe(response => {
786 modal.instance.dynamicContent.instance.isLoading = false;
787 let newProp: PropertyFEModel = this.propertiesUtils.convertAddPropertyBAToPropertyFE(response);
788 this.instanceFePropertiesMap[this.component.uniqueId].push(newProp);
789 modal.instance.close();
791 modal.instance.dynamicContent.instance.isLoading = false;
792 this.Notification.error({
793 message: 'Failed to add property:' + error,
798 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
799 new ButtonModel('Cancel', 'outline grey', () => {
800 modal.instance.close();
805 this.ModalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
806 modal.instance.open();
809 /*** SEARCH RELATED FUNCTIONS ***/
810 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
811 let instanceBePropertiesMap:InstanceBePropertiesMap;
812 this.componentServiceNg2
813 .filterComponentInstanceProperties(this.component, filterData)
814 .subscribe(response => {
816 this.processInstancePropertiesResponse(response, false);
817 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
818 this.searchPropertyName = filterData.propertyName;//mark in table
819 this.hierarchyNavTabs.triggerTabChange('Composition');
820 this.propertiesNavigationData = [];
821 this.displayClearSearch = true;
822 }, error => {}); //ignore error
826 clearSearch = () => {
827 this.instancesNavigationData = this.instances;
828 this.searchPropertyName = "";
829 this.hierarchyPropertiesDisplayOptions.searchText = "";
830 this.displayClearSearch = false;
831 this.advanceSearch.clearAll();
832 this.searchQuery = '';
835 clickOnClearSearch = () => {
837 this.selectFirstInstanceByDefault();
838 this.hierarchyNavTabs.triggerTabChange('Composition');
841 private isInput = (instanceType:string):boolean =>{
842 return instanceType === ResourceType.VF || instanceType === ResourceType.PNF || instanceType === ResourceType.CVFC || instanceType === ResourceType.CR;