2 Copyright 2020 TATA ELXSI
4 Licensed under the Apache License, Version 2.0 (the 'License');
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
16 Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
19 * @file NS Compose Component
21 import { HttpHeaders } from '@angular/common/http';
22 import { Component, ElementRef, Injector, ViewChild, ViewEncapsulation } from '@angular/core';
23 import { ActivatedRoute, Router } from '@angular/router';
24 import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
25 import { TranslateService } from '@ngx-translate/core';
26 import { NotifierService } from 'angular-notifier';
27 import { APIURLHEADER, CONSTANTNUMBER, ERRORDATA, MODALCLOSERESPONSEDATA, MODALCLOSERESPONSEWITHCP } from 'CommonModel';
28 import { ConfirmationTopologyComponent } from 'ConfirmationTopology';
29 import * as d3 from 'd3';
30 import { DataService } from 'DataService';
31 import { environment } from 'environment';
32 import * as HttpStatus from 'http-status-codes';
33 import * as jsyaml from 'js-yaml';
42 Tick, TickPath, VLC, VLD, VNFPROFILE
44 import { RestService } from 'RestService';
45 import { SharedService, isNullOrUndefined } from 'SharedService';
46 import { VNFD, VNFData } from 'VNFDModel';
50 * @Component takes NSComposerComponent.html as template url
53 selector: 'app-ns-composer',
54 templateUrl: './NSComposerComponent.html',
55 styleUrls: ['./NSComposerComponent.scss'],
56 encapsulation: ViewEncapsulation.None
58 /** Exporting a class @exports NSComposerComponent */
59 export class NSComposerComponent {
60 /** To inject services @public */
61 public injector: Injector;
62 /** View child contains graphContainer ref @public */
63 @ViewChild('graphContainer', { static: true }) public graphContainer: ElementRef;
64 /** dataService to pass the data from one component to another @public */
65 public dataService: DataService;
66 /** Contains VNFD Informations @public */
67 public nsPackageDetails: NSData = { id: '', name: '', description: '', version: '', designer: '' };
68 /** Contains VL Details @public */
69 public virtualLinkDesc: VLD = {
73 /** Contains the information of the type of modification @public */
74 public putType: string;
75 /** Contains index of old VLD @public */
76 public getOldVLDIndex: string[];
77 /** Conatins mousedown action @public */
78 public mousedownNode: COMPOSERNODES = null;
79 /** Conatins mouseup action @public */
80 public mouseupNode: COMPOSERNODES = null;
81 /** Conatins mousedownLink action @public */
82 public mousedownLink: COMPOSERNODES = null;
83 /** Conatins current Selection node action @public */
84 public currentSelectedNode: COMPOSERNODES = null;
85 /** Conatins current Selection node action @public */
86 public currentSelectedLink: COMPOSERNODES = null;
87 /** Need to show the NSD Details @public */
88 public isShowNSDDetails: boolean = true;
89 /** Contains the node information of VL @public */
90 public vlNodes: {}[] = [];
91 /** Need to show the VL Details @public */
92 public isShowVLDetails: boolean = false;
93 /** Contains the node information of VNF @public */
94 public vnfNodes: {}[] = [];
95 /** contains the VNF Details @public */
96 public vnfData: VNFPROFILE;
97 /** contains the Virtual Link connectivity Details @public */
98 public virtualLinkProfileID: string;
99 /** Need to show the VNF Details @public */
100 public isShowVNFDetails: boolean = false;
101 /** Contains the node information of CP @public */
102 public cpNodes: {}[] = [];
103 /** Need to show the CP Details */
105 /** Need to show the VNF Details @public */
106 public isShowCPDetails: boolean = false;
107 /** random number count @public */
108 public randomNumberLength: number;
109 /** Contains the vnfd information @public */
110 public vnfList: VNFD[] = [];
111 /** Add the activeclass for the selected @public */
112 public activeClass: string = 'active';
113 /** Add the fixed class for the freeze @public */
114 public fixedClass: string = 'fixed';
115 /** Check the loading results @public */
116 public isLoadingResults: boolean = true;
117 /** Give the message for the loading @public */
118 public message: string = 'PLEASEWAIT';
119 /** Get VNF selected node @public */
120 public getVNFSelectedData: VNFD;
121 /** Assign the forcesimulation active @public */
122 public forceSimulationActive: boolean = false;
123 /** Assign pinned class for the button when freezed @public */
124 public classApplied: boolean = false;
125 /** Contains sidebar open status @public */
126 public sideBarOpened: boolean = false;
127 /** Contains SVG attributes @private */
128 // eslint-disable-next-line @typescript-eslint/no-explicit-any
130 /** Contains the Drag line */
131 // eslint-disable-next-line @typescript-eslint/no-explicit-any
132 private dragLine: any;
133 /** Contains VL node @private */
134 // eslint-disable-next-line @typescript-eslint/no-explicit-any
136 /** Contains VNFD node @private */
137 // eslint-disable-next-line @typescript-eslint/no-explicit-any
138 private vnfdnode: any;
139 /** Contains CP node @private */
140 // eslint-disable-next-line @typescript-eslint/no-explicit-any
142 /** Rendered nodes represent VL @private */
143 // eslint-disable-next-line @typescript-eslint/no-explicit-any
144 private gvlNode: any;
145 /** Rendered nodes represent VL @private */
146 // eslint-disable-next-line @typescript-eslint/no-explicit-any
147 private gvnfdNode: any;
148 /** Rendered nodes represent VL @private */
149 // eslint-disable-next-line @typescript-eslint/no-explicit-any
150 private gcpNode: any;
151 /** Contains forced node animations @private */
152 // eslint-disable-next-line @typescript-eslint/no-explicit-any
154 /** Contains all the selected node @private */
155 private selectedNode: COMPOSERNODES[] = [];
156 /** Contains the connected point @private */
157 private connectionPoint: string;
158 /** Contains id of the node @private */
159 private identifier: string;
160 /** Contains copy of NSD information @private */
161 private nsdCopy: string;
162 /** Contains the VNFD copy @private */
163 private vnfdCopy: string;
164 /** Contains path information of the node */
165 // eslint-disable-next-line @typescript-eslint/no-explicit-any
167 /** Contains the node information @private */
168 private nodes: COMPOSERNODES[] = [];
169 /** Contains the link information of nodes @private */
170 private links: {}[] = [];
171 /** Contains the NS information @private */
172 private nsData: NSDDetails;
173 /** Instance of the rest service @private */
174 private restService: RestService;
175 /** Service holds the router information @private */
176 private router: Router;
177 /** Holds teh instance of AuthService class of type AuthService @private */
178 private activatedRoute: ActivatedRoute;
179 /** Notifier service to popup notification @private */
180 private notifierService: NotifierService;
181 /** Controls the header form @private */
182 private headers: HttpHeaders;
183 /** Contains tranlsate instance @private */
184 private translateService: TranslateService;
185 /** Contains lastkeypressed instance @private */
186 private lastKeyDown: number = -1;
187 /** Instance of the modal service @private */
188 private modalService: NgbModal;
189 /** Setting the Value of connection point refrence of the CP @private */
190 private setVnfdConnectionPointRef: string;
191 /** Setting the Value of VL name for confirmation @private */
192 private vlName: string;
193 /** Setting the Value of VNFD name for confirmation @private */
194 private setVnfdName: string;
195 /** Contains all methods related to shared @private */
196 private sharedService: SharedService;
197 /** Contains selected node VNF profile objects @private */
198 private selectedVNFProfile: VNFPROFILE[];
200 constructor(injector: Injector) {
201 this.injector = injector;
202 this.restService = this.injector.get(RestService);
203 this.dataService = this.injector.get(DataService);
204 this.router = this.injector.get(Router);
205 this.activatedRoute = this.injector.get(ActivatedRoute);
206 this.notifierService = this.injector.get(NotifierService);
207 this.translateService = this.injector.get(TranslateService);
208 this.modalService = this.injector.get(NgbModal);
209 this.sharedService = this.injector.get(SharedService);
211 /** Lifecyle Hooks the trigger before component is instantiated @public */
212 public ngOnInit(): void {
213 this.identifier = this.activatedRoute.snapshot.paramMap.get('id');
215 this.headers = new HttpHeaders({
216 'Content-Type': 'application/gzip',
217 Accept: 'application/json',
218 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
221 /** Events handles at drag on D3 region @public */
222 // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
223 public drag(ev: any): void {
224 if (ev.target.id === 'vl') {
225 ev.dataTransfer.setData('text', ev.target.id);
227 ev.dataTransfer.setData('text', ev.target.attributes['data-id'].value);
230 /** On clicking redirect to NS edit page @public */
231 public onEdit(): void {
232 this.router.navigate(['/packages/ns/edit/', this.identifier]).catch((): void => {
233 // Catch Navigation Error
236 /** Events handles drop at D3 region @public */
237 public drop(ev: DragEvent): void {
239 const getDropedName: string = ev.dataTransfer.getData('text');
240 if (getDropedName === 'vl') {
241 this.svg.selectAll('*').remove();
242 this.vldropComposer();
244 this.svg.selectAll('*').remove();
245 const vnfdName: string = ev.dataTransfer.getData('text');
246 this.vnfdropComposer(vnfdName);
249 /** Drop VL Composer Data @public */
250 public vldropComposer(): void {
251 this.randomNumberLength = CONSTANTNUMBER.randomNumber;
252 const generateId: string = 'ns_vl_' + this.sharedService.randomString();
253 if (this.nsData['virtual-link-desc'] === undefined) {
254 this.nsData['virtual-link-desc'] = [];
256 this.nsData['virtual-link-desc'].push({
258 'mgmt-network': false
260 this.putType = 'nsdadd';
261 this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
263 /** Drop VNFD Composer Data @public */
264 public vnfdropComposer(vnfdName: string): void {
265 const vnfID: string = 'ns_vnfd_' + this.sharedService.randomString();
266 if (this.nsData.df.length > 0) {
267 this.addVNFDID(vnfdName);
268 this.nsData.df.forEach((res: DF): void => {
269 if (res['vnf-profile'] === undefined) {
270 res['vnf-profile'] = [];
272 res['vnf-profile'].push({
274 'virtual-link-connectivity': [],
279 Object.assign(this.nsData.df, {
283 'virtual-link-connectivity': [],
288 this.putType = 'vnfdadd';
289 this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
291 /** Add the VNFD-ID while drop VNFD if not exists @public */
292 public addVNFDID(vnfdName: string): void {
293 const vnfdIDArray: string[] = this.nsData['vnfd-id'];
294 if (vnfdIDArray !== undefined) {
295 if (vnfdIDArray.indexOf(vnfdName) === -1) {
296 vnfdIDArray.push(vnfdName);
299 Object.assign(this.nsData, {
300 'vnfd-id': [vnfdName]
304 /** Events handles allow drop on D3 region @public */
305 public allowDrop(ev: DragEvent): void {
308 /** Save NSD Information @public */
309 public saveNSD(): void {
310 if (this.nsPackageDetails.id !== undefined) {
311 this.nsData.id = this.nsPackageDetails.id;
313 if (this.nsPackageDetails.name !== undefined) {
314 this.nsData.name = this.nsPackageDetails.name;
316 if (this.nsPackageDetails.description !== undefined) {
317 this.nsData.description = this.nsPackageDetails.description;
319 if (this.nsPackageDetails.version !== undefined) {
320 this.nsData.version = this.nsPackageDetails.version;
322 if (this.nsPackageDetails.designer !== undefined) {
323 this.nsData.designer = this.nsPackageDetails.designer;
325 this.putType = 'nsdUpdate';
326 this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
328 /** Save Virtual Link @public */
329 public saveVL(vlid: string): void {
330 this.nsData['virtual-link-desc'].forEach((result: VLD): void => {
331 if (result.id === vlid) {
332 result['mgmt-network'] = !isNullOrUndefined(this.virtualLinkDesc['mgmt-network']) ? this.virtualLinkDesc['mgmt-network'] : true;
335 this.putType = 'vlUpdate';
336 this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
338 /** Add the new Data @public */
339 public addData(apiURL: string, identifier: string, data: NSDDetails, putType: string): void {
340 this.isLoadingResults = true;
341 let successMessage: string = '';
342 if (putType === 'nsdadd') {
343 successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.ADDNSD';
344 } else if (putType === 'vnfdadd') {
345 successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.ADDVNFD';
346 } else if (putType === 'cpAdded') {
347 successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.ADDNS';
348 } else if (putType === 'nsdUpdate') {
349 successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.UPDATEDSUCCESSFULLY';
350 } else if (putType === 'vlUpdate') {
351 successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.UPDATEDSUCCESSFULLY';
352 } else if (putType === 'nsddelete') {
353 successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETENSD';
354 } else if (putType === 'vnfddelete') {
355 successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETEVNFD';
356 } else if (putType === 'nsdelete') {
357 successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETENS';
358 } else if (putType === 'linkdelete') {
359 successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETELINK';
361 /** Below hide for conflicts with light weight UI */
362 const apiURLHeader: APIURLHEADER = {
363 url: apiURL + '/' + identifier + '/nsd_content',
364 httpOptions: { headers: this.headers }
366 const nsData: NSDATACREATION = { nsd: { nsd: [] } };
368 nsData.nsd.nsd.push(data);
369 const descriptorInfo: string = jsyaml.dump(nsData, { sortKeys: true });
370 this.sharedService.targzFile({ packageType: 'nsd', id: this.identifier, descriptor: descriptorInfo })
371 .then((content: ArrayBuffer): void => {
372 this.restService.putResource(apiURLHeader, content).subscribe((res: {}): void => {
374 this.notifierService.notify('success', this.translateService.instant(successMessage));
375 this.isLoadingResults = false;
376 }, (error: ERRORDATA): void => {
378 this.restService.handleError(error, 'put');
379 this.isLoadingResults = false;
381 }).catch((): void => {
382 this.notifierService.notify('error', this.translateService.instant('ERROR'));
383 this.isLoadingResults = false;
386 /** Show Info @public */
387 public showInfo(): void {
388 // eslint-disable-next-line security/detect-non-literal-fs-filename
389 const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
390 modalRef.componentInstance.topologyType = 'Info';
391 modalRef.componentInstance.topologytitle = this.translateService.instant('PAGE.TOPOLOGY.INFO');
392 modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
396 }).catch((): void => {
397 // Catch Navigation Error
400 /** Event to freeze the animation @public */
401 public onFreeze(): void {
402 this.classApplied = !this.classApplied;
403 const alreadyFixedIsActive: boolean = d3.select('svg#graphContainer').classed(this.fixedClass);
404 d3.select('svg#graphContainer').classed(this.fixedClass, !alreadyFixedIsActive);
405 if (alreadyFixedIsActive) {
408 this.forceSimulationActive = alreadyFixedIsActive;
409 this.nodes.forEach((d: COMPOSERNODES): void => {
410 d.fx = (alreadyFixedIsActive) ? null : d.x;
411 d.fy = (alreadyFixedIsActive) ? null : d.y;
413 if (alreadyFixedIsActive) {
414 this.force.restart();
417 /** Events handles when dragended @public */
418 public toggleSidebar(): void {
419 this.sideBarOpened = !this.sideBarOpened;
420 this.deselectAllNodes();
421 this.showRightSideInfo(true, false, false, false);
423 /** Prepare information for node creation of VNFD @private */
424 private generateData(): void {
425 this.generateVNFData();
426 this.generateDataNSDTopology();
427 this.sideBarOpened = false;
429 /** Prepare the information of the VNFD @private */
430 private generateVNFData(): void {
431 this.restService.getResource(environment.VNFPACKAGESCONTENT_URL).subscribe((vnfdPackageData: VNFD[]): void => {
432 this.vnfList = vnfdPackageData;
433 }, (error: ERRORDATA): void => {
434 this.restService.handleError(error, 'get');
437 /** Prepare information for node creation of NSD Topology @private */
438 private generateDataNSDTopology(): void {
441 this.restService.getResource(environment.NSDESCRIPTORSCONTENT_URL + '/' + this.identifier).subscribe((nsData: NSDDetails): void => {
442 delete nsData._admin;
444 delete nsData._links;
445 this.nsData = nsData;
446 this.generateNSInfo(nsData);
447 if (nsData['virtual-link-desc'] !== undefined) {
448 /** Details of the VL */
449 this.nsDataVLD(nsData);
451 if (this.nsData.df.length > 0) {
452 this.nsData.df.forEach((res: DF): void => {
453 if (res['vnf-profile'] !== undefined) {
454 /** Details of the VNFD */
455 this.nsDataConstituentVNFD(nsData);
459 if (nsData.df.length > 0) {
460 this.nsDataVLDLinkCreation(nsData);
462 this.separateAndCreatenode();
463 }, (error: ERRORDATA): void => {
464 if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) {
465 this.router.navigateByUrl('404', { skipLocationChange: true }).catch((): void => {
466 // Catch Navigation Error
469 this.restService.handleError(error, 'get');
471 this.isLoadingResults = false;
472 this.isShowNSDDetails = false;
475 /** Generate the NS Package Information */
476 private generateNSInfo(nsData: NSDDetails): void {
477 this.nsPackageDetails.id = nsData.id;
478 this.nsPackageDetails.name = nsData.name;
479 this.nsPackageDetails.description = nsData.description;
480 this.nsPackageDetails.version = nsData.version;
481 this.nsPackageDetails.designer = nsData.designer;
483 /** nsData VL node creation function @private */
484 private nsDataVLD(nsData: NSDDetails): void {
485 nsData['virtual-link-desc'].forEach((res: VLD): void => {
486 this.nodes.push({ id: res.id, reflexive: false, type: 'vld', name: res.id, selectorId: res.id });
489 /** nsData VNFD node creation function @private */
490 private nsDataConstituentVNFD(nsData: NSDDetails): void {
491 nsData.df.forEach((resDF: DF): void => {
492 resDF['vnf-profile'].forEach((resVNF: VNFPROFILE): void => {
495 id: resVNF['vnfd-id'] + ':' + resVNF.id,
498 name: resVNF['vnfd-id'],
499 nodeIndex: resVNF.id,
500 selectorId: resVNF['vnfd-id'] + '_' + resVNF.id
502 if (resVNF['virtual-link-connectivity'] !== undefined) {
503 this.nsDataCP(resVNF, resVNF.id);
508 /** nsData CP node creation function @private */
509 private nsDataCP(resVNF: VNFPROFILE, vnfID: string): void {
510 resVNF['virtual-link-connectivity'].forEach((resultVLC: VLC, index: number): void => {
511 resultVLC['constituent-cpd-id'].forEach((resultCCI: CCI): void => {
514 id: vnfID + ':' + resultCCI['constituent-base-element-id'] + index + ':' + resultCCI['constituent-cpd-id'],
517 name: resultCCI['constituent-cpd-id'],
518 nodeIndex: resultCCI['constituent-base-element-id'],
519 selectorId: 'osm-' + resultCCI['constituent-cpd-id'] + '-' + vnfID + resultCCI['constituent-base-element-id'] + index
524 /** nsData Link node creation function @private */
525 private nsDataVLDLinkCreation(nsData: NSDDetails): void {
526 nsData.df.forEach((resDF: DF): void => {
527 if (resDF['vnf-profile'] !== undefined) {
528 resDF['vnf-profile'].forEach((resVNF: VNFPROFILE): void => {
529 this.nsdCopy = resVNF['vnfd-id'] + ':' + resVNF.id;
530 if (resVNF['virtual-link-connectivity'] !== undefined) {
531 this.nsDataVNFDConnectionPointRefrence(resVNF);
537 /** nsDataVNFDConnectionPointRefrence undefined Call this function @private */
538 private nsDataVNFDConnectionPointRefrence(resVNF: VNFPROFILE): void {
539 resVNF['virtual-link-connectivity'].forEach((resultVLC: VLC, index: number): void => {
540 resultVLC['constituent-cpd-id'].forEach((resultCCI: CCI): void => {
541 this.vnfdCopy = resultVLC['virtual-link-profile-id'];
542 this.connectionPoint = resVNF.id + ':' + resultCCI['constituent-base-element-id'] + index + ':' + resultCCI['constituent-cpd-id'];
543 const connectionPointPos: number = this.nodes.map((e: COMPOSERNODES): string => e.id).indexOf(this.connectionPoint);
544 const nsdPos: number = this.nodes.map((e: COMPOSERNODES): string => e.id).indexOf(this.nsdCopy);
545 const vnfdPos: number = this.nodes.map((e: COMPOSERNODES): string => e.id).indexOf(this.vnfdCopy);
548 // eslint-disable-next-line security/detect-object-injection
549 source: this.nodes[connectionPointPos],
550 // eslint-disable-next-line security/detect-object-injection
551 target: this.nodes[nsdPos]
554 // eslint-disable-next-line security/detect-object-injection
555 source: this.nodes[connectionPointPos],
556 // eslint-disable-next-line security/detect-object-injection
557 target: this.nodes[vnfdPos]
562 /** Separate and create node @private */
563 private separateAndCreatenode(): void {
564 this.seprateNodes(this.nodes);
565 this.createnode(this.nodes);
566 this.isLoadingResults = false;
568 /** Get the default Configuration of containers @private */
569 private getGraphContainerAttr(): GRAPHDETAILS {
582 sourcePaddingYes: 17,
592 /** Separate the nodes along with its tyep @private */
593 private seprateNodes(node: COMPOSERNODES[]): void {
594 this.vlNodes = []; this.vnfNodes = []; this.cpNodes = [];
595 node.forEach((nodeList: COMPOSERNODES): void => {
596 if (nodeList.type === 'vld') {
597 this.vlNodes.push(nodeList);
598 } else if (nodeList.type === 'vnfd') {
599 this.vnfNodes.push(nodeList);
600 } else if (nodeList.type === 'ns') {
601 this.cpNodes.push(nodeList);
605 /** Node is created and render at D3 region @private */
606 private createnode(node: COMPOSERNODES[]): void {
607 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
608 d3.selectAll('svg#graphContainer > *').remove();
609 d3.select(window).on('keydown', (): void => { this.keyDown(); });
610 d3.select(window).on('keyup', (): void => { this.keyUp(); });
611 this.svg = d3.select('#graphContainer')
612 .attr('oncontextmenu', 'return false;')
613 .attr('viewBox', `0 0 ${graphContainerAttr.width} ${graphContainerAttr.height}`)
614 .on('mousemove', (): void => { this.mousemove(); });
615 this.force = d3.forceSimulation()
616 .force('charge', d3.forceManyBody().strength(graphContainerAttr.strength))
617 .force('link', d3.forceLink().id((d: TickPath): string => d.id).distance(graphContainerAttr.distance))
618 .force('center', d3.forceCenter(graphContainerAttr.width / graphContainerAttr.forcex,
619 graphContainerAttr.height / graphContainerAttr.forcey))
620 .force('x', d3.forceX(graphContainerAttr.width / graphContainerAttr.forcex))
621 .force('y', d3.forceY(graphContainerAttr.height / graphContainerAttr.forcey))
622 .on('tick', (): void => { this.tick(); });
623 this.dragLine = this.svg.append('svg:path').attr('class', 'link dragline hidden').attr('d', 'M0,0L0,0');
624 this.path = this.svg.append('svg:g').selectAll('path');
625 this.vlNode = this.svg.append('svg:g').selectAll('vlnode');
626 this.vnfdnode = this.svg.append('svg:g').selectAll('vnfdnode');
627 this.cpnode = this.svg.append('svg:g').selectAll('cpnode');
631 /** update force layout (called automatically each iteration) @private */
632 private tick(): void {
633 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
634 // draw directed edges with proper padding from node centers
635 this.path.attr('class', 'link').attr('d', (d: Tick): string => {
636 const deltaX: number = d.target.x - d.source.x;
637 const deltaY: number = d.target.y - d.source.y;
638 const dist: number = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
639 const normX: number = deltaX / dist;
640 const normY: number = deltaY / dist;
641 const sourcePadding: number = d.left ? graphContainerAttr.sourcePaddingYes : graphContainerAttr.sourcePaddingNo;
642 const targetPadding: number = d.right ? graphContainerAttr.targetPaddingYes : graphContainerAttr.targetPaddingNo;
643 const sourceX: number = d.source.x + (sourcePadding * normX);
644 const sourceY: number = d.source.y + (sourcePadding * normY);
645 const targetX: number = d.target.x - (targetPadding * normX);
646 const targetY: number = d.target.y - (targetPadding * normY);
647 return `M${sourceX},${sourceY}L${targetX},${targetY}`;
648 }).on('dblclick', (d: Tick): void => { this.getDeleteLinkConfirmation(d); });
649 this.vlNode.attr('transform', (t: TickPath): string => `translate(${t.x},${t.y})`);
650 this.vnfdnode.attr('transform', (t: TickPath): string => `translate(${t.x},${t.y})`);
651 this.cpnode.attr('transform', (t: TickPath): string => `translate(${t.x},${t.y})`);
653 /** Update graph (called when needed) at D3 region @private */
654 private restart(node: COMPOSERNODES[]): void {
655 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
656 this.path = this.path.data(this.links);
657 this.vlNode = this.vlNode.data(this.vlNodes, (d: COMPOSERNODES): string => d.id);
658 this.vnfdnode = this.vnfdnode.data(this.vnfNodes, (d: COMPOSERNODES): string => d.id);
659 this.cpnode = this.cpnode.data(this.cpNodes, (d: COMPOSERNODES): string => d.id);
660 this.resetAndCreateNodes();
661 this.force.nodes(node).force('link').links(this.links);
662 this.force.alphaTarget(graphContainerAttr.alphaTarget).restart();
664 /** Rest and create nodes @private */
665 private resetAndCreateNodes(): void {
666 this.path.exit().remove();
667 this.vlNode.exit().remove();
668 this.vnfdnode.exit().remove();
669 this.cpnode.exit().remove();
674 this.path.merge(this.path);
675 this.vlNode = this.gvlNode.merge(this.vlNode);
676 this.vnfdnode = this.gvnfdNode.merge(this.vnfdnode);
677 this.cpnode = this.gcpNode.merge(this.cpnode);
679 /** setting the Path @private */
680 private getPathNodes(): void {
681 this.path = this.path.enter().append('svg:path');
683 /** Setting all the VL nodes @private */
684 private getVLNodes(): void {
685 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
686 this.gvlNode = this.vlNode.enter().append('svg:g');
687 this.gvlNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
688 this.gvlNode.append('svg:image')
690 .attr('x', graphContainerAttr.imageX)
691 .attr('y', graphContainerAttr.imageY)
692 .call(this.onDragDrop())
693 .attr('id', (d: COMPOSERNODES): string => d.selectorId)
694 .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
695 .attr('xlink:href', 'assets/images/VL.svg')
696 .on('mousedown', (d: COMPOSERNODES): void => { this.mouseDown(d); })
697 .on('mouseup', (d: COMPOSERNODES): void => { this.mouseUp(d); })
698 .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.vlNode, d); this.onNodeClickToggleSidebar(); })
699 .on('dblclick', (d: COMPOSERNODES): void => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); });
700 this.gvlNode.append('svg:text')
701 .attr('class', 'node_text')
702 .attr('y', graphContainerAttr.textY)
703 .text((d: COMPOSERNODES): string => d.id);
705 /** Setting all the VNFD nodes @private */
706 private getVNFDNodes(): void {
707 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
708 this.gvnfdNode = this.vnfdnode.enter().append('svg:g');
709 this.gvnfdNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
710 this.gvnfdNode.append('svg:image')
712 .attr('x', graphContainerAttr.imageX)
713 .attr('y', graphContainerAttr.imageY)
714 .call(this.onDragDrop())
715 .attr('id', (d: COMPOSERNODES): string => d.selectorId)
716 .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
717 .attr('xlink:href', 'assets/images/VNFD.svg')
718 .on('mousedown', (d: COMPOSERNODES): void => { this.mouseDown(d); })
719 .on('mouseup', (d: COMPOSERNODES): void => { this.mouseUp(d); })
720 .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.vnfdnode, d); this.onNodeClickToggleSidebar(); })
721 .on('dblclick', (d: COMPOSERNODES): void => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); });
722 this.gvnfdNode.append('svg:text')
723 .attr('class', 'node_text')
724 .attr('y', graphContainerAttr.textY)
725 .text((d: COMPOSERNODES): string => d.name);
727 /** Setting all the CP nodes @private */
728 private getCPNodes(): void {
729 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
730 this.gcpNode = this.cpnode.enter().append('svg:g');
731 this.gcpNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
732 this.gcpNode.append('svg:image')
734 .attr('x', graphContainerAttr.imageX)
735 .attr('y', graphContainerAttr.imageY)
736 .call(this.onDragDrop())
737 .attr('id', (d: COMPOSERNODES): string => d.selectorId)
738 .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
739 .attr('xlink:href', 'assets/images/CP.svg')
740 .on('mousedown', (d: COMPOSERNODES): void => { this.mouseDown(d); })
741 .on('mouseup', (d: COMPOSERNODES): void => { this.mouseUp(d); })
742 .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.cpnode, d); this.onNodeClickToggleSidebar(); })
743 .on('dblclick', (d: COMPOSERNODES): void => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); });
744 this.gcpNode.append('svg:text')
745 .attr('class', 'node_text')
746 .attr('y', graphContainerAttr.textY)
747 .text((d: COMPOSERNODES): string => d.name);
749 /** Events handles when mousemove it will capture the selected node data @private */
750 private mousemove(): void {
751 if (!this.mousedownNode) { return; }
752 this.dragLine.attr('d',
753 `M${this.mousedownNode.x},${this.mousedownNode.y}L${d3.mouse(d3.event.currentTarget)[0]},${d3.mouse(d3.event.currentTarget)[1]}`);
755 /** Get confirmation Before Deleting the Link in Topology @private */
756 private getAddConfirmation(mouseData: COMPOSERNODES, getNsData: NSDDetails, addType: string, getVLDIndex: string): void {
757 let findVNFName: string = '';
758 let findVLDID: string = '';
759 if (mouseData.type === 'vld') {
760 findVNFName = this.mouseupNode.name;
761 findVLDID = this.mousedownNode.id;
762 this.vlName = this.mousedownNode.name;
764 findVNFName = this.mousedownNode.name;
765 findVLDID = this.mouseupNode.id;
766 this.vlName = this.mouseupNode.name;
768 if (getNsData['vnfd-id'] !== undefined) {
769 getNsData['vnfd-id'].forEach((resVNFid: string): void => {
770 if (resVNFid === findVNFName) {
771 this.getVNFSelectedData = this.vnfList.filter((vnfList: VNFD): boolean => vnfList.id === findVNFName)[0];
772 this.setVnfdConnectionPointRef = this.getVNFSelectedData['mgmt-cp'];
773 this.setVnfdName = this.getVNFSelectedData['product-name'];
774 this.selectedVNFProfile = getNsData.df[0]['vnf-profile'];
778 if (this.vlName !== undefined && this.setVnfdName !== undefined && this.setVnfdConnectionPointRef !== undefined) {
779 // eslint-disable-next-line security/detect-non-literal-fs-filename
780 const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
781 modalRef.componentInstance.topologyType = 'Add';
782 modalRef.componentInstance.cpDetails = this.getVNFSelectedData['ext-cpd'];
783 this.translateService.get('PAGE.TOPOLOGY.ADDINGCP', {
784 vlname: '<b>' + this.vlName + '</b>',
785 vnfdname: '<b>' + this.setVnfdName + '</b>',
786 cpname: '<b>' + this.setVnfdConnectionPointRef + '</b>'
787 }).subscribe((res: string): void => {
788 modalRef.componentInstance.topologyname = res;
790 modalRef.componentInstance.topologytitle = this.translateService.instant('PAGE.TOPOLOGY.CONNECTIONPOINT');
791 modalRef.result.then((result: MODALCLOSERESPONSEWITHCP): void => {
793 this.generateCPForVNF(this.selectedVNFProfile, result.connection_point, getVLDIndex);
794 this.addData(environment.NSDESCRIPTORS_URL, this.identifier, getNsData, addType);
798 }).catch((): void => {
799 // Catch Navigation Error
803 this.notifierService.notify('error', this.translateService.instant('ERROR'));
806 /** Generate connection point for vnf using vld @private */
807 private generateCPForVNF(result: VNFPROFILE[], cp: string, getVLDIndex: string): void {
808 if (result !== undefined) {
809 result.forEach((resultVNFPROFILE: VNFPROFILE, index: number): void => {
810 if (getVLDIndex === resultVNFPROFILE.id) {
811 resultVNFPROFILE['virtual-link-connectivity'].push({
812 'constituent-cpd-id': [{
813 'constituent-base-element-id': getVLDIndex,
814 'constituent-cpd-id': cp
816 'virtual-link-profile-id': this.vlName
821 Object.assign(result, {
822 'virtual-link-connectivity': [{
823 'constituent-cpd-id': [{
824 'constituent-base-element-id': getVLDIndex,
825 'constituent-cpd-id': cp
827 'virtual-link-profile-id': this.vlName
832 /** Events handles when mousedown click it will capture the selected node data @private */
833 private mouseDown(d: COMPOSERNODES): void {
834 // eslint-disable-next-line deprecation/deprecation
835 event.preventDefault();
836 if (d3.event.ctrlKey) { return; }
837 if (d3.event.shiftKey) {
838 if (d.type === 'vnfd') {
839 this.selectedNode.push(d);
841 this.mousedownNode = d;
842 this.currentSelectedNode = (this.mousedownNode === this.currentSelectedNode) ? null : this.mousedownNode;
843 this.currentSelectedLink = null;
844 this.dragLine.style('marker-end', 'url(#end-arrow)').classed('hidden', false)
845 .attr('d', `M${this.mousedownNode.x},${this.mousedownNode.y}L${this.mousedownNode.x},${this.mousedownNode.y}`);
848 /** Event handles when mouseup event occures @private */
849 private mouseUp(d: COMPOSERNODES): void {
850 if (!this.mousedownNode) { return; }
851 this.dragLine.classed('hidden', true).style('marker-end', '');
852 this.mouseupNode = d;
853 if ((this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'vnfd') ||
854 (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'vld')) {
855 if (this.mouseupNode.type === 'vnfd') {
856 this.getOldVLDIndex = this.mouseupNode.id.split(':');
857 } else if (this.mousedownNode.type === 'vnfd') {
858 this.getOldVLDIndex = this.mousedownNode.id.split(':');
860 const setOldVLDindex: string = this.getOldVLDIndex[1];
861 this.putType = 'cpAdded';
862 this.getAddConfirmation(this.mousedownNode, this.nsData, this.putType, setOldVLDindex);
863 } else if (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'ns') {
865 this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNFCP'));
866 } else if (this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'ns') {
868 this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNFCP'));
869 } else if (this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'vld') {
871 this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVL'));
872 } else if (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'vnfd') {
874 this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNF'));
875 } else if (this.mousedownNode.type === 'ns' && this.mouseupNode.type === 'ns') {
877 this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKCP'));
880 this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVLVNF'));
882 this.resetMouseVars();
884 this.currentSelectedLink = d;
885 this.currentSelectedNode = null;
887 /** Mosue Drag Line false if it is not satisfied @private */
888 private deselectPath(): void {
889 this.dragLine.classed('hidden', true).style('marker-end', '').attr('d', 'M0,0L0,0');
891 /** reset Mouse varaibles @private */
892 private resetMouseVars(): void {
893 this.mousedownNode = null;
894 this.mouseupNode = null;
895 this.mousedownLink = null;
897 /** De-select all the selected nodes @private */
898 private deselectAllNodes(): void {
899 this.vlNode.select('image').classed(this.activeClass, false);
900 this.vnfdnode.select('image').classed(this.activeClass, false);
901 this.cpnode.select('image').classed(this.activeClass, false);
903 /** Show the right-side information @private */
904 private showRightSideInfo(nsdDetails: boolean, vldDetails: boolean, vnfDeails: boolean, cpDetails: boolean): void {
905 this.isShowNSDDetails = nsdDetails;
906 this.isShowVLDetails = vldDetails;
907 this.isShowVNFDetails = vnfDeails;
908 this.isShowCPDetails = cpDetails;
910 /** Events handles when Shift Click to perform create cp @private */
911 // eslint-disable-next-line @typescript-eslint/no-explicit-any
912 private singleClick(nodeSelected: any, d: COMPOSERNODES): void {
913 this.selectNodeExclusive(nodeSelected, d);
915 /** Selected nodes @private */
916 // eslint-disable-next-line @typescript-eslint/no-explicit-any
917 private selectNodeExclusive(nodeSeleced: any, d: COMPOSERNODES): void {
918 const alreadyIsActive: boolean = nodeSeleced.select('#' + d.selectorId).classed(this.activeClass);
919 this.deselectAllNodes();
920 nodeSeleced.select('#' + d.selectorId).classed(this.activeClass, !alreadyIsActive);
921 if (d.type === 'vld' && !alreadyIsActive) {
922 this.nsData['virtual-link-desc'].forEach((result: VLD): void => {
923 if (result.id === d.id) {
924 this.showRightSideInfo(false, true, false, false);
925 this.virtualLinkDesc = result;
928 } else if (d.type === 'vnfd' && !alreadyIsActive) {
929 this.nsData.df.forEach((res: DF): void => {
930 if (res['vnf-profile'] !== undefined) {
931 res['vnf-profile'].forEach((resVNF: VNFPROFILE): void => {
932 if (resVNF.id === d.nodeIndex && resVNF['vnfd-id'] === d.name) {
933 this.showRightSideInfo(false, false, true, false);
934 this.vnfData = resVNF;
939 } else if (d.type === 'ns' && !alreadyIsActive) {
940 this.nsData.df.forEach((resultDF: DF): void => {
941 if (resultDF['vnf-profile'] !== undefined) {
942 resultDF['vnf-profile'].forEach((resVNF: VNFPROFILE): void => {
943 if (resVNF['virtual-link-connectivity'] !== undefined) {
944 resVNF['virtual-link-connectivity'].forEach((resultVLC: VLC, index: number): void => {
945 resultVLC['constituent-cpd-id'].forEach((resultCCI: CCI): void => {
946 const connectionPointID: string = resVNF.id + ':' + resultCCI['constituent-base-element-id'] + index + ':' + resultCCI['constituent-cpd-id'];
947 if (connectionPointID === d.id) {
948 this.cpData = resultCCI;
949 this.vnfData = resVNF;
950 this.virtualLinkProfileID = resultVLC['virtual-link-profile-id'];
951 this.showRightSideInfo(false, false, false, true);
960 this.showRightSideInfo(true, false, false, false);
963 /** Get confirmation Before Deleting the Link in Topology @private */
964 private getDeleteLinkConfirmation(d: Tick): void {
965 // eslint-disable-next-line security/detect-non-literal-fs-filename
966 const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
967 modalRef.componentInstance.topologyType = 'Delete';
968 modalRef.componentInstance.topologyname = this.translateService.instant('PAGE.TOPOLOGY.LINK') + ' - ' + d.source.id;
969 modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.LINK';
970 modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
972 this.doubleClickLink(d);
974 }).catch((): void => {
975 // Catch Navigation Error
978 /** Events handles when Double Click to Delete the link @private */
979 private doubleClickLink(d: Tick): void {
980 let getID: string = '';
981 let getName: string = '';
982 let getNodeIndex: string;
983 if (d.source.type === 'ns') {
985 getName = d.source.name;
986 getNodeIndex = d.source.nodeIndex;
988 /** Split the selected node of connectionpoint */
989 const selectedNode: string[] = getID.split(':');
990 this.nsData.df.forEach((resultDF: DF): void => {
991 if (resultDF['vnf-profile'] !== undefined) {
992 resultDF['vnf-profile'].forEach((elementVNF: VNFPROFILE): void => {
993 const selectedVNFProfileID: string = selectedNode[0];
994 /** If VNF ID is equal to selected VNFProfile ID check the VLC of CCI to match the id and name to remove the VLC index */
995 if (selectedVNFProfileID === elementVNF.id) {
996 elementVNF['virtual-link-connectivity'].forEach((elementVLC: VLC, index: number): void => {
997 const posCCI: number = elementVLC['constituent-cpd-id'].findIndex((e: CCI): boolean => {
998 const getCID: string = elementVNF.id + ':' + e['constituent-base-element-id'] + index + ':' + e['constituent-cpd-id'];
999 return getID === getCID;
1001 if (posCCI !== -1) {
1002 elementVNF['virtual-link-connectivity'].splice(index, 1);
1009 this.putType = 'linkdelete';
1010 this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
1012 /** Get confirmation Before Deleting the Node in Topology @private */
1013 private getDeleteConfirmation(d: COMPOSERNODES): void {
1014 // eslint-disable-next-line security/detect-non-literal-fs-filename
1015 const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
1016 modalRef.componentInstance.topologyType = 'Delete';
1017 modalRef.componentInstance.topologyname = d.name;
1018 if (d.type === 'vld') {
1019 modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.VIRTUALLINK';
1020 } else if (d.type === 'vnfd') {
1021 modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.VNF';
1022 } else if (d.type === 'ns') {
1023 modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.CONNECTIONPOINT';
1025 modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
1027 this.doubleClick(d);
1029 }).catch((): void => {
1030 // Catch Navigation Error
1033 /** Events handles when Double Click to Delete @private */
1034 private doubleClick(d: COMPOSERNODES): void {
1035 const deletedNode: COMPOSERNODES = d;
1036 this.nodes.forEach((res: COMPOSERNODES, i: number): void => {
1037 if (res.id === d.id) {
1038 if (deletedNode.type === 'vld') {
1039 /** Remove the virtual-link-desc related to VL */
1040 const pos: number = this.nsData['virtual-link-desc'].map((e: VLD): string => e.id).indexOf(d.id);
1041 this.nsData['virtual-link-desc'].splice(pos, 1);
1042 /** Remove the virtual-link-connectivity between VL and VNFD */
1043 this.nsData.df.forEach((resultDF: DF): void => {
1044 if (resultDF['vnf-profile'] !== undefined) {
1045 resultDF['vnf-profile'].forEach((resVNF: VNFPROFILE): void => {
1046 const getVLArray: number[] = resVNF['virtual-link-connectivity'].map((e: VLC, index: number): number => {
1047 if (e['virtual-link-profile-id'] === d.id) {
1051 if (getVLArray.length > 0) {
1052 getVLArray.forEach((removeIndex: number): void => {
1053 const index: string = removeIndex.toString();
1054 // eslint-disable-next-line security/detect-object-injection
1055 resVNF['virtual-link-connectivity'].splice(resVNF['virtual-link-connectivity'][index], 1);
1061 this.putType = 'nsddelete';
1062 } else if (deletedNode.type === 'vnfd') {
1063 this.nsData.df.forEach((resultDF: DF): void => {
1064 if (resultDF['vnf-profile'] !== undefined) {
1065 /** Remove the vnf-profile related to VNFD */
1066 const posVNF: number = resultDF['vnf-profile'].findIndex((e: VNFPROFILE): boolean => e['vnfd-id'] === d.name && e.id === d.nodeIndex);
1067 resultDF['vnf-profile'].splice(posVNF, 1);
1068 /** Check the VNFD exists in any vnf-profile */
1069 const isVNFDExists: boolean = resultDF['vnf-profile'].some((e: VNFPROFILE): boolean => e['vnfd-id'] === d.name);
1070 /** If VNFD not exists in the vnf-profile remove from vnfd-id */
1071 if (!isVNFDExists) {
1072 const posVNFD: number = this.nsData['vnfd-id'].findIndex((e: string): boolean => e === d.name);
1073 this.nsData['vnfd-id'].splice(posVNFD, 1);
1077 this.putType = 'vnfddelete';
1078 } else if (deletedNode.type === 'ns') {
1079 /** Split the selected node */
1080 const selectedNode: string[] = d.id.split(':');
1081 this.nsData.df.forEach((resultDF: DF): void => {
1082 if (resultDF['vnf-profile'] !== undefined) {
1083 resultDF['vnf-profile'].forEach((elementVNF: VNFPROFILE): void => {
1084 const selectedVNFProfileID: string = selectedNode[0];
1085 /** If VNF ID is equal to selected VNFProfile ID check the VLC of CCI to match the id and name to remove the VLC index */
1086 if (selectedVNFProfileID === elementVNF.id) {
1087 elementVNF['virtual-link-connectivity'].forEach((elementVLC: VLC, index: number): void => {
1088 const posCCI: number = elementVLC['constituent-cpd-id'].findIndex((e: CCI): boolean => {
1089 const getID: string = elementVNF.id + ':' + e['constituent-base-element-id'] + index + ':' + e['constituent-cpd-id'];
1090 return d.id === getID;
1092 if (posCCI !== -1) {
1093 elementVNF['virtual-link-connectivity'].splice(index, 1);
1100 this.putType = 'nsdelete';
1102 this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
1106 /** drag event @private */
1107 // eslint-disable-next-line @typescript-eslint/no-explicit-any
1108 private onDragDrop(): any {
1109 return d3.drag().filter(this.dragFilter)
1110 .on('start', this.dragstarted)
1111 .on('drag', this.dragged)
1112 .on('end', this.dragended);
1114 /** Key press event @private */
1115 private keyDown(): void {
1116 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
1117 if (this.lastKeyDown !== -1) { return; }
1118 this.lastKeyDown = d3.event.keyCode;
1119 if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
1120 this.svg.classed('ctrl', true);
1123 /** Key realse event @private */
1124 private keyUp(): void {
1125 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
1126 this.lastKeyDown = -1;
1127 if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
1128 this.gvlNode.on('.drag', null);
1129 this.gvnfdNode.on('.drag', null);
1130 this.gcpNode.on('.drag', null);
1131 this.svg.classed('ctrl', false);
1134 /** Events handles when to drag using filter for the keys @private */
1135 private dragFilter(): boolean {
1136 return d3.event.ctrlKey && !d3.event.button;
1138 /** Events handles when dragstarted @private */
1139 private dragstarted(d: COMPOSERNODES): void {
1143 /** Events handles when dragged @private */
1144 private dragged(d: COMPOSERNODES): void {
1145 d.fx = d.x = d3.event.x;
1146 d.fy = d.y = d3.event.y;
1148 /** Events handles when dragended @private */
1149 private dragended(d: COMPOSERNODES): void {
1150 if (this.forceSimulationActive) {
1156 this.forceSimulationActive = false;
1159 /** Events handles when node double click @private */
1160 private onNodedblClickToggleSidebar(): void {
1161 this.sideBarOpened = false;
1163 /** Events handles when node single click @private */
1164 private onNodeClickToggleSidebar(): void {
1165 this.sideBarOpened = true;