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 .getComponentInputs(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, changedProperties);
473 request = this.componentInstanceServiceNg2
474 .updateInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
476 handleSuccess = (response) => {
477 // reset each changed property with new value and remove it from changed properties list
478 response.forEach((resProp) => {
479 const changedProp = <PropertyFEModel>this.changedData.shift();
480 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
483 console.log("updated instance properties: ", response);
486 } else if (this.selectedInstanceData instanceof GroupInstance) {
487 request = this.componentInstanceServiceNg2
488 .updateComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
489 handleSuccess = (response) => {
490 // reset each changed property with new value and remove it from changed properties list
491 response.forEach((resProp) => {
492 const changedProp = <PropertyFEModel>this.changedData.shift();
493 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
496 console.log("updated group instance properties: ", response);
498 } else if (this.selectedInstanceData instanceof PolicyInstance) {
499 request = this.componentInstanceServiceNg2
500 .updateComponentPolicyInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
501 handleSuccess = (response) => {
502 // reset each changed property with new value and remove it from changed properties list
503 response.forEach((resProp) => {
504 const changedProp = <PropertyFEModel>this.changedData.shift();
505 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
508 console.log("updated policy instance properties: ", response);
511 } else if (this.isInputsTabSelected) {
512 const changedInputs: InputBEModel[] = this.changedData.map((changedInput) => {
513 changedInput = <InputFEModel>changedInput;
514 const inputBE = new InputBEModel(changedInput);
515 inputBE.defaultValue = changedInput.getJSONDefaultValue();
518 request = this.componentServiceNg2
519 .updateComponentInputs(this.component, changedInputs);
520 handleSuccess = (response) => {
521 // reset each changed property with new value and remove it from changed properties list
522 response.forEach((resInput) => {
523 const changedInput = <InputFEModel>this.changedData.shift();
524 this.inputsUtils.resetInputDefaultValue(changedInput, resInput.defaultValue);
526 console.log("updated the component inputs and got this response: ", response);
530 this.savingChangedData = true;
533 this.savingChangedData = false;
534 handleSuccess && handleSuccess(response);
535 this.updateHasChangedData();
539 this.savingChangedData = false;
540 handleError && handleError(error);
541 this.updateHasChangedData();
548 reverseChangedData = ():void => {
549 // make reverse item handler
550 let handleReverseItem;
551 if (this.isPropertiesTabSelected) {
552 handleReverseItem = (changedItem) => {
553 changedItem = <PropertyFEModel>changedItem;
554 this.propertiesUtils.resetPropertyValue(changedItem, changedItem.value);
556 } else if (this.isInputsTabSelected) {
557 handleReverseItem = (changedItem) => {
558 changedItem = <InputFEModel>changedItem;
559 this.inputsUtils.resetInputDefaultValue(changedItem, changedItem.defaultValue);
563 this.changedData.forEach(handleReverseItem);
564 this.changedData = [];
565 this.updateHasChangedData();
568 updateHasChangedData = ():boolean => {
569 const curHasChangedData:boolean = (this.changedData.length > 0);
570 if (curHasChangedData !== this.hasChangedData) {
571 this.hasChangedData = curHasChangedData;
572 if(this.hasChangedData) {
573 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.hasChangedData, this.showUnsavedChangesAlert);
575 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
578 return this.hasChangedData;
581 doSaveChangedData = (onSuccessFunction?:Function, onError?:Function):void => {
582 this.saveChangedData().then(
584 this.Notification.success({
585 message: 'Successfully saved changes',
588 if(onSuccessFunction) onSuccessFunction();
591 this.Notification.error({
592 message: 'Failed to save changes!',
595 if(onError) onError();
600 showUnsavedChangesAlert = ():Promise<any> => {
601 let modalTitle:string;
602 if (this.isPropertiesTabSelected) {
603 modalTitle = `Unsaved properties for ${this.selectedInstanceData.name}`;
604 } else if (this.isInputsTabSelected) {
605 modalTitle = `Unsaved inputs for ${this.component.name}`;
608 return new Promise<any>((resolve, reject) => {
609 const modal = this.ModalServiceSdcUI.openCustomModal(
617 {id: 'cancelButton', text: 'Cancel', type: 'secondary', size: 'xsm', closeModal: true, callback: () => reject()},
618 {id: 'discardButton', text: 'Discard', type: 'secondary', size: 'xsm', closeModal: true, callback: () => { this.reverseChangedData(); resolve()}},
619 {id: 'saveButton', text: 'Save', type: 'primary', size: 'xsm', closeModal: true, disabled: !this.isValidChangedData, callback: () => this.doSaveChangedData(resolve, reject)}
620 ] as IModalButtonComponent[]
621 }, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
626 updatePropertyValueAfterDeclare = (input: InputFEModel) => {
627 if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
628 let propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
629 return feProperty.name == input.relatedPropertyName;
631 let inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
632 propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
633 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
634 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
638 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
639 updateCheckedPropertyCount = (increment: boolean): void => {
640 this.checkedPropertiesCount += (increment) ? 1 : -1;
641 console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount);
644 setInputTabIndication = (numInputs: number): void => {
645 this.propertyInputTabs.setTabIndication('Inputs', numInputs);
648 resetUnsavedChangesForInput = (input:InputFEModel) => {
649 this.inputsUtils.resetInputDefaultValue(input, input.defaultValue);
650 this.changedData = this.changedData.filter((changedItem) => changedItem.uniqueId !== input.uniqueId);
651 this.updateHasChangedData();
654 deleteInput = (input: InputFEModel) => {
655 //reset any unsaved changes to the input before deleting it
656 this.resetUnsavedChangesForInput(input);
658 console.log("==>" + this.constructor.name + ": deleteInput");
659 let inputToDelete = new InputBEModel(input);
661 this.componentServiceNg2
662 .deleteInput(this.component, inputToDelete)
663 .subscribe(response => {
664 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
666 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
667 this.changeSelectedInstance(this.selectedInstanceData);
668 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
670 // if (instanceFeProperties) {
671 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
672 // return prop.name == input.propertyName;
675 // if (propToEnable) {
676 // if (propToEnable.name == response.inputPath) response.inputPath = null;
677 // propToEnable.setNonDeclared(response.inputPath);
678 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
679 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
682 }, error => {}); //ignore error
685 deleteProperty = (property: PropertyFEModel) => {
686 let propertyToDelete = new PropertyFEModel(property);
687 this.loadingProperties = true;
688 let feMap = this.instanceFePropertiesMap;
689 this.componentServiceNg2
690 .deleteServiceProperty(this.component, propertyToDelete)
691 .subscribe(response => {
692 const props = feMap[this.component.uniqueId];
693 props.splice(props.findIndex(p => p.uniqueId === response),1);
694 this.loadingProperties = false;
696 this.loadingProperties = false;
697 console.error(error);
701 /*** addProperty ***/
702 addProperty = () => {
703 let modalTitle = 'Add Property';
704 const modal = this.ModalService.createCustomModal(new ModalModel(
709 new ButtonModel('Save', 'blue', () => {
710 modal.instance.dynamicContent.instance.isLoading = true;
711 const newProperty: PropertyBEModel = modal.instance.dynamicContent.instance.propertyModel;
712 this.componentServiceNg2.createServiceProperty(this.component, newProperty)
713 .subscribe(response => {
714 modal.instance.dynamicContent.instance.isLoading = false;
715 let newProp: PropertyFEModel = this.propertiesUtils.convertAddPropertyBAToPropertyFE(response);
716 this.instanceFePropertiesMap[this.component.uniqueId].push(newProp);
717 modal.instance.close();
719 modal.instance.dynamicContent.instance.isLoading = false;
720 this.Notification.error({
721 message: 'Failed to add property:' + error,
726 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
727 new ButtonModel('Cancel', 'outline grey', () => {
728 modal.instance.close();
733 this.ModalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
734 modal.instance.open();
737 /*** SEARCH RELATED FUNCTIONS ***/
738 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
739 let instanceBePropertiesMap:InstanceBePropertiesMap;
740 this.componentServiceNg2
741 .filterComponentInstanceProperties(this.component, filterData)
742 .subscribe(response => {
744 this.processInstancePropertiesResponse(response, false);
745 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
746 this.searchPropertyName = filterData.propertyName;//mark in table
747 this.hierarchyNavTabs.triggerTabChange('Composition');
748 this.propertiesNavigationData = [];
749 this.displayClearSearch = true;
750 }, error => {}); //ignore error
754 clearSearch = () => {
755 this.instancesNavigationData = this.instances;
756 this.searchPropertyName = "";
757 this.hierarchyPropertiesDisplayOptions.searchText = "";
758 this.displayClearSearch = false;
759 this.advanceSearch.clearAll();
760 this.searchQuery = '';
763 clickOnClearSearch = () => {
765 this.selectFirstInstanceByDefault();
766 this.hierarchyNavTabs.triggerTabChange('Composition');
769 private isInput = (instanceType:string):boolean =>{
770 return instanceType === ResourceType.VF || instanceType === ResourceType.PNF || instanceType === ResourceType.CVFC || instanceType === ResourceType.CR;