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 VNFComposerComponent
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, ERRORDATA, MODALCLOSERESPONSEDATA } 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';
34 import { RestService } from 'RestService';
35 import { SharedService, isNullOrUndefined } from 'SharedService';
36 import { COMPOSERNODES, EXTCPD, GRAPHDETAILS, INTCPD, IVLD, Tick, TickPath, VDU, VDUINTCPD, VNFD, VNFDATA, VNIR } from 'VNFDModel';
40 * @Component takes VNFComposerComponent.html as template url
43 templateUrl: './VNFComposerComponent.html',
44 styleUrls: ['./VNFComposerComponent.scss'],
45 encapsulation: ViewEncapsulation.None
47 /** Exporting a class @exports VNFComposerComponent */
48 export class VNFComposerComponent {
49 /** To inject services @public */
50 public injector: Injector;
51 /** View child contains graphContainer ref @public */
52 @ViewChild('graphContainer', { static: true }) public graphContainer: ElementRef;
53 /** dataService to pass the data from one component to another @public */
54 public dataService: DataService;
55 /** random number count @public */
56 public randomNumberLength: number;
57 /** Contains the vnfd information @public */
58 public vnfList: string[] = [];
59 /** Contains VNFD Information @public */
60 public vnfdInfo: VNFD = { 'product-name': '', description: '', version: '', id: '', provider: '' };
61 /** Contains right panel box information @public */
62 public showRightSideInfo: string = '';
63 /** Add the fixed class for the freeze @public */
64 public fixedClass: string = 'fixed';
65 /** Check the loading results @public */
66 public isLoadingResults: boolean = true;
67 /** Give the message for the loading @public */
68 public message: string = 'PLEASEWAIT';
69 /** Assign the forcesimulation active @public */
70 public forceSimulationActive: boolean = false;
71 /** Assign pinned class for the button when freezed @public */
72 public classApplied: boolean = false;
73 /** Contains sidebar open status @public */
74 public sideBarOpened: boolean = false;
75 /** Contains SVG attributes @private */
76 // eslint-disable-next-line @typescript-eslint/no-explicit-any
78 /** Contains forced node animations @private */
79 // eslint-disable-next-line @typescript-eslint/no-explicit-any
81 /** Contains the Drag line */
82 // eslint-disable-next-line @typescript-eslint/no-explicit-any
83 private dragLine: any;
84 /** Contains id of the node @private */
85 private identifier: string;
86 /** Contains path information of the node */
87 // eslint-disable-next-line @typescript-eslint/no-explicit-any
89 /** Contains node network @private */
90 // eslint-disable-next-line @typescript-eslint/no-explicit-any
92 /** Contains node network @private */
93 // eslint-disable-next-line @typescript-eslint/no-explicit-any
94 private virutualDeploymentUnit: any;
95 /** Contains node connectionPoint @private */
96 // eslint-disable-next-line @typescript-eslint/no-explicit-any
97 private connectionPoint: any;
98 /** Contains node intConnectionPoint @private */
99 // eslint-disable-next-line @typescript-eslint/no-explicit-any
100 private intConnectionPoint: any;
101 /** Contains the node information @private */
102 private nodes: COMPOSERNODES[] = [];
103 /** Contains the link information of nodes @private */
104 private links: {}[] = [];
105 /** Instance of the rest service @private */
106 private restService: RestService;
107 /** Service holds the router information @private */
108 private router: Router;
109 /** Service contails all the shared service information @private */
110 private sharedService: SharedService;
111 /** Holds teh instance of AuthService class of type AuthService @private */
112 private activatedRoute: ActivatedRoute;
113 /** Notifier service to popup notification @private */
114 private notifierService: NotifierService;
115 /** Controls the header form @private */
116 private headers: HttpHeaders;
117 /** Contains tranlsate instance @private */
118 private translateService: TranslateService;
119 /** Rendered nodes represent network @private */
120 // eslint-disable-next-line @typescript-eslint/no-explicit-any
121 private gNetwork: any;
122 /** Rendered nodes represent VDU @private */
123 // eslint-disable-next-line @typescript-eslint/no-explicit-any
124 private gVirutualDeploymentUnit: any;
125 /** Rendered nodes represent connection point @private */
126 // eslint-disable-next-line @typescript-eslint/no-explicit-any
127 private gConnectionPoint: any;
128 /** Rendered nodes represent internal connection point @private */
129 // eslint-disable-next-line @typescript-eslint/no-explicit-any
130 private gIntConnectionPoint: any;
131 /** Contains all the information about VNF Details @private */
132 private vnfdPackageDetails: VNFD;
133 /** Conatins mousedown action @private */
134 private mousedownNode: COMPOSERNODES = null;
135 /** Conatins mouseup action @private */
136 private mouseupNode: COMPOSERNODES = null;
137 /** Conatins current Selection node action @private */
138 private currentSelectedNode: COMPOSERNODES = null;
139 /** Add the activeNode for the selected @private */
140 private activeNode: string = 'active';
141 /** Contains lastkeypressed instance @private */
142 private lastKeyDown: number = -1;
143 /** Contains VDU Information @private */
144 private vduInfo: VDU;
145 /** Contains VDU Old value Information @private */
146 private oldVDUID: string;
147 /** Contains Internal VL Information @private */
148 private intvlInfo: IVLD;
149 /** Contains Internal VL Old value Information @private */
150 private oldintVLID: string;
151 /** Contains Connection Point Information @private */
152 private cpInfo: EXTCPD;
153 /** Contains Connection Point Old value Information @private */
154 private oldCPID: string;
155 /** Contains Internal Connection Point Information @private */
156 private intcpInfo: VNIR;
157 /** Instance of the modal service @private */
158 private modalService: NgbModal;
160 constructor(injector: Injector) {
161 this.injector = injector;
162 this.restService = this.injector.get(RestService);
163 this.dataService = this.injector.get(DataService);
164 this.router = this.injector.get(Router);
165 this.activatedRoute = this.injector.get(ActivatedRoute);
166 this.notifierService = this.injector.get(NotifierService);
167 this.translateService = this.injector.get(TranslateService);
168 this.sharedService = this.injector.get(SharedService);
169 this.modalService = this.injector.get(NgbModal);
172 * Lifecyle Hooks the trigger before component is instantiate
174 public ngOnInit(): void {
175 this.identifier = this.activatedRoute.snapshot.paramMap.get('id');
177 this.headers = new HttpHeaders({
178 'Content-Type': 'application/gzip',
179 Accept: 'application/json',
180 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
184 /** Prepare information for node creation of VNFD @public */
185 public generateData(): void {
186 this.nodes = []; this.links = []; this.vnfdPackageDetails = null;
187 this.showRightSideInfo = 'vnfdInfo';
188 this.restService.getResource(environment.VNFPACKAGESCONTENT_URL + '/' + this.identifier)
189 .subscribe((vnfdPackageDetails: VNFD): void => {
191 delete vnfdPackageDetails._admin;
192 delete vnfdPackageDetails._id;
193 delete vnfdPackageDetails._links;
194 this.vnfdPackageDetails = vnfdPackageDetails;
195 this.generateVDU(vnfdPackageDetails);
196 this.generateCPPoint(vnfdPackageDetails);
197 this.generateInternalVLD(vnfdPackageDetails);
198 this.generateInternalCP(vnfdPackageDetails);
199 this.generateIntVLCPLinks(vnfdPackageDetails);
200 this.generateVDUCPLinks(vnfdPackageDetails);
201 this.createNode(this.nodes);
202 this.generateVNFInfo(vnfdPackageDetails);
204 this.notifierService.notify('error', this.translateService.instant('ERROR'));
206 this.isLoadingResults = false;
207 }, (error: ERRORDATA): void => {
208 error.error = typeof error.error === 'string' ? jsyaml.load(error.error) : error.error;
209 if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) {
210 this.router.navigateByUrl('404', { skipLocationChange: true }).catch((): void => {
211 // Catch Navigation Error
214 this.restService.handleError(error, 'get');
216 this.isLoadingResults = false;
217 this.showRightSideInfo = '';
220 /** Generate the VNF Package Information */
221 public generateVNFInfo(vnfdPackageDetails: VNFD): void {
222 this.vnfdInfo['product-name'] = vnfdPackageDetails['product-name'];
223 this.vnfdInfo.description = vnfdPackageDetails.description;
224 this.vnfdInfo.version = vnfdPackageDetails.version;
225 this.vnfdInfo.id = vnfdPackageDetails.id;
226 this.vnfdInfo.provider = vnfdPackageDetails.provider;
228 /** Events handles at drag on D3 region @public */
229 // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
230 public drag(ev: any): void {
231 ev.dataTransfer.setData('text', ev.target.id);
233 /** Events handles drop at D3 region @public */
234 public drop(ev: DragEvent): void {
236 const getDropedName: string = ev.dataTransfer.getData('text');
237 if (getDropedName === 'vdu') {
238 this.svg.selectAll('*').remove();
239 this.vduDropCompose();
240 } else if (getDropedName === 'cp') {
241 this.svg.selectAll('*').remove();
242 this.cpDropCompose();
243 } else if (getDropedName === 'intvl') {
244 this.svg.selectAll('*').remove();
245 this.intvlDropCompose();
248 /** Events handles allow drop on D3 region @public */
249 public allowDrop(ev: DragEvent): void {
252 /** Generate and list VDU @public */
253 public generateVDU(vnfdPackageDetails: VNFD): void {
254 if (vnfdPackageDetails.vdu !== undefined) {
255 vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
265 /** Generate and list CP points @public */
266 public generateCPPoint(vnfdPackageDetails: VNFD): void {
267 if (vnfdPackageDetails['ext-cpd'] !== undefined) {
268 vnfdPackageDetails['ext-cpd'].forEach((cp: EXTCPD): void => {
270 id: cp['int-cpd'].cpd !== undefined ? cp['int-cpd'].cpd : cp.id,
278 /** Generate and list Internal VLD @public */
279 public generateInternalVLD(vnfdPackageDetails: VNFD): void {
280 if (vnfdPackageDetails['int-virtual-link-desc'] !== undefined) {
281 vnfdPackageDetails['int-virtual-link-desc'].forEach((ivld: IVLD): void => {
291 /** Generate and list Internal CP @public */
292 public generateInternalCP(vnfdPackageDetails: VNFD): void {
293 if (vnfdPackageDetails.vdu !== undefined) {
294 vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
295 if (vdu['int-cpd'] !== undefined) {
296 vdu['int-cpd'].forEach((intcpd: VDUINTCPD): void => {
297 if (intcpd['int-virtual-link-desc'] !== undefined) {
298 intcpd['virtual-network-interface-requirement'].forEach((vnir: VNIR): void => {
312 /** Generate VDU External and Internal CP Links @public */
313 public generateVDUCPLinks(vnfdPackageDetails: VNFD): void {
314 if (vnfdPackageDetails.vdu !== undefined) {
315 vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
316 const vduLink: string = vdu.id;
317 if (vdu['int-cpd'] !== undefined) {
318 vdu['int-cpd'].forEach((intCPD: VDUINTCPD): void => {
319 if (intCPD['int-virtual-link-desc'] !== undefined) {
320 intCPD['virtual-network-interface-requirement'].forEach((vnir: VNIR): void => {
321 this.links.push({ source: vduLink, target: intCPD.id });
324 this.links.push({ source: vduLink, target: intCPD.id });
331 /** Generate Network/VLD/Internal VirtualLink, CP Links @public */
332 public generateIntVLCPLinks(vnfdPackageDetails: VNFD): void {
333 if (vnfdPackageDetails.vdu !== undefined) {
334 vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
335 if (vdu['int-cpd'] !== undefined) {
336 vdu['int-cpd'].forEach((intCPD: VDUINTCPD): void => {
337 const vldName: string = intCPD['int-virtual-link-desc'];
338 if (intCPD['int-virtual-link-desc'] !== undefined) {
339 intCPD['virtual-network-interface-requirement'].forEach((vnir: VNIR): void => {
340 this.links.push({ source: vldName, target: intCPD.id });
348 /** VNFD details can be saved on users inputs @public */
349 public saveVNFD(): void {
350 this.vnfdPackageDetails['product-name'] = this.vnfdInfo['product-name'];
351 this.vnfdPackageDetails.description = this.vnfdInfo.description;
352 this.vnfdPackageDetails.version = this.vnfdInfo.version;
353 this.vnfdPackageDetails.id = this.vnfdInfo.id;
354 this.vnfdPackageDetails.provider = this.vnfdInfo.provider;
355 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
357 /** VDU details can be saved on users inputs @public */
358 public saveVDU(getVDUID: string): void {
359 const getOLDVDUID: string = this.oldVDUID;
360 this.vnfdPackageDetails.vdu.forEach((ref: VDU): void => {
361 if (ref.id === getVDUID) {
362 ref.id = this.vduInfo.id;
363 ref.name = this.vduInfo.name;
364 ref.description = this.vduInfo.description !== undefined ? this.vduInfo.description : '';
365 ref['sw-image-desc'] = this.vduInfo['sw-image-desc'];
368 this.vnfdPackageDetails['ext-cpd'].forEach((extCPD: EXTCPD): void => {
369 if (extCPD['int-cpd'] !== undefined) {
370 if (extCPD['int-cpd']['vdu-id'] === getOLDVDUID) {
371 extCPD['int-cpd']['vdu-id'] = this.vduInfo.id;
375 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
377 /** IntVL details can be saved on users inputs @public */
378 public saveIntVL(intVLID: string): void {
379 const getOldID: string = this.oldintVLID;
380 this.vnfdPackageDetails['int-virtual-link-desc'].forEach((ivldDetails: IVLD): void => {
381 if (ivldDetails.id === intVLID) {
382 ivldDetails.id = this.intvlInfo.id;
385 this.vnfdPackageDetails.vdu.forEach((vduDetails: VDU): void => {
386 if (vduDetails['int-cpd'] !== undefined) {
387 vduDetails['int-cpd'].forEach((intCPDDetails: VDUINTCPD): void => {
388 if (intCPDDetails['int-virtual-link-desc'] !== undefined) {
389 if (intCPDDetails['int-virtual-link-desc'] === getOldID) {
390 intCPDDetails['int-virtual-link-desc'] = this.intvlInfo.id;
396 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
398 /** IntVL details can be saved on users inputs @public */
399 public saveCP(cpID: string): void {
400 const getOldCP: string = this.oldCPID;
401 this.vnfdPackageDetails['ext-cpd'].forEach((ref: EXTCPD): void => {
402 if (ref.id === cpID) {
403 ref.id = this.cpInfo.id;
406 if (this.vnfdPackageDetails['mgmt-cp'] === getOldCP) {
407 this.vnfdPackageDetails['mgmt-cp'] = this.cpInfo.id;
409 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
411 /** Edit topology @public */
412 public onEdit(): void {
413 this.router.navigate(['/packages/vnf/edit/', this.identifier]).catch((): void => {
414 // Catch Navigation Error
417 /** Show Info @public */
418 public showInfo(): void {
419 // eslint-disable-next-line security/detect-non-literal-fs-filename
420 const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
421 modalRef.componentInstance.topologyType = 'Info';
422 modalRef.componentInstance.topologytitle = this.translateService.instant('PAGE.TOPOLOGY.INFO');
423 modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
427 }).catch((): void => {
428 // Catch Navigation Error
431 /** Event to freeze the animation @public */
432 public onFreeze(): void {
433 this.classApplied = !this.classApplied;
434 const alreadyFixedIsActive: boolean = d3.select('svg#graphContainer').classed(this.fixedClass);
435 d3.select('svg#graphContainer').classed(this.fixedClass, !alreadyFixedIsActive);
436 if (alreadyFixedIsActive) {
439 this.forceSimulationActive = alreadyFixedIsActive;
440 this.nodes.forEach((d: COMPOSERNODES): void => {
441 d.fx = (alreadyFixedIsActive) ? null : d.x;
442 d.fy = (alreadyFixedIsActive) ? null : d.y;
444 if (alreadyFixedIsActive) {
445 this.force.restart();
448 /** Events handles when dragended @public */
449 public toggleSidebar(): void {
450 this.sideBarOpened = !this.sideBarOpened;
451 this.deselectAllNodes();
452 this.showRightSideInfo = 'vnfdInfo';
454 /** Get the default Configuration of containers @private */
455 private getGraphContainerAttr(): GRAPHDETAILS {
468 sourcePaddingYes: 17,
478 /** Node is created and render at D3 region @private */
479 private createNode(nodes: VNFD[]): void {
480 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
481 d3.selectAll('svg#graphContainer > *').remove();
482 d3.select(window).on('keydown', (): void => { this.keyDown(); });
483 d3.select(window).on('keyup', (): void => { this.keyUp(); });
484 this.svg = d3.select('#graphContainer')
485 .attr('oncontextmenu', 'return false;')
486 .attr('viewBox', `0 0 ${graphContainerAttr.width} ${graphContainerAttr.height}`)
487 .on('mousemove', (): void => { this.mousemove(); });
488 this.force = d3.forceSimulation()
489 .force('link', d3.forceLink().id((d: TickPath): string => d.id).distance(graphContainerAttr.distance))
490 .force('charge', d3.forceManyBody().strength(graphContainerAttr.strength))
491 .force('x', d3.forceX(graphContainerAttr.width / graphContainerAttr.forcex))
492 .force('y', d3.forceY(graphContainerAttr.height / graphContainerAttr.forcey))
493 .on('tick', (): void => { this.tick(); });
494 this.path = this.svg.append('svg:g').selectAll('path');
495 this.dragLine = this.svg.append('svg:path').attr('class', 'link dragline hidden').attr('d', 'M0,0L0,0');
496 this.network = this.svg.append('svg:g').selectAll('network');
497 this.virutualDeploymentUnit = this.svg.append('svg:g').selectAll('virutualDeploymentUnit');
498 this.connectionPoint = this.svg.append('svg:g').selectAll('connectionPoint');
499 this.intConnectionPoint = this.svg.append('svg:g').selectAll('intConnectionPoint');
502 /** Update force layout (called automatically each iteration) @private */
503 private tick(): void {
504 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
505 this.path.attr('d', (d: Tick): string => {
506 const deltaX: number = d.target.x - d.source.x; const deltaY: number = d.target.y - d.source.y;
507 const dist: number = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
508 const normX: number = deltaX / dist; const normY: number = deltaY / dist;
509 const sourcePadding: number = d.left ? graphContainerAttr.sourcePaddingYes : graphContainerAttr.sourcePaddingNo;
510 const targetPadding: number = d.right ? graphContainerAttr.targetPaddingYes : graphContainerAttr.targetPaddingNo;
511 const sourceX: number = d.source.x + (sourcePadding * normX); const sourceY: number = d.source.y + (sourcePadding * normY);
512 const targetX: number = d.target.x - (targetPadding * normX); const targetY: number = d.target.y - (targetPadding * normY);
513 return `M${sourceX},${sourceY}L${targetX},${targetY}`;
514 }).on('dblclick', (d: Tick): void => { this.getDeleteLinkConfirmation(d); });
515 this.network.attr('transform', (d: TickPath): string => `translate(${d.x},${d.y})`);
516 this.virutualDeploymentUnit.attr('transform', (d: TickPath): string => `translate(${d.x},${d.y})`);
517 this.connectionPoint.attr('transform', (d: TickPath): string => `translate(${d.x},${d.y})`);
518 this.intConnectionPoint.attr('transform', (d: TickPath): string => `translate(${d.x},${d.y})`);
520 /** Update graph (called when needed) @private */
521 private restart(nodes: VNFD[]): void {
522 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
523 this.path = this.path.data(this.links);
524 const cpNodes: {}[] = []; const vduNodes: {}[] = []; const vlNodes: {}[] = []; const intcpNodes: {}[] = []; //Nodes are known by id
525 nodes.forEach((nodeList: COMPOSERNODES): void => {
526 if (nodeList.type === 'cp') { cpNodes.push(nodeList); }
527 else if (nodeList.type === 'vdu') { vduNodes.push(nodeList); }
528 else if (nodeList.type === 'intvl') { vlNodes.push(nodeList); }
529 else if (nodeList.type === 'intcp') { intcpNodes.push(nodeList); }
531 this.network = this.network.data(vlNodes, (d: VNFD): string => d.id);
532 this.virutualDeploymentUnit = this.virutualDeploymentUnit.data(vduNodes, (d: VNFD): string => d.id);
533 this.connectionPoint = this.connectionPoint.data(cpNodes, (d: VNFD): string => d.id);
534 this.intConnectionPoint = this.intConnectionPoint.data(intcpNodes, (d: VNFD): string => d.id);
535 this.resetAndCreateNodes();
536 this.force.nodes(nodes).force('link').links(this.links); //Set the graph in motion
537 this.force.alphaTarget(graphContainerAttr.alphaTarget).restart();
539 /** Rest and create nodes @private */
540 private resetAndCreateNodes(): void {
541 this.path.exit().remove();
542 this.network.exit().remove();
543 this.virutualDeploymentUnit.exit().remove();
544 this.connectionPoint.exit().remove();
545 this.intConnectionPoint.exit().remove();
548 this.getgVirutualDeploymentUnit();
549 this.getgConnectionPoint();
550 this.getgIntConnectionPoint();
551 this.network = this.gNetwork.merge(this.network);
552 this.virutualDeploymentUnit = this.gVirutualDeploymentUnit.merge(this.virutualDeploymentUnit);
553 this.connectionPoint = this.gConnectionPoint.merge(this.connectionPoint);
554 this.intConnectionPoint = this.gIntConnectionPoint.merge(this.intConnectionPoint);
555 this.path.merge(this.path);
557 /** Setting the Path @private */
558 private getPathNodes(): void {
559 this.path = this.path.enter().append('svg:path').attr('class', 'link');
561 /** Settings all the network attributes of nodes @private */
562 private getgNetwork(): void {
563 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
564 this.gNetwork = this.network.enter().append('svg:g');
565 this.gNetwork.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
566 this.gNetwork.append('svg:image')
568 .attr('x', graphContainerAttr.imageX)
569 .attr('y', graphContainerAttr.imageY)
570 .call(this.onDragDrop())
571 .attr('id', (d: COMPOSERNODES): string => d.id)
572 .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
573 .attr('xlink:href', 'assets/images/INTVL.svg')
574 .on('mousedown', (d: COMPOSERNODES): void => { this.mouseDown(d); })
575 .on('mouseup', (d: COMPOSERNODES): void => { this.mouseUp(d); })
576 .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.network, d); this.onNodeClickToggleSidebar(); })
577 .on('dblclick', (d: COMPOSERNODES): void => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); });
578 this.gNetwork.append('svg:text')
579 .attr('class', 'node_text')
580 .attr('y', graphContainerAttr.textY)
581 .text((d: COMPOSERNODES): string => d.id);
583 /** Settings all the connection point attributes of nodes @private */
584 private getgVirutualDeploymentUnit(): void {
585 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
586 this.gVirutualDeploymentUnit = this.virutualDeploymentUnit.enter().append('svg:g');
587 this.gVirutualDeploymentUnit.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
588 this.gVirutualDeploymentUnit.append('svg:image')
590 .attr('x', graphContainerAttr.imageX)
591 .attr('y', graphContainerAttr.imageY)
592 .call(this.onDragDrop())
593 .attr('id', (d: COMPOSERNODES): string => d.id)
594 .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
595 .attr('xlink:href', 'assets/images/VDU.svg')
596 .on('mousedown', (d: COMPOSERNODES): void => { this.mouseDown(d); })
597 .on('mouseup', (d: COMPOSERNODES): void => { this.mouseUp(d); })
598 .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.virutualDeploymentUnit, d); this.onNodeClickToggleSidebar(); })
599 .on('dblclick', (d: COMPOSERNODES): void => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); });
600 this.gVirutualDeploymentUnit.append('svg:text')
601 .attr('class', 'node_text')
602 .attr('y', graphContainerAttr.textY)
603 .text((d: COMPOSERNODES): string => d.id);
605 /** Settings all the connection point attributes of nodes @private */
606 private getgConnectionPoint(): void {
607 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
608 this.gConnectionPoint = this.connectionPoint.enter().append('svg:g');
609 this.gVirutualDeploymentUnit.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
610 this.gConnectionPoint.append('svg:image')
612 .attr('x', graphContainerAttr.imageX)
613 .attr('y', graphContainerAttr.imageY)
614 .call(this.onDragDrop())
615 .attr('id', (d: COMPOSERNODES): string => d.id)
616 .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
617 .attr('xlink:href', 'assets/images/CP-VNF.svg')
618 .on('mousedown', (d: COMPOSERNODES): void => { this.mouseDown(d); })
619 .on('mouseup', (d: COMPOSERNODES): void => { this.mouseUp(d); })
620 .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.connectionPoint, d); this.onNodeClickToggleSidebar(); })
621 .on('dblclick', (d: COMPOSERNODES): void => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); });
622 this.gConnectionPoint.append('svg:text')
623 .attr('class', 'node_text')
624 .attr('y', graphContainerAttr.textY)
625 .text((d: COMPOSERNODES): string => d.name);
627 /** Settings all the internal connection point attributes of nodes @private */
628 private getgIntConnectionPoint(): void {
629 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
630 this.gIntConnectionPoint = this.intConnectionPoint.enter().append('svg:g');
631 this.gIntConnectionPoint.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
632 this.gIntConnectionPoint.append('svg:image')
634 .attr('x', graphContainerAttr.imageX)
635 .attr('y', graphContainerAttr.imageY)
636 .call(this.onDragDrop())
637 .attr('id', (d: COMPOSERNODES): string => d.id)
638 .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
639 .attr('xlink:href', 'assets/images/INTCP.svg')
640 .on('mousedown', (d: COMPOSERNODES): void => { this.mouseDown(d); })
641 .on('mouseup', (d: COMPOSERNODES): void => { this.mouseUp(d); })
642 .on('click', (d: COMPOSERNODES): void => { this.singleClick(this.intConnectionPoint, d); this.onNodeClickToggleSidebar(); })
643 .on('dblclick', (d: COMPOSERNODES): void => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); });
644 this.gIntConnectionPoint.append('svg:text')
645 .attr('class', 'node_text')
646 .attr('y', graphContainerAttr.textY)
647 .text((d: COMPOSERNODES): string => d.name);
649 /** Drop VDU Composer Data @private */
650 private vduDropCompose(): void {
651 const randomID: string = this.sharedService.randomString();
652 if (this.vnfdPackageDetails['mgmt-cp'] === undefined) {
653 this.notifierService.notify('error', this.translateService.instant('PAGE.TOPOLOGY.ADDCPBEFOREVDU'));
655 if (this.vnfdPackageDetails.vdu === undefined) {
656 this.vnfdPackageDetails.vdu = [];
658 this.vnfdPackageDetails.vdu.push({
659 id: 'vdu_' + randomID,
660 name: 'vdu_' + randomID,
662 'sw-image-desc': 'ubuntu',
664 'monitoring-parameter': [],
665 'virtual-compute-desc': '',
666 'virtual-storage-desc': []
668 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
671 /** Drop CP Composer Data @private */
672 private cpDropCompose(): void {
673 const randomID: string = this.sharedService.randomString();
674 if (this.vnfdPackageDetails['ext-cpd'] === undefined) {
675 this.vnfdPackageDetails['ext-cpd'] = [];
677 this.vnfdPackageDetails['ext-cpd'].push({
678 id: 'cp_' + randomID,
681 if (this.vnfdPackageDetails['mgmt-cp'] === undefined) {
682 this.vnfdPackageDetails['mgmt-cp'] = 'cp_' + randomID;
684 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
686 /** Drop IntVL Composer Data @private */
687 private intvlDropCompose(): void {
688 const randomID: string = this.sharedService.randomString();
689 if (this.vnfdPackageDetails['int-virtual-link-desc'] === undefined) {
690 this.vnfdPackageDetails['int-virtual-link-desc'] = [];
692 this.vnfdPackageDetails['int-virtual-link-desc'].push({
693 id: 'vnf_vl_' + randomID
695 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
697 /** Add the Add Nodes Data @private */
698 private addNodes(apiURL: string, identifier: string, data: VNFD): void {
699 this.isLoadingResults = true;
700 const apiURLHeader: APIURLHEADER = {
701 url: apiURL + '/' + identifier + '/package_content',
702 httpOptions: { headers: this.headers }
704 const vnfData: VNFDATA = {};
706 const descriptorInfo: string = jsyaml.dump(vnfData, { sortKeys: true });
707 this.sharedService.targzFile({ packageType: 'vnfd', id: this.identifier, descriptor: descriptorInfo })
708 .then((content: ArrayBuffer): void => {
709 this.restService.putResource(apiURLHeader, content).subscribe((res: {}): void => {
711 this.notifierService.notify('success', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.UPDATEDSUCCESSFULLY'));
712 this.isLoadingResults = false;
713 }, (error: ERRORDATA): void => {
715 this.restService.handleError(error, 'put');
716 this.isLoadingResults = false;
718 }).catch((): void => {
719 this.notifierService.notify('error', this.translateService.instant('ERROR'));
720 this.isLoadingResults = false;
723 /** Events handles when mousedown click it will capture the selected node data @private */
724 private mouseDown(d: COMPOSERNODES): void {
725 // eslint-disable-next-line deprecation/deprecation
726 event.preventDefault();
727 if (d3.event.ctrlKey) { return; }
728 if (d3.event.shiftKey) {
729 this.mousedownNode = d;
730 this.currentSelectedNode = (this.mousedownNode === this.currentSelectedNode) ? null : this.mousedownNode;
731 this.dragLine.classed('hidden', false)
732 .attr('d', `M${this.mousedownNode.x},${this.mousedownNode.y}L${this.mousedownNode.x},${this.mousedownNode.y}`);
735 /** Event handles when mouseup event occures @private */
736 private mouseUp(d: COMPOSERNODES): void {
737 if (!this.mousedownNode) { return; }
738 this.dragLine.classed('hidden', true);
739 this.mouseupNode = d;
740 if (this.mousedownNode.type === 'vdu') {
741 this.vduMouseDownNode();
742 } else if (this.mousedownNode.type === 'cp') {
743 this.cpMouseDownNode();
744 } else if (this.mousedownNode.type === 'intvl') {
745 this.intVLMouseDownNode();
746 } else if (this.mousedownNode.type === 'intcp') {
747 this.intCPMouseDownNode();
749 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.INVALIDSELECTION'));
752 this.resetMouseActions();
753 this.currentSelectedNode = null;
755 /** Establish a connection point between vdu and other nodes @private */
756 private vduMouseDownNode(): void {
757 if (this.mousedownNode.type === 'vdu' && this.mouseupNode.type === 'cp') {
758 this.vduCPConnection(this.mousedownNode.id, this.mouseupNode.id);
759 } else if (this.mousedownNode.type === 'vdu' && this.mouseupNode.type === 'intcp') {
760 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVDUANDINTCP'));
762 } else if (this.mousedownNode.type === 'vdu' && this.mouseupNode.type === 'vdu') {
763 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVDUANDVDU'));
765 } else if (this.mousedownNode.type === 'vdu' && this.mouseupNode.type === 'intvl') {
766 this.vduIntvlConnection(this.mousedownNode.id, this.mouseupNode.id);
769 /** Establish a connection point between cp and other nodes @private */
770 private cpMouseDownNode(): void {
771 if (this.mousedownNode.type === 'cp' && this.mouseupNode.type === 'vdu') {
772 this.vduCPConnection(this.mouseupNode.id, this.mousedownNode.id);
773 } else if (this.mousedownNode.type === 'cp' && this.mouseupNode.type === 'intvl') {
774 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKCPANDVNFVL'));
776 } else if (this.mousedownNode.type === 'cp' && this.mouseupNode.type === 'intcp') {
777 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKCPANDINTCP'));
779 } else if (this.mousedownNode.type === 'cp' && this.mouseupNode.type === 'cp') {
780 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKCPANDCP'));
784 /** Establish a connection piont between intvl and other nodes @private */
785 private intVLMouseDownNode(): void {
786 if (this.mousedownNode.type === 'intvl' && this.mouseupNode.type === 'cp') {
787 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVNFVLANDCP'));
789 } else if (this.mousedownNode.type === 'intvl' && this.mouseupNode.type === 'vdu') {
790 this.vduIntvlConnection(this.mouseupNode.id, this.mousedownNode.id);
791 } else if (this.mousedownNode.type === 'intvl' && this.mouseupNode.type === 'intvl') {
792 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVNFVLANDVNFVL'));
794 } else if (this.mousedownNode.type === 'intvl' && this.mouseupNode.type === 'intcp') {
795 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVNFVLANDONTCP'));
799 /** Establish a connection point between intcp and other nodes @private */
800 private intCPMouseDownNode(): void {
801 if (this.mousedownNode.type === 'intcp' && this.mouseupNode.type === 'vdu') {
802 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKINTCPANDVDU'));
804 } else if (this.mousedownNode.type === 'intcp' && this.mouseupNode.type === 'cp') {
805 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKINTCPANDCP'));
807 } else if (this.mousedownNode.type === 'intcp' && this.mouseupNode.type === 'intvl') {
808 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKINTCPANDVNFVL'));
810 } else if (this.mousedownNode.type === 'intcp' && this.mouseupNode.type === 'intcp') {
811 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKINTCPANDINTCP'));
815 /** Establish a connection between VDU & CP vice versa @private */
816 private vduCPConnection(nodeA: string, nodeB: string): void {
817 const vduExternalID: string = nodeA + '-eth_' + this.sharedService.randomString();
818 if (this.vnfdPackageDetails.vdu !== undefined) {
819 this.vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
820 const vduID: string = vdu.id;
821 if (vdu.id === nodeA) {
822 if (this.vnfdPackageDetails['ext-cpd'] !== undefined) {
823 this.vnfdPackageDetails['ext-cpd'].forEach((extcpd: EXTCPD, index: number): void => {
824 if (extcpd.id === nodeB) {
825 if (vdu['int-cpd'] === undefined) {
828 vdu['int-cpd'].push({
830 'virtual-network-interface-requirement': [
834 'virtual-interface': { type: 'PARAVIRT' }
838 // eslint-disable-next-line security/detect-object-injection
839 this.vnfdPackageDetails['ext-cpd'][index] = {
852 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
855 /** Establish a connection between vdu & intvl and vice versa @private */
856 private vduIntvlConnection(nodeA: string, nodeB: string): void {
857 const vduInternalID: string = nodeA + '-eth_' + this.sharedService.randomString();
858 if (this.vnfdPackageDetails.vdu !== undefined) {
859 this.vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
860 if (vdu.id === nodeA) {
861 if (vdu['int-cpd'] === undefined) {
864 vdu['int-cpd'].push({
866 'int-virtual-link-desc': nodeB,
867 'virtual-network-interface-requirement': [
871 'virtual-interface': { type: 'PARAVIRT' }
878 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
881 /** Events handles when mousemove it will capture the selected node data @private */
882 private mousemove(): void {
883 if (!this.mousedownNode) { return; }
884 this.dragLine.attr('d',
885 `M${this.mousedownNode.x},${this.mousedownNode.y}L${d3.mouse(d3.event.currentTarget)[0]},${d3.mouse(d3.event.currentTarget)[1]}`);
887 /** reset Mouse varaibles @private */
888 private resetMouseActions(): void {
889 this.mousedownNode = null;
890 this.mouseupNode = null;
892 /** drag event @private */
893 // eslint-disable-next-line @typescript-eslint/no-explicit-any
894 private onDragDrop(): any {
895 return d3.drag().filter(this.dragFilter)
896 .on('start', this.dragstarted)
897 .on('drag', this.dragged)
898 .on('end', this.dragended);
900 /** Key press event @private */
901 private keyDown(): void {
902 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
903 if (this.lastKeyDown !== -1) { return; }
904 this.lastKeyDown = d3.event.keyCode;
905 if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
906 this.svg.classed('ctrl', true);
909 /** Key realse event @private */
910 private keyUp(): void {
911 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
912 this.lastKeyDown = -1;
913 if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
914 this.gNetwork.on('.drag', null);
915 this.gVirutualDeploymentUnit.on('.drag', null);
916 this.gConnectionPoint.on('.drag', null);
917 this.gIntConnectionPoint.on('.drag', null);
918 this.svg.classed('ctrl', false);
921 /** Mosue Drag Line false if it is not satisfied @private */
922 private deselectPath(): void {
923 this.dragLine.classed('hidden', true).attr('d', 'M0,0L0,0');
925 /** Events handles when Shift Click to perform create cp @private */
926 // eslint-disable-next-line @typescript-eslint/no-explicit-any
927 private singleClick(nodeSelected: any, d: COMPOSERNODES): void {
928 this.selectedNode(nodeSelected, d);
930 /** Get confirmation Before Deleting the Node in Topology @private */
931 private getDeleteNodeConfirmation(d: COMPOSERNODES): void {
932 // eslint-disable-next-line security/detect-non-literal-fs-filename
933 const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
934 modalRef.componentInstance.topologyType = 'Delete';
935 modalRef.componentInstance.topologyname = d.name;
936 if (d.type === 'vdu') {
937 modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.VDU';
938 } else if (d.type === 'intvl') {
939 modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.INTVL';
940 } else if (d.type === 'cp') {
941 modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.CONNECTIONPOINT';
942 } else if (d.type === 'intcp') {
943 modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.INTCP';
945 modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
949 }).catch((): void => {
950 // Catch Navigation Error
953 /** Delete nodes @private */
954 private deleteNode(d: COMPOSERNODES): void {
955 this.nodes.forEach((node: VNFD): void => {
956 if (node.id === d.id) {
957 if (d.type === 'cp') {
958 if (this.vnfdPackageDetails['ext-cpd'] !== undefined) {
959 let getRelatedVDUCPD: string; let getRelatedVDUID: string;
960 const posExtCPD: number = this.vnfdPackageDetails['ext-cpd'].findIndex((e: EXTCPD): boolean => {
961 if (e.id === d.name) {
962 if (e['int-cpd'] !== undefined) {
963 getRelatedVDUCPD = e['int-cpd'].cpd; getRelatedVDUID = e['int-cpd']['vdu-id'];
970 if (posExtCPD !== -1) {
971 this.vnfdPackageDetails['ext-cpd'].splice(posExtCPD, 1);
973 if (getRelatedVDUCPD !== undefined && getRelatedVDUID !== undefined) {
974 this.vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
975 if (vdu.id === getRelatedVDUID) {
976 const posINTCPD: number = vdu['int-cpd'].findIndex((intCPD: VDUINTCPD): boolean => intCPD.id === getRelatedVDUCPD);
977 if (posINTCPD !== -1) {
978 vdu['int-cpd'].splice(posINTCPD, 1);
984 } else if (d.type === 'intcp') {
985 this.vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
986 const posINTCPD: number = vdu['int-cpd'].findIndex((intCPD: VDUINTCPD): boolean => intCPD.id === d.id);
987 if (posINTCPD !== -1) {
988 vdu['int-cpd'].splice(posINTCPD, 1);
991 } else if (d.type === 'intvl') {
992 const posINTVLD: number = this.vnfdPackageDetails['int-virtual-link-desc'].findIndex((intVLD: IVLD): boolean => intVLD.id === d.id);
993 if (posINTVLD !== -1) {
994 this.vnfdPackageDetails['int-virtual-link-desc'].splice(posINTVLD, 1);
996 if (this.vnfdPackageDetails.vdu !== undefined) {
997 this.vnfdPackageDetails.vdu.forEach((vduDetails: VDU): void => {
998 if (vduDetails['int-cpd'] !== undefined) {
999 const newVDUintCPDArray: VDUINTCPD[] = vduDetails['int-cpd'].filter((item: VDUINTCPD): boolean => item['int-virtual-link-desc'] !== undefined ? item['int-virtual-link-desc'] !== d.id ? true : false : true);
1000 vduDetails['int-cpd'] = newVDUintCPDArray;
1004 } else if (d.type === 'vdu') {
1005 const getRelatedExtCPD: string[] = [];
1006 const posVDU: number = this.vnfdPackageDetails.vdu.findIndex((vduDetails: VDU): boolean => {
1007 if (vduDetails.id === d.id) {
1008 if (vduDetails['int-cpd'] !== undefined) {
1009 vduDetails['int-cpd'].forEach((intCPDDetails: VDUINTCPD): void => {
1010 if (intCPDDetails['int-virtual-link-desc'] === undefined) {
1011 getRelatedExtCPD.push(intCPDDetails.id);
1020 if (posVDU !== -1) {
1021 this.vnfdPackageDetails.vdu.splice(posVDU, 1);
1023 getRelatedExtCPD.forEach((CPDID: string, index: number): void => {
1024 this.vnfdPackageDetails['ext-cpd'].forEach((extCPD: EXTCPD): void => {
1025 if (extCPD['int-cpd'] !== undefined) {
1026 if (extCPD['int-cpd'].cpd === CPDID) {
1027 extCPD['int-cpd'] = {};
1033 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.INVALIDSELECTION'));
1035 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
1039 /** Get confirmation before deleting the ink in Topology @private */
1040 private getDeleteLinkConfirmation(d: Tick): void {
1041 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.YOUCANNOTDELETELINK'));
1043 /** Selected nodes @private */
1044 // eslint-disable-next-line @typescript-eslint/no-explicit-any
1045 private selectedNode(nodeSeleced: any, d: COMPOSERNODES): void {
1046 const alreadyIsActive: boolean = nodeSeleced.select('#' + d.id).classed(this.activeNode);
1047 this.deselectAllNodes();
1048 nodeSeleced.select('#' + d.id).classed(this.activeNode, !alreadyIsActive);
1049 if (d.type === 'vdu' && !alreadyIsActive) {
1050 this.vnfdPackageDetails.vdu.forEach((res: VDU): void => {
1051 if (res.id === d.id) {
1052 this.showRightSideInfo = 'vduInfo';
1054 this.oldVDUID = res.id;
1057 } else if (d.type === 'cp' && !alreadyIsActive) {
1058 this.vnfdPackageDetails['ext-cpd'].forEach((cp: EXTCPD): void => {
1059 const getCPDID: string = cp['int-cpd'] !== undefined ? cp['int-cpd'].cpd : cp.id;
1060 if (getCPDID === d.id) {
1061 this.showRightSideInfo = 'cpInfo';
1063 this.oldCPID = cp.id;
1066 } else if (d.type === 'intvl' && !alreadyIsActive) {
1067 this.vnfdPackageDetails['int-virtual-link-desc'].forEach((ivld: IVLD): void => {
1068 if (ivld.id === d.id) {
1069 this.showRightSideInfo = 'intvlInfo';
1070 this.intvlInfo = ivld;
1071 this.oldintVLID = ivld.id;
1074 } else if (d.type === 'intcp' && !alreadyIsActive) {
1075 this.vnfdPackageDetails.vdu.forEach((vdu: VDU): void => {
1076 vdu['int-cpd'].forEach((intcpd: VDUINTCPD): void => {
1077 if (intcpd.id === d.id) {
1078 if (intcpd['int-virtual-link-desc'] !== undefined) {
1079 intcpd['virtual-network-interface-requirement'].forEach((vnir: VNIR): void => {
1080 this.intcpInfo = vnir;
1081 this.showRightSideInfo = 'intcpInfo';
1088 this.showRightSideInfo = 'vnfdInfo';
1091 /** De-select all the selected nodes @private */
1092 private deselectAllNodes(): void {
1093 this.network.select('image').classed(this.activeNode, false);
1094 this.virutualDeploymentUnit.select('image').classed(this.activeNode, false);
1095 this.connectionPoint.select('image').classed(this.activeNode, false);
1096 this.intConnectionPoint.select('image').classed(this.activeNode, false);
1098 /** Events handles when to drag using filter for the keys @private */
1099 private dragFilter(): boolean {
1100 return d3.event.ctrlKey && !d3.event.button;
1102 /** Events handles when dragstarted @private */
1103 private dragstarted(d: COMPOSERNODES): void {
1107 /** Events handles when dragged @private */
1108 private dragged(d: COMPOSERNODES): void {
1109 d.fx = d.x = d3.event.x;
1110 d.fy = d.y = d3.event.y;
1112 /** Events handles when dragended @private */
1113 private dragended(d: COMPOSERNODES): void {
1114 if (this.forceSimulationActive) {
1120 this.forceSimulationActive = false;
1123 /** Events handles when node double click @private */
1124 private onNodedblClickToggleSidebar(): void {
1125 this.sideBarOpened = false;
1127 /** Events handles when node single click @private */
1128 private onNodeClickToggleSidebar(): void {
1129 this.sideBarOpened = true;