2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2021 Nordix Foundation. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 import {Component, Inject, ViewChild} from '@angular/core';
24 Component as ComponentData,
29 import {SdcUiCommon, SdcUiServices} from 'onap-ui-angular';
30 import {TopologyTemplateService} from "../../services/component-services/topology-template.service";
31 import {Tab, Tabs} from "../../components/ui/tabs/tabs.component";
32 import * as _ from 'lodash';
33 import {OutputFEModel} from "../../../models/attributes-outputs/output-fe-model";
34 import {OutputBEModel} from "../../../models/attributes-outputs/output-be-model";
35 import {EVENTS, ResourceType, WorkspaceMode} from "../../../utils/constants";
36 import {ComponentModeService} from "../../services/component-services/component-mode.service";
37 import {EventListenerService} from "app/services";
38 import {HierarchyNavService} from "./services/hierarchy-nav.service";
39 import {ComponentServiceNg2} from "../../services/component-services/component.service";
40 import {ComponentInstanceServiceNg2} from "../../services/component-instance-services/component-instance.service";
41 import {KeysPipe} from "../../pipes/keys.pipe";
43 InstanceAttributesAPIMap,
44 InstanceBeAttributesMap,
45 InstanceFeAttributesMap
46 } from "app/models/attributes-outputs/attribute-fe-map";
48 InstanceBePropertiesMap
49 } from "app/models/properties-inputs/property-fe-map";
50 import {ModalService} from "../../services/modal.service";
51 import {InstanceFeDetails} from "../../../models/instance-fe-details";
52 import {HierarchyDisplayOptions} from "../../components/logic/hierarchy-navigtion/hierarchy-display-options";
53 import {UnsavedChangesComponent} from "../../components/ui/forms/unsaved-changes/unsaved-changes.component";
54 import {SimpleFlatAttribute} from "app/models/attributes-outputs/simple-flat-attribute";
55 import {AttributeFEModel} from "../../../models/attributes-outputs/attribute-fe-model";
56 import {AttributesUtils} from "./services/attributes.utils";
57 import {OutputsUtils} from "app/ng2/pages/attributes-outputs/services/outputs.utils";
58 import {AttributesService} from "app/ng2/services/attributes.service";
59 import {DerivedFEAttribute} from "../../../models/attributes-outputs/derived-fe-attribute";
60 import {AttributeBEModel} from "../../../models/attributes-outputs/attribute-be-model";
61 import {AttributeCreatorComponent} from "app/ng2/pages/attributes-outputs/attribute-creator/attribute-creator.component";
62 import {AttributeRowSelectedEvent} from "app/ng2/components/logic/attributes-table/attributes-table.component";
64 const SERVICE_SELF_TITLE = "SELF";
67 selector: 'attributes-outputs',
68 templateUrl: './attributes-outputs.page.component.html',
69 styleUrls: ['./attributes-outputs.page.component.less', '../../../../assets/styles/table-style.less']
71 export class AttributesOutputsComponent {
72 title = "Attributes & Outputs";
74 @ViewChild('componentAttributesTable')
77 component: ComponentData;
78 componentInstanceNamesMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();//instanceUniqueId, {name, iconClass}
80 attributesNavigationData = [];
81 instancesNavigationData = [];
83 instanceFeAttributesMap: InstanceFeAttributesMap;
84 outputs: Array<OutputFEModel> = [];
85 instances: Array<ComponentInstance> = [];
87 attributeStructureHeader: string;
89 selectedFlatAttribute: SimpleFlatAttribute = new SimpleFlatAttribute();
90 selectedInstanceData: ComponentInstance = null;
91 checkedAttributesCount: number = 0;
93 hierarchyAttributesDisplayOptions: HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
94 hierarchyInstancesDisplayOptions: HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name', 'archived', null, 'iconClass');
95 searchAttributeName: string;
97 isOutputsTabSelected: boolean;
98 isAttributesTabSelected: boolean;
100 resourceIsReadonly: boolean;
101 loadingInstances: boolean = false;
102 loadingOutputs: boolean = false;
103 loadingAttributes: boolean = false;
104 changedData: Array<AttributeFEModel | OutputFEModel>;
105 hasChangedData: boolean;
106 isValidChangedData: boolean;
107 savingChangedData: boolean;
108 stateChangeStartUnregister: Function;
109 serviceBeAttributesMap: InstanceBeAttributesMap;
111 @ViewChild('hierarchyNavTabs') hierarchyNavTabs: Tabs;
112 @ViewChild('attributeOutputTabs') attributeOutputTabs: Tabs;
116 private attributesService: AttributesService,
117 private hierarchyNavService: HierarchyNavService,
118 private attributesUtils: AttributesUtils,
119 private outputsUtils: OutputsUtils,
120 private componentServiceNg2: ComponentServiceNg2,
121 private componentInstanceServiceNg2: ComponentInstanceServiceNg2,
122 @Inject("$stateParams") _stateParams,
123 @Inject("$scope") private $scope: ng.IScope,
124 @Inject("$state") private $state: ng.ui.IStateService,
125 @Inject("Notification") private Notification: any,
126 private componentModeService: ComponentModeService,
127 private EventListenerService: EventListenerService,
128 private ModalServiceSdcUI: SdcUiServices.ModalService,
129 private ModalService: ModalService,
130 private keysPipe: KeysPipe,
131 private topologyTemplateService: TopologyTemplateService
134 this.instanceFeAttributesMap = new InstanceFeAttributesMap();
135 /* 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
136 than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
137 this.component = _stateParams.component;
138 this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.onCheckout);
139 this.updateViewMode();
141 this.changedData = [];
142 this.updateHasChangedData();
143 this.isValidChangedData = true;
147 this.loadingOutputs = true;
148 this.loadingInstances = true;
149 this.loadingAttributes = true;
150 this.topologyTemplateService
151 .getComponentOutputsWithAttributes(this.component.componentType, this.component.uniqueId)
152 .subscribe(response => {
153 if (response.outputs) {
154 response.outputs.forEach(output => {
155 const newOutput: OutputFEModel = new OutputFEModel(output);
156 this.outputsUtils.resetOutputDefaultValue(newOutput, output.defaultValue);
157 this.outputs.push(newOutput);
161 this.Notification.error({
162 message: 'Failed to Initialize:' + error,
166 this.loadingOutputs = false;
168 this.componentServiceNg2
169 .getComponentResourceAttributesData(this.component)
170 .subscribe(response => {
172 this.instances.push(...response.componentInstances);
174 // add the service self instance to the top of the list.
175 const serviceInstance = new ComponentInstance();
176 serviceInstance.name = SERVICE_SELF_TITLE;
177 serviceInstance.uniqueId = this.component.uniqueId;
178 this.instances.unshift(serviceInstance);
179 if (this.instances) {
180 this.instances.forEach(instance => {
181 this.instancesNavigationData.push(instance);
182 this.componentInstanceNamesMap[instance.uniqueId] = <InstanceFeDetails>{
184 iconClass: instance.iconClass,
185 originArchived: instance.originArchived
189 this.selectFirstInstanceByDefault();
191 this.Notification.error({
192 message: 'Failed to Initialize:' + error,
196 this.loadingInstances = false;
197 this.loadingAttributes = false;
200 this.stateChangeStartUnregister = this.$scope.$on('$stateChangeStart', (event, toState, toParams) => {
201 // stop if has changed attributes
202 if (this.hasChangedData) {
203 event.preventDefault();
204 this.showUnsavedChangesAlert().then(() => {
205 this.$state.go(toState, toParams);
212 this.EventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE);
213 this.stateChangeStartUnregister();
216 selectFirstInstanceByDefault = () => {
217 if (this.instancesNavigationData.length > 0) {
218 this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
222 updateViewMode = () => {
223 this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW;
226 onCheckout = (component: ComponentData) => {
227 this.component = component;
228 this.updateViewMode();
231 isSelf = (): boolean => {
232 return this.selectedInstanceData && this.selectedInstanceData.uniqueId == this.component.uniqueId;
235 getServiceAttributes() {
236 this.loadingAttributes = true;
237 this.topologyTemplateService
238 .getServiceAttributes(this.component.uniqueId)
239 .subscribe((response) => {
240 this.serviceBeAttributesMap = new InstanceBeAttributesMap();
241 this.serviceBeAttributesMap[this.component.uniqueId] = response;
242 this.processInstanceAttributesResponse(this.serviceBeAttributesMap, false, null);
244 this.Notification.error({
245 message: 'Failed to get Service Attribute:' + error,
249 this.loadingAttributes = false;
253 onInstanceSelectedUpdate = (instance: ComponentInstance) => {
254 // stop if has changed attributes
255 if (this.hasChangedData) {
256 this.showUnsavedChangesAlert().then(() => {
257 this.changeSelectedInstance(instance)
261 this.changeSelectedInstance(instance);
264 changeSelectedInstance = (instance: ComponentInstance) => {
265 this.selectedInstanceData = instance;
266 this.loadingAttributes = true;
267 this.instanceFeAttributesMap = undefined;
268 if (instance instanceof ComponentInstance) {
269 let instanceBeAttributesMap: InstanceBeAttributesMap | InstanceBePropertiesMap = new InstanceBeAttributesMap();
270 if (this.isOutput(instance.originType)) {
271 this.componentInstanceServiceNg2
272 .getComponentInstanceOutputs(this.component, instance)
273 .subscribe(response => {
274 instanceBeAttributesMap[instance.uniqueId] = response;
275 this.processInstanceAttributesResponse(instanceBeAttributesMap, true, instance.uniqueId);
277 this.Notification.error({
278 message: 'Failed to change Selected Instance:' + error,
282 this.loadingAttributes = false;
284 } else if (this.isSelf()) {
285 this.getServiceAttributes();
287 this.componentInstanceServiceNg2
288 .getComponentInstanceAttributes(this.component, instance.uniqueId)
289 .subscribe(response => {
290 instanceBeAttributesMap = new InstanceBeAttributesMap();
291 instanceBeAttributesMap[instance.uniqueId] = response;
292 this.processInstanceAttributesResponse(instanceBeAttributesMap, false, instance.uniqueId);
294 this.Notification.error({
295 message: 'Failed to change Selected Instance:' + error,
299 this.loadingAttributes = false;
301 this.componentInstanceServiceNg2
302 .getComponentInstanceProperties(this.component, instance.uniqueId)
303 .subscribe(response => {
304 instanceBeAttributesMap = new InstanceBePropertiesMap();
305 instanceBeAttributesMap[instance.uniqueId] = response;
306 this.processInstanceAttributesResponse(instanceBeAttributesMap, false, instance.uniqueId);
308 this.Notification.error({
309 message: 'Failed to change Selected Instance:' + error,
313 this.loadingAttributes = false;
316 this.resourceIsReadonly = (instance.componentName === "vnfConfiguration");
318 this.loadingAttributes = false;
321 //clear selected attribute from the navigation
322 this.selectedFlatAttribute = new SimpleFlatAttribute();
323 this.attributesNavigationData = [];
327 * Entry point handling response from server
329 processInstanceAttributesResponse = (instanceBeAttributesMap: InstanceBePropertiesMap | InstanceBeAttributesMap, originTypeIsVF: boolean, instanceId: string) => {
330 let attributesMap = this.attributesUtils.convertAttributesMapToFEAndCreateChildren(instanceBeAttributesMap, originTypeIsVF, this.outputs); //create flattened children, disable declared attribs, and init values
331 if (!this.instanceFeAttributesMap) {
332 this.instanceFeAttributesMap = attributesMap;
333 } else if (instanceId) {
334 let toAdd: AttributeFEModel[];
335 if (instanceBeAttributesMap instanceof InstanceBeAttributesMap) {
336 toAdd = this.instanceFeAttributesMap[instanceId].filter(currentAtr => !attributesMap[instanceId].some(newAtr => newAtr.name === currentAtr.name))
337 this.instanceFeAttributesMap[instanceId] = attributesMap[instanceId];
339 toAdd = attributesMap[instanceId].filter(currentAtr => !this.instanceFeAttributesMap[instanceId].some(newAtr => newAtr.name === currentAtr.name))
341 this.instanceFeAttributesMap[instanceId] = this.instanceFeAttributesMap[instanceId].concat(toAdd);
343 this.checkedAttributesCount = 0;
347 /*** VALUE CHANGE EVENTS ***/
348 dataChanged = (item: AttributeFEModel | OutputFEModel) => {
350 if (this.isAttributesTabSelected && item instanceof AttributeFEModel) {
351 itemHasChanged = item.hasValueObjChanged();
352 } else if (this.isOutputsTabSelected && item instanceof OutputFEModel) {
353 itemHasChanged = item.hasChanged();
356 const dataChangedIdx = this.changedData.findIndex((changedItem) => changedItem === item);
357 if (itemHasChanged) {
358 if (dataChangedIdx === -1) {
359 this.changedData.push(item);
362 if (dataChangedIdx !== -1) {
363 this.changedData.splice(dataChangedIdx, 1);
367 if (this.isAttributesTabSelected) {
368 this.isValidChangedData = this.changedData.every((changedItem) => (<AttributeFEModel>changedItem).valueObjIsValid);
369 } else if (this.isOutputsTabSelected) {
370 this.isValidChangedData = this.changedData.every((changedItem) => (<OutputFEModel>changedItem).defaultValueObjIsValid);
372 this.updateHasChangedData();
376 /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
379 * Handle select node in navigation area, and select the row in table
381 onAttributeSelectedUpdate = ($event) => {
382 this.selectedFlatAttribute = $event;
383 let parentAttribute: AttributeFEModel = this.attributesService.getParentAttributeFEModelFromPath(this.instanceFeAttributesMap[this.selectedFlatAttribute.instanceName], this.selectedFlatAttribute.path);
384 parentAttribute.expandedChildAttributeId = this.selectedFlatAttribute.path;
388 * When user select row in table, this will prepare the hierarchy object for the tree.
390 selectAttributeRow = (attributeRowSelectedEvent: AttributeRowSelectedEvent) => {
391 let attribute = attributeRowSelectedEvent.attributeModel;
392 let instanceName = attributeRowSelectedEvent.instanceName;
393 this.attributeStructureHeader = null;
395 // Build hierarchy tree for the navigation and update attributesNavigationData with it.
396 if (!(this.selectedInstanceData instanceof ComponentInstance) || this.selectedInstanceData.originType !== ResourceType.VF) {
397 let simpleFlatAttributes: Array<SimpleFlatAttribute>;
398 if (attribute instanceof AttributeFEModel) {
399 simpleFlatAttributes = this.hierarchyNavService.getSimpleAttributesTree(attribute, instanceName);
400 } else if (attribute instanceof DerivedFEAttribute) {
401 // Need to find parent AttributeFEModel
402 let parentAttributeFEModel: AttributeFEModel = _.find(this.instanceFeAttributesMap[instanceName], (tmpFeAttribute): boolean => {
403 return attribute.attributesName.indexOf(tmpFeAttribute.name) === 0;
405 simpleFlatAttributes = this.hierarchyNavService.getSimpleAttributesTree(parentAttributeFEModel, instanceName);
407 this.attributesNavigationData = simpleFlatAttributes;
410 // Update the header in the navigation tree with attribute name.
411 this.attributeStructureHeader = (attribute.attributesName.split('#'))[0];
413 // Set selected attribute in table
414 this.selectedFlatAttribute = this.hierarchyNavService.createSimpleFlatAttribute(attribute, instanceName);
415 this.hierarchyNavTabs.triggerTabChange('Attribute Structure');
418 tabChanged = (event) => {
419 // stop if has changed attributes
420 if (this.hasChangedData) {
421 this.attributeOutputTabs.triggerTabChange(this.currentMainTab.title);
422 this.showUnsavedChangesAlert().then(() => {
423 this.attributeOutputTabs.selectTab(this.attributeOutputTabs.tabs.find((tab) => tab.title === event.title));
428 this.currentMainTab = this.attributeOutputTabs.tabs.find((tab) => tab.title === event.title);
429 this.isAttributesTabSelected = this.currentMainTab.title === "Attributes";
430 this.isOutputsTabSelected = this.currentMainTab.title === "Outputs";
431 this.attributeStructureHeader = null;
432 this.searchQuery = '';
436 /*** DECLARE ATTRIBUTES/OUTPUTS ***/
437 declareAttributes = (): void => {
438 let selectedComponentInstancesAttributes: InstanceBeAttributesMap = new InstanceBeAttributesMap();
439 let selectedComponentInstancesOutputs: InstanceBeAttributesMap = new InstanceBeAttributesMap();
440 let instancesIds = this.keysPipe.transform(this.instanceFeAttributesMap, []);
442 angular.forEach(instancesIds, (instanceId: string): void => {
443 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
444 if (selectedInstanceData instanceof ComponentInstance) {
445 if (!this.isOutput(selectedInstanceData.originType)) {
446 // convert Attribute FE model -> Attribute BE model, extract only checked
447 selectedComponentInstancesAttributes[instanceId] = this.attributesService.getCheckedAttributes(this.instanceFeAttributesMap[instanceId]);
449 selectedComponentInstancesOutputs[instanceId] = this.attributesService.getCheckedAttributes(this.instanceFeAttributesMap[instanceId]);
454 let outputsToCreate: InstanceAttributesAPIMap = new InstanceAttributesAPIMap(selectedComponentInstancesOutputs, selectedComponentInstancesAttributes);
455 this.topologyTemplateService
456 .createOutput(this.component, outputsToCreate, this.isSelf())
457 .subscribe((response) => {
458 this.setOutputTabIndication(response.length);
459 this.checkedAttributesCount = 0;
460 response.forEach((output: OutputBEModel) => {
461 const newOutput: OutputFEModel = new OutputFEModel(output);
462 this.outputsUtils.resetOutputDefaultValue(newOutput, output.defaultValue);
463 this.outputs.push(newOutput);
464 this.updateAttributeValueAfterDeclare(newOutput);
469 saveChangedData = (): Promise<(AttributeBEModel | OutputBEModel)[]> => {
470 return new Promise((resolve, reject) => {
471 if (!this.isValidChangedData) {
472 reject('Changed data is invalid - cannot save!');
475 if (!this.changedData.length) {
480 // make request and its handlers
482 let handleSuccess, handleError;
483 if (this.isAttributesTabSelected) {
484 const changedAttribs = this.changedData.map((changedAttrib) => {
485 changedAttrib = <AttributeFEModel>changedAttrib;
486 const attribBE = new AttributeBEModel(changedAttrib);
487 attribBE.toscaPresentation = new ToscaPresentationData();
488 attribBE.toscaPresentation.ownerId = changedAttrib.parentUniqueId;
489 attribBE.value = changedAttrib.getJSONValue();
490 attribBE.name = changedAttrib.origName || changedAttrib.name;
491 delete attribBE.origName;
495 if (this.selectedInstanceData instanceof ComponentInstance) {
497 console.log("changedAttribs", changedAttribs);
498 request = this.topologyTemplateService.updateServiceAttributes(this.component.uniqueId, _.map(changedAttribs, cp => {
499 delete cp.constraints;
503 request = this.componentInstanceServiceNg2
504 .updateInstanceAttributes(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedAttribs);
506 handleSuccess = (response) => {
507 // reset each changed attribute with new value and remove it from changed attributes list
508 response.forEach((resAttrib) => {
509 const changedAttrib = <AttributeFEModel>this.changedData.shift();
510 this.attributesUtils.resetAttributeValue(changedAttrib, resAttrib.value);
513 console.log("updated instance attributes: ", response);
516 } else if (this.isOutputsTabSelected) {
517 const changedOutputs: OutputBEModel[] = this.changedData.map((changedOutput) => {
518 changedOutput = <OutputFEModel>changedOutput;
519 const outputBE = new OutputBEModel(changedOutput);
520 outputBE.defaultValue = changedOutput.getJSONDefaultValue();
523 request = this.componentServiceNg2.updateComponentOutputs(this.component, changedOutputs);
524 handleSuccess = (response) => {
525 // reset each changed attribute with new value and remove it from changed attributes list
526 response.forEach((resOutput) => {
527 const changedOutput = <OutputFEModel>this.changedData.shift();
528 this.outputsUtils.resetOutputDefaultValue(changedOutput, resOutput.defaultValue);
529 changedOutput.required = resOutput.required;
534 this.savingChangedData = true;
537 this.savingChangedData = false;
538 handleSuccess && handleSuccess(response);
539 this.updateHasChangedData();
543 this.savingChangedData = false;
544 handleError && handleError(error);
545 this.updateHasChangedData();
554 reverseChangedData = (): void => {
555 // make reverse item handler
556 let handleReverseItem;
557 if (this.isAttributesTabSelected) {
558 handleReverseItem = (changedItem) => {
559 changedItem = <AttributeFEModel>changedItem;
560 this.attributesUtils.resetAttributeValue(changedItem, changedItem.value);
561 this.checkedAttributesCount = 0;
563 } else if (this.isOutputsTabSelected) {
564 handleReverseItem = (changedItem) => {
565 changedItem = <OutputFEModel>changedItem;
566 this.outputsUtils.resetOutputDefaultValue(changedItem, changedItem.defaultValue);
567 changedItem.required = changedItem.requiredOrig;
571 this.changedData.forEach(handleReverseItem);
572 this.changedData = [];
573 this.updateHasChangedData();
576 updateHasChangedData = (): boolean => {
577 const curHasChangedData: boolean = (this.changedData.length > 0);
578 if (curHasChangedData !== this.hasChangedData) {
579 this.hasChangedData = curHasChangedData;
580 if (this.hasChangedData) {
581 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.hasChangedData, this.showUnsavedChangesAlert);
583 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
586 return this.hasChangedData;
589 doSaveChangedData = (onSuccessFunction?: Function, onError?: Function): void => {
590 this.saveChangedData().then(
592 this.Notification.success({
593 message: 'Successfully saved changes',
596 if (onSuccessFunction) onSuccessFunction();
597 if (this.isAttributesTabSelected) {
598 this.checkedAttributesCount = 0;
602 this.Notification.error({
603 message: 'Failed to save changes!',
606 if (onError) onError();
611 showUnsavedChangesAlert = (): Promise<any> => {
612 let modalTitle: string;
613 if (this.isAttributesTabSelected) {
614 modalTitle = `Unsaved attributes for ${this.selectedInstanceData.name}`;
615 } else if (this.isOutputsTabSelected) {
616 modalTitle = `Unsaved outputs for ${this.component.name}`;
619 return new Promise<any>((resolve, reject) => {
620 this.ModalServiceSdcUI.openCustomModal(
624 type: SdcUiCommon.ModalType.custom,
625 testId: "navigate-modal",
631 type: SdcUiCommon.ButtonType.secondary,
634 callback: () => reject()
639 type: SdcUiCommon.ButtonType.secondary,
643 this.reverseChangedData();
650 type: SdcUiCommon.ButtonType.primary,
653 disabled: !this.isValidChangedData,
654 callback: () => this.doSaveChangedData(resolve, reject)
656 ] as SdcUiCommon.IModalButtonComponent[]
657 } as SdcUiCommon.IModalConfig, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
662 updateAttributeValueAfterDeclare = (output: OutputFEModel) => {
663 const attributeList = this.instanceFeAttributesMap[output.instanceUniqueId];
665 const instanceName = output.instanceUniqueId.slice(output.instanceUniqueId.lastIndexOf('.') + 1);
666 const attributeForUpdatingVal = attributeList.find((feAttribute: AttributeFEModel) => {
667 return feAttribute.name == output.relatedAttributeName &&
668 (feAttribute.name == output.relatedAttributeName || output.name === instanceName.concat('_').concat(feAttribute.name.replace(/[.]/g, '_')));
670 const outputPath = (output.outputPath && output.outputPath != attributeForUpdatingVal.name) ? output.outputPath : undefined;
671 attributeForUpdatingVal.setAsDeclared(outputPath); //set attribute as declared before assigning value
672 // this.attributesService.disableRelatedAttributes(attributeForUpdatingVal, outputPath);
673 this.attributesUtils.resetAttributeValue(attributeForUpdatingVal, output.relatedAttributeValue, outputPath);
677 //used for declare button, to keep count of newly checked attributes (and ignore declared attributes)
678 updateCheckedAttributeCount = (increment: boolean): void => {
679 this.checkedAttributesCount += (increment) ? 1 : -1;
682 setOutputTabIndication = (numOutputs: number): void => {
683 this.attributeOutputTabs.setTabIndication('Outputs', numOutputs);
686 deleteOutput = (output: OutputFEModel) => {
687 let outputToDelete = new OutputBEModel(output);
689 this.componentServiceNg2
690 .deleteOutput(this.component, outputToDelete)
691 .subscribe(response => {
692 this.outputs = this.outputs.filter(output => output.uniqueId !== response.uniqueId);
694 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning attributes within the response, use commented code below instead!
695 this.changeSelectedInstance(this.selectedInstanceData);
697 this.Notification.error({
698 message: 'Failed to delete Output:' + error,
704 deleteAttribute = (attribute: AttributeFEModel) => {
705 const attributeToDelete = new AttributeFEModel(attribute);
706 this.loadingAttributes = true;
707 const feMap = this.instanceFeAttributesMap;
708 this.topologyTemplateService
709 .deleteServiceAttribute(this.component.uniqueId, attributeToDelete)
710 .subscribe((response) => {
711 const attribs = feMap[this.component.uniqueId];
712 attribs.splice(attribs.findIndex(p => p.uniqueId === response), 1);
714 this.Notification.error({
715 message: 'Failed to delete Attribute:' + error,
719 this.loadingAttributes = false;
723 addAttribute = () => {
724 let modalTitle = 'Add Attribute';
725 let modal = this.ModalService.createCustomModal(new ModalModel(
730 new ButtonModel('Save', 'blue', () => {
731 modal.instance.dynamicContent.instance.isLoading = true;
732 const newAttribute: AttributeBEModel = modal.instance.dynamicContent.instance.attributeModel;
733 this.topologyTemplateService.createServiceAttribute(this.component.uniqueId, newAttribute)
734 .subscribe((response) => {
735 modal.instance.dynamicContent.instance.isLoading = false;
736 const newAttrib: AttributeFEModel = this.attributesUtils.convertAddAttributeBEToAttributeFE(response);
737 this.instanceFeAttributesMap[this.component.uniqueId].push(newAttrib);
738 modal.instance.close();
740 modal.instance.dynamicContent.instance.isLoading = false;
741 this.Notification.error({
742 message: 'Failed to add Attribute:' + error,
746 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
747 new ButtonModel('Cancel', 'outline grey', () => {
748 modal.instance.close();
753 this.ModalService.addDynamicContentToModal(modal, AttributeCreatorComponent, {});
754 modal.instance.open();
757 private isOutput = (instanceType: string): boolean => {
758 return instanceType === ResourceType.VF || instanceType === ResourceType.PNF || instanceType === ResourceType.CVFC || instanceType === ResourceType.CR;