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>_.find(this.changedData, changedDataObject => changedDataObject.uniqueId === resProp.uniqueId);
536 this.changedData = _.filter(this.changedData, changedDataObject => changedDataObject.uniqueId !== resProp.uniqueId);
537 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
540 console.log("updated instance properties: ", response);
543 } else if (this.selectedInstanceData instanceof GroupInstance) {
544 request = this.componentInstanceServiceNg2
545 .updateComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
546 handleSuccess = (response) => {
547 // reset each changed property with new value and remove it from changed properties list
548 response.forEach((resProp) => {
549 const changedProp = <PropertyFEModel>this.changedData.shift();
550 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
553 console.log("updated group instance properties: ", response);
555 } else if (this.selectedInstanceData instanceof PolicyInstance) {
556 request = this.componentInstanceServiceNg2
557 .updateComponentPolicyInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
558 handleSuccess = (response) => {
559 // reset each changed property with new value and remove it from changed properties list
560 response.forEach((resProp) => {
561 const changedProp = <PropertyFEModel>this.changedData.shift();
562 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
565 console.log("updated policy instance properties: ", response);
568 } else if (this.isInputsTabSelected) {
569 const changedInputs: InputBEModel[] = this.changedData.map((changedInput) => {
570 changedInput = <InputFEModel>changedInput;
571 const inputBE = new InputBEModel(changedInput);
572 inputBE.defaultValue = changedInput.getJSONDefaultValue();
575 request = this.componentServiceNg2
576 .updateComponentInputs(this.component, changedInputs);
577 handleSuccess = (response) => {
578 // reset each changed property with new value and remove it from changed properties list
579 response.forEach((resInput) => {
580 const changedInput = <InputFEModel>this.changedData.shift();
581 this.inputsUtils.resetInputDefaultValue(changedInput, resInput.defaultValue);
583 console.log("updated the component inputs and got this response: ", response);
587 this.savingChangedData = true;
590 this.savingChangedData = false;
591 handleSuccess && handleSuccess(response);
592 this.updateHasChangedData();
596 this.savingChangedData = false;
597 handleError && handleError(error);
598 this.updateHasChangedData();
605 reverseChangedData = ():void => {
606 // make reverse item handler
607 let handleReverseItem;
608 if (this.isPropertiesTabSelected) {
609 handleReverseItem = (changedItem) => {
610 changedItem = <PropertyFEModel>changedItem;
611 this.propertiesUtils.resetPropertyValue(changedItem, changedItem.value);
613 } else if (this.isInputsTabSelected) {
614 handleReverseItem = (changedItem) => {
615 changedItem = <InputFEModel>changedItem;
616 this.inputsUtils.resetInputDefaultValue(changedItem, changedItem.defaultValue);
620 this.changedData.forEach(handleReverseItem);
621 this.changedData = [];
622 this.updateHasChangedData();
625 updateHasChangedData = ():boolean => {
626 const curHasChangedData:boolean = (this.changedData.length > 0);
627 if (curHasChangedData !== this.hasChangedData) {
628 this.hasChangedData = curHasChangedData;
629 if(this.hasChangedData) {
630 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.hasChangedData, this.showUnsavedChangesAlert);
632 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
635 return this.hasChangedData;
638 doSaveChangedData = (onSuccessFunction?:Function, onError?:Function):void => {
639 this.saveChangedData().then(
641 this.Notification.success({
642 message: 'Successfully saved changes',
645 if(onSuccessFunction) onSuccessFunction();
648 this.Notification.error({
649 message: 'Failed to save changes!',
652 if(onError) onError();
657 showUnsavedChangesAlert = ():Promise<any> => {
658 let modalTitle:string;
659 if (this.isPropertiesTabSelected) {
660 modalTitle = `Unsaved properties for ${this.selectedInstanceData.name}`;
661 } else if (this.isInputsTabSelected) {
662 modalTitle = `Unsaved inputs for ${this.component.name}`;
665 return new Promise<any>((resolve, reject) => {
666 const modal = this.ModalServiceSdcUI.openCustomModal(
674 {id: 'cancelButton', text: 'Cancel', type: 'secondary', size: 'xsm', closeModal: true, callback: () => reject()},
675 {id: 'discardButton', text: 'Discard', type: 'secondary', size: 'xsm', closeModal: true, callback: () => { this.reverseChangedData(); resolve()}},
676 {id: 'saveButton', text: 'Save', type: 'primary', size: 'xsm', closeModal: true, disabled: !this.isValidChangedData, callback: () => this.doSaveChangedData(resolve, reject)}
677 ] as IModalButtonComponent[]
678 }, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
683 updatePropertyValueAfterDeclare = (input: InputFEModel) => {
684 if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
685 let propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
686 return feProperty.name == input.relatedPropertyName;
688 let inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
689 propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
690 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
691 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
695 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
696 updateCheckedPropertyCount = (increment: boolean): void => {
697 this.checkedPropertiesCount += (increment) ? 1 : -1;
698 console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount);
701 setInputTabIndication = (numInputs: number): void => {
702 this.propertyInputTabs.setTabIndication('Inputs', numInputs);
705 setPolicyTabIndication = (numPolicies: number): void => {
706 this.propertyInputTabs.setTabIndication('Policies', numPolicies);
709 resetUnsavedChangesForInput = (input:InputFEModel) => {
710 this.inputsUtils.resetInputDefaultValue(input, input.defaultValue);
711 this.changedData = this.changedData.filter((changedItem) => changedItem.uniqueId !== input.uniqueId);
712 this.updateHasChangedData();
715 deleteInput = (input: InputFEModel) => {
716 //reset any unsaved changes to the input before deleting it
717 this.resetUnsavedChangesForInput(input);
719 console.log("==>" + this.constructor.name + ": deleteInput");
720 let inputToDelete = new InputBEModel(input);
722 this.componentServiceNg2
723 .deleteInput(this.component, inputToDelete)
724 .subscribe(response => {
725 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
727 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
728 this.changeSelectedInstance(this.selectedInstanceData);
729 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
731 // if (instanceFeProperties) {
732 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
733 // return prop.name == input.propertyName;
736 // if (propToEnable) {
737 // if (propToEnable.name == response.inputPath) response.inputPath = null;
738 // propToEnable.setNonDeclared(response.inputPath);
739 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
740 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
743 }, error => {}); //ignore error
746 deletePolicy = (policy: PolicyInstance) => {
747 this.loadingPolicies = true;
748 this.componentServiceNg2
749 .deletePolicy(this.component, policy)
750 .subscribe(response => {
751 this.policies = this.policies.filter(policy => policy.uniqueId !== response.uniqueId);
752 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
753 this.changeSelectedInstance(this.selectedInstanceData);
754 this.loadingPolicies = false;
758 deleteProperty = (property: PropertyFEModel) => {
759 let propertyToDelete = new PropertyFEModel(property);
760 this.loadingProperties = true;
761 let feMap = this.instanceFePropertiesMap;
762 this.componentServiceNg2
763 .deleteServiceProperty(this.component, propertyToDelete)
764 .subscribe(response => {
765 const props = feMap[this.component.uniqueId];
766 props.splice(props.findIndex(p => p.uniqueId === response),1);
767 this.loadingProperties = false;
769 this.loadingProperties = false;
770 console.error(error);
774 /*** addProperty ***/
775 addProperty = () => {
776 let modalTitle = 'Add Property';
777 const modal = this.ModalService.createCustomModal(new ModalModel(
782 new ButtonModel('Save', 'blue', () => {
783 modal.instance.dynamicContent.instance.isLoading = true;
784 const newProperty: PropertyBEModel = modal.instance.dynamicContent.instance.propertyModel;
785 this.componentServiceNg2.createServiceProperty(this.component, newProperty)
786 .subscribe(response => {
787 modal.instance.dynamicContent.instance.isLoading = false;
788 let newProp: PropertyFEModel = this.propertiesUtils.convertAddPropertyBAToPropertyFE(response);
789 this.instanceFePropertiesMap[this.component.uniqueId].push(newProp);
790 modal.instance.close();
792 modal.instance.dynamicContent.instance.isLoading = false;
793 this.Notification.error({
794 message: 'Failed to add property:' + error,
799 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
800 new ButtonModel('Cancel', 'outline grey', () => {
801 modal.instance.close();
806 this.ModalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
807 modal.instance.open();
810 /*** SEARCH RELATED FUNCTIONS ***/
811 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
812 let instanceBePropertiesMap:InstanceBePropertiesMap;
813 this.componentServiceNg2
814 .filterComponentInstanceProperties(this.component, filterData)
815 .subscribe(response => {
817 this.processInstancePropertiesResponse(response, false);
818 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
819 this.searchPropertyName = filterData.propertyName;//mark in table
820 this.hierarchyNavTabs.triggerTabChange('Composition');
821 this.propertiesNavigationData = [];
822 this.displayClearSearch = true;
823 }, error => {}); //ignore error
827 clearSearch = () => {
828 this.instancesNavigationData = this.instances;
829 this.searchPropertyName = "";
830 this.hierarchyPropertiesDisplayOptions.searchText = "";
831 this.displayClearSearch = false;
832 this.advanceSearch.clearAll();
833 this.searchQuery = '';
836 clickOnClearSearch = () => {
838 this.selectFirstInstanceByDefault();
839 this.hierarchyNavTabs.triggerTabChange('Composition');
842 private isInput = (instanceType:string):boolean =>{
843 return instanceType === ResourceType.VF || instanceType === ResourceType.PNF || instanceType === ResourceType.CVFC || instanceType === ResourceType.CR;