diff options
Diffstat (limited to 'usecaseui-portal/src/app/views/network')
8 files changed, 2237 insertions, 0 deletions
diff --git a/usecaseui-portal/src/app/views/network/ccvpn-network/ccvpn-network.component.css b/usecaseui-portal/src/app/views/network/ccvpn-network/ccvpn-network.component.css new file mode 100644 index 00000000..53cf02b4 --- /dev/null +++ b/usecaseui-portal/src/app/views/network/ccvpn-network/ccvpn-network.component.css @@ -0,0 +1,117 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.outer{ + width: 20%; + float: left; +} +.content{ + width: 100px; + margin: 30px 0; +} + +.submit,.delete,.add{ + padding:10px 20px; + width: 100px; + margin: 0 auto; + background: dodgerblue; + border: none; + border-radius: 10px; + color: #fff; + cursor: pointer; +} + +#tpContainer{ + position: relative; + width:100%; + height: 95%; + margin-top: 15px; + float: left; + background: #EEF9FF; +} +#tpContainer .no-network{ + width: 300px; + margin: 0 auto; + height: 280px; + position: absolute; + top: 50%; + left: 50%; + margin-top: -140px; + margin-left: -150px; +} +.no-network img{ + width: 100%; +} +.no-network p{ + text-align: center; + color: #A0AACD; + font-size: 18px; + margin-top: 20px; +} +.model { + position: relative; + padding: 15px; + height: 100vh; + width: 100%; +} +.model h2{ + display: inline-block; + margin: 0; + color: #3C4F8C; + margin-left: 10px; + display: inline-block; +} +.model .title-modelshow{ + color: #A0AACD; +} +.model .creation { + background-color: #fff; + width: 20%; + position: absolute; + left: 0; + margin-top: 30px; + margin-left: 30px; + border-radius: 5px; + box-shadow: 0 0 10px #9e9e9e; + padding: 10px; + height: 80vh; + overflow: auto; +} +.model .creation .v_color{ + height: 17px; + float: left; + margin-left: -11px; + margin-top: 5px; + border-left: 4px #3fa8eb solid; +} +.w_font4{ + font-weight: 400; +} +.title-span{ + margin-left: 10%; + font-size: 12px; +} +.red-span{ + color: red; + margin-right: 3px; +} +.choose li nz-select,.choose li input{ + display: block !important; + margin: 5px 10% 15px; + width: 80%; +} + + + diff --git a/usecaseui-portal/src/app/views/network/ccvpn-network/ccvpn-network.component.html b/usecaseui-portal/src/app/views/network/ccvpn-network/ccvpn-network.component.html new file mode 100644 index 00000000..fb025d96 --- /dev/null +++ b/usecaseui-portal/src/app/views/network/ccvpn-network/ccvpn-network.component.html @@ -0,0 +1,152 @@ +<!-- + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<nz-spin [nzSpinning]="isSpinning" nzSize="large"> +<div class="model"> + <!--chart--> + <button nz-button nzType="primary" *ngIf="!nonetwork" style="margin-top: 2px;display: inline-block" (click)="showForm()" + [disabled]='isVisible' [attr.disabled] ='isVisible?true:undefined'> + {{"i18nTextDefine_CreateLink" | translate}} + </button> + <h2 *ngIf="!nonetwork" [ngClass]="{'title-modelshow':isVisible == true}"> + Please configure network links for registered devices and partner system. + </h2> + <div id="tpContainer" style="overflow: hidden;"> + <div *ngIf="nonetwork" style="padding: 20px"> + <h2> + There is not any terminal device can be used for configuration + </h2> + <br> + <h2> + please register external network into ONAP. + </h2> + </div> + <div class="no-network" *ngIf="nonetwork"> + <img src="assets/images/no-network-available.png" alt="No network available"> + <p>No network available</p> + </div> + </div> + <!--Popup--> + <div class="creation" id="d3_form" *ngIf="isVisible==true"> + <span class="v_color"></span> + <h3 class="w_font4"> {{"i18nTextDefine_SetAttribtes" | translate}} </h3> + <ul class="choose"> + <li> + <span class="title-span"><span class="red-span">*</span> {{"i18nTextDefine_LinkName" | translate}} </span> + <input nz-input [(ngModel)]="linkName" maxlength="20"> + </li> + </ul> + <h4> {{"i18nTextDefine_LeftPort" | translate}} </h4> + <ul class="choose"> + <li> + <span class="title-span"><span class="red-span">*</span> {{"i18nTextDefine_Network" | translate}} </span> + <nz-select [(ngModel)]="networkVal1" nzShowSearch nzAllowClear (ngModelChange)="network1Change($event)"> + <nz-option *ngFor="let option of networkOption" [nzLabel]="option.network" [nzValue]="option.network"></nz-option> + </nz-select> + </li> + <li> + <span class="title-span"> <span class="red-span">*</span> {{"i18nTextDefine_Node" | translate}} </span> + <nz-select [(ngModel)]="selectedNode1" nzShowSearch nzAllowClear (ngModelChange)="node1Change($event)"> + <nz-option *ngFor="let node of nodeOption1[networkVal1]" [nzValue]="node" [nzLabel]="node"></nz-option> + </nz-select> + </li> + <li> + <span class="title-span"><span class="red-span">*</span> {{"i18nTextDefine_TerminalPoint" | translate}} </span> + <!-- <input nz-input id="city-one" value=""> --> + <nz-select [(ngModel)]="selecteTpName1" nzShowSearch nzAllowClear> + <nz-option *ngFor="let tp of tpOption1" [nzValue]="tp" [nzLabel]="tp"></nz-option> + </nz-select> + </li> + </ul> + <h4> {{"i18nTextDefine_RightPort" | translate}} </h4> + <label nz-checkbox [(ngModel)]="inputshow"> {{"i18nTextDefine_PartnerNetwork" | translate}} </label> + <ul class="choose"> + <li> + <span class="title-span"><span *ngIf="inputshow" class="red-span">*</span> {{"i18nTextDefine_HostUrl" | translate}} </span> + <input nz-input [(ngModel)]="cloudUrl" [disabled]='!inputshow' [attr.disabled] ='!inputshow?true:undefined'> + </li> + <li> + <span class="title-span"><span class="red-span">*</span> {{"i18nTextDefine_Network" | translate}} </span> + <input nz-input *ngIf="inputshow" [(ngModel)]="cloudNetwork"> + <nz-select *ngIf="!inputshow" [(ngModel)]="networkVal2" nzShowSearch nzAllowClear (ngModelChange)="network2Change($event)"> + <nz-option *ngFor="let option of networkOption" [nzLabel]="option.network" [nzValue]="option.network"> </nz-option> + </nz-select> + </li> + <li> + <span class="title-span"><span class="red-span">*</span> {{"i18nTextDefine_Node" | translate}} </span> + <input nz-input *ngIf="inputshow" [(ngModel)]="cloudNode"> + <nz-select *ngIf="!inputshow" [(ngModel)]="selectedNode2" nzShowSearch nzAllowClear (ngModelChange)="node2Change($event)"> + <nz-option *ngFor="let node of nodeOption1[networkVal2]" [nzValue]="node" [nzLabel]="node"></nz-option> + </nz-select> + </li> + <li> + <span class="title-span"><span class="red-span">*</span> {{"i18nTextDefine_TerminalPoint" | translate}} </span> + <input nz-input *ngIf="inputshow" [(ngModel)]="cloudTp"> + <nz-select *ngIf="!inputshow" [(ngModel)]="selecteTpName2" nzShowSearch nzAllowClear> + <nz-option *ngFor="let tp of tpOption2" [nzValue]="tp" [nzLabel]="tp"></nz-option> + </nz-select> + </li> + </ul> + <button nz-button nzType="primary" nzSize="small" style="width: 60px;" (click)="submitForm()"> {{"i18nTextDefine_modelOk" | translate}} </button> + <button nz-button nzType="default" nzSize="small" style="width: 60px;" (click)="hideForm()"> {{"i18nTextDefine_Cancel" | translate}} </button> + </div> + <div class="creation" id="delbox" *ngIf="delBoxisVisible==true"> + <span class="v_color"></span> + <ul class="choose"> + <li> + <span class="title-span"> {{"i18nTextDefine_LinkName" | translate}} </span> + <input nz-input [(ngModel)]="delLinkname" disabled="disabled"> + </li> + </ul> + <h4> {{"i18nTextDefine_LeftPort" | translate}} </h4> + <ul class="choose"> + <li> + <span class="title-span"> {{"i18nTextDefine_Network" | translate}} </span> + <input nz-input [(ngModel)]="delNetwork1" disabled="disabled"> + </li> + <li> + <span class="title-span"> {{"i18nTextDefine_Node" | translate}} </span> + <input nz-input [(ngModel)]="delNode1" disabled="disabled"> + </li> + <li> + <span class="title-span"> {{"i18nTextDefine_TerminalPoint" | translate}} </span> + <input nz-input [(ngModel)]="delTp1" disabled="disabled"> + </li> + </ul> + <h4> {{"i18nTextDefine_RightPort" | translate}} </h4> + <ul class="choose"> + <li *ngIf="delcloud"> + <span class="title-span"> {{"i18nTextDefine_HostUrl" | translate}} </span> + <input nz-input [(ngModel)]="delcloudUrl" disabled="disabled"> + </li> + <li> + <span class="title-span"> {{"i18nTextDefine_Network" | translate}} </span> + <input nz-input [(ngModel)]="delNetwork2" disabled="disabled"> + </li> + <li> + <span class="title-span"> {{"i18nTextDefine_Node" | translate}} </span> + <input nz-input [(ngModel)]="delNode2" disabled="disabled"> + </li> + <li> + <span class="title-span"> {{"i18nTextDefine_TerminalPoint" | translate}} </span> + <input nz-input [(ngModel)]="delTp2" disabled="disabled"> + </li> + </ul> + <button nz-button nzType="primary" nzSize="small" class="del-button" style="width: 90px;" (click)="delLink()" *ngIf="!delcloud"> {{"i18nTextDefine_DeleteLink" | translate}} </button> + <button nz-button nzType="primary" nzSize="small" class="del-button" style="width: 90px;" (click)="delCloudLink()" *ngIf="delcloud"> {{"i18nTextDefine_DeleteLink" | translate}} </button> + <button nz-button nzType="default" nzSize="small" class="del-button" style="width: 60px;" (click)="hideForm()"> {{"i18nTextDefine_Cancel" | translate}} </button> + </div> +</div> +</nz-spin> diff --git a/usecaseui-portal/src/app/views/network/ccvpn-network/ccvpn-network.component.spec.ts b/usecaseui-portal/src/app/views/network/ccvpn-network/ccvpn-network.component.spec.ts new file mode 100644 index 00000000..9ec321c5 --- /dev/null +++ b/usecaseui-portal/src/app/views/network/ccvpn-network/ccvpn-network.component.spec.ts @@ -0,0 +1,40 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CcvpnNetworkComponent } from './ccvpn-network.component'; + +describe('CcvpnNetworkComponent', () => { + let component: CcvpnNetworkComponent; + let fixture: ComponentFixture<CcvpnNetworkComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CcvpnNetworkComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CcvpnNetworkComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/usecaseui-portal/src/app/views/network/ccvpn-network/ccvpn-network.component.ts b/usecaseui-portal/src/app/views/network/ccvpn-network/ccvpn-network.component.ts new file mode 100644 index 00000000..56009546 --- /dev/null +++ b/usecaseui-portal/src/app/views/network/ccvpn-network/ccvpn-network.component.ts @@ -0,0 +1,1268 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +import { Component, EventEmitter, OnInit, Output } from '@angular/core'; +import * as d3 from 'd3'; +import * as $ from 'jquery'; +import { networkHttpservice } from '../../../core/services/networkHttpservice.service'; + +@Component({ + selector: 'app-ccvpn-network', + templateUrl: './ccvpn-network.component.html', + styleUrls: ['./ccvpn-network.component.css'] +}) +export class CcvpnNetworkComponent implements OnInit { + + constructor(private myhttp: networkHttpservice) { + } + + ngOnInit() { + let thisNg = this; + thisNg.getD3Data(); + + + //Local cloud TP port connection, click on the right to expand the details + $('#tpContainer').on('click', '.line-port', function () { + thisNg.isVisible = false; + thisNg.delBoxisVisible = true; + thisNg.delcloud = false; + + thisNg.delTp1 = $(this).attr('data-tp1'); + thisNg.delTp2 = $(this).attr('data-tp2'); + thisNg.delNode1 = $(this).attr('data-node1'); + thisNg.delNode2 = $(this).attr('data-node2'); + thisNg.delVersion = $(this).attr('data-version'); + thisNg.delLinkname = $(this).attr('data-link'); + thisNg.delcloudUrl = null; + thisNg.delLinkIndex = $(this); + + let dataD3 = thisNg.d3Data; + for (let p = 0; p < dataD3.length; p++) {//Determine which Domain network the two tp ports belong to + if (dataD3[p]['name'] == thisNg.delTp1) { + thisNg.network.push(dataD3[p]['source']['name']); + } + if (dataD3[p]['name'] == thisNg.delTp2) { + thisNg.network.push(dataD3[p]['source']['name']); + } + } + thisNg.delNetwork1 = thisNg.network[0]; + thisNg.delNetwork2 = thisNg.network[1]; + }); + + //External cloud connection, click on the right to expand the details + $('#tpContainer').on('click', '.cloudline', function () { + thisNg.isVisible = false; + thisNg.delBoxisVisible = true; + thisNg.delcloud = true; + + thisNg.delTp1 = $(this).attr('data-tp1'); + thisNg.delTp2 = $(this).attr('data-tp2'); + thisNg.delNode1 = $(this).attr('data-node1'); + thisNg.delNode2 = $(this).attr('data-node2'); + thisNg.delVersion = $(this).attr('data-version'); + thisNg.delNetwork1 = $(this).attr('data-network'); + thisNg.delNetwork2 = $(this).attr('data-cloudnetwork'); + thisNg.delcloudUrl = $(this).attr('data-url'); + thisNg.delLinkname = $(this).attr('data-link'); + thisNg.aaiId = $(this).attr('data-aaiid'); + thisNg.getCloudUrl(thisNg.aaiId); + }); + } + + addLinkDisabled = true; + nonetwork = false; + isVisible = false; + outCloudShow = false; + inputshow = false; + delBoxisVisible = false; + isSpinning = true; + + d3Data = [];//D3Render the required data + logicalLinks = [];//logicalLinks Existing connection data returned by the interface + linkName = null;//Linked name link-name + networkOption = [];//Form network drop-down box filled data + nodeOption1 = {};//Node drop-down box filled data + tpOption1 = [];//Node drop-down box filled data + tpOption2 = [];//Node drop-down box filled data + networkVal1 = null;//network1 Drop-down box default data + networkVal2 = null;//network2 Drop-down box default data + selectedNode1 = null;//node1 Drop-down box default data + selectedNode2 = null;//node2 Drop-down box default data + selecteTpName1 = null;//TP1 Drop-down box default data + selecteTpName2 = null;//TP2 Drop-down box default data + cloudUrl = null;//External cloud URL address + cloudNetwork = null;//External cloud network name + cloudNode = null;//External cloud Node name + cloudTp = null;//External cloud Tp name + + dataCloud = [];//External cloud information + dataCloudLink = []; + aaiId = ''; + + + //When the connection is deleted, the data displayed in the right frame + delLinkname = null; + delNetwork1 = null; + delNode1 = null; + delTp1 = null; + delcloudUrl = null; + delNetwork2 = null; + delNode2 = null; + delTp2 = null; + delVersion = null; + delLinkIndex = null; + network = []; + delcloud = false; + + winWidth = $('#tpContainer').width(); + winHeight = $('#tpContainer').height(); + charge = -300; + + imgmap = { + '1': 'assets/images/cloud-county1.png', + '2': 'assets/images/tp.png', + '3': 'assets/images/cloud-out.png', + }; + tpoption = { + container: '#tpContainer', + data: '', + width: 1000, + height: this.winHeight + }; + + showForm(): void { + if (this.addLinkDisabled == false) { + this.isVisible = true; + this.delBoxisVisible = false; + } + } + + hideForm(): void { + this.isVisible = false; + this.delBoxisVisible = false; + this.linkName = null; + this.networkVal1 = null;//Initialize the default data of the network1 drop-down box + this.networkVal2 = null;//Initialize the network2 drop-down box default data + this.selectedNode1 = null;//Initialize the default data of the node1 drop-down box + this.selectedNode2 = null;//Initialize the default data of the node2 drop-down box + this.selecteTpName1 = null;//Initialize the default data of the TP1 drop-down box + this.selecteTpName2 = null;//Initialize the default data of the TP2 drop-down box + this.cloudUrl = null;//External cloud URL address + this.cloudNetwork = null;//External cloud network name + this.cloudNode = null;//External cloud Node name + this.cloudTp = null;//External cloud Tp name + } + + //Get cloud image data + getD3Data() { + this.isSpinning = true; + this.myhttp.getNetworkD3Data() + .subscribe((data) => { + this.isSpinning = false; + if (data.length == 0) { + this.addLinkDisabled = false; + this.nonetwork = true; + return; + } + this.nonetwork = false; + for (let ii = 0; ii < data.length; ii++) {//Determine if there is external cloud information in the data, and kick it out. + if (data[ii]['aaiId'] != null) { + this.dataCloud = data.splice(ii, 1); + } + } + + for (let i = 0; i < data.length; i++) { + let name1 = {}, name2 = {}; + let nodess = []; + name1['name'] = name2['network'] = data[i]['networkId']; + name1['type'] = '1'; + name1['source'] = i; + this.d3Data.push(name1); + for (let c = 0; c < data[i]["pnfs"].length; c++) { + nodess.push(data[i]['pnfs'][c]['pnfName']); + this.nodeOption1[name2['network']] = nodess; + } + this.networkOption.push(name2); + } + for (let i = 0; i < data.length; i++) { + let tp_length = data[i]['tps'].length; + for (let h = 0; h < tp_length; h++) { + let name2 = {}; + let interface_name = data[i]['tps'][h]['interface-name']; + name2['name'] = interface_name; + name2['type'] = '2'; + name2['source'] = i; + this.d3Data.push(name2); + } + } + for (let b = 0; b < this.d3Data.length; b++) { + this.d3Data[b]['target'] = b; + } + this.initPosition(this.d3Data); + setTimeout(this.render(this.d3Data, this.imgmap, this.dataCloud, this.charge, data), 0); + }, (err) => { + console.log(err); + }); + + } + + //Get the initial connection status of the cloud image getlogicalLinksData + getLinksData() { + this.myhttp.getLogicalLinksData() + .subscribe((data) => { + if (data["status"] == "FAILED") { + return; + } + for (let i = 0; i < data["logical-link"].length; i++) {//Determine whether there is an external cloud connection in the obtained connection, and kick it out. + if (data['logical-link'][i]['relationship-list']['relationship'].length > 2) { + this.dataCloudLink = data['logical-link'].splice(i, 1); + } + } + + for (let i = 0; i < data["logical-link"].length; i++) { + let textval = []; + textval[0] = data['logical-link'][i]['relationship-list']['relationship'][0]['relationship-data'][1]['relationship-value'];//tp1 + textval[1] = data['logical-link'][i]['relationship-list']['relationship'][1]['relationship-data'][1]['relationship-value'];//tp2 + textval[2] = data['logical-link'][i]['resource-version'];//version + textval[3] = data['logical-link'][i]['relationship-list']['relationship'][0]['relationship-data'][0]['relationship-value'];//node1 + textval[4] = data['logical-link'][i]['relationship-list']['relationship'][1]['relationship-data'][0]['relationship-value'];//node2 + textval[5] = data['logical-link'][i]['operational-status']; + textval[6] = data['logical-link'][i]['link-name']; + this.logicalLinks.push(textval); + this.chose(textval); + } + if (this.dataCloudLink.length > 0) { + this.getcloudLine(this.dataCloudLink); + } + }, (err) => { + console.log(err); + }); + } + + //D3Cloud rendering + render(nodes, imgmap, dataCloud, charge, dataD3) { + let thiss = this; + let _this = this.tpoption, + width = null, + height = _this.height; + if (_this.width > 800) { + width = _this.width; + } else { + width = 800; + } + if (dataD3.length <= 4) { + charge = -300; + } else if (dataD3.length > 4 && dataD3.length <= 6) { + charge = -160; + } else if (dataD3.length > 6 && dataD3.length <= 10) { + charge = -110; + } else { + charge = -100; + } + let svg = d3.select(_this.container).append('svg') + .attr('width', width) + .attr('height', height) + .attr('id', 'content-svg') + .style('pointer-events', 'all') + .style('position', 'absolute') + .style('top', '1%') + .style('right', '2%'), + graph = svg.append('g').attr('class', 'graph').attr('id', 'graph'), + + _g_nodes = graph.selectAll('g.node') + .data(nodes) + .enter() + .append('g') + .style('display', function (d) { + let display = 'block'; + switch (d.type) { + case '1': + display = 'none'; + break; + case '2': + display = 'none'; + break; + default: + break; + } + return display; + }) + .style('cursor', 'pointer') + .attr('class', 'node'), + + _g_lines = graph.selectAll('line.line') + .data(nodes) + .enter() + .append('g') + .style('display', 'none') + .attr('class', 'line'); + + + _g_lines.append('line') + .style('stroke', '#93c62d' + ) + .style('stroke-width', 2); + + _g_nodes.append('image') + .attr('width', function (d) { + let width = 40; + switch (d.type) { + case '1': + width = 4.4 * width; + break; + case '2': + width = 0.12 * width; + break; + default: + break; + } + return width; + }) + .attr('height', function (d) { + let height = 20; + switch (d.type) { + case '1': + height = 3.5 * height; + break; + case '2': + height = 0.2 * height; + break; + default: + break; + } + return height; + }) + .attr('xlink:href', function (d) { + return imgmap[d.type]; + }); + + _g_nodes.append('text') + .text(function (d) { + return d.name; + }) + .style('transform', function (d) { + let x = null; + let y = null; + switch (d.type) { + case '1': + x = 7; + y = -7; + break; + case '2': + x = 1; + y = -2; + break; + default: + break; + } + return 'translate(' + x + '%,' + y + '%)'; + }) + .style('font-size', function (d) { + let size = 14; + switch (d.type) { + case '1': + size = 14; + break; + case '2': + size = 12; + break; + default: + break; + } + return size; + }) + .style('fill', function (d) { + let color = '#666'; + switch (d.type) { + case '1': + color = '#666'; + break; + case '2': + color = '#666'; + break; + default: + break; + } + return color; + }) + .style('font-weight', '500'); + + + //Add custom attributes online + _g_lines.each(function (d, i) { + let _this = d3.select(this); + if (d.name) { + _this.attr('data-text', d.name); + } + }); + + let force = d3.layout.force() + .size([1000, this.winHeight]) + .linkDistance(5) + // .theta(0.6) + .charge(charge) + .nodes(nodes) + .links(nodes) + .start(); + + force.on('tick', function () { + if (force.alpha() <= 0.04) { + + _g_nodes.style('display', function (d) { + let display = 'block'; + switch (d.type) { + case '1': + display = 'block'; + break; + case '2': + display = 'none'; + break; + default: + break; + } + return display; + }); + + nodes.forEach(function (d, i) { + d.x = d.x - 25 < 0 ? 25 : d.x; + d.x = d.x + 25 > width ? width - 25 : d.x; + d.y = d.y - 15 < 0 ? 15 : d.y; + d.y = d.y + 15 > height ? height - 15 : d.y; + }); + + _g_nodes.attr('transform', function (d) { + + let image = d3.select(this).select('image')[0][0], + halfWidth = parseFloat(image.attributes[0]['value']) / 2, + halfHeight = parseFloat(image.attributes[1]['value']) / 2; + let xx = d.x - halfWidth, + yy = d.y - halfHeight; + return 'translate(' + xx + ',' + yy + ')'; + }); + + _g_lines.select('line') + .attr('x1', function (d) { + return d.source.x; + }) + .attr('y1', function (d) { + return d.source.y; + }) + .attr('x2', function (d) { + return d.target.x; + }) + .attr('y2', function (d) { + return d.target.y; + }); + + _g_nodes.select('text').attr('dy', function (d) { + let image = this.previousSibling, + height = parseFloat(image.attributes[1]['value']), + fontSize = 12; + return height + 1.5 * fontSize; + }); + } + }); + + force.on('end', function () { + force.stop(); + if (dataCloud.length > 0) { + thiss.getoutCloud(dataCloud, imgmap); + } + thiss.getLinksData(); + thiss.addLinkDisabled = false; + }); + + }; + + //Topology drag and drop effect + getDragBehavior(force) { + + return d3.behavior.drag() + .origin(function (d) { + return d; + }) + .on('dragstart', dragstart) + .on('drag', dragging) + .on('dragend', dragend); + + function dragstart(d) { + d3.event.sourceEvent.stopPropagation(); + d3.select(this).classed('dragging', true); + force.start(); + } + + function dragging(d) { + d.x = d3.event.x; + d.y = d3.event.y; + } + + function dragend(d) { + d3.select(this).classed('dragging', false); + } + + } + + //Initialize node location + initPosition(datas) { + let origin = [this.tpoption.width / 2, this.tpoption.height / 2]; + let points = this.getVertices(origin, Math.min(this.tpoption.width / 2, this.tpoption.height / 2), datas.length); + datas.forEach((item, i) => { + item.x = points[i].x; + item.y = points[i].y; + }); + } + + //Get anchor points based on polygons + getVertices(origin, r, n) { + if (typeof n !== 'number') return; + let ox = origin[0]; + let oy = origin[1]; + let angle = 30 * n / n; + let i = 0; + let points = []; + let tempAngle = 0; + while (i < n) { + tempAngle = (i * angle * Math.PI) / 180; + points.push({ + x: ox - r * Math.sin(tempAngle), + y: oy - r * Math.cos(tempAngle), + }); + i++; + } + return points; + } + + //Rendering an external cloud + getoutCloud(dataCloud, imgmap) { + let _this = this, + width; + let networkId = dataCloud[0]['networkId']; + if (_this.tpoption.width > 800) { + width = _this.tpoption.width; + } else { + width = 800; + } + let svg = d3.select('#content-svg'); + svg.append('g').attr('class', 'out').attr('id', 'out').style({ 'display': 'block' }).attr('transform', 'translate(' + (width - 200) + ',0)'); + let out = d3.select('#out'); + out.append('image').style('width', '200').style('height', '118').attr('xlink:href', imgmap['3']); + out.append('text').text(networkId) + .style('transform', 'translate(0,0)') + .style('font-size', '16') + .style('font-weight', '400') + .attr('dx', '40') + .attr('dy', '70') + .style('fill', '#666'); + } + + //External cloud connection + getcloudLine(dataCloudLink) { + let textval = []; + textval[0] = dataCloudLink[0]['relationship-list']['relationship'][0]['relationship-data'][1]['relationship-value'];//tp1 + textval[1] = dataCloudLink[0]['relationship-list']['relationship'][1]['relationship-data'][1]['relationship-value'];//tp2 + textval[2] = dataCloudLink[0]['resource-version'];//version + textval[3] = dataCloudLink[0]['relationship-list']['relationship'][0]['relationship-data'][0]['relationship-value'];//node1 + textval[4] = dataCloudLink[0]['relationship-list']['relationship'][1]['relationship-data'][0]['relationship-value'];//node2 + textval[5] = dataCloudLink[0]['operational-status'];//status + textval[6] = dataCloudLink[0]['relationship-list']['relationship'][2]['relationship-data'][0]['relationship-value'];//aaiId + textval[7] = this.dataCloud[0]['networkId']; + let dataD3 = this.d3Data; + let arr = [ + textval[0], + textval[1] + ]; + for (let p = 0; p < dataD3.length; p++) {//Determine which Domain network the two tp ports belong to + for (let pp = 0; pp < arr.length; pp++) {//Determine which Domain network the two tp ports belong to + if (dataD3[p]['name'] == arr[pp]) { + textval[8] = dataD3[p]['source']['name'];//network1 + } + } + } + textval[9] = dataCloudLink[0]['link-name']; + let lines_json = {}; + let _this = this, + width; + if (_this.tpoption.width > 800) { + width = _this.tpoption.width; + } else { + width = 800; + } + for (let i = 0; i < $(".node").length; i++) { + if ($('.node').eq(i).find('text').html() == textval[8]) { + //Get the x, y coordinates of the second level + let translates = $('.node').eq(i).css('transform'); + lines_json['x1'] = parseFloat(translates.substring(7).split(',')[4]); + lines_json['y1'] = parseFloat(translates.substring(7).split(',')[5]); + lines_json['x2'] = width - 100; + lines_json['y2'] = 100; + } + } + let x1 = lines_json['x1']; + let y1 = lines_json['y1']; + let x2 = lines_json['x2']; + let y2 = lines_json['y2']; + let color = '#14bb58'; + if (textval[5] == 'up') { + color = '#14bb58'; + } else { + color = 'red'; + } + let line = '<line class=\'line cloudline line-click\' stroke=\'' + color + '\' stroke-width=\'2\' style=\'cursor:pointer\'></line>'; + let svg = d3.select('#graph'); + $('.cloudline').remove(); + $('#graph').prepend(line); + $('.cloudline').attr({ + x1: x1 + 100, + y1: y1 + 10, + x2: x2, + y2: y2, + 'data-tp1': textval[0], + 'data-tp2': textval[1], + 'data-version': textval[2], + 'data-node1': textval[3], + 'data-node2': textval[4], + 'data-network': textval[8], + 'data-cloudnetwork': textval[7], + 'data-url': '', + 'data-aaiid': textval[6], + 'data-link': textval[9], + }); + svg.html(svg.html()); + this.getCloudUrl(textval[6]); + this.getExtAAIIdVersion(textval[6]); + } + + + //Query external cloud host url address + getCloudUrl(aaiId) { + this.myhttp.queryCloudUrl(aaiId) + .subscribe((data) => { + this.delcloudUrl = data['service-url']; + $('.cloudline').attr({ + 'data-url': data['service-url'] + }); + }, (err) => { + console.log(err); + }); + } + + //Query external cloud ext-aai-id resource-version + getExtAAIIdVersion(aaiId) { + this.myhttp.queryExtAAIIdVersion(aaiId) + .subscribe((data) => { + this.delVersion = data["resource-version"]; + $('.cloudline').attr({ + 'data-version': data["resource-version"], + }); + }, (err) => { + console.log(err); + }); + } + + + //The right form drop-down box data is filled with three levels of linkage + //Left Port + network1Change(value: string): void { + this.selectedNode1 = this.nodeOption1[value][0]; + this.getPInterfaces1(); + } + + node1Change(): void { + this.getPInterfaces1(); + } + + //Get the TP data under the specified node + getPInterfaces1() { + let params = { + pnfName: this.selectedNode1, + }; + this.myhttp.getPInterfacesData(params) + .subscribe((data) => { + this.tpOption1 = []; + for (let i = 0; i < data.length; i++) { + let tpName = data[i]['interface-name']; + this.tpOption1.push(tpName); + } + this.selecteTpName1 = this.tpOption1[0]; + }, (err) => { + console.log(err); + }); + } + + //Right Port + network2Change(value: string): void { + this.selectedNode2 = this.nodeOption1[value][0]; + this.getPInterfaces2(); + } + + node2Change(): void { + this.getPInterfaces2(); + } + + //Get the TP data under the specified node + getPInterfaces2() { + let params = { + pnfName: this.selectedNode2, + }; + this.myhttp.getPInterfacesData(params) + .subscribe((data) => { + this.tpOption2 = []; + for (let i = 0; i < data.length; i++) { + let tpName = data[i]['interface-name']; + this.tpOption2.push(tpName); + } + this.selecteTpName2 = this.tpOption2[0]; + }, (err) => { + console.log(err); + }); + } + + //Submit form, connect + submitForm(): void { + //When the page ONAP is not selected, the local cloud TP connection + let _thiss = this; + if (this.inputshow == false) { + if (this.linkName == null || this.networkVal1 == null || this.selectedNode1 == null || this.selecteTpName1 == null || this.networkVal2 == null || this.selectedNode2 == null || this.selecteTpName2 == null) { + alert('The service port cannot be empty. Please select the port information.'); + return; + } else if (this.networkVal1 == this.networkVal2) { + alert('The TP port under the same cloud service cannot be connected!'); + return; + } + let tp_links = [], + tp1 = this.selecteTpName1, + tp2 = this.selecteTpName2; + for (let i = 0; i < $(".line-port").length; i++) { + let data_text1 = $('.line-port').eq(i).attr('data-tp1'); + let data_text2 = $('.line-port').eq(i).attr('data-tp2'); + tp_links.push(data_text1); + tp_links.push(data_text2); + } + if (tp_links.indexOf(tp1) != -1 || tp_links.indexOf(tp2) != -1) { + alert('This port number connection already exists!'); + return; + } + this.createTpLinks(); + + } else { + //When the page ONAP is selected, the external cloud is created, and the connection is made. + if (this.linkName == null || this.networkVal1 == null || this.selectedNode1 == null || this.selecteTpName1 == null || this.cloudUrl == null || this.cloudNetwork == null || this.cloudNode == null || this.cloudTp == null) { + alert('The service port cannot be empty. Please fill in the complete port information.'); + return; + } + let tp_links = [], + tp1 = this.selecteTpName1; + for (let i = 0; i < $(".line-port").length; i++) { + let data_text1 = $('.line-port').eq(i).attr('data-tp1'); + tp_links.push(data_text1); + } + if (tp_links.indexOf(tp1) != -1) { + alert('This port number connection already exists!'); + return; + } + + let time = this.cloudNetwork + new Date().getTime();//Create aaiid for the external cloud, this identifier is unique and cannot be repeated + this.createCloudUrls(time) + } + } + + //Create tp connection call interface createLink + createTpLinks() { + let params = { + 'link-name': this.linkName, + 'link-type': 'cross-link', + 'operational-status': 'up', + 'relationship-list': { + 'relationship': [ + { + 'related-to': 'p-interface', + 'related-link': '/aai/v14/network/pnfs/pnf/' + this.selectedNode1 + '/p-interfaces/p-interface/' + this.selecteTpName1, + 'relationship-data': [ + { + 'relationship-key': 'pnf.pnf-id', + 'relationship-value': this.selectedNode1 + }, + { + 'relationship-key': 'p-interface.p-interface-id', + 'relationship-value': this.selecteTpName1, + } + ] + }, + { + 'related-to': 'p-interface', + 'related-link': '/aai/v14/network/pnfs/pnf/' + this.selectedNode2 + '/p-interfaces/p-interface/' + this.selecteTpName2, + 'relationship-data': [ + { + 'relationship-key': 'pnf.pnf-id', + 'relationship-value': this.selectedNode2 + }, + { + 'relationship-key': 'p-interface.p-interface-id', + 'relationship-value': this.selecteTpName2 + } + ] + } + ] + } + }; + this.myhttp.createLink(params) + .subscribe((data) => { + if (data['status'] == 'SUCCESS') { + this.queryAddLink(); + } + }, (err) => { + console.log(err); + console.log('Create connection interface call failed'); + }); + } + + //Query the newly added connection immediately after creating the tp cable + queryAddLink() { + let linkName = this.linkName, + selecteTpName1 = this.selecteTpName1, + selecteTpName2 = this.selecteTpName2, + selectedNode1 = this.selectedNode1, + selectedNode2 = this.selectedNode2; + let params = { + 'link-name': linkName, + }; + this.myhttp.querySpecificLinkInfo(params) + .subscribe((data) => { + let version = data['resource-version'], + operational_status = data['operational-status'], + linkname = data['link-name']; + let textval = [selecteTpName1, selecteTpName2, version, selectedNode1, selectedNode2, operational_status, linkname]; + this.hideForm(); + this.chose(textval); + }, (err) => { + console.log(err); + }); + } + + //Connection between two TP coordinates + chose(textval) { + let lines_json = {}; + lines_json['tp1'] = textval[0]; + lines_json['tp2'] = textval[1]; + lines_json['version'] = textval[2]; + lines_json['node1'] = textval[3]; + lines_json['node2'] = textval[4]; + lines_json['status'] = textval[5]; + lines_json['linkname'] = textval[6]; + for (let i = 0; i < $(".node").length; i++) { + if ($('.node').eq(i).find('text').html() == textval[0]) { + $('.node').eq(i).show(); + //Get the x, y coordinates of the second level + let translates = $('.node').eq(i).css('transform'); + lines_json['x1'] = parseFloat(translates.substring(7).split(',')[4]); + lines_json['y1'] = parseFloat(translates.substring(7).split(',')[5]); + } + if ($('.node').eq(i).find('text').html() == textval[1]) { + $('.node').eq(i).show(); + let translates = $('.node').eq(i).css('transform'); + lines_json['x2'] = parseFloat(translates.substring(7).split(',')[4]); + lines_json['y2'] = parseFloat(translates.substring(7).split(',')[5]); + } + } + this.addLine(lines_json); + } + + //Connection between two TPs + addLine(lines) { + let tp1 = lines.tp1; + let tp2 = lines.tp2; + let version = lines.version; + let node1 = lines.node1; + let node2 = lines.node2; + let status = lines.status; + let linkname = lines.linkname; + let x1 = lines.x1; + let y1 = lines.y1; + let x2 = lines.x2; + let y2 = lines.y2; + let color = '#14bb58'; + if (status == 'up') { + color = '#14bb58'; + } else { + color = 'red'; + } + let line = '<line class=\'line line-port line-click\' stroke=\'' + color + '\' stroke-width=\'2\' style=\'cursor:pointer\'></line>'; + let svg = d3.select('#graph'); + $('#graph').prepend(line); + $('.line').first().attr({ + x1: x1, + y1: y1, + x2: x2, + y2: y2, + 'data-tp1': tp1, + 'data-tp2': tp2, + 'data-version': version, + 'data-node1': node1, + 'data-node2': node2, + 'data-link': linkname + }); + svg.html(svg.html()); + } + + //After creating an external cloud connection, query the connection immediately + queryOutCloudLink(time) { + let networkVal1 = this.networkVal1, + selectedNode1 = this.selectedNode1, + selecteTpName1 = this.selecteTpName1, + cloudUrl = this.cloudUrl, + cloudNetWork = this.cloudNetwork, + cloudNode = this.cloudNode, + cloudTp = this.cloudTp, + linkname = this.linkName; + let params = { + 'link-name': linkname, + }; + this.myhttp.querySpecificLinkInfo(params) + .subscribe((data) => { + let status = data['operational-status']; + let link_name = data['link-name']; + this.outCloudShow = true; + this.hideForm(); + this.outCloud(this.imgmap); + setTimeout(this.cloudLine(networkVal1, selectedNode1, selecteTpName1, cloudUrl, cloudNetWork, cloudNode, cloudTp, status, link_name, time), 0); + }, (err) => { + console.log(err); + }); + } + + //Add external cloud + outCloud(imgmap) { + let _this = this, + width; + if (_this.tpoption.width > 800) { + width = _this.tpoption.width; + } else { + width = 800; + } + let svg = d3.select('#content-svg'); + svg.append('g').attr('class', 'out').attr('id', 'out').style({ 'display': 'block' }).attr('transform', 'translate(' + (width - 200) + ',0)'); + let out = d3.select('#out'); + out.append('image').style('width', '200').style('height', '118').attr('xlink:href', imgmap['3']); + out.append('text').text('Partner Network') + .style('transform', 'translate(0,0)') + .style('font-size', '16') + .style('font-weight', 'bold') + .attr('dx', '40') + .attr('dy', '70') + .style('fill', '#fff'); + } + + //Add external cloud connection + cloudLine(networkVal1, selectedNode1, selecteTpName1, cloudUrl, cloudNetWork, cloudNode, cloudTp, status, link_name, time) { + let lines_json = {}; + let _this = this, + width; + if (_this.tpoption.width > 800) { + width = _this.tpoption.width; + } else { + width = 800; + } + for (let i = 0; i < $(".node").length; i++) { + if ($('.node').eq(i).find('text').html() == networkVal1) { + //Get the x, y coordinates of the second level + let translates = $('.node').eq(i).css('transform'); + lines_json['x1'] = parseFloat(translates.substring(7).split(',')[4]); + lines_json['y1'] = parseFloat(translates.substring(7).split(',')[5]); + lines_json['x2'] = width - 100; + lines_json['y2'] = 100; + } + } + let x1 = lines_json['x1']; + let y1 = lines_json['y1']; + let x2 = lines_json['x2']; + let y2 = lines_json['y2']; + let color = '#14bb58'; + if (status == 'up') { + color = '#14bb58'; + } else { + color = 'red'; + } + let line = '<line class=\'line cloudline line-click\' stroke=\'' + color + '\' stroke-width=\'2\' style=\'cursor:pointer\'></line>'; + let svg = d3.select('#graph'); + $('.cloudline').remove(); + $('#graph').prepend(line); + $('.cloudline').attr({ + x1: x1 + 100, + y1: y1 + 10, + x2: x2, + y2: y2, + 'data-tp1': selecteTpName1, + 'data-tp2': cloudTp, + 'data-node1': selectedNode1, + 'data-node2': cloudNode, + 'data-network': networkVal1, + 'data-cloudnetwork': cloudNetWork, + 'data-url': cloudUrl, + 'data-aaiid': time, + 'data-link': link_name + }); + svg.html(svg.html()); + this.getExtAAIIdVersion(time); + } + + //Create an external cloud, call the following 5 interfaces when connecting:createCloudNetwork,createPnfs,createCloudTp,createCloudLinks,createCloudUrls + createCloudNetwork(time) { + let _thiss = this; + let params = { + '-xmlns': 'http://org.onap.aai.inventory/v14', + 'in-maint': 'false', + "network-id": this.cloudNetwork, + "provider-id": "", + "client-id": "", + "te-topo-id": "", + "relationship-list": { + "relationship": [{ + "related-to": "ext-aai-network", + 'related-link': '/aai/v14/network/ext-aai-networks/ext-aai-network/' + time + }] + } + }; + + //Do some asynchronous operations + _thiss.myhttp.createNetwrok(params) + .subscribe((data) => { + if (data["status"] == "SUCCESS") { + _thiss.createPnfs(time) + } + }, (err) => { + console.log(err); + }); + + } + + createPnfs(time) { + let _thiss = this; + let params = { + "-xmlns": "http://org.onap.aai.inventory/v14", + "pnf-name": this.cloudNode, + "pnf-id": this.cloudNode, + "in-maint": "true", + "relationship-list": { + "relationship": [ + { + "related-to": "ext-aai-network", + "relationship-label": "org.onap.relationships.inventory.BelongsTo", + "related-link": "/aai/v14/network/ext-aai-networks/ext-aai-network/" + time, + "relationship-data": { + "relationship-key": "ext-aai-network.aai-id", + "relationship-value": time + } + }, + { + "related-to": "network-resource", + "relationship-label": "tosca.relationships.network.LinksTo", + "related-link": "/aai/v14/network/network-resources/network-resource/" + this.cloudNetwork + } + ] + } + }; + + //Do some asynchronous operations + _thiss.myhttp.createPnf(params) + .subscribe((data) => { + if (data["status"] == "SUCCESS") { + _thiss.createCloudTp(time) + } + }, (err) => { + console.log(err); + }); + } + + createCloudTp(time) { + let _thiss = this; + let params = { + "-xmlns": "http://org.onap.aai.inventory/v14", + "interface-name": this.cloudTp, + "speed-value": "1000000", + "in-maint": "true", + "network-ref": "", + "transparent": "true", + "operational-status": "up" + }; + + let cloudNodeName = this.cloudNode; + //Do some asynchronous operations + _thiss.myhttp.createTp(params, cloudNodeName) + .subscribe((data) => { + if (data["status"] == "SUCCESS") { + _thiss.createCloudLinks(time) + } + }, (err) => { + console.log(err); + }); + } + + createCloudLinks(time) { + let _thiss = this; + let params = { + "-xmlns": "http://org.onap.aai.inventory/v14", + "link-name": this.linkName, + "in-maint": "false", + "link-type": "cross-link", + "speed-value": "", + "operational-status": "up", + "relationship-list": { + "relationship": [ + { + "related-to": "p-interface", + "relationship-label": "tosca.relationships.network.LinksTo", + "related-link": "/aai/v14/network/pnfs/pnf/" + this.selectedNode1 + "/p-interfaces/p-interface/" + this.selecteTpName1, + "relationship-data": [ + { + "relationship-key": "pnf.pnf-name", + "relationship-value": this.selectedNode1 + }, + { + "relationship-key": "p-interface.interface-name", + "relationship-value": this.selecteTpName1 + } + ], + "related-to-property": [{ + "property-key": "p-interface.prov-status" + }] + }, + { + "related-to": "p-interface", + "relationship-label": "tosca.relationships.network.LinksTo", + "related-link": "/aai/v14/network/pnfs/pnf/" + this.cloudNode + "/p-interfaces/p-interface/" + this.cloudTp, + "relationship-data": [ + { + "relationship-key": "pnf.pnf-name", + "relationship-value": this.cloudNode + }, + { + "relationship-key": "p-interface.interface-name", + "relationship-value": this.cloudTp + } + ], + "related-to-property": [{ + "property-key": "p-interface.prov-status" + }] + }, + { + "related-to": "ext-aai-network", + "relationship-label": "org.onap.relationships.inventory.BelongsTo", + "related-link": "/aai/v14/network/ext-aai-networks/ext-aai-network/" + time, + "relationship-data": [ + { + "relationship-key": "ext-aai-network.aai-id", + "relationship-value": time + } + ] + } + ] + } + }; + + //Do some asynchronous operations + _thiss.myhttp.createCloudLink(params) + .subscribe((data) => { + // resolve(data['status']); + if (data["status"] == "SUCCESS") { + _thiss.queryOutCloudLink(time); + } + }, (err) => { + console.log(err); + }); + } + + createCloudUrls(time) { + let _thiss = this; + let params = { + '-xmlns': 'http://org.onap.aai.inventory/v14', + 'aai-id': time, + 'esr-system-info': { + 'esr-system-info-id': 'example-esr-system-info-id-val-0', + 'service-url': this.cloudUrl, + 'user-name': 'demo', + 'password': 'demo123456!', + 'system-type': 'ONAP' + } + }; + _thiss.myhttp.createCloudUrl(params) + .subscribe((data) => { + if (data['status'] == 'SUCCESS') { + _thiss.createCloudNetwork(time); + } + }, (err) => { + console.log(err); + }); + } + + //Local cloud TP port Delete connection Call interface deleteLink + delLink(): void { + let deltp1 = this.delTp1, + deltp2 = this.delTp2, + version = this.delVersion, + dellinkname = this.delLinkname, + delLinkIndex = this.delLinkIndex; + let params = { + 'logical-link': dellinkname, + 'resource-version': version, + }; + this.myhttp.deleteLink(params) + .subscribe((data) => { + if (data['status'] == 'SUCCESS') { + this.delLine(deltp1, deltp2); + delLinkIndex.remove(); + } + }, (err) => { + console.log(err); + console.log('Deleting a connection interface call failed'); + }); + } + + delLine(val1, val2) { + this.delBoxisVisible = false; + for (let i = 0; i < $(".node").length; i++) { + if ($('.node').eq(i).find('text').html() == val1) { + $('.node').eq(i).hide(); + } + if ($('.node').eq(i).find('text').html() == val2) { + $('.node').eq(i).hide(); + } + } + } + + + //External cloud Delete connection Call interface deleteCloudLink + delCloudLink(): void { + let deltp1 = this.delTp1, + deltp2 = this.delTp2, + version = this.delVersion, + aaiId = this.aaiId; + let params = { + "aaiId": aaiId, + "version": version, + }; + this.myhttp.deleteCloudLink(params) + .subscribe((data) => { + if (data['status'] == 'SUCCESS') { + this.delLine(deltp1, deltp2); + $('.cloudline').remove(); + $('#out').remove(); + } + }, (err) => { + console.log(err); + console.log('Deleting a connection interface call failed'); + }); + } + +} diff --git a/usecaseui-portal/src/app/views/network/mdons-network/mdons-network.component.html b/usecaseui-portal/src/app/views/network/mdons-network/mdons-network.component.html new file mode 100644 index 00000000..2fb79db1 --- /dev/null +++ b/usecaseui-portal/src/app/views/network/mdons-network/mdons-network.component.html @@ -0,0 +1,99 @@ +<!-- + Copyright (C) 2020 Fujitsu Network Communications, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<nz-spin nzTip="Loading resource details..." [nzSpinning]="isSpinning" nzSize="large"> +<div> + <h1>{{"i18nTextDefine_InterDomainTitle" | translate}}</h1> + <form id="createForm"> + <ul> + <li> + <label for="linkName"><span class="red-span">*</span>{{"i18nTextDefine_LinkName" | translate}}</label> + <input nz-input [(ngModel)]="linkName" name="linkName" maxlength="20" required> + </li> + <li> + <h2>{{"i18nTextDefine_NearEnd" | translate}} :</h2> + </li> + <li> + <label for="dm1"><span class="red-span">*</span>{{"i18nTextDefine_Domain" | translate}} 1</label> + <nz-select name="dm1" [(ngModel)]="dm1Selected" nzShowSearch nzAllowClear (ngModelChange)="dm1Change()"> + <nz-option *ngFor="let dm of dm1List" [nzValue]="dm.id" [nzLabel]="dm.name"></nz-option> + </nz-select> + </li> + <li> + <label for="ep1"><span class="red-span">*</span>{{"i18nTextDefine_Node" | translate}} 1</label> + <nz-select name="ep1" [disabled]="dm2Disable" [(ngModel)]="endPoint1Selected" nzShowSearch nzAllowClear (ngModelChange)="node1Change()"> + <nz-option *ngFor="let node of nodeList1" [nzValue]="node.id" [nzLabel]="node.name"></nz-option> + </nz-select> + </li> + <li> + <label for="nni1"><span class="red-span">*</span>{{"i18nTextDefine_Interface" | translate}} 1</label> + <nz-select name="nni1" [disabled]="dm2Disable" [(ngModel)]="pInterface1Selected" nzShowSearch nzAllowClear> + <nz-option *ngFor="let ip of pInterfaceList1" [nzValue]="ip.id" [nzLabel]="ip.name" ></nz-option> + </nz-select> + </li> + <li> + <h2>{{"i18nTextDefine_FarEnd" | translate}} :</h2> + </li> + <li> + <label for="dm2"><span class="red-span">*</span>{{"i18nTextDefine_Domain" | translate}} 2</label> + <nz-select name="dm2" [disabled]="dm2Disable" [(ngModel)]="dm2Selected" nzShowSearch nzAllowClear (ngModelChange)="dm2Change()"> + <nz-option *ngFor="let dm of dm2List" [nzValue]="dm.id" [nzLabel]="dm.name"></nz-option> + </nz-select> + </li> + <li> + <label for="ep2"><span class="red-span">*</span>{{"i18nTextDefine_Node" | translate}} 2</label> + <nz-select name="ep2" [disabled]="node2Disable || dm2Disable" [(ngModel)]="endPoint2Selected" nzShowSearch nzAllowClear (ngModelChange)="node2Change()"> + <nz-option *ngFor="let node of nodeList2" [nzValue]="node.id" [nzLabel]="node.name"></nz-option> + </nz-select> + </li> + <li> + <label for="nni2"><span class="red-span">*</span>{{"i18nTextDefine_Interface" | translate}} 2</label> + <nz-select name="nni2" [disabled]="node2Disable || dm2Disable" [(ngModel)]="pInterface2Selected" nzShowSearch nzAllowClear> + <nz-option *ngFor="let ip of pInterfaceList2" [nzValue]="ip.id" [nzLabel]="ip.name"></nz-option> + </nz-select> + </li> + <!-- future feature add <li> + <label nz-checkbox [(ngModel)]="messageShow" [ngModelOptions]="{standalone: true}"> Is External Network? </label> + </li> --> + </ul> + </form> + <div class="center"><span *ngIf="messageShow" class="red-span">{{"i18nTextDefine_ExternalNetworkMessage" | translate}}</span></div> + <button class="submit" [disabled]="isSpinning" nz-button nzType="primary" nzSize="small" (click)="submitForm()" [nzLoading]="isConfirmCreating" form="createForm"><span>{{"i18nTextDefine_CreateLink" | translate}}</span></button> + <button class="submit delete topright" nz-button nzType="primary" nzSize="small" (click)="showDelete()"><span>{{"i18nTextDefine_DeleteLink" | translate}}</span></button> +</div> +<nz-modal + [(nzVisible)]="delBoxisVisible" + [nzTitle]="modalTitle" + [nzContent]="modalContent" + [nzFooter]="modalFooter" + (nzOnCancel)="hideDel()"> + <ng-template #modalTitle> + <h2 class="red">{{"i18nTextDefine_DeleteLink" | translate}}</h2> + </ng-template> + <ng-template #modalContent> + <div> + <label for="delLinkName"><span class="red-span">*</span>{{"i18nTextDefine_LinkName" | translate}}</label> + <nz-select name="delLinkName" [(ngModel)]="logicalLinkSelected" nzShowSearch nzAllowClear> + <nz-option *ngFor="let ll of logicalLinkList" [nzValue]="ll.id" [nzLabel]="ll.name"></nz-option> + </nz-select> + </div> + </ng-template> + <ng-template #modalFooter> + <button class="delete" nz-button nzType="primary" (click)="delLink()" [nzLoading]="isConfirmDeleting">{{"i18nTextDefine_DeleteLink" | translate}}</button> + <button nz-button nzType="default" (click)="hideDel()">{{"i18nTextDefine_Cancel" | translate}}</button> + </ng-template> +</nz-modal> +</nz-spin>
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/network/mdons-network/mdons-network.component.less b/usecaseui-portal/src/app/views/network/mdons-network/mdons-network.component.less new file mode 100644 index 00000000..6a2465f4 --- /dev/null +++ b/usecaseui-portal/src/app/views/network/mdons-network/mdons-network.component.less @@ -0,0 +1,105 @@ +/* + Copyright (C) 2020 Fujitsu Network Communications, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.submit { + position: relative; + height:41px; + background:#0DA9E2; + border-radius:6px; + margin:auto;.red-span{ + color: red; + margin-right: 3px; + } + display: block; + span { + color: #fff; + font-weight: 400; + font-size: 18px; + } +} +.delete{ + background:rgb(185, 41, 15); + border-color:rgb(185, 41, 15); +} +.topright{ + position: absolute; + top: 0px; + right: 0px; +} +ul{ + margin-left: 30px; +} +ul li { + margin-bottom: 10px; + width: 50%; + margin-right: 5%; + float: left; + text-align: left; + input{ + width: 49%; + height: 27px; + float:right; + } +} +label { + display: inline-block; + width: 50%; + min-width: 80px; + font: 700 14px "Arial"; + overflow: hidden; + text-align: left; + word-break: break-all; + margin-top: 12px; +} +form{ + display: inline-block; + } + +.red{ + color: rgb(185, 41, 15); +} +.red-span{ + position: relative; + font: 700 14px "Arial"; + color: red; + margin: auto; +} +.center{ + display: flex; +} + +h1{ + background-color: #dce1e7; + text-align: center; +} +form .ant-select +{ + height: 27px; +} +.dropdown{ +overflow: visible; +} +.ant-modal{ + width: auto !important; +} +.ant-btn-danger{ + color: #fff; + background-color: #ff4d4f; + border-color: #ff4d4f; +} +div .ant-select +{ + width: 100%; +} diff --git a/usecaseui-portal/src/app/views/network/mdons-network/mdons-network.component.spec.ts b/usecaseui-portal/src/app/views/network/mdons-network/mdons-network.component.spec.ts new file mode 100644 index 00000000..59be9d0c --- /dev/null +++ b/usecaseui-portal/src/app/views/network/mdons-network/mdons-network.component.spec.ts @@ -0,0 +1,40 @@ +/* + Copyright (C) 2020 Fujitsu Network Communications, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MdonsNetworkComponent } from './mdons-network.component'; + +describe('MdonsNetworkComponent', () => { + let component: MdonsNetworkComponent; + let fixture: ComponentFixture<MdonsNetworkComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ MdonsNetworkComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MdonsNetworkComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/usecaseui-portal/src/app/views/network/mdons-network/mdons-network.component.ts b/usecaseui-portal/src/app/views/network/mdons-network/mdons-network.component.ts new file mode 100644 index 00000000..98f7b434 --- /dev/null +++ b/usecaseui-portal/src/app/views/network/mdons-network/mdons-network.component.ts @@ -0,0 +1,416 @@ +/* + Copyright (C) 2020 Fujitsu Network Communications, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +import { Component, OnInit, HostBinding, ViewChild } from '@angular/core'; +import { slideToRight } from '../../../shared/utils/animates'; +import { ServiceListService } from '../../../core/services/serviceList.service'; +import { networkHttpservice } from '../../../core/services/networkHttpservice.service'; +import { Observable } from 'rxjs'; +import { NzModalService } from 'ng-zorro-antd'; + +@Component({ + selector: 'app-mdons-network', + templateUrl: './mdons-network.component.html', + styleUrls: ['./mdons-network.component.less'], + animations: [slideToRight] +}) +export class MdonsNetworkComponent implements OnInit { + + @HostBinding('@routerAnimate') routerAnimateState; + @ViewChild('notification') notification: any; + + ngOnInit(): void { + //Load all the data + this.getAllResources().subscribe(() => { + this.getDomainList(); + }); + } + constructor(private serviceHttp: ServiceListService, private networkHttp: networkHttpservice,private modalService: NzModalService) + { + + } + + // variables + isSpinning = false; + messageShow = false; + dm2Disable=true; + node2Disable=true; + isConfirmCreating = false; + linkName = null; + data= []; + dataNNI=[] + dm1List = []; + dm1Selected = null; + dm2List = []; + dm2Selected = null; + nodeList1= []; + nodeList2= []; + endPoint1Selected = null; + endPoint2Selected = null; + pInterfaceList1= []; + pInterfaceList2= []; + pInterface1Selected = null; + pInterface2Selected = null; + logicalLinkList = []; + logicalLinkSelected=null; + isConfirmDeleting =null; + + delBoxisVisible = false; + + //Fetching All domains and nodes (ie. NNI Nodes) + getAllResources():Observable<boolean>{ + this.isSpinning = true; + return new Observable(observer => { + this.networkHttp.getNetworkD3Data() + .subscribe((data) => { + this.data=data.slice(); + if (data.length == 0) { + //write logic for error message + observer.error("No data avaliable"); + observer.complete(); + } + this.serviceHttp.getAllNI("NNI") + .subscribe((data) => { + this.dataNNI=data.slice(); + }, (err) => { + console.log(err); + }); + observer.next(true); + observer.complete(); + this.isSpinning = false; + }) + }) + } + + //get domain list + getDomainList(){ + for (let i = 0; i < this.data.length; i++) { + let dm = {}; + dm['id']=i; + dm['name']=this.data[i]['networkId']; + this.dm1List.push(dm); + } + this.dm2List=this.dm1List.slice(); + } + + //On change of domain 1 + dm1Change(): void { + this.dm2List=this.dm1List.slice(); + this.dm2Disable=true; + if(this.dm1Selected!=null){ + this.dm2Selected = null; + this.endPoint1Selected = null; + this.pInterface1Selected = null; + this.dm2List.splice(this.dm1Selected, 1); + this.dm2Disable=false; + this.getNodeList1(); + } + } + + //On change of domain 2 + dm2Change(): void { + this.node2Disable=true; + if(this.dm2Selected!=null){ + this.endPoint2Selected = null; + this.pInterface2Selected = null; + this.getNodeList2(); + this.node2Disable=false; + } + } + + //Fetch respective nodes for 1 + getNodeList1(){ + this.nodeList1=[]; + for (let i = 0; i < this.data[this.dm1Selected]["pnfs"].length; i++) { + let node={}; + node['id']=this.data[this.dm1Selected]['pnfs'][i]['pnfName']; + this.serviceHttp.getPnfDetail(this.data[this.dm1Selected]['pnfs'][i]['pnfName']) + .subscribe((data) => { + node['name']=data['pnf-id'] + }, (err) => { + console.log(err); + }); + this.nodeList1.push(node); + } + } + + //Fetch respective nodes for 1 + getNodeList2(){ + this.nodeList2=[]; + for (let i = 0; i < this.data[this.dm2Selected]["pnfs"].length; i++) { + let node={}; + node['id']=this.data[this.dm2Selected]['pnfs'][i]['pnfName']; + this.serviceHttp.getPnfDetail(this.data[this.dm2Selected]['pnfs'][i]['pnfName']) + .subscribe((data) => { + node['name']=data['pnf-id'] + }, (err) => { + console.log(err); + }); + this.nodeList2.push(node); + } + } + + //On change of node 1 + node1Change(): void { + this.pInterface1Selected = null; + this.getPInterfaces1(); + } + + //Get the Physical Interface data under the node 1 + getPInterfaces1() { + let params = { + pnfName: this.endPoint1Selected, + }; + this.networkHttp.getPInterfacesData(params) + .subscribe((data) => { + this.pInterfaceList1 = []; + let iplist=[]; + for (let i = 0; i < data.length; i++) { + let pi = {}; + this.dataNNI.find(function(element) { + if (element.includes(data[i]['interface-name'])) + { + pi['id']= data[i]['interface-name']; + pi['name']= element.replace(data[i]['interface-name'],""); + iplist.push(pi); + return true; + } + return false; + }) + } + this.pInterfaceList1=iplist.slice(); + }, (err) => { + console.log(err); + }); + } + + //On change of node 2 + node2Change(): void { + this.pInterface2Selected = null; + this.getPInterfaces2(); + } + + //Get the Physical Interface data under the node 2 + getPInterfaces2() { + let params = { + pnfName: this.endPoint2Selected, + }; + this.networkHttp.getPInterfacesData(params) + .subscribe((data) => { + this.pInterfaceList2 = []; + let iplist=[]; + for (let i = 0; i < data.length; i++) { + let pi = {}; + this.dataNNI.find(function(element) { + if (element.includes(data[i]['interface-name'])) + { + pi['id']= data[i]['interface-name']; + pi['name']= element.replace(data[i]['interface-name'],""); + iplist.push(pi); + return true; + } + return false; + }); + } + this.pInterfaceList2=iplist.slice(); + }, (err) => { + console.log(err); + }); + } + //Create Logical connection, call interface createLink + createLogicalLink() { + let params = { + 'link-name': this.linkName, + 'link-type': 'inter-domain', + 'operational-status': 'up', + 'relationship-list': { + 'relationship': [ + { + 'related-to': 'p-interface', + 'related-link': '/aai/v14/network/pnfs/pnf/' + this.endPoint1Selected + '/p-interfaces/p-interface/' + this.pInterface1Selected, + 'relationship-data': [ + { + 'relationship-key': 'pnf.pnf-id', + 'relationship-value': this.endPoint1Selected + }, + { + 'relationship-key': 'p-interface.p-interface-id', + 'relationship-value': this.pInterface1Selected, + } + ] + }, + { + 'related-to': 'p-interface', + 'related-link': '/aai/v14/network/pnfs/pnf/' + this.endPoint2Selected + '/p-interfaces/p-interface/' + this.pInterface2Selected, + 'relationship-data': [ + { + 'relationship-key': 'pnf.pnf-id', + 'relationship-value': this.endPoint2Selected + }, + { + 'relationship-key': 'p-interface.p-interface-id', + 'relationship-value': this.pInterface2Selected + } + ] + } + ] + } + }; + this.networkHttp.createLink(params) + .subscribe((data) => { + if (data['status'] == 'SUCCESS') { + this.queryLogicalLink(); + } + else if (data['status'] == 'FAILED') { + console.log("Link Creation Failed : ", data); + alert('\n\nLink Creation FAILED'); + this.isConfirmCreating=false; + } + }, (err) => { + console.log(err); + console.log('Create connection interface call failed'); + this.isConfirmCreating=false; + }); + } + + //Query the newly added connection immediately after creating the logical link + queryLogicalLink() { + let linkName = this.linkName; + let params = { + 'link-name': linkName, + }; + this.networkHttp.querySpecificLinkInfo(params) + .subscribe((data) => { + console.log("Created Link: ", data); + alert('\n\nLink Created With, \n\nName : ' + data['link-name'] + '\nResource version : ' + data['resource-version']); + + //Resetting the form + this.linkName = null; + this.dm1Selected = null; + this.dm2Selected = null; + this.endPoint1Selected = null; + this.endPoint2Selected = null; + this.pInterface1Selected = null; + this.pInterface2Selected = null; + this.dm2Disable=true; + this.node2Disable=true; + this.isConfirmCreating=false; + }, (err) => { + console.log(err); + }); + } + + //When the form is submitted + submitForm(){ + this.isConfirmCreating=true; + if (this.linkName == null ||this.linkName == ''|| this.dm1Selected == null || this.dm2Selected == null || this.endPoint1Selected == null || this.endPoint2Selected == null || this.pInterface1Selected == null || this.pInterface2Selected == null) { + alert('Mandatory fields cannot be empty. Please select the right information.'); + this.isConfirmCreating=false; + return; + } + else{ + this.createLogicalLink(); + } + } + + //Pop for confirming deletion + showDeleteConfirm(): void { + this.modalService.confirm({ + nzTitle: 'Confirm', + nzContent: '<b>Are you sure you want to delete the link?</b>', + nzOkText: 'Yes', + nzOkType: 'danger', + nzOnOk: () => this.deteleLink(), + nzCancelText: 'No' + }); + } + + //When detele link is clicked + showDelete(){ + this.getLinksData(); + this.delBoxisVisible = true; + } + + //Delete link validaton + delLink(){ + if (this.logicalLinkSelected===null || this.logicalLinkSelected.length===0) { + alert('Mandatory fields cannot be empty. Please select the right information.'); + return; + } + else{ + this.showDeleteConfirm(); + } + } + + //Delete link + deteleLink(){ + this.isConfirmDeleting = true; + let params = { + 'logical-link': this.logicalLinkList[this.logicalLinkSelected]['name'], + 'resource-version': this.logicalLinkList[this.logicalLinkSelected]['resourceVersion'], + }; + this.networkHttp.deleteLink(params) + .subscribe((data) => { + if (data['status'] == 'SUCCESS') { + alert('Link ' + this.logicalLinkList[this.logicalLinkSelected]['name'] + ' deleted successfully.'); + this.delBoxisVisible = false; + this.isConfirmDeleting = false; + this.logicalLinkSelected = null; + } + else if (data['status'] == 'FAILED') + { + this.isConfirmDeleting = false; + alert('Link deletion failed!'); + console.log("Response :", data); + console.log('Deleting the logical link failed'); + } + }, (err) => { + this.isConfirmDeleting = false; + alert('Link deletion failed!'); + console.log(err); + console.log('Deleting a connection interface call failed'); + }); + } + + //On cancel of deletion + hideDel(){ + this.delBoxisVisible=false; + } + + //Get Logical links + getLinksData() { + this.isSpinning = true; + this.logicalLinkList=[]; + this.networkHttp.getLogicalLinksData() + .subscribe((data) => { + let j = 0; + for (let i = 0; i < data['logical-link'].length; i++) { + if(data['logical-link'][i]['link-type']=="inter-domain"){ + let logicalLink = {}; + logicalLink['id']=j++; + logicalLink['resourceVersion']=data['logical-link'][i]['resource-version']; + logicalLink['name']=data['logical-link'][i]['link-name']; + this.logicalLinkList.push(logicalLink); + } + } + this.isSpinning = false; + }, (err) => { + alert('Fetching logical links failed!'); + console.log(err); + console.log('Fetching logical links failed!'); + this.isSpinning = false; + }) + } +} |