Initial Commit - NG UI
[osm/NG-UI.git] / src / app / packages / ns-packages / ns-composer / NSComposerComponent.ts
1 /*
2  Copyright 2020 TATA ELXSI
3
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
7
8   http://www.apache.org/licenses/LICENSE-2.0
9
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.
15
16  Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
17 */
18 /**
19  * @file NS Compose Component
20  */
21 // tslint:disable: no-increment-decrement
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, CONSTANTNUMBER, ERRORDATA, MODALCLOSERESPONSEDATA, MODALCLOSERESPONSEWITHCP } 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 { COMPOSERNODES, CONSTITUENTVNFD, GRAPHDETAILS, NSDDetails, Tick, TickPath, VLD, VNFDCONNECTIONPOINTREF } from 'NSDModel';
36 import { RestService } from 'RestService';
37 import { SharedService } from 'SharedService';
38 import { isNullOrUndefined } from 'util';
39 import { VNFData, VNFDDetails } from 'VNFDModel';
40
41 /**
42  * Creating component
43  * @Component takes NSComposerComponent.html as template url
44  */
45 @Component({
46   selector: 'app-ns-composer',
47   templateUrl: './NSComposerComponent.html',
48   styleUrls: ['./NSComposerComponent.scss'],
49   encapsulation: ViewEncapsulation.None
50 })
51 /** Exporting a class @exports NSComposerComponent */
52 export class NSComposerComponent {
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   /** Contains VNFD Informations @public */
60   public vnfdPackageDetails: VNFData = { identifier: '', shortName: '', vendor: '', description: '', version: '', id: '', name: '' };
61   /** Contains VL Details @public */
62   public vlDetails: VLD = {
63     name: '',
64     'mgmt-network': true,
65     'vim-network-name': '',
66     type: '',
67     id: ''
68   };
69   /** Contains the information of the type of modification @public  */
70   public putType: string;
71   /** Conatins mousedown action @public */
72   public mousedownNode: COMPOSERNODES = null;
73   /** Conatins mouseup action @public */
74   public mouseupNode: COMPOSERNODES = null;
75   /** Conatins mousedownLink action @public */
76   public mousedownLink: COMPOSERNODES = null;
77   /** Conatins current Selection node action @public */
78   public currentSelectedNode: COMPOSERNODES = null;
79   /** Conatins current Selection node action @public */
80   public currentSelectedLink: COMPOSERNODES = null;
81   /** Need to show the NSD Details @public */
82   public isShowNSDDetails: boolean = true;
83   /** Contains the node information of VL @public */
84   public vlNodes: {}[] = [];
85   /** Need to show the VL Details @public */
86   public isShowVLDetails: boolean = false;
87   /** Contains the node information of VNF @public */
88   public vnfNodes: {}[] = [];
89   /** contains the VNF Details @public */
90   public vnfData: CONSTITUENTVNFD;
91   /** Need to show the VNF Details @public */
92   public isShowVNFDetails: boolean = false;
93   /** Contains the node information of CP @public */
94   public cpNodes: {}[] = [];
95   /** Need to show the CP Details */
96   public cpData: VNFDCONNECTIONPOINTREF;
97   /** Need to show the VNF Details @public */
98   public isShowCPDetails: boolean = false;
99   /** random number count @public */
100   public randomNumberLength: number;
101   /** Contains the vnfd information @public */
102   public vnfList: VNFDDetails[] = [];
103   /** Add the activeclass for the selected @public */
104   public activeClass: string = 'active';
105   /** Add the fixed class for the freeze @public */
106   public fixedClass: string = 'fixed';
107   /** Check the loading results @public */
108   public isLoadingResults: boolean = true;
109   /** Give the message for the loading @public */
110   public message: string = 'PLEASEWAIT';
111   /** Get VNF selected node @public */
112   public getVNFSelectedData: VNFDDetails[];
113   /** Assign the forcesimulation active @public */
114   public forceSimulationActive: boolean = false;
115   /** Assign pinned class for the button when freezed @public */
116   public classApplied: boolean = false;
117   /** Contains sidebar open status @public */
118   public sideBarOpened: boolean = false;
119   /** Contains SVG attributes @private */
120   // tslint:disable-next-line:no-any
121   private svg: any;
122   /** Contains the Drag line */
123   // tslint:disable-next-line: no-any
124   private dragLine: any;
125   /** Contains VL node @private */
126   // tslint:disable-next-line:no-any
127   private vlNode: any;
128   /** Contains VNFD node @private */
129   // tslint:disable-next-line:no-any
130   private vnfdnode: any;
131   /** Contains CP node @private */
132   // tslint:disable-next-line:no-any
133   private cpnode: any;
134   /** Rendered nodes represent VL @private */
135   // tslint:disable-next-line:no-any
136   private gvlNode: any;
137   /** Rendered nodes represent VL @private */
138   // tslint:disable-next-line:no-any
139   private gvnfdNode: any;
140   /** Rendered nodes represent VL @private */
141   // tslint:disable-next-line:no-any
142   private gcpNode: any;
143   /** Contains forced node animations @private */
144   // tslint:disable-next-line:no-any
145   private force: any;
146   /** Contains all the selected node @private */
147   private selectedNode: COMPOSERNODES[] = [];
148   /** variables used for CP @private */
149   private iConnectionPointRef: number = 0;
150   /** Contains the connected point @private */
151   private connectionPoint: string;
152   /** Contains all the NSD information @private */
153   private nsd: string;
154   /** Contains all the VNFD information @private */
155   private vnfd: string;
156   /** Contains id of the node @private */
157   private identifier: string;
158   /** Variables used for cp @private */
159   private jConnectionPointRef: number = 0;
160   /** Contains copy of NSD information @private */
161   private nsdCopy: string;
162   /** Contains the VNFD copy @private */
163   private vnfdCopy: string;
164   /** Contains name of the node @private */
165   private name: string;
166   /** Contains member vnf index value of the node @private */
167   private memberVnfIndexValue: number = 0;
168   /** Contains path information of the node */
169   // tslint:disable-next-line:no-any
170   private path: any;
171   /** Contains the node information @private */
172   private nodes: COMPOSERNODES[] = [];
173   /** Contains the link information of nodes @private */
174   private links: {}[] = [];
175   /** Contains the NS information @private */
176   private nsData: NSDDetails;
177   /** Instance of the rest service @private */
178   private restService: RestService;
179   /** Service holds the router information @private */
180   private router: Router;
181   /** Holds teh instance of AuthService class of type AuthService @private */
182   private activatedRoute: ActivatedRoute;
183   /** Notifier service to popup notification @private */
184   private notifierService: NotifierService;
185   /** Controls the header form @private */
186   private headers: HttpHeaders;
187   /** Contains tranlsate instance @private */
188   private translateService: TranslateService;
189   /** Contains lastkeypressed instance @private */
190   private lastKeyDown: number = -1;
191   /** Instance of the modal service @private */
192   private modalService: NgbModal;
193   /** Setting the Value of connection point refrence of the CP @private */
194   private setVnfdConnectionPointRef: string;
195   /** Setting the Value of VL name for confirmation @private */
196   private vlName: string;
197   /** Setting the Value of VNFD name for confirmation @private */
198   private setVnfdName: string;
199   /** Contains all methods related to shared @private */
200   private sharedService: SharedService;
201   /** Contains selected node VLD objects @private */
202   private selectedVLDResult: VLD;
203
204   constructor(injector: Injector) {
205     this.injector = injector;
206     this.restService = this.injector.get(RestService);
207     this.dataService = this.injector.get(DataService);
208     this.router = this.injector.get(Router);
209     this.activatedRoute = this.injector.get(ActivatedRoute);
210     this.notifierService = this.injector.get(NotifierService);
211     this.translateService = this.injector.get(TranslateService);
212     this.modalService = this.injector.get(NgbModal);
213     this.sharedService = this.injector.get(SharedService);
214   }
215   /** Lifecyle Hooks the trigger before component is instantiate @public */
216   public ngOnInit(): void {
217     // tslint:disable-next-line:no-backbone-get-set-outside-model
218     this.identifier = this.activatedRoute.snapshot.paramMap.get('id');
219     this.generateData();
220     this.headers = new HttpHeaders({
221       'Content-Type': 'application/zip',
222       Accept: 'application/json',
223       'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
224     });
225   }
226   /** Events handles at drag on D3 region @public */
227   // tslint:disable-next-line:no-any
228   public drag(ev: any): void {
229     if (ev.target.id === 'vl') {
230       ev.dataTransfer.setData('text', ev.target.id);
231     } else {
232       ev.dataTransfer.setData('text', ev.target.attributes['data-id'].value);
233     }
234   }
235   /** On clicking redirect to NS edit page @public */
236   public onEdit(): void {
237     this.router.navigate(['/packages/ns/edit/', this.identifier]).catch(() => {
238       // Catch Navigation Error
239     });
240   }
241   /** Events handles drop at D3 region @public */
242   public drop(ev: DragEvent): void {
243     event.preventDefault();
244     this.name = ev.dataTransfer.getData('text');
245     if (this.name === 'vl') {
246       this.svg.selectAll('*').remove();
247       this.vldropComposer();
248     } else {
249       this.svg.selectAll('*').remove();
250       this.vnfd = ev.dataTransfer.getData('text');
251       this.vnfdropComposer();
252     }
253   }
254   /** Drop VL Composer Data @public */
255   public vldropComposer(): void {
256     this.randomNumberLength = CONSTANTNUMBER.randomNumber;
257     const generateId: string = 'ns_vl_' + this.randomString(
258       this.randomNumberLength,
259       '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
260     );
261     if (this.nsData.vld !== undefined) {
262       this.nsData.vld.push({
263         'vim-network-name': 'PUBLIC',
264         name: generateId,
265         'mgmt-network': true,
266         type: 'ELAN',
267         id: generateId
268       });
269     } else {
270       Object.assign(this.nsData, {
271         vld: [{
272           'vim-network-name': 'PUBLIC',
273           name: generateId,
274           'mgmt-network': true,
275           type: 'ELAN',
276           id: generateId
277         }]
278       });
279     }
280     this.putType = 'nsdadd';
281     this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
282   }
283   /** Drop VNFD Composer Data @public */
284   public vnfdropComposer(): void {
285     if (this.nsData['constituent-vnfd'] !== undefined) {
286       this.nsData['constituent-vnfd'].push({
287         'vnfd-id-ref': this.vnfd,
288         'member-vnf-index': ++this.memberVnfIndexValue
289       });
290     } else {
291       Object.assign(this.nsData, {
292         'constituent-vnfd': [{
293           'vnfd-id-ref': this.vnfd,
294           'member-vnf-index': ++this.memberVnfIndexValue
295         }]
296       });
297     }
298     this.putType = 'vnfdadd';
299     this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
300   }
301   /** Events handles allow drop on D3 region @public */
302   public allowDrop(ev: DragEvent): void {
303     ev.preventDefault();
304   }
305   /** Save NSD Information @public */
306   public saveNSD(): void {
307     if (this.vnfdPackageDetails.shortName !== undefined) {
308       this.nsData['short-name'] = this.vnfdPackageDetails.shortName;
309     }
310     if (this.vnfdPackageDetails.vendor !== undefined) {
311       this.nsData.vendor = this.vnfdPackageDetails.vendor;
312     }
313     if (this.vnfdPackageDetails.description !== undefined) {
314       this.nsData.description = this.vnfdPackageDetails.description;
315     }
316     if (this.vnfdPackageDetails.version !== undefined) {
317       this.nsData.version = this.vnfdPackageDetails.version;
318     }
319     if (this.vnfdPackageDetails.id !== undefined) {
320       this.nsData.id = this.vnfdPackageDetails.id;
321     }
322     if (this.vnfdPackageDetails.name !== undefined) {
323       this.nsData.name = this.vnfdPackageDetails.name;
324     }
325     this.putType = 'nsdUpdate';
326     this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
327   }
328   /** Save Virtual Link @public */
329   public saveVL(vlid: string): void {
330     this.nsData.vld.forEach((result: VLD) => {
331       if (result.id === vlid) {
332         result.name = this.vlDetails.name;
333         result['mgmt-network'] = !isNullOrUndefined(this.vlDetails['mgmt-network']) ? this.vlDetails['mgmt-network'] : true;
334         result['vim-network-name'] = !isNullOrUndefined(this.vlDetails['vim-network-name']) ? this.vlDetails['vim-network-name'] : '';
335         result.type = this.vlDetails.type;
336         result.id = this.vlDetails.id;
337       }
338     });
339     this.putType = 'vlUpdate';
340     this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
341   }
342   /** Add the new Data @public */
343   public addData(apiURL: string, identifier: string, data: NSDDetails, putType: string): void {
344     this.isLoadingResults = true;
345     let successMessage: string = '';
346     if (putType === 'nsdadd') {
347       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.ADDNSD';
348     } else if (putType === 'vnfdadd') {
349       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.ADDVNFD';
350     } else if (putType === 'cpAdded') {
351       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.ADDNS';
352     } else if (putType === 'nsdUpdate') {
353       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.UPDATEDSUCCESSFULLY';
354     } else if (putType === 'vlUpdate') {
355       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.UPDATEDSUCCESSFULLY';
356     } else if (putType === 'nsddelete') {
357       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETENSD';
358     } else if (putType === 'vnfddelete') {
359       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETEVNFD';
360     } else if (putType === 'nsdelete') {
361       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETENS';
362     } else if (putType === 'linkdelete') {
363       successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETELINK';
364     }
365     /** Below hide for conflicts with light weight UI */
366     const apiURLHeader: APIURLHEADER = {
367       url: apiURL + '/' + identifier + '/nsd_content',
368       httpOptions: { headers: this.headers }
369     };
370     const nsData: {} = {};
371     nsData['nsd:nsd-catalog'] = {};
372     nsData['nsd:nsd-catalog'].nsd = [];
373     nsData['nsd:nsd-catalog'].nsd.push(data);
374     const descriptorInfo: string = jsyaml.dump(nsData, {sortKeys: true});
375     this.sharedService.targzFile({ packageType: 'nsd', id: this.identifier, descriptor: descriptorInfo })
376       .then((content: ArrayBuffer): void => {
377         this.restService.putResource(apiURLHeader, content).subscribe((res: {}) => {
378           this.generateData();
379           this.notifierService.notify('success', this.translateService.instant(successMessage));
380           this.isLoadingResults = false;
381         }, (error: ERRORDATA) => {
382           this.generateData();
383           this.restService.handleError(error, 'put');
384           this.isLoadingResults = false;
385         });
386       }).catch((): void => {
387         this.notifierService.notify('error', this.translateService.instant('ERROR'));
388         this.isLoadingResults = false;
389       });
390   }
391   /** Show Info @public */
392   public showInfo(): void {
393     const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
394     modalRef.componentInstance.topologyType = 'Info';
395     modalRef.componentInstance.topologytitle = this.translateService.instant('PAGE.TOPOLOGY.INFO');
396     modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
397       if (result) {
398         // empty
399       }
400     }).catch();
401   }
402   /** Event to freeze the animation @public */
403   public onFreeze(): void {
404     this.classApplied = !this.classApplied;
405     const alreadyFixedIsActive: boolean = d3.select('svg#graphContainer').classed(this.fixedClass);
406     d3.select('svg#graphContainer').classed(this.fixedClass, !alreadyFixedIsActive);
407     if (alreadyFixedIsActive) {
408       this.force.stop();
409     }
410     this.forceSimulationActive = alreadyFixedIsActive;
411     this.nodes.forEach((d: COMPOSERNODES) => {
412       d.fx = (alreadyFixedIsActive) ? null : d.x;
413       d.fy = (alreadyFixedIsActive) ? null : d.y;
414     });
415     if (alreadyFixedIsActive) {
416       this.force.restart();
417     }
418   }
419   /** Events handles when dragended @public */
420   public toggleSidebar(): void {
421     this.sideBarOpened = !this.sideBarOpened;
422     this.deselectAllNodes();
423     this.showRightSideInfo(true, false, false, false);
424   }
425   /** Prepare information for node creation of VNFD @private */
426   private generateData(): void {
427     this.generateVNFData();
428     this.generateDataNSDTopology();
429     this.sideBarOpened = false;
430   }
431   /** Prepare the information of the VNFD @private */
432   private generateVNFData(): void {
433     this.restService.getResource(environment.VNFPACKAGESCONTENT_URL).subscribe((vnfdPackageData: VNFDDetails[]) => {
434       this.vnfList = vnfdPackageData;
435     }, (error: ERRORDATA) => {
436       this.restService.handleError(error, 'get');
437     });
438   }
439   /** Prepare information for node creation of NSD Topology @private */
440   private generateDataNSDTopology(): void {
441     this.nodes = [];
442     this.links = [];
443     this.iConnectionPointRef = 0;
444     this.jConnectionPointRef = 0;
445     this.restService.getResource(environment.NSDESCRIPTORSCONTENT_URL + '/' + this.identifier).subscribe((nsData: NSDDetails) => {
446       delete nsData._admin;
447       delete nsData._id;
448       this.nsData = nsData;
449       this.vnfdPackageDetails.shortName = nsData['short-name'];
450       this.vnfdPackageDetails.vendor = nsData.vendor;
451       this.vnfdPackageDetails.description = nsData.description;
452       this.vnfdPackageDetails.version = nsData.version;
453       this.vnfdPackageDetails.id = nsData.id;
454       this.vnfdPackageDetails.name = nsData.name;
455       if (nsData.vld !== undefined) {
456         /** Details of the VL */
457         this.nsDataVLD(nsData);
458       }
459       if (nsData['constituent-vnfd'] !== undefined) {
460         /** Details of the VNFD */
461         this.nsDataConstituentVNFD(nsData);
462       }
463       if (nsData.vld !== undefined) {
464         this.nsDataVLDLinkCreation(nsData);
465       }
466       this.separateAndCreatenode();
467     }, (error: ERRORDATA) => {
468       if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) {
469         this.router.navigateByUrl('404', { skipLocationChange: true }).catch();
470       } else {
471         this.restService.handleError(error, 'get');
472       }
473       this.isLoadingResults = false;
474       this.isShowNSDDetails = false;
475     });
476   }
477   /** nsData-vld undefined Call this function @private */
478   private nsDataVLD(nsData: NSDDetails): void {
479     nsData.vld.forEach((res: VLD) => {
480       this.nodes.push({ id: res.id, reflexive: false, type: 'vld', name: res.id, selectorId: res.id });
481       this.nsd = res.id;
482       if (res['vnfd-connection-point-ref'] !== undefined) {
483         res['vnfd-connection-point-ref'].forEach((result: VNFDCONNECTIONPOINTREF) => {
484           this.nodes.push(
485             {
486               id: this.nsd + ++this.iConnectionPointRef + ':' + result['vnfd-connection-point-ref'],
487               reflexive: false,
488               type: 'ns',
489               name: result['vnfd-connection-point-ref'],
490               nodeIndex: result['member-vnf-index-ref'],
491               selectorId: result['vnfd-connection-point-ref'] + '_' + result['member-vnf-index-ref'] + '-osm-' + this.nsd
492             });
493         });
494       }
495     });
496   }
497   /** nsData constituent-vnfd undefined Call this function @private */
498   private nsDataConstituentVNFD(nsData: NSDDetails): void {
499     nsData['constituent-vnfd'].forEach((res: CONSTITUENTVNFD) => {
500       this.nodes.push(
501         {
502           id: res['vnfd-id-ref'] + ':' + res['member-vnf-index'],
503           reflexive: false,
504           type: 'vnfd',
505           name: res['vnfd-id-ref'],
506           nodeIndex: res['member-vnf-index'],
507           selectorId: res['vnfd-id-ref'] + '_' + res['member-vnf-index']
508         });
509       this.vnfd = res['vnfd-id-ref'];
510       this.memberVnfIndexValue = res['member-vnf-index'];
511     });
512   }
513
514   /** nsData-vld undefined Call this function @private */
515   private nsDataVLDLinkCreation(nsData: NSDDetails): void {
516     nsData.vld.forEach((res: VLD) => {
517       this.nsdCopy = res.id;
518       if (res['vnfd-connection-point-ref'] !== undefined) {
519         this.nsDataVNFDConnectionPointRefrence(res);
520       }
521     });
522   }
523   /** nsData-vnfd-connection-point-ref undefined Call this function @private */
524   private nsDataVNFDConnectionPointRefrence(res: VLD): void {
525     res['vnfd-connection-point-ref'].forEach((result: VNFDCONNECTIONPOINTREF) => {
526       this.connectionPoint = this.nsdCopy + ++this.jConnectionPointRef + ':' + result['vnfd-connection-point-ref'];
527       this.vnfdCopy = result['vnfd-id-ref'] + ':' + result['member-vnf-index-ref'];
528       const connectionPointPos: number = this.nodes.map((e: COMPOSERNODES) => { return e.id; }).indexOf(this.connectionPoint);
529       const nsdPos: number = this.nodes.map((e: COMPOSERNODES) => { return e.id; }).indexOf(this.nsdCopy);
530       const vnfdPos: number = this.nodes.map((e: COMPOSERNODES) => { return e.id; }).indexOf(this.vnfdCopy);
531       this.links.push(
532         {
533           source: this.nodes[connectionPointPos],
534           target: this.nodes[nsdPos]
535         },
536         {
537           source: this.nodes[connectionPointPos],
538           target: this.nodes[vnfdPos]
539         });
540     });
541   }
542   /** Generate random string @private  */
543   private randomString(length: number, chars: string): string {
544     let result: string = '';
545     for (let randomStringRef: number = length; randomStringRef > 0; --randomStringRef) {
546       result += chars[Math.floor(Math.random() * chars.length)];
547     }
548     return result;
549   }
550   /** Separate and create node @private */
551   private separateAndCreatenode(): void {
552     this.seprateNodes(this.nodes);
553     this.createnode(this.nodes);
554     this.isLoadingResults = false;
555   }
556   /** Get the default Configuration of containers @private */
557   private getGraphContainerAttr(): GRAPHDETAILS {
558     return {
559       width: 700,
560       height: 400,
561       nodeHeight: 50,
562       nodeWidth: 35,
563       textX: -35,
564       textY: 30,
565       radius: 5,
566       distance: 50,
567       strength: -500,
568       forcex: 2,
569       forcey: 2,
570       sourcePaddingYes: 17,
571       sourcePaddingNo: 12,
572       targetPaddingYes: 4,
573       targetPaddingNo: 3,
574       alphaTarget: 0.3,
575       imageX: -25,
576       imageY: -25,
577       shiftKeyCode: 17
578     };
579   }
580   /** Separate the nodes along with its tyep @private */
581   private seprateNodes(node: COMPOSERNODES[]): void {
582     this.vlNodes = []; this.vnfNodes = []; this.cpNodes = [];
583     node.forEach((nodeList: COMPOSERNODES) => {
584       if (nodeList.type === 'vld') {
585         this.vlNodes.push(nodeList);
586       } else if (nodeList.type === 'vnfd') {
587         this.vnfNodes.push(nodeList);
588       } else if (nodeList.type === 'ns') {
589         this.cpNodes.push(nodeList);
590       }
591     });
592   }
593   /** Node is created and render at D3 region @private */
594   private createnode(node: COMPOSERNODES[]): void {
595     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
596     d3.selectAll('svg#graphContainer > *').remove();
597     d3.select(window).on('keydown', () => { this.keyDown(); });
598     d3.select(window).on('keyup', () => { this.keyUp(); });
599     this.svg = d3.select('#graphContainer')
600       .attr('oncontextmenu', 'return false;')
601       .attr('width', graphContainerAttr.width)
602       .attr('height', graphContainerAttr.height)
603       .on('mousemove', () => { this.mousemove(); });
604     this.force = d3.forceSimulation()
605       .force('charge', d3.forceManyBody().strength(graphContainerAttr.strength))
606       .force('link', d3.forceLink().id((d: TickPath) => d.id).distance(graphContainerAttr.distance))
607       .force('center', d3.forceCenter(graphContainerAttr.width / graphContainerAttr.forcex,
608         graphContainerAttr.height / graphContainerAttr.forcey))
609       .force('x', d3.forceX(graphContainerAttr.width / graphContainerAttr.forcex))
610       .force('y', d3.forceY(graphContainerAttr.height / graphContainerAttr.forcey))
611       .on('tick', () => { this.tick(); });
612     this.dragLine = this.svg.append('svg:path').attr('class', 'link dragline hidden').attr('d', 'M0,0L0,0');
613     this.path = this.svg.append('svg:g').selectAll('path');
614     this.vlNode = this.svg.append('svg:g').selectAll('vlnode');
615     this.vnfdnode = this.svg.append('svg:g').selectAll('vnfdnode');
616     this.cpnode = this.svg.append('svg:g').selectAll('cpnode');
617     // app starts here
618     this.restart(node);
619   }
620   /** update force layout (called automatically each iteration) @private */
621   private tick(): void {
622     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
623     // draw directed edges with proper padding from node centers
624     this.path.attr('class', 'link').attr('d', (d: Tick) => {
625       const deltaX: number = d.target.x - d.source.x;
626       const deltaY: number = d.target.y - d.source.y;
627       const dist: number = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
628       const normX: number = deltaX / dist;
629       const normY: number = deltaY / dist;
630       const sourcePadding: number = d.left ? graphContainerAttr.sourcePaddingYes : graphContainerAttr.sourcePaddingNo;
631       const targetPadding: number = d.right ? graphContainerAttr.targetPaddingYes : graphContainerAttr.targetPaddingNo;
632       const sourceX: number = d.source.x + (sourcePadding * normX);
633       const sourceY: number = d.source.y + (sourcePadding * normY);
634       const targetX: number = d.target.x - (targetPadding * normX);
635       const targetY: number = d.target.y - (targetPadding * normY);
636       return `M${sourceX},${sourceY}L${targetX},${targetY}`;
637     }).on('dblclick', (d: Tick) => { this.getDeleteLinkConfirmation(d); });
638     this.vlNode.attr('transform', (t: TickPath) => `translate(${t.x},${t.y})`);
639     this.vnfdnode.attr('transform', (t: TickPath) => `translate(${t.x},${t.y})`);
640     this.cpnode.attr('transform', (t: TickPath) => `translate(${t.x},${t.y})`);
641   }
642   /** Update graph (called when needed) at D3 region @private */
643   private restart(node: COMPOSERNODES[]): void {
644     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
645     this.path = this.path.data(this.links);
646     this.vlNode = this.vlNode.data(this.vlNodes, (d: COMPOSERNODES) => d.id);
647     this.vnfdnode = this.vnfdnode.data(this.vnfNodes, (d: COMPOSERNODES) => d.id);
648     this.cpnode = this.cpnode.data(this.cpNodes, (d: COMPOSERNODES) => d.id);
649     this.resetAndCreateNodes();
650     this.force.nodes(node).force('link').links(this.links);
651     this.force.alphaTarget(graphContainerAttr.alphaTarget).restart();
652   }
653   /** Rest and create nodes @private */
654   private resetAndCreateNodes(): void {
655     this.path.exit().remove();
656     this.vlNode.exit().remove();
657     this.vnfdnode.exit().remove();
658     this.cpnode.exit().remove();
659     this.getPathNodes();
660     this.getVLNodes();
661     this.getVNFDNodes();
662     this.getCPNodes();
663     this.path.merge(this.path);
664     this.vlNode = this.gvlNode.merge(this.vlNode);
665     this.vnfdnode = this.gvnfdNode.merge(this.vnfdnode);
666     this.cpnode = this.gcpNode.merge(this.cpnode);
667   }
668   /** setting the Path @private */
669   private getPathNodes(): void {
670     this.path = this.path.enter().append('svg:path');
671   }
672   /** Setting all the VL nodes @private */
673   private getVLNodes(): void {
674     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
675     this.gvlNode = this.vlNode.enter().append('svg:g');
676     this.gvlNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
677     this.gvlNode.append('svg:image')
678       .style('opacity', 1)
679       .attr('x', graphContainerAttr.imageX)
680       .attr('y', graphContainerAttr.imageY)
681       .attr('id', (d: COMPOSERNODES) => { return d.selectorId; })
682       .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
683       .attr('xlink:href', 'assets/images/VL.svg')
684       .on('mousedown', (d: COMPOSERNODES) => { this.mouseDown(d); })
685       .on('mouseup', (d: COMPOSERNODES) => { this.mouseUp(d); })
686       .on('click', (d: COMPOSERNODES) => { this.singleClick(this.vlNode, d); this.onNodeClickToggleSidebar(); })
687       .on('dblclick', (d: COMPOSERNODES) => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); });
688     this.gvlNode.append('svg:text')
689       .attr('class', 'node_text')
690       .attr('y', graphContainerAttr.textY)
691       .text((d: COMPOSERNODES) => d.id);
692   }
693   /** Setting all the VNFD nodes @private */
694   private getVNFDNodes(): void {
695     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
696     this.gvnfdNode = this.vnfdnode.enter().append('svg:g');
697     this.gvnfdNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
698     this.gvnfdNode.append('svg:image')
699       .style('opacity', 1)
700       .attr('x', graphContainerAttr.imageX)
701       .attr('y', graphContainerAttr.imageY)
702       .attr('id', (d: COMPOSERNODES) => { return d.selectorId; })
703       .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
704       .attr('xlink:href', 'assets/images/VNFD.svg')
705       .on('mousedown', (d: COMPOSERNODES) => { this.mouseDown(d); })
706       .on('mouseup', (d: COMPOSERNODES) => { this.mouseUp(d); })
707       .on('click', (d: COMPOSERNODES) => { this.singleClick(this.vnfdnode, d); this.onNodeClickToggleSidebar(); })
708       .on('dblclick', (d: COMPOSERNODES) => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); });
709     this.gvnfdNode.append('svg:text')
710       .attr('class', 'node_text')
711       .attr('y', graphContainerAttr.textY)
712       .text((d: COMPOSERNODES) => d.id);
713   }
714   /** Setting all the CP nodes @private */
715   private getCPNodes(): void {
716     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
717     this.gcpNode = this.cpnode.enter().append('svg:g');
718     this.gcpNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee');
719     this.gcpNode.append('svg:image')
720       .style('opacity', 1)
721       .attr('x', graphContainerAttr.imageX)
722       .attr('y', graphContainerAttr.imageY)
723       .attr('id', (d: COMPOSERNODES) => { return d.selectorId; })
724       .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight)
725       .attr('xlink:href', 'assets/images/CP.svg')
726       .on('mousedown', (d: COMPOSERNODES) => { this.mouseDown(d); })
727       .on('mouseup', (d: COMPOSERNODES) => { this.mouseUp(d); })
728       .on('click', (d: COMPOSERNODES) => { this.singleClick(this.cpnode, d); this.onNodeClickToggleSidebar(); })
729       .on('dblclick', (d: COMPOSERNODES) => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); });
730     this.gcpNode.append('svg:text')
731       .attr('class', 'node_text')
732       .attr('y', graphContainerAttr.textY)
733       .text((d: COMPOSERNODES) => d.id);
734   }
735   /** Events handles when mousemove it will capture the selected node data @private */
736   private mousemove(): void {
737     if (!this.mousedownNode) { return; }
738     this.dragLine.attr('d',
739       `M${this.mousedownNode.x},${this.mousedownNode.y}L${d3.mouse(d3.event.currentTarget)[0]},${d3.mouse(d3.event.currentTarget)[1]}`);
740   }
741   /** Get confirmation Before Deleting the Link in Topology @private */
742   private getAddConfirmation(mouseData: COMPOSERNODES, getNsData: NSDDetails, addType: string, getVLDIndex: number): void {
743     let findVNFName: string = '';
744     let findVLDID: string = '';
745     if (mouseData.type === 'vld') {
746       findVNFName = this.mouseupNode.name;
747       findVLDID = this.mousedownNode.id;
748     } else {
749       findVNFName = this.mousedownNode.name;
750       findVLDID = this.mouseupNode.id;
751     }
752     getNsData.vld.forEach((result: VLD) => {
753       if (result.id === findVLDID) {
754         this.vlName = result.name;
755         this.getVNFSelectedData = this.vnfList.filter((vnfList: VNFDDetails) => vnfList.id === findVNFName);
756         this.setVnfdConnectionPointRef = this.getVNFSelectedData[0]['mgmt-interface'].cp;
757         this.setVnfdName = this.getVNFSelectedData[0].name;
758         this.selectedVLDResult = result;
759       }
760     });
761     if (this.vlName !== undefined && this.setVnfdName !== undefined && this.setVnfdConnectionPointRef !== undefined) {
762       const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
763       modalRef.componentInstance.topologyType = 'Add';
764       modalRef.componentInstance.cpDetails = this.getVNFSelectedData[0]['connection-point'];
765       this.translateService.get('PAGE.TOPOLOGY.ADDINGCP', {
766         vlname: '<b>' + this.vlName + '</b>',
767         vnfdname: '<b>' + this.setVnfdName + '</b>',
768         cpname: '<b>' + this.setVnfdConnectionPointRef + '</b>'
769       }).subscribe((res: string) => {
770         modalRef.componentInstance.topologyname = res;
771       });
772       modalRef.componentInstance.topologytitle = this.translateService.instant('PAGE.TOPOLOGY.CONNECTIONPOINT');
773       modalRef.result.then((result: MODALCLOSERESPONSEWITHCP) => {
774         if (result) {
775           this.nsData = getNsData;
776           this.generateCPForVNF(this.selectedVLDResult, result.connection_point, getVLDIndex);
777           this.addData(environment.NSDESCRIPTORS_URL, this.identifier, getNsData, addType);
778         } else {
779           this.deselectPath();
780         }
781       }).catch();
782     } else {
783       this.deselectPath();
784       this.notifierService.notify('error', this.translateService.instant('ERROR'));
785     }
786   }
787
788   /** Generate connection point for vnf using vld @private */
789   private generateCPForVNF(result: VLD, cp: string, getVLDIndex: number): void {
790     if (result['vnfd-connection-point-ref'] !== undefined) {
791       result['vnfd-connection-point-ref'].push({
792         'member-vnf-index-ref': getVLDIndex,
793         'vnfd-connection-point-ref': cp,
794         'vnfd-id-ref': this.getVNFSelectedData[0].name
795       });
796     } else {
797       Object.assign(result, {
798         'vnfd-connection-point-ref': [{
799           'member-vnf-index-ref': getVLDIndex,
800           'vnfd-connection-point-ref': cp,
801           'vnfd-id-ref': this.getVNFSelectedData[0].name
802         }]
803       });
804     }
805   }
806
807   /** Events handles when mousedown click it will capture the selected node data @private */
808   private mouseDown(d: COMPOSERNODES): void {
809     event.preventDefault();
810     if (d3.event.ctrlKey) { return; }
811     if (d3.event.shiftKey) {
812       if (d.type === 'vnfd') {
813         this.selectedNode.push(d);
814       }
815       this.mousedownNode = d;
816       this.currentSelectedNode = (this.mousedownNode === this.currentSelectedNode) ? null : this.mousedownNode;
817       this.currentSelectedLink = null;
818       this.dragLine.style('marker-end', 'url(#end-arrow)').classed('hidden', false)
819         .attr('d', `M${this.mousedownNode.x},${this.mousedownNode.y}L${this.mousedownNode.x},${this.mousedownNode.y}`);
820     }
821   }
822   /** Event handles when mouseup event occures @private */
823   private mouseUp(d: COMPOSERNODES): void {
824     if (!this.mousedownNode) { return; }
825     this.dragLine.classed('hidden', true).style('marker-end', '');
826     this.mouseupNode = d;
827     if (this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'vnfd') {
828       const getOldVLDIndex: string[] = this.mouseupNode.id.split(':');
829       const setOldVLDindex: number = +getOldVLDIndex[1];
830       this.putType = 'cpAdded';
831       this.getAddConfirmation(this.mousedownNode, this.nsData, this.putType, setOldVLDindex);
832     } else if (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'vld') {
833       const getOldVLDIndex: string[] = this.mousedownNode.id.split(':');
834       const setOldVLDindex: number = +getOldVLDIndex[1];
835       this.putType = 'cpAdded';
836       this.getAddConfirmation(this.mousedownNode, this.nsData, this.putType, setOldVLDindex);
837     } else if (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'ns') {
838       this.deselectPath();
839       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNFCP'));
840     } else if (this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'ns') {
841       this.deselectPath();
842       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNFCP'));
843     } else if (this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'vld') {
844       this.deselectPath();
845       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVL'));
846     } else if (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'vnfd') {
847       this.deselectPath();
848       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNF'));
849     } else if (this.mousedownNode.type === 'ns' && this.mouseupNode.type === 'ns') {
850       this.deselectPath();
851       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKCP'));
852     } else {
853       this.deselectPath();
854       this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVLVNF'));
855     }
856     this.resetMouseVars();
857     // select new link
858     this.currentSelectedLink = d;
859     this.currentSelectedNode = null;
860   }
861   /** Mosue Drag Line false if it is not satisfied @private */
862   private deselectPath(): void {
863     this.dragLine.classed('hidden', true).style('marker-end', '').attr('d', 'M0,0L0,0');
864   }
865   /** reset Mouse varaibles @private */
866   private resetMouseVars(): void {
867     this.mousedownNode = null;
868     this.mouseupNode = null;
869     this.mousedownLink = null;
870   }
871   /** De-select all the selected nodes @private */
872   private deselectAllNodes(): void {
873     this.vlNode.select('image').classed(this.activeClass, false);
874     this.vnfdnode.select('image').classed(this.activeClass, false);
875     this.cpnode.select('image').classed(this.activeClass, false);
876   }
877   /** Show the right-side information @private */
878   private showRightSideInfo(nsdDetails: boolean, vldDetails: boolean, vnfDeails: boolean, cpDetails: boolean): void {
879     this.isShowNSDDetails = nsdDetails;
880     this.isShowVLDetails = vldDetails;
881     this.isShowVNFDetails = vnfDeails;
882     this.isShowCPDetails = cpDetails;
883   }
884   /** Events handles when Shift Click to perform create cp @private */
885   // tslint:disable-next-line: no-any
886   private singleClick(nodeSelected: any, d: COMPOSERNODES): void {
887     this.selectNodeExclusive(nodeSelected, d);
888   }
889   /** Selected nodes @private */
890   // tslint:disable-next-line: no-any
891   private selectNodeExclusive(nodeSeleced: any, d: COMPOSERNODES): void {
892     const alreadyIsActive: boolean = nodeSeleced.select('#' + d.selectorId).classed(this.activeClass);
893     this.deselectAllNodes();
894     nodeSeleced.select('#' + d.selectorId).classed(this.activeClass, !alreadyIsActive);
895     if (d.type === 'vld' && !alreadyIsActive) {
896       this.nsData.vld.forEach((result: VLD) => {
897         if (result.id === d.id) {
898           this.showRightSideInfo(false, true, false, false);
899           this.vlDetails = result;
900         }
901       });
902     } else if (d.type === 'vnfd' && !alreadyIsActive) {
903       this.nsData['constituent-vnfd'].forEach((result: CONSTITUENTVNFD) => {
904         if (result['member-vnf-index'] === d.nodeIndex && result['vnfd-id-ref'] === d.name) {
905           this.showRightSideInfo(false, false, true, false);
906           this.vnfData = result;
907         }
908       });
909     } else if (d.type === 'ns' && !alreadyIsActive) {
910       this.nsData.vld.forEach((result: VLD) => {
911         if (result['vnfd-connection-point-ref'] !== undefined) {
912           result['vnfd-connection-point-ref'].forEach((resultCP: VNFDCONNECTIONPOINTREF) => {
913             if (resultCP['member-vnf-index-ref'] === d.nodeIndex && resultCP['vnfd-connection-point-ref'] === d.name) {
914               this.cpData = resultCP;
915               this.vlDetails = result;
916               this.showRightSideInfo(false, false, false, true);
917             }
918           });
919         }
920       });
921     } else {
922       this.showRightSideInfo(true, false, false, false);
923     }
924   }
925   /** Get confirmation Before Deleting the Link in Topology @private */
926   private getDeleteLinkConfirmation(d: Tick): void {
927     const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
928     modalRef.componentInstance.topologyType = 'Delete';
929     modalRef.componentInstance.topologyname = this.translateService.instant('PAGE.TOPOLOGY.LINK');
930     modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.LINK';
931     modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
932       if (result) {
933         this.doubleClickLink(d);
934       }
935     }).catch();
936   }
937   /** Events handles when Double Click to Delete the link @private */
938   private doubleClickLink(d: Tick): void {
939     let getID: string = '';
940     if (d.target.type === 'vld') {
941       getID = d.target.id;
942     } else if (d.source.type === 'vld') {
943       getID = d.source.id;
944     }
945     this.nodes.forEach((res: COMPOSERNODES) => {
946       if (res.id === getID) {
947         if (this.nsData.vld !== undefined) {
948           this.nsData.vld.forEach((vldresult: VLD) => {
949             if (vldresult.id === getID) {
950               delete vldresult['vnfd-connection-point-ref'];
951             }
952           });
953         }
954       }
955     });
956     this.putType = 'linkdelete';
957     this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
958   }
959   /** Get confirmation Before Deleting the Node in Topology @private */
960   private getDeleteConfirmation(d: COMPOSERNODES): void {
961     const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' });
962     modalRef.componentInstance.topologyType = 'Delete';
963     modalRef.componentInstance.topologyname = d.name;
964     if (d.type === 'vld') {
965       modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.VIRTUALLINK';
966     } else if (d.type === 'vnfd') {
967       modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.VNF';
968     } else if (d.type === 'ns') {
969       modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.CONNECTIONPOINT';
970     }
971     modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
972       if (result) {
973         this.doubleClick(d);
974       }
975     }).catch();
976   }
977   /** Events handles when Double Click to Delete @private */
978   private doubleClick(d: COMPOSERNODES): void {
979     const deletedNode: COMPOSERNODES = d;
980     this.nodes.forEach((res: COMPOSERNODES) => {
981       if (res.id === d.id) {
982         if (deletedNode.type === 'vld') {
983           const pos: number = this.nsData.vld.map((e: VLD) => { return e.id; }).indexOf(d.id);
984           this.nsData.vld.splice(pos, 1);
985           this.putType = 'nsddelete';
986         } else if (deletedNode.type === 'vnfd') {
987           const constituentVNFD: string[] = [];
988           if (this.nsData['constituent-vnfd'] !== undefined) {
989             this.nsData['constituent-vnfd'].forEach((ref: CONSTITUENTVNFD) => {
990               constituentVNFD.push(ref['vnfd-id-ref'] + ':' + ref['member-vnf-index']);
991             });
992           }
993           const pos: number = constituentVNFD.map((e: string) => { return e; }).indexOf(d.id);
994           this.nsData['constituent-vnfd'].splice(pos, 1);
995           const getCP: string[] = d.id.split(':');
996           const memberVnfIndexRef: number = +getCP[1];
997           const vnfdIDRef: string = getCP[0];
998           if (this.nsData.vld !== undefined) {
999             this.nsData.vld.forEach((resf: VLD) => {
1000               if (resf['vnfd-connection-point-ref'] !== undefined) {
1001                 resf['vnfd-connection-point-ref'].forEach((connectionPoint: VNFDCONNECTIONPOINTREF, index: number) => {
1002                   if (+connectionPoint['member-vnf-index-ref'] === memberVnfIndexRef && connectionPoint['vnfd-id-ref'] === vnfdIDRef) {
1003                     resf['vnfd-connection-point-ref'].splice(index, 1);
1004                   }
1005                 });
1006               }
1007             });
1008           }
1009           this.putType = 'vnfddelete';
1010         } else if (deletedNode.type === 'ns') {
1011           const getCP: string[] = d.selectorId.split('-osm-');
1012           const memberVnfIndexRef: number = d.nodeIndex;
1013           const vnfdIDRef: string = getCP[getCP.length - 1];
1014           if (this.nsData.vld !== undefined) {
1015             this.nsData.vld.forEach((resf: VLD) => {
1016               if (resf['vnfd-connection-point-ref'] !== undefined && resf.id === vnfdIDRef) {
1017                 resf['vnfd-connection-point-ref'].forEach((connectionPoint: VNFDCONNECTIONPOINTREF, index: number) => {
1018                   if (connectionPoint['member-vnf-index-ref'] === memberVnfIndexRef) {
1019                     resf['vnfd-connection-point-ref'].splice(index, 1);
1020                   }
1021                 });
1022               }
1023             });
1024           }
1025           this.putType = 'nsdelete';
1026         }
1027         this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType);
1028       }
1029     });
1030   }
1031   /** Key press event @private */
1032   private keyDown(): void {
1033     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
1034     if (this.lastKeyDown !== -1) { return; }
1035     this.lastKeyDown = d3.event.keyCode;
1036     if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
1037       this.gvlNode.call(d3.drag()
1038         .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)
1039       );
1040       this.gvnfdNode.call(d3.drag()
1041         .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)
1042       );
1043       this.gcpNode.call(d3.drag()
1044         .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)
1045       );
1046       this.svg.classed('ctrl', true);
1047     }
1048   }
1049   /** Key realse event @private */
1050   private keyUp(): void {
1051     const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr();
1052     this.lastKeyDown = -1;
1053     if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) {
1054       this.gvlNode.on('.drag', null);
1055       this.gvnfdNode.on('.drag', null);
1056       this.gcpNode.on('.drag', null);
1057       this.svg.classed('ctrl', false);
1058     }
1059   }
1060   /** Events handles when dragstarted @private */
1061   private dragstarted(d: COMPOSERNODES): void {
1062     d.fx = d.x;
1063     d.fy = d.y;
1064   }
1065   /** Events handles when dragged @private */
1066   private dragged(d: COMPOSERNODES): void {
1067     d.fx = d.x = d3.event.x;
1068     d.fy = d.y = d3.event.y;
1069   }
1070   /** Events handles when dragended @private */
1071   private dragended(d: COMPOSERNODES): void {
1072     if (this.forceSimulationActive) {
1073       d.fx = null;
1074       d.fy = null;
1075     } else {
1076       d.fx = d.x;
1077       d.fy = d.y;
1078       this.forceSimulationActive = false;
1079     }
1080   }
1081   /** Events handles when node double click   @private */
1082   private onNodedblClickToggleSidebar(): void {
1083     this.sideBarOpened = false;
1084   }
1085   /** Events handles when node single click   @private */
1086   private onNodeClickToggleSidebar(): void {
1087     this.sideBarOpened = true;
1088   }
1089 }