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, GETAPIURLHEADER, 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 } from 'SharedService';
36 import { isNullOrUndefined } from 'util';
38 COMPOSERNODES, CONNECTIONPOINT, GRAPHDETAILS, InternalVLD, Tick, TickPath,
39 VDU, VDUInternalConnectionPoint, VLDInternalConnectionPoint, VNFDInterface, VNFDNODE
44 * @Component takes VNFComposerComponent.html as template url
47 templateUrl: './VNFComposerComponent.html',
48 styleUrls: ['./VNFComposerComponent.scss'],
49 encapsulation: ViewEncapsulation.None
51 /** Exporting a class @exports VNFComposerComponent */
52 export class VNFComposerComponent {
53 /** To inject services @public */
54 public injector: Injector;
55 /** View child contains graphContainer ref @public */
56 @ViewChild('graphContainer', { static: true }) public graphContainer: ElementRef;
57 /** dataService to pass the data from one component to another @public */
58 public dataService: DataService;
59 /** random number count @public */
60 public randomNumberLength: number;
61 /** Contains the vnfd information @public */
62 public vnfList: string[] = [];
63 /** Contains node type @public */
64 public nodeTypeRef: string;
65 /** Contains VNFD Information @public */
66 public vnfdInfo: VNFDNODE = { shortName: '', description: '', version: '', id: '', name: '' };
67 /** Contains right panel box information @public */
68 public showRightSideInfo: string = '';
69 /** Add the fixed class for the freeze @public */
70 public fixedClass: string = 'fixed';
71 /** Check the loading results @public */
72 public isLoadingResults: boolean = true;
73 /** Give the message for the loading @public */
74 public message: string = 'PLEASEWAIT';
75 /** Assign the forcesimulation active @public */
76 public forceSimulationActive: boolean = false;
77 /** Assign pinned class for the button when freezed @public */
78 public classApplied: boolean = false;
79 /** Contains sidebar open status @public */
80 public sideBarOpened: boolean = false;
82 /** Contains SVG attributes @private */
83 // tslint:disable-next-line:no-any
85 /** Contains forced node animations @private */
86 // tslint:disable-next-line:no-any
88 /** Contains the Drag line */
89 // tslint:disable-next-line: no-any
90 private dragLine: any;
91 /** Contains id of the node @private */
92 private identifier: string;
93 /** Contains path information of the node */
94 // tslint:disable-next-line:no-any
96 /** Contains node network @private */
97 // tslint:disable-next-line:no-any
99 /** Contains node network @private */
100 // tslint:disable-next-line:no-any
101 private virutualDeploymentUnit: any;
102 /** Contains node connectionPoint @private */
103 // tslint:disable-next-line:no-any
104 private connectionPoint: any;
105 /** Contains node intConnectionPoint @private */
106 // tslint:disable-next-line:no-any
107 private intConnectionPoint: any;
108 /** Contains the node information @private */
109 private nodes: VNFDNODE[] = [];
110 /** Contains the link information of nodes @private */
111 private links: {}[] = [];
112 /** Instance of the rest service @private */
113 private restService: RestService;
114 /** Service holds the router information @private */
115 private router: Router;
116 /** Service contails all the shared service information @private */
117 private sharedService: SharedService;
118 /** Holds teh instance of AuthService class of type AuthService @private */
119 private activatedRoute: ActivatedRoute;
120 /** Notifier service to popup notification @private */
121 private notifierService: NotifierService;
122 /** Controls the header form @private */
123 private headers: HttpHeaders;
124 /** Contains tranlsate instance @private */
125 private translateService: TranslateService;
126 /** Rendered nodes represent network @private */
127 // tslint:disable-next-line:no-any
128 private gNetwork: any;
129 /** Rendered nodes represent VDU @private */
130 // tslint:disable-next-line:no-any
131 private gVirutualDeploymentUnit: any;
132 /** Rendered nodes represent connection point @private */
133 // tslint:disable-next-line:no-any
134 private gConnectionPoint: any;
135 /** Rendered nodes represent internal connection point @private */
136 // tslint:disable-next-line:no-any
137 private gIntConnectionPoint: any;
138 /** Contains all the information about VNF Details @private */
139 private vnfdPackageDetails: VNFDNODE;
140 /** Conatins mousedown action @private */
141 private mousedownNode: COMPOSERNODES = null;
142 /** Conatins mouseup action @private */
143 private mouseupNode: COMPOSERNODES = null;
144 /** Conatins current Selection node action @private */
145 private currentSelectedNode: COMPOSERNODES = null;
146 /** Add the activeNode for the selected @private */
147 private activeNode: string = 'active';
148 /** Contains lastkeypressed instance @private */
149 private lastKeyDown: number = -1;
150 /** Contains VDU Information @private */
151 private vduInfo: VDU;
152 /** Contains Internal VL Information @private */
153 private intvlInfo: InternalVLD;
154 /** Contains Connection Point Information @private */
155 private cpInfo: CONNECTIONPOINT;
156 /** Contains Internal Connection Point Information @private */
157 private intcpInfo: VLDInternalConnectionPoint;
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 // tslint:disable-next-line:no-backbone-get-set-outside-model
177 this.identifier = this.activatedRoute.snapshot.paramMap.get('id');
179 this.headers = new HttpHeaders({
180 'Content-Type': 'application/zip',
181 Accept: 'application/json',
182 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
186 /** Prepare information for node creation of VNFD @public */
187 public generateData(): void {
188 this.nodes = []; this.links = []; this.vnfdPackageDetails = null;
189 this.showRightSideInfo = 'vnfdInfo';
190 const httpOptions: GETAPIURLHEADER = {
191 headers: new HttpHeaders({
192 'Content-Type': 'application/zip',
193 Accept: 'text/plain',
194 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
198 this.restService.getResource(environment.VNFPACKAGES_URL + '/' + this.identifier + '/vnfd', httpOptions)
199 .subscribe((vnfdPackageDetails: VNFDNODE) => {
201 const getJson: string = jsyaml.load(vnfdPackageDetails.toString(), { json: true });
202 if (getJson.hasOwnProperty('vnfd-catalog')) {
203 this.vnfdPackageDetails = getJson['vnfd-catalog'].vnfd[0];
204 } else if (getJson.hasOwnProperty('vnfd:vnfd-catalog')) {
205 this.vnfdPackageDetails = getJson['vnfd:vnfd-catalog'].vnfd[0];
206 } else if (getJson.hasOwnProperty('vnfd')) {
207 // tslint:disable-next-line: no-string-literal
208 this.vnfdPackageDetails = getJson['vnfd'][0];
210 this.generateCPPoint(this.vnfdPackageDetails);
211 this.generateVDU(this.vnfdPackageDetails);
212 this.generateInternalVLD(this.vnfdPackageDetails);
213 this.generateInternalCP(this.vnfdPackageDetails);
214 this.generateIntVLCPLinks(this.vnfdPackageDetails);
215 this.generateVDUCPLinks(this.vnfdPackageDetails);
216 this.createNode(this.nodes);
217 this.vnfdInfo.shortName = this.vnfdPackageDetails['short-name'];
218 this.vnfdInfo.description = this.vnfdPackageDetails.description;
219 this.vnfdInfo.version = this.vnfdPackageDetails.version;
220 this.vnfdInfo.id = this.vnfdPackageDetails.id;
221 this.vnfdInfo.name = this.vnfdPackageDetails.name;
223 this.notifierService.notify('error', this.translateService.instant('ERROR'));
225 this.isLoadingResults = false;
226 }, (error: ERRORDATA) => {
227 error.error = typeof error.error === 'string' ? jsyaml.load(error.error) : error.error;
228 if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) {
229 this.router.navigateByUrl('404', { skipLocationChange: true }).catch();
231 this.restService.handleError(error, 'get');
233 this.isLoadingResults = false;
234 this.showRightSideInfo = '';
237 /** Events handles at drag on D3 region @public */
238 // tslint:disable-next-line:no-any
239 public drag(ev: any): void {
240 ev.dataTransfer.setData('text', ev.target.id);
242 /** Events handles drop at D3 region @public */
243 public drop(ev: DragEvent): void {
245 this.nodeTypeRef = ev.dataTransfer.getData('text');
246 if (this.nodeTypeRef === 'vdu') {
247 this.svg.selectAll('*').remove();
248 this.vduDropCompose();
249 } else if (this.nodeTypeRef === 'cp') {
250 this.svg.selectAll('*').remove();
251 this.cpDropCompose();
252 } else if (this.nodeTypeRef === 'intvl') {
253 this.svg.selectAll('*').remove();
254 this.intvlDropCompose();
257 /** Events handles allow drop on D3 region @public */
258 public allowDrop(ev: DragEvent): void {
261 /** Generate and list CP points @public */
262 public generateCPPoint(vnfdPackageDetails: VNFDNODE): void {
263 if (vnfdPackageDetails['connection-point'] !== undefined) {
264 vnfdPackageDetails['connection-point'].forEach((cp: CONNECTIONPOINT) => {
265 this.nodes.push({ id: cp.name, nodeTypeRef: 'cp', name: cp.name, type: cp.type });
269 /** Generate and list VDU @public */
270 public generateVDU(vnfdPackageDetails: VNFDNODE): void {
271 if (vnfdPackageDetails.vdu !== undefined) {
272 vnfdPackageDetails.vdu.forEach((vdu: VDU) => {
274 id: vdu.name, nodeTypeRef: 'vdu', 'cloud-init-file': vdu['cloud-init-file'], count: vdu.count, description: vdu.description,
275 vduID: vdu.id, name: vdu.name, interface: vdu.interface, 'vm-flavor': vdu['vm-flavor']
280 /** Generate and list Internal VLD @public */
281 public generateInternalVLD(vnfdPackageDetails: VNFDNODE): void {
282 if (vnfdPackageDetails['internal-vld'] !== undefined) {
283 vnfdPackageDetails['internal-vld'].forEach((internalVLD: InternalVLD) => {
285 id: internalVLD.name, nodeTypeRef: 'intvl', intVLID: internalVLD.id,
286 'internal-connection-point': internalVLD['internal-connection-point'],
287 'ip-profile-ref': internalVLD['ip-profile-ref'], name: internalVLD.name, 'short-name': internalVLD['short-name'],
288 type: internalVLD.type
293 /** Generate and list Internal CP @public */
294 public generateInternalCP(vnfdPackageDetails: VNFDNODE): void {
295 if (vnfdPackageDetails.vdu !== undefined) {
296 vnfdPackageDetails.vdu.forEach((intCP: VDUInternalConnectionPoint) => {
297 if (intCP['internal-connection-point'] !== undefined) {
298 intCP['internal-connection-point'].forEach((internalCP: VDUInternalConnectionPoint) => {
300 id: internalCP.name, nodeTypeRef: 'intcp', name: internalCP.name,
301 'short-name': internalCP['short-name'], type: internalCP.type
308 /** Generate VDU External and Internal CP Links @public */
309 public generateVDUCPLinks(vnfdPackageDetails: VNFDNODE): void {
310 if (vnfdPackageDetails.vdu !== undefined) {
311 vnfdPackageDetails.vdu.forEach((vdu: VDU) => {
312 const vduLink: string = vdu.name;
313 if (vdu.interface !== undefined) {
314 vdu.interface.forEach((interfaceDetails: VNFDInterface) => {
315 if (interfaceDetails['external-connection-point-ref'] !== undefined) {
316 this.links.push({ source: vduLink, target: interfaceDetails['external-connection-point-ref'] });
318 if (interfaceDetails['internal-connection-point-ref'] !== undefined) {
319 this.links.push({ source: vduLink, target: interfaceDetails['internal-connection-point-ref'] });
326 /** Generate Network/VLD/Internal VirtualLink, CP Links @public */
327 public generateIntVLCPLinks(vnfdPackageDetails: VNFDNODE): void {
328 if (vnfdPackageDetails['internal-vld'] !== undefined) {
329 vnfdPackageDetails['internal-vld'].forEach((internalVLD: InternalVLD) => {
330 const vldName: string = internalVLD.name;
331 if (internalVLD['internal-connection-point'] !== undefined) {
332 internalVLD['internal-connection-point'].forEach((intCP: VLDInternalConnectionPoint) => {
333 this.links.push({ source: vldName, target: intCP['id-ref'] });
339 /** VNFD details can be saved on users inputs @public */
340 public saveVNFD(): void {
341 this.vnfdPackageDetails['short-name'] = this.vnfdInfo.shortName;
342 this.vnfdPackageDetails.description = this.vnfdInfo.description;
343 this.vnfdPackageDetails.version = this.vnfdInfo.version;
344 this.vnfdPackageDetails.id = this.vnfdInfo.id;
345 this.vnfdPackageDetails.name = this.vnfdInfo.name;
346 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
347 delete this.vnfdPackageDetails.shortName;
349 /** VDU details can be saved on users inputs @public */
350 public saveVDU(vduID: string): void {
351 this.vnfdPackageDetails.vdu.forEach((ref: VDU) => {
352 if (ref.id === vduID) {
353 ref.count = this.vduInfo.count;
354 ref.description = this.vduInfo.description;
355 ref.image = this.vduInfo.image;
356 ref.id = this.vduInfo.id;
357 ref.name = this.vduInfo.name;
360 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
362 /** IntVL details can be saved on users inputs @public */
363 public saveIntVL(intVLID: string): void {
364 this.vnfdPackageDetails['internal-vld'].forEach((ref: InternalVLD) => {
365 if (ref.id === intVLID) {
366 ref['short-name'] = this.intvlInfo.shortName;
367 ref.name = this.intvlInfo.name;
368 ref.type = this.intvlInfo.type;
369 ref['ip-profile-ref'] = !isNullOrUndefined(this.intvlInfo.ipProfileRef) ? this.intvlInfo.ipProfileRef : '';
370 ref.id = this.intvlInfo.id;
371 delete ref.shortName;
372 delete ref.ipProfileRef;
375 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
377 /** IntVL details can be saved on users inputs @public */
378 public saveCP(cpName: string): void {
379 this.vnfdPackageDetails['connection-point'].forEach((ref: CONNECTIONPOINT) => {
380 if (ref.name === cpName) {
381 if (!isNullOrUndefined(this.cpInfo.type)) {
382 ref.type = this.cpInfo.type;
384 ref.name = this.cpInfo.name;
387 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
389 /** Edit topology @public */
390 public onEdit(): void {
391 this.router.navigate(['/packages/vnf/edit/', this.identifier]).catch();
393 /** Show Info @public */
394 public showInfo(): void {
395 const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
396 modalRef.componentInstance.topologyType = 'Info';
397 modalRef.componentInstance.topologytitle = this.translateService.instant('PAGE.TOPOLOGY.INFO');
398 modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
404 /** Event to freeze the animation @public */
405 public onFreeze(): void {
406 this.classApplied = !this.classApplied;
407 const alreadyFixedIsActive: boolean = d3.select('svg#graphContainer').classed(this.fixedClass);
408 d3.select('svg#graphContainer').classed(this.fixedClass, !alreadyFixedIsActive);
409 if (alreadyFixedIsActive) {
412 this.forceSimulationActive = alreadyFixedIsActive;
413 this.nodes.forEach((d: COMPOSERNODES) => {
414 d.fx = (alreadyFixedIsActive) ? null : d.x;
415 d.fy = (alreadyFixedIsActive) ? null : d.y;
417 if (alreadyFixedIsActive) {
418 this.force.restart();
421 /** Events handles when dragended @public */
422 public toggleSidebar(): void {
423 this.sideBarOpened = !this.sideBarOpened;
424 this.deselectAllNodes();
425 this.showRightSideInfo = 'vnfdInfo';
427 /** Get the default Configuration of containers @private */
428 private getGraphContainerAttr(): GRAPHDETAILS {
441 sourcePaddingYes: 17,
451 /** Node is created and render at D3 region @private */
452 private createNode(nodes: VNFDNODE[]): void {
453 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
454 d3.selectAll('svg#graphContainer > *').remove();
455 d3.select(window).on('keydown', () => { this.keyDown(); });
456 d3.select(window).on('keyup', () => { this.keyUp(); });
457 this.svg = d3.select('#graphContainer').attr('oncontextmenu', 'return false;').attr('width', graphContainerAttr.width)
458 .attr('height', graphContainerAttr.height).on('mousemove', () => { this.mousemove(); });
459 this.force = d3.forceSimulation()
460 .force('link', d3.forceLink().id((d: TickPath) => d.id).distance(graphContainerAttr.distance))
461 .force('charge', d3.forceManyBody().strength(graphContainerAttr.strength))
462 .force('x', d3.forceX(graphContainerAttr.width / graphContainerAttr.forcex))
463 .force('y', d3.forceY(graphContainerAttr.height / graphContainerAttr.forcey))
464 .on('tick', () => { this.tick(); });
465 this.path = this.svg.append('svg:g').selectAll('path');
466 this.dragLine = this.svg.append('svg:path').attr('class', 'link dragline hidden').attr('d', 'M0,0L0,0');
467 this.network = this.svg.append('svg:g').selectAll('network');
468 this.virutualDeploymentUnit = this.svg.append('svg:g').selectAll('virutualDeploymentUnit');
469 this.connectionPoint = this.svg.append('svg:g').selectAll('connectionPoint');
470 this.intConnectionPoint = this.svg.append('svg:g').selectAll('intConnectionPoint');
473 /** Update force layout (called automatically each iteration) @private */
474 private tick(): void {
475 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
476 this.path.attr('d', (d: Tick) => {
477 const deltaX: number = d.target.x - d.source.x; const deltaY: number = d.target.y - d.source.y;
478 const dist: number = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
479 const normX: number = deltaX / dist; const normY: number = deltaY / dist;
480 const sourcePadding: number = d.left ? graphContainerAttr.sourcePaddingYes : graphContainerAttr.sourcePaddingNo;
481 const targetPadding: number = d.right ? graphContainerAttr.targetPaddingYes : graphContainerAttr.targetPaddingNo;
482 const sourceX: number = d.source.x + (sourcePadding * normX); const sourceY: number = d.source.y + (sourcePadding * normY);
483 const targetX: number = d.target.x - (targetPadding * normX); const targetY: number = d.target.y - (targetPadding * normY);
484 return `M${sourceX},${sourceY}L${targetX},${targetY}`;
485 }).on('dblclick', (d: Tick) => { this.getDeleteLinkConfirmation(d); });
486 this.network.attr('transform', (d: TickPath) => `translate(${d.x},${d.y})`);
487 this.virutualDeploymentUnit.attr('transform', (d: TickPath) => `translate(${d.x},${d.y})`);
488 this.connectionPoint.attr('transform', (d: TickPath) => `translate(${d.x},${d.y})`);
489 this.intConnectionPoint.attr('transform', (d: TickPath) => `translate(${d.x},${d.y})`);
491 /** Update graph (called when needed) @private */
492 private restart(nodes: VNFDNODE[]): void {
493 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
494 this.path = this.path.data(this.links);
495 const cpNodes: {}[] = []; const vduNodes: {}[] = []; const vlNodes: {}[] = []; const intcpNodes: {}[] = []; //Nodes are known by id
496 nodes.forEach((nodeList: VNFDNODE) => {
497 if (nodeList.nodeTypeRef === 'cp') { cpNodes.push(nodeList); }
498 else if (nodeList.nodeTypeRef === 'vdu') { vduNodes.push(nodeList); }
499 else if (nodeList.nodeTypeRef === 'intvl') { vlNodes.push(nodeList); }
500 else if (nodeList.nodeTypeRef === 'intcp') { intcpNodes.push(nodeList); }
502 this.network = this.network.data(vlNodes, (d: { id: number }) => d.id);
503 this.virutualDeploymentUnit = this.virutualDeploymentUnit.data(vduNodes, (d: { id: number }) => d.id);
504 this.connectionPoint = this.connectionPoint.data(cpNodes, (d: { id: number }) => d.id);
505 this.intConnectionPoint = this.intConnectionPoint.data(intcpNodes, (d: { id: number }) => d.id);
506 this.resetAndCreateNodes();
507 this.force.nodes(nodes).force('link').links(this.links); //Set the graph in motion
508 this.force.alphaTarget(graphContainerAttr.alphaTarget).restart();
510 /** Rest and create nodes @private */
511 private resetAndCreateNodes(): void {
512 this.path.exit().remove();
513 this.network.exit().remove();
514 this.virutualDeploymentUnit.exit().remove();
515 this.connectionPoint.exit().remove();
516 this.intConnectionPoint.exit().remove();
519 this.getgVirutualDeploymentUnit();
520 this.getgConnectionPoint();
521 this.getgIntConnectionPoint();
522 this.network = this.gNetwork.merge(this.network);
523 this.virutualDeploymentUnit = this.gVirutualDeploymentUnit.merge(this.virutualDeploymentUnit);
524 this.connectionPoint = this.gConnectionPoint.merge(this.connectionPoint);
525 this.intConnectionPoint = this.gIntConnectionPoint.merge(this.intConnectionPoint);
526 this.path.merge(this.path);
528 /** Setting the Path @private */
529 private getPathNodes(): void {
530 this.path = this.path.enter().append('svg:path').attr('class', 'link');
532 /** Settings all the network attributes of nodes @private */
533 private getgNetwork(): void {
534 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
535 this.gNetwork = this.network.enter().append('svg:g');
536 this.gNetwork.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
537 this.gNetwork.append('svg:image')
539 .attr('x', graphContainerAttr.imageX)
540 .attr('y', graphContainerAttr.imageY)
541 .attr('id', (d: VNFDNODE) => { return d.id; })
542 .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
543 .attr('xlink:href', 'assets/images/INTVL.svg')
544 .on('mousedown', (d: VNFDNODE) => { this.mouseDown(d); })
545 .on('mouseup', (d: VNFDNODE) => { this.mouseUp(d); })
546 .on('click', (d: VNFDNODE) => { this.singleClick(this.network, d); this.onNodeClickToggleSidebar(); })
547 .on('dblclick', (d: VNFDNODE) => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); });
548 this.gNetwork.append('svg:text')
549 .attr('class', 'node_text')
550 .attr('y', graphContainerAttr.textY)
551 .text((d: { id: number }) => d.id);
553 /** Settings all the connection point attributes of nodes @private */
554 private getgVirutualDeploymentUnit(): void {
555 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
556 this.gVirutualDeploymentUnit = this.virutualDeploymentUnit.enter().append('svg:g');
557 this.gVirutualDeploymentUnit.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
558 this.gVirutualDeploymentUnit.append('svg:image')
560 .attr('x', graphContainerAttr.imageX)
561 .attr('y', graphContainerAttr.imageY)
562 .attr('id', (d: VNFDNODE) => { return d.id; })
563 .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
564 .attr('xlink:href', 'assets/images/VDU.svg')
565 .on('mousedown', (d: VNFDNODE) => { this.mouseDown(d); })
566 .on('mouseup', (d: VNFDNODE) => { this.mouseUp(d); })
567 .on('click', (d: VNFDNODE) => { this.singleClick(this.virutualDeploymentUnit, d); this.onNodeClickToggleSidebar(); })
568 .on('dblclick', (d: VNFDNODE) => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); });
569 this.gVirutualDeploymentUnit.append('svg:text')
570 .attr('class', 'node_text')
571 .attr('y', graphContainerAttr.textY)
572 .text((d: { id: string }) => d.id);
574 /** Settings all the connection point attributes of nodes @private */
575 private getgConnectionPoint(): void {
576 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
577 this.gConnectionPoint = this.connectionPoint.enter().append('svg:g');
578 this.gVirutualDeploymentUnit.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
579 this.gConnectionPoint.append('svg:image')
581 .attr('x', graphContainerAttr.imageX)
582 .attr('y', graphContainerAttr.imageY)
583 .attr('id', (d: VNFDNODE) => { return d.id; })
584 .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
585 .attr('xlink:href', 'assets/images/CP-VNF.svg')
586 .on('mousedown', (d: VNFDNODE) => { this.mouseDown(d); })
587 .on('mouseup', (d: VNFDNODE) => { this.mouseUp(d); })
588 .on('click', (d: VNFDNODE) => { this.singleClick(this.connectionPoint, d); this.onNodeClickToggleSidebar(); })
589 .on('dblclick', (d: VNFDNODE) => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); });
590 this.gConnectionPoint.append('svg:text')
591 .attr('class', 'node_text')
592 .attr('y', graphContainerAttr.textY)
593 .text((d: { id: string }) => d.id);
595 /** Settings all the internal connection point attributes of nodes @private */
596 private getgIntConnectionPoint(): void {
597 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
598 this.gIntConnectionPoint = this.intConnectionPoint.enter().append('svg:g');
599 this.gIntConnectionPoint.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
600 this.gIntConnectionPoint.append('svg:image')
602 .attr('x', graphContainerAttr.imageX)
603 .attr('y', graphContainerAttr.imageY)
604 .attr('id', (d: VNFDNODE) => { return d.id; })
605 .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
606 .attr('xlink:href', 'assets/images/INTCP.svg')
607 .on('mousedown', (d: VNFDNODE) => { this.mouseDown(d); })
608 .on('mouseup', (d: VNFDNODE) => { this.mouseUp(d); })
609 .on('click', (d: VNFDNODE) => { this.singleClick(this.intConnectionPoint, d); this.onNodeClickToggleSidebar(); })
610 .on('dblclick', (d: VNFDNODE) => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); });
611 this.gIntConnectionPoint.append('svg:text')
612 .attr('class', 'node_text')
613 .attr('y', graphContainerAttr.textY)
614 .text((d: { id: string }) => d.id);
616 /** Drop VDU Composer Data @private */
617 private vduDropCompose(): void {
618 const randomID: string = this.sharedService.randomString();
619 const vduNode: VNFDNODE[] = [{
620 nodeTypeRef: 'vdu', id: 'vdu_' + randomID, count: 1, description: '', name: 'vdu_' + randomID, image: 'ubuntu',
621 interface: [], 'internal-connection-point': [], 'monitoring-param': [], 'vm-flavor': {}
623 const nodeCopy: VNFDNODE[] = this.nodes;
624 Array.prototype.push.apply(vduNode, nodeCopy);
625 this.nodes = vduNode;
626 if (this.vnfdPackageDetails.vdu === undefined) { this.vnfdPackageDetails.vdu = []; }
627 this.vnfdPackageDetails.vdu.push({
628 id: 'vdu_' + randomID, count: 1, description: '', name: 'vdu_' + randomID, image: 'ubuntu',
629 interface: [], 'internal-connection-point': [], 'monitoring-param': [], 'vm-flavor': {}
631 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
633 /** Drop CP Composer Data @private */
634 private cpDropCompose(): void {
635 const randomID: string = this.sharedService.randomString();
636 const cpNode: VNFDNODE[] = [{ nodeTypeRef: 'cp', id: 'cp_' + randomID, name: 'cp_' + randomID }];
637 const nodeCopy: VNFDNODE[] = this.nodes;
638 Array.prototype.push.apply(cpNode, nodeCopy);
640 if (this.vnfdPackageDetails['connection-point'] === undefined) {
641 this.vnfdPackageDetails['connection-point'] = [];
643 this.vnfdPackageDetails['connection-point'].push({
644 id: 'cp_' + randomID, name: 'cp_' + randomID, type: 'VPORT'
646 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
648 /** Drop IntVL Composer Data @private */
649 private intvlDropCompose(): void {
650 const randomID: string = this.sharedService.randomString();
651 const intvlNode: VNFDNODE[] = [{
652 nodeTypeRef: 'intvl', id: 'vnf_vl_' + randomID, name: 'vnf_vl_' + randomID, 'short-name': 'vnf_vl_' + randomID, 'ip-profile-ref': '',
655 const nodeCopy: VNFDNODE[] = this.nodes;
656 Array.prototype.push.apply(intvlNode, nodeCopy);
657 this.nodes = intvlNode;
658 if (this.vnfdPackageDetails['internal-vld'] === undefined) { this.vnfdPackageDetails['internal-vld'] = []; }
659 this.vnfdPackageDetails['internal-vld'].push({
660 id: 'vnf_vl_' + randomID, name: 'vnf_vl_' + randomID, 'short-name': 'vnf_vl_' + randomID,
661 'ip-profile-ref': '', type: 'ELAN', 'internal-connection-point': []
663 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
665 /** Add the Add Nodes Data @private */
666 private addNodes(apiURL: string, identifier: string, data: VNFDNODE): void {
667 this.isLoadingResults = true;
668 const apiURLHeader: APIURLHEADER = {
669 url: apiURL + '/' + identifier + '/package_content',
670 httpOptions: { headers: this.headers }
672 const vnfData: {} = {};
673 vnfData['vnfd:vnfd-catalog'] = {};
674 vnfData['vnfd:vnfd-catalog'].vnfd = [];
675 vnfData['vnfd:vnfd-catalog'].vnfd.push(data);
676 const descriptorInfo: string = jsyaml.dump(vnfData, { sortKeys: true });
677 this.sharedService.targzFile({ packageType: 'vnfd', id: this.identifier, descriptor: descriptorInfo })
678 .then((content: ArrayBuffer): void => {
679 this.restService.putResource(apiURLHeader, content).subscribe((res: {}) => {
681 this.notifierService.notify('success', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.UPDATEDSUCCESSFULLY'));
682 this.isLoadingResults = false;
683 }, (error: ERRORDATA) => {
685 this.restService.handleError(error, 'put');
686 this.isLoadingResults = false;
688 }).catch((): void => {
689 this.notifierService.notify('error', this.translateService.instant('ERROR'));
690 this.isLoadingResults = false;
693 /** Events handles when mousedown click it will capture the selected node data @private */
694 private mouseDown(d: VNFDNODE): void {
695 event.preventDefault();
696 if (d3.event.ctrlKey) { return; }
697 if (d3.event.shiftKey) {
698 this.mousedownNode = d;
699 this.currentSelectedNode = (this.mousedownNode === this.currentSelectedNode) ? null : this.mousedownNode;
700 this.dragLine.classed('hidden', false)
701 .attr('d', `M${this.mousedownNode.x},${this.mousedownNode.y}L${this.mousedownNode.x},${this.mousedownNode.y}`);
704 /** Event handles when mouseup event occures @private */
705 private mouseUp(d: VNFDNODE): void {
706 if (!this.mousedownNode) { return; }
707 this.dragLine.classed('hidden', true);
708 this.mouseupNode = d;
709 if (this.mousedownNode.nodeTypeRef === 'vdu') {
710 this.vduMouseDownNode();
711 } else if (this.mousedownNode.nodeTypeRef === 'cp') {
712 this.cpMouseDownNode();
713 } else if (this.mousedownNode.nodeTypeRef === 'intvl') {
714 this.intVLMouseDownNode();
715 } else if (this.mousedownNode.nodeTypeRef === 'intcp') {
716 this.intCPMouseDownNode();
718 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.INVALIDSELECTION'));
721 this.resetMouseActions();
722 this.currentSelectedNode = null;
724 /** Establish a connection point between vdu and other nodes @private */
725 private vduMouseDownNode(): void {
726 if (this.mousedownNode.nodeTypeRef === 'vdu' && this.mouseupNode.nodeTypeRef === 'cp') {
727 this.vduCPConnection(this.mousedownNode.id, this.mouseupNode.id);
728 } else if (this.mousedownNode.nodeTypeRef === 'vdu' && this.mouseupNode.nodeTypeRef === 'intcp') {
729 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVDUANDINTCP'));
731 } else if (this.mousedownNode.nodeTypeRef === 'vdu' && this.mouseupNode.nodeTypeRef === 'vdu') {
732 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVDUANDVDU'));
734 } else if (this.mousedownNode.nodeTypeRef === 'vdu' && this.mouseupNode.nodeTypeRef === 'intvl') {
735 this.vduIntvlConnection(this.mousedownNode.id, this.mouseupNode.id);
739 /** Establish a connection point between cp and other nodes @private */
740 private cpMouseDownNode(): void {
741 if (this.mousedownNode.nodeTypeRef === 'cp' && this.mouseupNode.nodeTypeRef === 'vdu') {
742 this.vduCPConnection(this.mouseupNode.id, this.mousedownNode.id);
743 } else if (this.mousedownNode.nodeTypeRef === 'cp' && this.mouseupNode.nodeTypeRef === 'intvl') {
744 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKCPANDVNFVL'));
746 } else if (this.mousedownNode.nodeTypeRef === 'cp' && this.mouseupNode.nodeTypeRef === 'intcp') {
747 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKCPANDINTCP'));
749 } else if (this.mousedownNode.nodeTypeRef === 'cp' && this.mouseupNode.nodeTypeRef === 'cp') {
750 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKCPANDCP'));
755 /** Establish a connection piont between intvl and other nodes @private */
756 private intVLMouseDownNode(): void {
757 if (this.mousedownNode.nodeTypeRef === 'intvl' && this.mouseupNode.nodeTypeRef === 'cp') {
758 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVNFVLANDCP'));
760 } else if (this.mousedownNode.nodeTypeRef === 'intvl' && this.mouseupNode.nodeTypeRef === 'vdu') {
761 this.vduIntvlConnection(this.mouseupNode.id, this.mousedownNode.id);
762 } else if (this.mousedownNode.nodeTypeRef === 'intvl' && this.mouseupNode.nodeTypeRef === 'intvl') {
763 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVNFVLANDVNFVL'));
765 } else if (this.mousedownNode.nodeTypeRef === 'intvl' && this.mouseupNode.nodeTypeRef === 'intcp') {
766 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVNFVLANDONTCP'));
771 /** Establish a connection point between intcp and other nodes @private */
772 private intCPMouseDownNode(): void {
773 if (this.mousedownNode.nodeTypeRef === 'intcp' && this.mouseupNode.nodeTypeRef === 'vdu') {
774 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKINTCPANDVDU'));
776 } else if (this.mousedownNode.nodeTypeRef === 'intcp' && this.mouseupNode.nodeTypeRef === 'cp') {
777 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKINTCPANDCP'));
779 } else if (this.mousedownNode.nodeTypeRef === 'intcp' && this.mouseupNode.nodeTypeRef === 'intvl') {
780 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKINTCPANDVNFVL'));
782 } else if (this.mousedownNode.nodeTypeRef === 'intcp' && this.mouseupNode.nodeTypeRef === 'intcp') {
783 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKINTCPANDINTCP'));
788 /** Establish a connection between VDU & CP vice versa @private */
789 private vduCPConnection(nodeA: string, nodeB: string): void {
790 this.vnfdPackageDetails.vdu.forEach((vduDetails: VDU) => {
791 if (vduDetails.id === nodeA) {
792 if (vduDetails.interface === undefined) { vduDetails.interface = []; }
793 vduDetails.interface.push({
794 'external-connection-point-ref': nodeB, 'mgmt-interface': true,
795 name: 'eth_' + this.sharedService.randomString(),
796 'virtual-interface': { type: 'VIRTIO' },
799 if (vduDetails['internal-connection-point'] === undefined) {
800 vduDetails['internal-connection-point'] = [];
802 if (vduDetails['monitoring-param'] === undefined) {
803 vduDetails['monitoring-param'] = [];
805 if (vduDetails['vm-flavor'] === undefined) {
806 vduDetails['vm-flavor'] = {};
810 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
814 /** Establish a connection between vdu & intvl and vice versa @private */
815 private vduIntvlConnection(nodeA: string, nodeB: string): void {
816 const setIntCP: string = 'intcp_' + this.sharedService.randomString();
817 this.vnfdPackageDetails['internal-vld'].forEach((vldInternal: InternalVLD) => {
818 if (vldInternal.id === nodeB) {
819 if (vldInternal['internal-connection-point'] === undefined) { vldInternal['internal-connection-point'] = []; }
820 vldInternal['internal-connection-point'].push({ 'id-ref': setIntCP });
823 this.vnfdPackageDetails.vdu.forEach((vduDetails: VDU) => {
824 if (vduDetails.id === nodeA) {
825 if (vduDetails.interface === undefined) {
826 vduDetails.interface = [];
828 vduDetails.interface.push({
829 'internal-connection-point-ref': setIntCP, name: 'int_' + setIntCP, type: 'INTERNAL', 'virtual-interface': { type: 'VIRTIO' }
831 if (vduDetails['internal-connection-point'] === undefined) {
832 vduDetails['internal-connection-point'] = [];
834 vduDetails['internal-connection-point'].push({
835 id: setIntCP, name: setIntCP, 'short-name': setIntCP, type: 'VPORT'
839 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
843 /** Events handles when mousemove it will capture the selected node data @private */
844 private mousemove(): void {
845 if (!this.mousedownNode) { return; }
846 this.dragLine.attr('d',
847 `M${this.mousedownNode.x},${this.mousedownNode.y}L${d3.mouse(d3.event.currentTarget)[0]},${d3.mouse(d3.event.currentTarget)[1]}`);
849 /** reset Mouse varaibles @private */
850 private resetMouseActions(): void {
851 this.mousedownNode = null;
852 this.mouseupNode = null;
854 /** Key press event @private */
855 private keyDown(): void {
856 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
857 if (this.lastKeyDown !== -1) { return; }
858 this.lastKeyDown = d3.event.keyCode;
859 if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
860 this.gNetwork.call(d3.drag().on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended));
861 this.gVirutualDeploymentUnit.call(d3.drag().on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended));
862 this.gConnectionPoint.call(d3.drag().on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended));
863 this.gIntConnectionPoint.call(d3.drag().on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended));
864 this.svg.classed('ctrl', true);
867 /** Key realse event @private */
868 private keyUp(): void {
869 const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
870 this.lastKeyDown = -1;
871 if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
872 this.gNetwork.on('.drag', null);
873 this.gVirutualDeploymentUnit.on('.drag', null);
874 this.gConnectionPoint.on('.drag', null);
875 this.gIntConnectionPoint.on('.drag', null);
876 this.svg.classed('ctrl', false);
879 /** Mosue Drag Line false if it is not satisfied @private */
880 private deselectPath(): void {
881 this.dragLine.classed('hidden', true).attr('d', 'M0,0L0,0');
883 /** Events handles when Shift Click to perform create cp @private */
884 // tslint:disable-next-line: no-any
885 private singleClick(nodeSelected: any, d: VNFDNODE): void {
886 this.selectedNode(nodeSelected, d);
888 /** Get confirmation Before Deleting the Node in Topology @private */
889 private getDeleteNodeConfirmation(d: VNFDNODE): void {
890 const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
891 modalRef.componentInstance.topologyType = 'Delete';
892 modalRef.componentInstance.topologyname = d.name;
893 if (d.nodeTypeRef === 'vdu') {
894 modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.VDU';
895 } else if (d.nodeTypeRef === 'intvl') {
896 modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.INTVL';
897 } else if (d.nodeTypeRef === 'cp') {
898 modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.CONNECTIONPOINT';
899 } else if (d.nodeTypeRef === 'intcp') {
900 modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.INTCP';
902 modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
908 /** Delete nodes @private */
909 private deleteNode(d: VNFDNODE): void {
910 const deletedNode: VNFDNODE = d;
911 this.nodes.forEach((node: VNFDNODE) => {
912 if (node.id === d.id) {
913 if (deletedNode.nodeTypeRef === 'cp') {
914 if (this.vnfdPackageDetails.vdu !== undefined) {
915 this.vnfdPackageDetails.vdu.forEach((vduDetails: VDU) => {
916 if (vduDetails.interface !== undefined) {
917 const interfacePos: number = vduDetails.interface.map((e: VNFDInterface) => { return e['external-connection-point-ref']; })
919 if (interfacePos >= 0) {
920 vduDetails.interface.splice(interfacePos, 1);
925 const cpPos: number = this.vnfdPackageDetails['connection-point'].map((e: CONNECTIONPOINT) => { return e.name; })
928 this.vnfdPackageDetails['connection-point'].splice(cpPos, 1);
930 } else if (deletedNode.nodeTypeRef === 'intcp') {
931 this.vnfdPackageDetails.vdu.forEach((vduDetails: VDU) => {
933 const interfacePos: number = vduDetails.interface.map((e: VNFDInterface) => { return e['internal-connection-point-ref']; })
935 if (interfacePos >= 0) {
936 vduDetails.interface.splice(interfacePos, 1);
938 // Delete Internal CP
939 const interCPPos: number = vduDetails['internal-connection-point']
940 .map((e: VDUInternalConnectionPoint) => { return e.id; })
942 if (interCPPos >= 0) {
943 vduDetails['internal-connection-point'].splice(interCPPos, 1);
946 if (this.vnfdPackageDetails['internal-vld'] !== undefined && this.vnfdPackageDetails['internal-vld'].length > 0) {
947 this.vnfdPackageDetails['internal-vld'].forEach((internalVLD: InternalVLD) => {
948 const interfacePos: number = internalVLD['internal-connection-point']
949 .map((e: VLDInternalConnectionPoint) => { return e['id-ref']; }).indexOf(d.id);
950 if (interfacePos >= 0) {
951 internalVLD['internal-connection-point'].splice(interfacePos, 1);
955 } else if (deletedNode.nodeTypeRef === 'intvl') {
956 const intvlPos: number = this.vnfdPackageDetails['internal-vld']
957 .map((e: InternalVLD) => { return e.name; }).indexOf(d.id);
959 this.vnfdPackageDetails['internal-vld'].splice(intvlPos, 1);
961 } else if (deletedNode.nodeTypeRef === 'vdu') {
962 const internalCPList: string[] = [];
963 if (deletedNode.interface !== undefined && deletedNode.interface.length > 0) {
964 deletedNode.interface.forEach((interfaceNode: InternalVLD) => {
965 if (interfaceNode['internal-connection-point-ref'] !== undefined) {
966 internalCPList.push(interfaceNode['internal-connection-point-ref']);
970 internalCPList.forEach((list: string) => {
971 if (this.vnfdPackageDetails['internal-vld'] !== undefined && this.vnfdPackageDetails['internal-vld'].length > 0) {
972 this.vnfdPackageDetails['internal-vld'].forEach((internalVLD: InternalVLD) => {
973 const interfacePos: number = internalVLD['internal-connection-point']
974 .map((e: VLDInternalConnectionPoint) => { return e['id-ref']; }).indexOf(list);
975 if (interfacePos >= 0) {
976 internalVLD['internal-connection-point'].splice(interfacePos, 1);
981 const vduPos: number = this.vnfdPackageDetails.vdu.map((e: VDU) => { return e.id; }).indexOf(d.id);
983 this.vnfdPackageDetails.vdu.splice(vduPos, 1);
986 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.INVALIDSELECTION'));
988 this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails);
992 /** Get confirmation before deleting the ink in Topology @private */
993 private getDeleteLinkConfirmation(d: Tick): void {
994 this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.YOUCANNOTDELETELINK'));
996 /** Selected nodes @private */
997 // tslint:disable-next-line: no-any
998 private selectedNode(nodeSeleced: any, d: VNFDNODE): void {
999 const alreadyIsActive: boolean = nodeSeleced.select('#' + d.id).classed(this.activeNode);
1000 this.deselectAllNodes();
1001 nodeSeleced.select('#' + d.id).classed(this.activeNode, !alreadyIsActive);
1002 if (d.nodeTypeRef === 'vdu' && !alreadyIsActive) {
1003 this.vnfdPackageDetails.vdu.forEach((res: VDU) => {
1004 if (res.name === d.id) {
1005 this.showRightSideInfo = 'vduInfo';
1009 } else if (d.nodeTypeRef === 'intvl' && !alreadyIsActive) {
1010 this.vnfdPackageDetails['internal-vld'].forEach((res: InternalVLD) => {
1011 if (res.name === d.id) {
1012 this.showRightSideInfo = 'intvlInfo';
1013 this.intvlInfo = res;
1014 this.intvlInfo.shortName = res['short-name'];
1015 this.intvlInfo.ipProfileRef = res['ip-profile-ref'];
1018 } else if (d.nodeTypeRef === 'cp' && !alreadyIsActive) {
1019 this.vnfdPackageDetails['connection-point'].forEach((res: CONNECTIONPOINT) => {
1020 if (res.name === d.id) {
1021 this.showRightSideInfo = 'cpInfo';
1026 else if (d.nodeTypeRef === 'intcp' && !alreadyIsActive) {
1028 this.showRightSideInfo = 'intcpInfo';
1029 this.intcpInfo.shortName = d['short-name'];
1031 this.showRightSideInfo = 'vnfdInfo';
1034 /** De-select all the selected nodes @private */
1035 private deselectAllNodes(): void {
1036 this.network.select('image').classed(this.activeNode, false);
1037 this.virutualDeploymentUnit.select('image').classed(this.activeNode, false);
1038 this.connectionPoint.select('image').classed(this.activeNode, false);
1039 this.intConnectionPoint.select('image').classed(this.activeNode, false);
1041 /** Events handles when dragstarted @private */
1042 private dragstarted(d: COMPOSERNODES): void {
1046 /** Events handles when dragged @private */
1047 private dragged(d: COMPOSERNODES): void {
1048 d.fx = d.x = d3.event.x;
1049 d.fy = d.y = d3.event.y;
1051 /** Events handles when dragended @private */
1052 private dragended(d: COMPOSERNODES): void {
1053 if (this.forceSimulationActive) {
1059 this.forceSimulationActive = false;
1062 /** Events handles when node double click @private */
1063 private onNodedblClickToggleSidebar(): void {
1064 this.sideBarOpened = false;
1066 /** Events handles when node single click @private */
1067 private onNodeClickToggleSidebar(): void {
1068 this.sideBarOpened = true;