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