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 instances: Array<ComponentInstance|GroupInstance|PolicyInstance> = [];
66 propertyStructureHeader: string;
68 selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
69 selectedInstanceData: ComponentInstance|GroupInstance|PolicyInstance = null;
70 checkedPropertiesCount: number = 0;
72 hierarchyPropertiesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
73 hierarchyInstancesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name', 'archived', null, 'iconClass');
74 displayClearSearch = false;
75 searchPropertyName:string;
77 isInputsTabSelected:boolean;
78 isPropertiesTabSelected:boolean;
80 resourceIsReadonly:boolean;
81 loadingInstances:boolean = false;
82 loadingInputs:boolean = false;
83 loadingProperties:boolean = false;
84 changedData:Array<PropertyFEModel|InputFEModel>;
85 hasChangedData:boolean;
86 isValidChangedData:boolean;
87 savingChangedData:boolean;
88 stateChangeStartUnregister:Function;
89 serviceBePropertiesMap: InstanceBePropertiesMap;
91 @ViewChild('hierarchyNavTabs') hierarchyNavTabs: Tabs;
92 @ViewChild('propertyInputTabs') propertyInputTabs: Tabs;
93 @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
95 constructor(private propertiesService: PropertiesService,
96 private hierarchyNavService: HierarchyNavService,
97 private propertiesUtils:PropertiesUtils,
98 private inputsUtils:InputsUtils,
99 private componentServiceNg2:ComponentServiceNg2,
100 private componentInstanceServiceNg2:ComponentInstanceServiceNg2,
101 @Inject("$stateParams") _stateParams,
102 @Inject("$scope") private $scope:ng.IScope,
103 @Inject("$state") private $state:ng.ui.IStateService,
104 @Inject("Notification") private Notification:any,
105 private componentModeService:ComponentModeService,
106 private ModalService:ModalService,
107 private EventListenerService:EventListenerService,
108 private ModalServiceSdcUI: SdcUiComponents.ModalService) {
110 this.instanceFePropertiesMap = new InstanceFePropertiesMap();
112 /* 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
113 than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
114 this.component = _stateParams.component;
115 this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.onCheckout);
116 this.updateViewMode();
118 this.changedData = [];
119 this.updateHasChangedData();
120 this.isValidChangedData = true;
124 console.log("==>" + this.constructor.name + ": ngOnInit");
125 this.loadingInputs = true;
126 this.loadingInstances = true;
127 this.loadingProperties = true;
128 this.componentServiceNg2
129 .getComponentInputsWithProperties(this.component)
130 .subscribe(response => {
131 _.forEach(response.inputs, (input: InputBEModel) => {
132 const newInput: InputFEModel = new InputFEModel(input);
133 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
134 this.inputs.push(newInput); //only push items that were declared via SDC
136 this.loadingInputs = false;
139 this.componentServiceNg2
140 .getComponentResourcePropertiesData(this.component)
141 .subscribe(response => {
143 this.instances.push(...response.componentInstances);
144 this.instances.push(...response.groupInstances);
145 this.instances.push(...response.policies);
147 // add the service self instance to the top of the list.
148 const serviceInstance = new ComponentInstance();
149 serviceInstance.name = SERVICE_SELF_TITLE;
150 serviceInstance.uniqueId = this.component.uniqueId;
151 this.instances.unshift(serviceInstance);
153 _.forEach(this.instances, (instance) => {
154 this.instancesNavigationData.push(instance);
155 this.componentInstanceNamesMap[instance.uniqueId] = <InstanceFeDetails>{name: instance.name, iconClass:instance.iconClass, originArchived:instance.originArchived};
157 this.loadingInstances = false;
158 if (this.instancesNavigationData[0] == undefined) {
159 this.loadingProperties = false;
161 this.selectFirstInstanceByDefault();
164 this.stateChangeStartUnregister = this.$scope.$on('$stateChangeStart', (event, toState, toParams) => {
165 // stop if has changed properties
166 if (this.hasChangedData) {
167 event.preventDefault();
168 this.showUnsavedChangesAlert().then(() => {
169 this.$state.go(toState, toParams);
176 this.EventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE);
177 this.stateChangeStartUnregister();
180 selectFirstInstanceByDefault = () => {
181 if (this.instancesNavigationData[0] !== undefined) {
182 this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
186 updateViewMode = () => {
187 this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW;
190 onCheckout = (component:ComponentData) => {
191 this.component = component;
192 this.updateViewMode();
195 isSelf = ():boolean => {
196 return this.selectedInstanceData && this.selectedInstanceData.uniqueId == this.component.uniqueId;
199 getServiceProperties(){
200 this.loadingProperties = false;
201 this.componentServiceNg2
202 .getServiceProperties(this.component)
203 .subscribe(response => {
204 this.serviceBePropertiesMap = new InstanceBePropertiesMap();
205 this.serviceBePropertiesMap[this.component.uniqueId] = response;
206 this.processInstancePropertiesResponse(this.serviceBePropertiesMap, false);
207 this.loadingProperties = false;
209 this.loadingProperties = false;
213 onInstanceSelectedUpdate = (instance: ComponentInstance|GroupInstance|PolicyInstance) => {
214 // stop if has changed properties
215 if (this.hasChangedData) {
216 this.showUnsavedChangesAlert().then((resolve)=> {
217 this.changeSelectedInstance(instance)
222 this.changeSelectedInstance(instance);
225 changeSelectedInstance = (instance: ComponentInstance|GroupInstance|PolicyInstance) => {
226 this.selectedInstanceData = instance;
227 this.loadingProperties = true;
228 if (instance instanceof ComponentInstance) {
229 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
230 if (this.isInput(instance.originType)) {
231 this.componentInstanceServiceNg2
232 .getComponentInstanceInputs(this.component, instance)
233 .subscribe(response => {
234 instanceBePropertiesMap[instance.uniqueId] = response;
235 this.processInstancePropertiesResponse(instanceBePropertiesMap, true);
236 this.loadingProperties = false;
239 } else if (this.isSelf()) {
240 this.getServiceProperties();
242 this.componentInstanceServiceNg2
243 .getComponentInstanceProperties(this.component, instance.uniqueId)
244 .subscribe(response => {
245 instanceBePropertiesMap[instance.uniqueId] = response;
246 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
247 this.loadingProperties = false;
252 this.resourceIsReadonly = (instance.componentName === "vnfConfiguration");
253 } else if (instance instanceof GroupInstance) {
254 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
255 this.componentInstanceServiceNg2
256 .getComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
257 .subscribe((response) => {
258 instanceBePropertiesMap[instance.uniqueId] = response;
259 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
260 this.loadingProperties = false;
262 } else if (instance instanceof PolicyInstance) {
263 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
264 this.componentInstanceServiceNg2
265 .getComponentPolicyInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
266 .subscribe((response) => {
267 instanceBePropertiesMap[instance.uniqueId] = response;
268 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
269 this.loadingProperties = false;
272 this.loadingProperties = false;
275 if (this.searchPropertyName) {
278 //clear selected property from the navigation
279 this.selectedFlatProperty = new SimpleFlatProperty();
280 this.propertiesNavigationData = [];
284 * Entry point handling response from server
286 processInstancePropertiesResponse = (instanceBePropertiesMap: InstanceBePropertiesMap, originTypeIsVF: boolean) => {
287 this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
288 this.checkedPropertiesCount = 0;
292 /*** VALUE CHANGE EVENTS ***/
293 dataChanged = (item:PropertyFEModel|InputFEModel) => {
295 if (this.isPropertiesTabSelected && item instanceof PropertyFEModel) {
296 itemHasChanged = item.hasValueObjChanged();
297 } else if (this.isInputsTabSelected && item instanceof InputFEModel) {
298 itemHasChanged = item.hasDefaultValueChanged();
301 const dataChangedIdx = this.changedData.findIndex((changedItem) => changedItem === item);
302 if (itemHasChanged) {
303 if (dataChangedIdx === -1) {
304 this.changedData.push(item);
307 if (dataChangedIdx !== -1) {
308 this.changedData.splice(dataChangedIdx, 1);
312 if (this.isPropertiesTabSelected) {
313 this.isValidChangedData = this.changedData.every((changedItem) => (<PropertyFEModel>changedItem).valueObjIsValid);
314 } else if (this.isInputsTabSelected) {
315 this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid);
317 this.updateHasChangedData();
321 /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
324 * Handle select node in navigation area, and select the row in table
326 onPropertySelectedUpdate = ($event) => {
327 console.log("==>" + this.constructor.name + ": onPropertySelectedUpdate");
328 this.selectedFlatProperty = $event;
329 let parentProperty:PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
330 parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
334 * When user select row in table, this will prepare the hirarchy object for the tree.
336 selectPropertyRow = (propertyRowSelectedEvent:PropertyRowSelectedEvent) => {
337 console.log("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
338 let property = propertyRowSelectedEvent.propertyModel;
339 let instanceName = propertyRowSelectedEvent.instanceName;
340 this.propertyStructureHeader = null;
342 // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
343 if (!(this.selectedInstanceData instanceof ComponentInstance) || this.selectedInstanceData.originType !== ResourceType.VF) {
344 let simpleFlatProperty:Array<SimpleFlatProperty>;
345 if (property instanceof PropertyFEModel) {
346 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
347 } else if (property instanceof DerivedFEProperty) {
348 // Need to find parent PropertyFEModel
349 let parentPropertyFEModel:PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty):boolean => {
350 return property.propertiesName.indexOf(tmpFeProperty.name)===0;
352 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
354 this.propertiesNavigationData = simpleFlatProperty;
357 // Update the header in the navigation tree with property name.
358 this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
360 // Set selected property in table
361 this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
362 this.hierarchyNavTabs.triggerTabChange('Property Structure');
366 selectInstanceRow = ($event) => {//get instance name
367 this.selectedInstanceData = _.find(this.instancesNavigationData, (instance:ComponentInstance) => {
368 return instance.name == $event;
370 this.hierarchyNavTabs.triggerTabChange('Composition');
373 tabChanged = (event) => {
374 // stop if has changed properties
375 if (this.hasChangedData) {
376 this.propertyInputTabs.triggerTabChange(this.currentMainTab.title);
377 this.showUnsavedChangesAlert().then((proceed) => {
378 this.propertyInputTabs.selectTab(this.propertyInputTabs.tabs.find((tab) => tab.title === event.title));
384 console.log("==>" + this.constructor.name + ": tabChanged " + event);
385 this.currentMainTab = this.propertyInputTabs.tabs.find((tab) => tab.title === event.title);
386 this.isPropertiesTabSelected = this.currentMainTab.title === "Properties";
387 this.isInputsTabSelected = this.currentMainTab.title === "Inputs";
388 this.propertyStructureHeader = null;
389 this.searchQuery = '';
394 /*** DECLARE PROPERTIES/INPUTS ***/
395 declareProperties = (): void => {
396 console.log("==>" + this.constructor.name + ": declareProperties");
398 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
399 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
400 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
401 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
402 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
404 angular.forEach(instancesIds, (instanceId: string): void => {
405 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
406 if (selectedInstanceData instanceof ComponentInstance) {
407 if (!this.isInput(selectedInstanceData.originType)) {
408 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
410 selectedComponentInstancesInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
412 } else if (selectedInstanceData instanceof GroupInstance) {
413 selectedGroupInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
414 } else if (selectedInstanceData instanceof PolicyInstance) {
415 selectedPolicyInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
419 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
421 this.componentServiceNg2
422 .createInput(this.component, inputsToCreate, this.isSelf())
423 .subscribe(response => {
424 this.setInputTabIndication(response.length);
425 this.checkedPropertiesCount = 0;
426 _.forEach(response, (input: InputBEModel) => {
427 let newInput: InputFEModel = new InputFEModel(input);
428 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
429 this.inputs.push(newInput);
430 this.updatePropertyValueAfterDeclare(newInput);
432 }, error => {}); //ignore error
435 saveChangedData = ():Promise<(PropertyBEModel|InputBEModel)[]> => {
436 return new Promise((resolve, reject) => {
437 if (!this.isValidChangedData) {
438 reject('Changed data is invalid - cannot save!');
441 if (!this.changedData.length) {
446 // make request and its handlers
448 let handleSuccess, handleError;
449 if (this.isPropertiesTabSelected) {
450 const changedProperties: PropertyBEModel[] = this.changedData.map((changedProp) => {
451 changedProp = <PropertyFEModel>changedProp;
452 const propBE = new PropertyBEModel(changedProp);
453 propBE.value = changedProp.getJSONValue();
457 if (this.selectedInstanceData instanceof ComponentInstance) {
458 if (this.isInput(this.selectedInstanceData.originType)) {
459 request = this.componentInstanceServiceNg2
460 .updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedProperties);
461 handleSuccess = (response) => {
462 // reset each changed property with new value and remove it from changed properties list
463 response.forEach((resInput) => {
464 const changedProp = <PropertyFEModel>this.changedData.shift();
465 this.propertiesUtils.resetPropertyValue(changedProp, resInput.value);
467 console.log('updated instance inputs:', response);
471 request = this.componentServiceNg2.updateServiceProperties(this.component, _.map(changedProperties, cp => {
472 delete cp.constraints;
476 request = this.componentInstanceServiceNg2
477 .updateInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
479 handleSuccess = (response) => {
480 // reset each changed property with new value and remove it from changed properties list
481 response.forEach((resProp) => {
482 const changedProp = <PropertyFEModel>this.changedData.shift();
483 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
486 console.log("updated instance properties: ", response);
489 } else if (this.selectedInstanceData instanceof GroupInstance) {
490 request = this.componentInstanceServiceNg2
491 .updateComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
492 handleSuccess = (response) => {
493 // reset each changed property with new value and remove it from changed properties list
494 response.forEach((resProp) => {
495 const changedProp = <PropertyFEModel>this.changedData.shift();
496 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
499 console.log("updated group instance properties: ", response);
501 } else if (this.selectedInstanceData instanceof PolicyInstance) {
502 request = this.componentInstanceServiceNg2
503 .updateComponentPolicyInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
504 handleSuccess = (response) => {
505 // reset each changed property with new value and remove it from changed properties list
506 response.forEach((resProp) => {
507 const changedProp = <PropertyFEModel>this.changedData.shift();
508 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
511 console.log("updated policy instance properties: ", response);
514 } else if (this.isInputsTabSelected) {
515 const changedInputs: InputBEModel[] = this.changedData.map((changedInput) => {
516 changedInput = <InputFEModel>changedInput;
517 const inputBE = new InputBEModel(changedInput);
518 inputBE.defaultValue = changedInput.getJSONDefaultValue();
521 request = this.componentServiceNg2
522 .updateComponentInputs(this.component, changedInputs);
523 handleSuccess = (response) => {
524 // reset each changed property with new value and remove it from changed properties list
525 response.forEach((resInput) => {
526 const changedInput = <InputFEModel>this.changedData.shift();
527 this.inputsUtils.resetInputDefaultValue(changedInput, resInput.defaultValue);
529 console.log("updated the component inputs and got this response: ", response);
533 this.savingChangedData = true;
536 this.savingChangedData = false;
537 handleSuccess && handleSuccess(response);
538 this.updateHasChangedData();
542 this.savingChangedData = false;
543 handleError && handleError(error);
544 this.updateHasChangedData();
551 reverseChangedData = ():void => {
552 // make reverse item handler
553 let handleReverseItem;
554 if (this.isPropertiesTabSelected) {
555 handleReverseItem = (changedItem) => {
556 changedItem = <PropertyFEModel>changedItem;
557 this.propertiesUtils.resetPropertyValue(changedItem, changedItem.value);
559 } else if (this.isInputsTabSelected) {
560 handleReverseItem = (changedItem) => {
561 changedItem = <InputFEModel>changedItem;
562 this.inputsUtils.resetInputDefaultValue(changedItem, changedItem.defaultValue);
566 this.changedData.forEach(handleReverseItem);
567 this.changedData = [];
568 this.updateHasChangedData();
571 updateHasChangedData = ():boolean => {
572 const curHasChangedData:boolean = (this.changedData.length > 0);
573 if (curHasChangedData !== this.hasChangedData) {
574 this.hasChangedData = curHasChangedData;
575 if(this.hasChangedData) {
576 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.hasChangedData, this.showUnsavedChangesAlert);
578 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
581 return this.hasChangedData;
584 doSaveChangedData = (onSuccessFunction?:Function, onError?:Function):void => {
585 this.saveChangedData().then(
587 this.Notification.success({
588 message: 'Successfully saved changes',
591 if(onSuccessFunction) onSuccessFunction();
594 this.Notification.error({
595 message: 'Failed to save changes!',
598 if(onError) onError();
603 showUnsavedChangesAlert = ():Promise<any> => {
604 let modalTitle:string;
605 if (this.isPropertiesTabSelected) {
606 modalTitle = `Unsaved properties for ${this.selectedInstanceData.name}`;
607 } else if (this.isInputsTabSelected) {
608 modalTitle = `Unsaved inputs for ${this.component.name}`;
611 return new Promise<any>((resolve, reject) => {
612 const modal = this.ModalServiceSdcUI.openCustomModal(
620 {id: 'cancelButton', text: 'Cancel', type: 'secondary', size: 'xsm', closeModal: true, callback: () => reject()},
621 {id: 'discardButton', text: 'Discard', type: 'secondary', size: 'xsm', closeModal: true, callback: () => { this.reverseChangedData(); resolve()}},
622 {id: 'saveButton', text: 'Save', type: 'primary', size: 'xsm', closeModal: true, disabled: !this.isValidChangedData, callback: () => this.doSaveChangedData(resolve, reject)}
623 ] as IModalButtonComponent[]
624 }, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
629 updatePropertyValueAfterDeclare = (input: InputFEModel) => {
630 if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
631 let propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
632 return feProperty.name == input.relatedPropertyName;
634 let inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
635 propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
636 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
637 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
641 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
642 updateCheckedPropertyCount = (increment: boolean): void => {
643 this.checkedPropertiesCount += (increment) ? 1 : -1;
644 console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount);
647 setInputTabIndication = (numInputs: number): void => {
648 this.propertyInputTabs.setTabIndication('Inputs', numInputs);
651 resetUnsavedChangesForInput = (input:InputFEModel) => {
652 this.inputsUtils.resetInputDefaultValue(input, input.defaultValue);
653 this.changedData = this.changedData.filter((changedItem) => changedItem.uniqueId !== input.uniqueId);
654 this.updateHasChangedData();
657 deleteInput = (input: InputFEModel) => {
658 //reset any unsaved changes to the input before deleting it
659 this.resetUnsavedChangesForInput(input);
661 console.log("==>" + this.constructor.name + ": deleteInput");
662 let inputToDelete = new InputBEModel(input);
664 this.componentServiceNg2
665 .deleteInput(this.component, inputToDelete)
666 .subscribe(response => {
667 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
669 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
670 this.changeSelectedInstance(this.selectedInstanceData);
671 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
673 // if (instanceFeProperties) {
674 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
675 // return prop.name == input.propertyName;
678 // if (propToEnable) {
679 // if (propToEnable.name == response.inputPath) response.inputPath = null;
680 // propToEnable.setNonDeclared(response.inputPath);
681 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
682 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
685 }, error => {}); //ignore error
688 deleteProperty = (property: PropertyFEModel) => {
689 let propertyToDelete = new PropertyFEModel(property);
690 this.loadingProperties = true;
691 let feMap = this.instanceFePropertiesMap;
692 this.componentServiceNg2
693 .deleteServiceProperty(this.component, propertyToDelete)
694 .subscribe(response => {
695 const props = feMap[this.component.uniqueId];
696 props.splice(props.findIndex(p => p.uniqueId === response),1);
697 this.loadingProperties = false;
699 this.loadingProperties = false;
700 console.error(error);
704 /*** addProperty ***/
705 addProperty = () => {
706 let modalTitle = 'Add Property';
707 const modal = this.ModalService.createCustomModal(new ModalModel(
712 new ButtonModel('Save', 'blue', () => {
713 modal.instance.dynamicContent.instance.isLoading = true;
714 const newProperty: PropertyBEModel = modal.instance.dynamicContent.instance.propertyModel;
715 this.componentServiceNg2.createServiceProperty(this.component, newProperty)
716 .subscribe(response => {
717 modal.instance.dynamicContent.instance.isLoading = false;
718 let newProp: PropertyFEModel = this.propertiesUtils.convertAddPropertyBAToPropertyFE(response);
719 this.instanceFePropertiesMap[this.component.uniqueId].push(newProp);
720 modal.instance.close();
722 modal.instance.dynamicContent.instance.isLoading = false;
723 this.Notification.error({
724 message: 'Failed to add property:' + error,
729 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
730 new ButtonModel('Cancel', 'outline grey', () => {
731 modal.instance.close();
736 this.ModalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
737 modal.instance.open();
740 /*** SEARCH RELATED FUNCTIONS ***/
741 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
742 let instanceBePropertiesMap:InstanceBePropertiesMap;
743 this.componentServiceNg2
744 .filterComponentInstanceProperties(this.component, filterData)
745 .subscribe(response => {
747 this.processInstancePropertiesResponse(response, false);
748 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
749 this.searchPropertyName = filterData.propertyName;//mark in table
750 this.hierarchyNavTabs.triggerTabChange('Composition');
751 this.propertiesNavigationData = [];
752 this.displayClearSearch = true;
753 }, error => {}); //ignore error
757 clearSearch = () => {
758 this.instancesNavigationData = this.instances;
759 this.searchPropertyName = "";
760 this.hierarchyPropertiesDisplayOptions.searchText = "";
761 this.displayClearSearch = false;
762 this.advanceSearch.clearAll();
763 this.searchQuery = '';
766 clickOnClearSearch = () => {
768 this.selectFirstInstanceByDefault();
769 this.hierarchyNavTabs.triggerTabChange('Composition');
772 private isInput = (instanceType:string):boolean =>{
773 return instanceType === ResourceType.VF || instanceType === ResourceType.PNF || instanceType === ResourceType.CVFC || instanceType === ResourceType.CR;