summaryrefslogtreecommitdiffstats
path: root/usecaseui-portal/src/app/views
diff options
context:
space:
mode:
Diffstat (limited to 'usecaseui-portal/src/app/views')
-rw-r--r--usecaseui-portal/src/app/views/alarm/alarm.component.css164
-rw-r--r--usecaseui-portal/src/app/views/alarm/alarm.component.html138
-rw-r--r--usecaseui-portal/src/app/views/alarm/alarm.component.less244
-rw-r--r--usecaseui-portal/src/app/views/alarm/alarm.component.spec.ts66
-rw-r--r--usecaseui-portal/src/app/views/alarm/alarm.component.ts301
-rw-r--r--usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.css321
-rw-r--r--usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.html275
-rw-r--r--usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.spec.ts24
-rw-r--r--usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.ts723
-rw-r--r--usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.css365
-rw-r--r--usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.html421
-rw-r--r--usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.spec.ts69
-rw-r--r--usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.ts815
-rw-r--r--usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.css119
-rw-r--r--usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.html152
-rw-r--r--usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.spec.ts40
-rw-r--r--usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.ts1270
-rw-r--r--usecaseui-portal/src/app/views/fcaps/fcaps.component.html3
-rw-r--r--usecaseui-portal/src/app/views/fcaps/fcaps.component.less0
-rw-r--r--usecaseui-portal/src/app/views/fcaps/fcaps.component.spec.ts25
-rw-r--r--usecaseui-portal/src/app/views/fcaps/fcaps.component.ts15
-rw-r--r--usecaseui-portal/src/app/views/home/home.component.css158
-rw-r--r--usecaseui-portal/src/app/views/home/home.component.html102
-rw-r--r--usecaseui-portal/src/app/views/home/home.component.less265
-rw-r--r--usecaseui-portal/src/app/views/home/home.component.spec.ts42
-rw-r--r--usecaseui-portal/src/app/views/home/home.component.ts531
-rw-r--r--usecaseui-portal/src/app/views/management/management.component.html39
-rw-r--r--usecaseui-portal/src/app/views/management/management.component.less79
-rw-r--r--usecaseui-portal/src/app/views/management/management.component.spec.ts25
-rw-r--r--usecaseui-portal/src/app/views/management/management.component.ts68
-rw-r--r--usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.css75
-rw-r--r--usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.html79
-rw-r--r--usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.less76
-rw-r--r--usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.spec.ts68
-rw-r--r--usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.ts159
-rw-r--r--usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.css126
-rw-r--r--usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.html63
-rw-r--r--usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.less136
-rw-r--r--usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.spec.ts45
-rw-r--r--usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.ts145
-rw-r--r--usecaseui-portal/src/app/views/performance/performance.component.css26
-rw-r--r--usecaseui-portal/src/app/views/performance/performance.component.html17
-rw-r--r--usecaseui-portal/src/app/views/performance/performance.component.less11
-rw-r--r--usecaseui-portal/src/app/views/performance/performance.component.spec.ts25
-rw-r--r--usecaseui-portal/src/app/views/performance/performance.component.ts16
-rw-r--r--usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.css67
-rw-r--r--usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.html333
-rw-r--r--usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.less182
-rw-r--r--usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.spec.ts25
-rw-r--r--usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.ts668
-rw-r--r--usecaseui-portal/src/app/views/services/services-list/services-list.component.css145
-rw-r--r--usecaseui-portal/src/app/views/services/services-list/services-list.component.html745
-rw-r--r--usecaseui-portal/src/app/views/services/services-list/services-list.component.less380
-rw-r--r--usecaseui-portal/src/app/views/services/services-list/services-list.component.spec.ts25
-rw-r--r--usecaseui-portal/src/app/views/services/services-list/services-list.component.ts1410
-rw-r--r--usecaseui-portal/src/app/views/services/services.component.html18
-rw-r--r--usecaseui-portal/src/app/views/services/services.component.less0
-rw-r--r--usecaseui-portal/src/app/views/services/services.component.spec.ts25
-rw-r--r--usecaseui-portal/src/app/views/services/services.component.ts15
59 files changed, 11964 insertions, 0 deletions
diff --git a/usecaseui-portal/src/app/views/alarm/alarm.component.css b/usecaseui-portal/src/app/views/alarm/alarm.component.css
new file mode 100644
index 00000000..25bf187e
--- /dev/null
+++ b/usecaseui-portal/src/app/views/alarm/alarm.component.css
@@ -0,0 +1,164 @@
+/*
+ Copyright (C) 2018 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.
+*/
+.title {
+ font: 700 18px/18px "思源黑体";
+ color: #4c5e70;
+ margin-bottom: 18px;
+}
+hr {
+ border: none;
+ height: 2px;
+ background-color: #dce1e7;
+ margin-bottom: 20px;
+}
+.select {
+ margin-bottom: 20px;
+}
+.select span {
+ display: inline-block;
+ font: 700 14px "Arial";
+ color: #4c5e70;
+}
+.select nz-dropdown {
+ vertical-align: middle;
+}
+.select nz-dropdown :hover {
+ border-color: #147dc2;
+}
+.select nz-dropdown button {
+ width: 165px;
+ height: 30px;
+ background-color: #eceff4;
+ text-align: left;
+ border-color: #9fa9ab;
+}
+.select nz-dropdown button span {
+ font-weight: 400;
+ display: inline-block;
+ width: 120px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ padding-top: 2px;
+}
+.select nz-dropdown button i {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+}
+.select .search {
+ margin-left: 20px;
+ height: 30px;
+ padding: 0 10px;
+}
+.select .search span {
+ color: #fff;
+ font-weight: 400;
+}
+.content .title {
+ border-radius: 5px 5px 0 0;
+ background-color: #fff;
+ height: 106px;
+ border-bottom: 1px solid #f0f0f0;
+ margin-bottom: 0;
+}
+.content .title ul {
+ display: flex;
+ display: -webkit-flex;
+ justify-content: space-around;
+ align-items: center;
+ padding: 0;
+ margin: 0;
+ height: 100%;
+}
+.content .title ul li {
+ list-style: none;
+ padding-left: 32px;
+ width: 100%;
+ border-left: 1px solid #eceff4;
+}
+.content .title ul li h5 {
+ font: 500 14px "Arial";
+ color: #3d4d65;
+}
+.content .title ul li p {
+ font: 500 24px "Arial";
+ color: #3fa8eb;
+ margin-bottom: 0;
+}
+.content .title ul li:nth-child(1) {
+ border: none;
+}
+.content .chart {
+ background-color: #fff;
+ position: relative;
+ padding-bottom: 24px;
+}
+.content .chart h3 {
+ font: 700 18px/18px "思源黑体";
+ color: #4c5e70;
+ padding: 20px 15px;
+ margin: 0;
+ width: 12%;
+ display: inline-block;
+}
+.content .chart .AlarmChart {
+ height: 0px;
+ overflow: hidden;
+ border-bottom: 1px solid #f5f5f5;
+ transition: all 0.3s linear;
+}
+.content .chart .alarmChart-active {
+ height: 386px;
+}
+.content .chart .open-close {
+ width: 50px;
+ height: 25px;
+ position: absolute;
+ left: 50%;
+ bottom: 0px;
+ transform: translate(-25px, 0);
+ border: none;
+ outline: none;
+ cursor: pointer;
+ background-color: #fff;
+ background: url(../../../assets/images/open-close.png) no-repeat center -27px;
+}
+.content .chart .open-close:hover {
+ background: url(../../../assets/images/open-close.png) no-repeat center -79px;
+}
+.content .chart .open-close-active {
+ background: url(../../../assets/images/open-close.png) center -1px;
+}
+.content .chart .open-close-active:hover {
+ background: url(../../../assets/images/open-close.png) no-repeat center -53px;
+}
+.content .tablelist {
+ background-color: #fff;
+ padding: 24px 10px 0px;
+ border-radius: 0 0 5px 5px;
+}
+.content .tablelist .action {
+ padding: 10px 0 0 20px;
+}
+.content .tablelist .action .details {
+ display: inline-block;
+ width: 16px;
+ height: 16px;
+ background: url(../../../assets/images/icon.png) center -113px;
+}
+.content .tablelist .action .details:hover {
+ background: url(../../../assets/images/icon.png) no-repeat center -128px;
+}
diff --git a/usecaseui-portal/src/app/views/alarm/alarm.component.html b/usecaseui-portal/src/app/views/alarm/alarm.component.html
new file mode 100644
index 00000000..312ec236
--- /dev/null
+++ b/usecaseui-portal/src/app/views/alarm/alarm.component.html
@@ -0,0 +1,138 @@
+<!--
+ 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.
+-->
+<h3 class="title"> <span (click)="detailHide()" style="cursor:pointer; float:right;" *ngIf="detailshow">Alarm</span> <span *ngIf="detailshow">Device Alarm Details</span> </h3>
+<div style="padding:0px 20px 20px 20px;">
+ <div class="charts" [@showHideAnimate]="state">
+ <div class="chartsleft">
+ <div class="active sctive_closed">
+ <div>Active</div>
+ <div>13,980</div>
+ <div><nz-progress [nzPercent]="30" [nzShowInfo]="false"></nz-progress></div>
+ <div>There are 13980 faults waiting to be solved</div>
+ </div>
+ <div class="closed sctive_closed">
+ <div>Closed</div>
+ <div>23,980</div>
+ <div><nz-progress [nzPercent]="50" [nzShowInfo]="false"></nz-progress></div>
+ <div>23,980 faults have been fixed</div>
+ </div>
+ </div>
+ <div class="chartsright">
+ <span>Daily Total</span>
+ <app-line [initData]="alarmChartInit" [chartData]="alarmChartData"></app-line>
+ </div>
+ </div>
+ <div class="select" [@showHideAnimate]="state">
+ <div class="query_criteria">
+ <div class="query_item">
+ <span>Source Name: </span>
+ <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomLeft'">
+ <button nz-button nz-dropdown><span>{{sourceNameSelected}}</span> <i class="anticon anticon-down"></i></button>
+ <ul nz-menu>
+ <li nz-menu-item (click)="choseSourceName(item)" *ngFor="let item of sourceNameList">
+ <a>{{item}}</a>
+ </li>
+ </ul>
+ </nz-dropdown>
+ </div>
+ <div class="query_item" style="margin-left: 1.5%;">
+ <span>Priority: </span>
+ <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomLeft'">
+ <button nz-button nz-dropdown><span>{{prioritySelected}}</span> <i class="anticon anticon-down"></i></button>
+ <ul nz-menu>
+ <li nz-menu-item (click)="chosePriority(item)" *ngFor="let item of priorityList">
+ <a>{{item}}</a>
+ </li>
+ </ul>
+ </nz-dropdown>
+ </div>
+ <div class="query_item" style="margin-left:-2%;">
+ <span>Status: </span>
+ <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomLeft'">
+ <button nz-button nz-dropdown><span>{{statusSelected}}</span> <i class="anticon anticon-down"></i></button>
+ <ul nz-menu>
+ <li nz-menu-item (click)="choseStatus(item)" *ngFor="let item of statusList">
+ <a>{{item}}</a>
+ </li>
+ </ul>
+ </nz-dropdown>
+ </div>
+ <div class="query_time" style="margin-left: -3%;">
+ <span>Report Time: </span>
+ <nz-range-picker [(ngModel)]="dateRange" (ngModelChange)="onChange($event)"
+ ></nz-range-picker>
+ <!-- <nz-range-picker [nzFormat]="dateFormat"></nz-range-picker> -->
+ </div>
+ <button class="search" nz-button [nzType]="'primary'" (click)="getAlarmFormData()"><i class="anticon anticon-search"></i><span>Search</span></button>
+ </div>
+ </div>
+ <div class="content" [@showHideAnimate]="state">
+ <!-- <div class="title">
+ <ul>
+ <li>
+ <h5>All</h5>
+ <p>{{alarmList.all }}</p>
+ </li>
+ <li>
+ <h5>Closed</h5>
+ <p>{{alarmList.closed }}</p>
+ </li>
+ <li>
+ <h5>Active</h5>
+ <p>{{alarmList.activeNum }}</p>
+ </li>
+ </ul>
+ </div> -->
+ <!-- <div class="chart">
+ <h3>Alarm Chart</h3>
+ <div class="AlarmChart" [ngClass]="{'alarmChart-active':alarmShow}">
+ <app-line [initData]="alarmChartInit" [chartData]="alarmChartData"></app-line>
+ </div>
+ </div> -->
+ <div class="tablelist">
+ <nz-table #nzTable [nzData]="list" [(nzPageSize)]="pageSize" nzShowSizeChanger nzShowQuickJumper
+ [nzPageSizeOptions]="[5,10,15,20]" nzSize="middle">
+ <thead (nzSortChange)="sort($event)" nzSingleSort>
+ <tr>
+ <th nzWidth="5%" style="padding-left:20px;">NO</th>
+ <th nzWidth="12%">Source Name</th>
+ <th nzWidth="7%">Priority</th>
+ <th nzWidth="18%">SpecificProblem</th>
+ <th nzWidth="15%">Report Time</th>
+ <th nzWidth="15%">Clear Time</th>
+ <th nzWidth="8%">Status</th>
+ <th nzWidth="10%">Action</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let item of nzTable.data; let i = index;">
+ <td style="padding-left: 20px;">{{i+1}}</td>
+ <td>{{item.sourceName}}</td>
+ <td>{{item.priority}}</td>
+ <td>{{item.specificProblem}}</td>
+ <td>{{item.startEpochMicrosec | date:'yyyy-MM-dd HH:mm:ss'}}</td>
+ <td>{{item.startEpochMicrosecCleared | date:'yyyy-MM-dd HH:mm:ss'}}</td>
+ <td>{{item.status}}</td>
+ <td class="action"><a (click)="detailShow(item)"><i class="details"></i></a></td>
+ </tr>
+ </tbody>
+ </nz-table>
+ </div>
+ </div>
+ <div [@showHideAnimate]="state2">
+ <app-details [detailId]="detailId"></app-details>
+ </div>
+</div> \ No newline at end of file
diff --git a/usecaseui-portal/src/app/views/alarm/alarm.component.less b/usecaseui-portal/src/app/views/alarm/alarm.component.less
new file mode 100644
index 00000000..92c9b7a4
--- /dev/null
+++ b/usecaseui-portal/src/app/views/alarm/alarm.component.less
@@ -0,0 +1,244 @@
+/*
+ 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.
+*/
+.title {
+ font: 500 16px/16px "ArialMT";
+ color: #3C4F8C;
+ margin: 20px;
+}
+hr {
+ border: none;
+ height: 2px;
+ background-color: #dce1e7;
+ margin-bottom: 20px;
+}
+.select {
+ margin-bottom: 15px;
+ width: 100%;
+ .query_criteria {
+ width: 100%;
+ .query_item {
+ width: 20%;
+ display: inline-block;
+ span {
+ display: inline-block;
+ font: 500 13px "ArialMT";
+ color: #3C4F8C;
+ }
+ nz-dropdown {
+ vertical-align: middle;
+ width: 55%;
+ :hover{
+ border-color: #48C6EF;
+ }
+ button {
+ width: 100%;
+ height: 30px;
+ background-color: #fff;
+ text-align: left;
+ border-color: #EEEEEE ;
+ border-radius: 2px;
+ span {
+ font-weight: 400;
+ color:rgba(60,79,140,0.5);
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ padding-top: 2px;
+ }
+ i {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ }
+ }
+ }
+ }
+
+ .query_time{
+ display: inline-block;
+ span {
+ font: 500 13px "ArialMT";
+ color: #3C4F8C;
+ }
+ }
+ .search {
+ margin-left: 0.8%;
+ height: 30px;
+ padding: 0 10px;
+ span {
+ color: #fff;
+ font-weight: 400;
+ }
+ }
+ }
+}
+.charts{
+ width: 100%;
+ height: 250px;
+ margin-bottom: 25px;
+ .chartsleft {
+ width: 30%;
+ height: 100%;
+ float: left;
+ margin-right: 2%;
+ color: #fff;
+ font-family:"ArialMT";
+ .sctive_closed {
+ height: 48.75%;
+ padding: 12px;
+ width: 100%;
+ :first-child{
+ font-size: 14px;
+ }
+ :nth-child(2) {
+ font-size: 18px;
+ }
+ :nth-child(3) {
+ font-size: 12px;
+ }
+ }
+ .active {
+ margin-bottom: 5px;
+ background: -webkit-linear-gradient(left, #FB7788 , #FB93C2); /* Safari 5.1 - 6.0 */
+ background: -o-linear-gradient(right, #FB7788, #FB93C2); /* Opera 11.1 - 12.0 */
+ background: -moz-linear-gradient(right, #FB7788, #FB93C2); /* Firefox 3.6 - 15 */
+ background: linear-gradient(to right, #FB7788 , #FB93C2); /* 标准的语法(必须放在最后) */
+ }
+ .closed {
+ margin-top: 2px;
+ background: -webkit-linear-gradient(left, #7A8BAE , #A6BFE4); /* Safari 5.1 - 6.0 */
+ background: -o-linear-gradient(right, #7A8BAE , #A6BFE4); /* Opera 11.1 - 12.0 */
+ background: -moz-linear-gradient(right, #7A8BAE , #A6BFE4); /* Firefox 3.6 - 15 */
+ background: linear-gradient(to right, #7A8BAE , #A6BFE4); /* 标准的语法(必须放在最后) */
+ }
+
+ }
+ .chartsright {
+ background-color: #fff;
+ width: 68%;
+ padding: 20px;
+ float: left;
+ height: 100%;
+ .picker {
+ float: right; margin-right: 3%;
+ }
+ .datapicker {
+ padding-left: 700px;
+ }
+ }
+}
+.content {
+ .title {
+ border-radius: 5px 5px 0 0;
+ background-color: #fff;
+ height: 106px;
+ border-bottom: 1px solid #f0f0f0;
+ margin-bottom: 0;
+ ul {
+ display: flex;
+ display: -webkit-flex;
+ justify-content: space-around;
+ align-items: center;
+ padding: 0;
+ margin: 0;
+ height: 100%;
+ li {
+ list-style: none;
+ padding-left: 32px;
+ width: 100%;
+ border-left: 1px solid #eceff4;
+ h5 {
+ font: 500 14px "Arial";
+ color: #3d4d65;
+ }
+ p {
+ font: 500 24px "Arial";
+ color: #3fa8eb;
+ margin-bottom: 0;
+ }
+ }
+ li:nth-child(1){
+ border: none;
+ }
+ }
+ }
+ .chart {
+ background-color: #fff;
+ position: relative;
+ padding-bottom: 24px;
+ h3 {
+ font: 700 18px/18px "思源黑体";
+ color: #4c5e70;
+ padding: 20px 15px;
+ margin: 0;
+ width: 12%;
+ display: inline-block;
+ }
+ .AlarmChart {
+ height: 0px;
+ overflow: hidden;
+ border-bottom: 1px solid #f5f5f5;
+ transition: all 0.3s linear;
+ }
+ .alarmChart-active {
+ height: 386px;
+ }
+ .open-close {
+ width: 50px;
+ height: 25px;
+ position: absolute;
+ left: 50%;
+ bottom: 0px;
+ transform: translate(-25px,0);
+ border: none;
+ outline: none;
+ cursor: pointer;
+ background-color: #fff;
+ background: url(../../../assets/images/open-close.png) no-repeat center -27px;
+ &:hover {
+ background: url(../../../assets/images/open-close.png) no-repeat center -79px;
+ }
+ }
+ .open-close-active {
+ background: url(../../../assets/images/open-close.png) center -1px;
+ &:hover {
+ background: url(../../../assets/images/open-close.png) no-repeat center -53px;
+ }
+ }
+ }
+ .tablelist {
+ // background-color: #fff;
+ // padding: 24px 10px 0px;
+ border-radius: 0 0 5px 5px;
+ .action{
+ padding: 10px 0 0 20px;
+ .details{
+ display: inline-block;
+ width: 16px;
+ height: 16px;
+ background: url(../../../assets/images/icon.png) center -113px;
+ &:hover {
+ background: url(../../../assets/images/icon.png) no-repeat center -128px;
+ }
+ }
+ }
+ }
+}
+
+
+
+
+
diff --git a/usecaseui-portal/src/app/views/alarm/alarm.component.spec.ts b/usecaseui-portal/src/app/views/alarm/alarm.component.spec.ts
new file mode 100644
index 00000000..9f01597e
--- /dev/null
+++ b/usecaseui-portal/src/app/views/alarm/alarm.component.spec.ts
@@ -0,0 +1,66 @@
+import { async, ComponentFixture, TestBed, inject, fakeAsync } from '@angular/core/testing';
+import { NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { NgxEchartsModule } from 'ngx-echarts';
+import { NgZorroAntdModule } from 'ng-zorro-antd';
+import { TranslateModule, TranslateLoader, TranslateService, TranslateFakeLoader } from '@ngx-translate/core';
+import { HttpClientModule } from '@angular/common/http';
+import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { NZ_I18N, en_US } from 'ng-zorro-antd';
+
+import { AlarmComponent } from './alarm.component';
+import { DetailsComponent } from '../../shared/components/details/details.component';
+import { LineComponent } from '../../shared/components/charts/line/line.component';
+import { HomesService } from '../../core/services/homes.service';
+
+fdescribe('AlarmComponent', () => {
+ let component: AlarmComponent;
+ let fixture: ComponentFixture<AlarmComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [AlarmComponent, DetailsComponent, LineComponent],
+ imports: [TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: TranslateFakeLoader } }),
+ NgZorroAntdModule.forRoot(),
+ NgxEchartsModule,
+ HttpClientModule,
+ BrowserAnimationsModule,
+ HttpClientTestingModule],
+ providers: [TranslateService, HomesService,
+ { provide: NZ_I18N, useValue: en_US }],
+ schemas: [
+ CUSTOM_ELEMENTS_SCHEMA,
+ NO_ERRORS_SCHEMA
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AlarmComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', inject([HttpTestingController, HomesService],
+ (httpMock: HttpTestingController, service: HomesService) => {
+ expect(component).toBeTruthy();
+ }));
+
+ it('expects service to fetch data with proper sorting',
+ inject([HttpTestingController, HomesService],
+ (httpMock: HttpTestingController, service: HomesService) => {
+ // We call the service
+ service.getqueryAllSourceNames().subscribe(data => {
+ expect(data.pageInfo.totalRecordCount).toBe(21);
+ expect(data.pageInfo.pageNumber).toBe(0);
+ expect(data.data.length).toBe(7);
+ });
+ // We set the expectations for the HttpClient mock
+ const req = httpMock.expectOne('http://.../data/contacts');
+ expect(req.request.method).toEqual('GET');
+ // Then we set the fake data to be returned by the mock
+ req.flush({ data: ...});
+ })
+ );
+});
diff --git a/usecaseui-portal/src/app/views/alarm/alarm.component.ts b/usecaseui-portal/src/app/views/alarm/alarm.component.ts
new file mode 100644
index 00000000..32e3456f
--- /dev/null
+++ b/usecaseui-portal/src/app/views/alarm/alarm.component.ts
@@ -0,0 +1,301 @@
+/*
+ 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, OnInit, Input, Output, EventEmitter, HostBinding, Pipe, PipeTransform } from '@angular/core';
+import { HomesService } from '../../core/services/homes.service';
+import { showHideAnimate, slideToRight } from '../../animates';
+import { DatePipe } from '@angular/common';
+@Component({
+ selector: 'app-alarm',
+ templateUrl: './alarm.component.html',
+ styleUrls: ['./alarm.component.less'],
+ animations: [
+ showHideAnimate, slideToRight
+ ],
+ providers: [DatePipe]
+})
+export class AlarmComponent implements OnInit {
+ size = 'day';
+ @HostBinding('@routerAnimate') routerAnimateState; //Routing animation
+ public currentPage: number = 1;
+ public pageSize: number = 10;
+ public sourceName: string = '';
+ public priority: string = '';
+ public startTime: string = this.myhttp.dateformater(Date.now() - 30 * 24 * 60 * 60 * 1000);
+ public endTime: string = this.datePipe.transform(new Date(), 'yyyy-MM-dd HH:mm:ss');
+ public vfStatus: string = '';
+ public sourceNameList: Array<any> = ['---auto---'];
+ list: any;
+ sourcenames: any;
+ constructor(
+ private datePipe: DatePipe,
+ private myhttp: HomesService) { }
+ ngOnInit() {
+ this.getAlarmFormData();
+ this.getSourceNames();
+
+ // this.getstatuscount();
+ }
+
+ // Filter box
+ sourceNameSelected = this.sourceNameList[0];
+
+ priorityList = ['---auto---', 'Critical', 'Major', 'Minor', 'Warning'];
+ prioritySelected = this.priorityList[0];
+
+
+ statusList = ['---auto---', 'active', 'Close'];
+ statusSelected = this.statusList[0];
+
+ choseSourceName(item) {
+ if (item == "---auto---") {
+ this.sourceName = '';
+ } else {
+ this.sourceName = item;
+ }
+ this.sourceNameSelected = item;
+
+ }
+ chosePriority(item) {
+ this.prioritySelected = item;
+ if (item == "---auto---") {
+ this.priority = '';
+ } else {
+ this.priority = item;
+ }
+ }
+ choseStatus(item) {
+ this.statusSelected = item;
+ if (item == "---auto---") {
+ this.vfStatus = '';
+ } else {
+ this.vfStatus = item;
+ }
+ }
+ getSourceNames() {
+ this.myhttp.getSourceNames().subscribe((data) => {
+ for (let i = 0; i < data.length; i++) {
+ this.sourceNameList.push(data[i]);
+ }
+ this.sourceNameSelected = this.sourceNameList[0];
+ })
+ }
+
+ // Date screening
+ dateRange = [(new Date(), -30), new Date()];
+ onChange(result: Date): void {
+ this.startTime = this.datePipe.transform(result[0], 'yyyy-MM-dd');
+ this.endTime = this.datePipe.transform(result[1], 'yyyy-MM-dd');
+ }
+ dateRange2 = [(new Date(), -30), new Date()];
+ onChange2(result: Date): void {
+ this.startTime = this.datePipe.transform(result[0], 'yyyy-MM-dd');
+ this.endTime = this.datePipe.transform(result[1], 'yyyy-MM-dd');
+ }
+
+ // total
+ alarmList = {
+ all: 0,
+ closed: 0,
+ activeNum: 0
+ }
+ // total data
+ // getstatuscount() {
+ // this.myhttp.getstatuscount().subscribe((data) => {
+ // this.alarmList.activeNum = data[0];
+ // this.alarmList.closed = data[1];
+ // this.alarmList.all = (data[0] - 0) + (data[1] - 0);
+
+ // })
+ // }
+ getAlarmFormData() {
+ this.myhttp.getAlarmFormData(this.currentPage, this.pageSize, this.sourceName, this.priority, this.startTime, this.endTime, this.vfStatus).subscribe((data) => {
+ this.list = data.alarms;
+ })
+ // this.getAlarmChartData(event);
+ }
+ getAlarmChartData() {
+ let paramsObj = {
+ // sourceName: this.sourceName,
+ // startTime: this.startTime,
+ // endTime: this.endTime,
+ // format: 'day'
+ }
+ this.myhttp.getHomeAlarmChartData(paramsObj)
+ .subscribe((data) => {
+ this.alarmChartData = {
+ xAxis: {
+ data: data.dateList
+ },
+ series: [
+ { data: data.allList },
+ { data: data.ActiveList },
+ ]
+ }
+ }, (err) => {
+ console.log(err);
+ })
+ }
+ // day alarmchartdata
+ // day() {
+ // let paramsObj = {
+ // sourceName: this.sourceName,
+ // startTime: this.startTime,
+ // endTime: this.endTime,
+ // format: "day"
+ // }
+ // this.myhttp.getHomeAlarmChartData(paramsObj)
+ // .subscribe((data) => {
+ // this.alarmChartData = {
+ // xAxis: {
+ // data: data.dateList
+ // },
+ // series: [
+ // { data: data.allList },
+ // { data: data.ActiveList },
+ // { data: data.closedList }
+ // ]
+ // }
+ // }, (err) => {
+ // console.log(err);
+ // })
+ // }
+ // month() {
+ // let paramsObj = {
+ // sourceName: this.sourceName,
+ // startTime: this.startTime,
+ // endTime: this.endTime,
+ // format: "month"
+ // }
+ // this.myhttp.getHomeAlarmChartData(paramsObj)
+ // .subscribe((data) => {
+ // this.alarmChartData = {
+ // xAxis: {
+ // data: data.dateList
+ // },
+ // series: [
+ // { data: data.allList },
+ // { data: data.ActiveList },
+ // { data: data.closedList }
+ // ]
+ // }
+ // }, (err) => {
+ // console.log(err);
+ // })
+ // }
+ //Line chart
+ alarmShow = false;
+ alarmChartData: Object;
+ alarmChartInit: Object = {
+ height: 200,
+ option: {
+ legend: {
+ icon: "circle",
+ itemWidth: 10,
+ itemHeight: 10,
+ bottom: '-5px',
+ data: ['Active', 'Fixed']
+ },
+ tooltip: {
+ trigger: 'axis',
+ },
+ dataZoom: [
+ {
+ type: 'slider',
+ show: true,
+ start: 1,
+ height: 10,
+ end: 60,
+ bottom: '9%'
+ }
+ ],
+ xAxis: {
+ data: []
+ },
+ series: [
+ {
+ name: 'Active',
+ type: 'bar',
+ data: [],
+ barWidth: 10,
+ barGap: 1,
+ itemStyle: {
+ normal: {
+ barBorderRadius: [5],
+ color: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [{
+ offset: 0, color: '#FB7788'
+ }, {
+ offset: 1, color: '#FB93C2'
+ }],
+ },
+ opacity: 1,
+ }
+ }
+ },
+ {
+ name: 'Fixed',
+ type: 'bar',
+ data: [],
+ barWidth: 10,
+ barGap: 1,
+ itemStyle: {
+ normal: {
+ barBorderRadius: [5],
+ color: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [{
+ offset: 0, color: '#7A8BAE'
+ }, {
+ offset: 1, color: '#A6BFE4'
+ }],
+ },
+ opacity: 1,
+ }
+ }
+ },
+ ]
+ }
+ };
+ sort(e) {
+
+ }
+ //Detail page title display
+ detailshow = false;
+ // Show hidden animation
+ state = "show";
+ state2 = "hide";
+ detailId: string;
+ detailShow(item) {
+ this.state = 'hide';
+ this.state2 = 'show';
+ this.detailshow = true;
+ this.detailId = item.id;
+ }
+ detailHide() {
+ this.state = 'show';
+ this.state2 = 'hide';
+ this.detailshow = false;
+ }
+}
diff --git a/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.css b/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.css
new file mode 100644
index 00000000..efeec683
--- /dev/null
+++ b/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.css
@@ -0,0 +1,321 @@
+/*
+ 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.
+*/
+.title {
+ font: 700 18px/18px "思源黑体";
+ color: #4c5e70;
+ margin-bottom: 18px;
+}
+hr {
+ border: none;
+ height: 2px;
+ background-color: #dce1e7;
+ margin-bottom: 10px;
+}
+.model {
+ background-color: #F7F8FC;
+ overflow-y: auto;
+}
+.creation-model{
+ position: relative;
+}
+.top-title{
+ width: 100%;
+ padding: 20px;
+ position: relative;
+ display: inline-block;
+}
+.model .back,.model .back:hover{
+ position: absolute;
+ top: 10px;
+ right: 20px;
+ display: inline-block;
+ width: 35px;
+ height: 35px;
+ background:url("../../../assets/images/Return-icon.png") no-repeat!important;
+ background-size: 100%!important;
+ border-radius:4px;
+ color: #D7D7D7;
+ cursor: pointer;
+}
+.model .back:hover{
+ background: url("../../../assets/images/Return-icon-active.png")!important;
+ background-size: 100%!important;
+}
+.top-title h3.title {
+ height: 35px;
+ width: 80%;
+ font-size:16px;
+ font-family:ArialMT;
+ color:#3C4F8C;
+ line-height:35px;
+ display: inline-block;
+
+}
+.model .submit{
+ position: absolute;
+ width:90px;
+ height: 35px;
+ top: 10px;
+ right: 85px;
+ color: #fff;
+ font-size: 18px;
+ background:#0DA9E2;
+ border-radius:4px;
+ border: none!important;
+ border-color:rgba(0,0,0,0)!important;
+}
+.model .submit:hover{
+ background:#09C6E2;
+ border: none;
+}
+.model .creation {
+ width: 100%;
+ overflow-y: auto;
+ border-radius: 5px;
+ padding: 15px;
+}
+.model .creation h3 {
+ height: 20px;
+ font: 700 16px/20px "Arial";
+ margin: 5px 0px;
+ color: #000;
+}
+/* SOTN VPN */
+.model .creation .service-title{
+ margin:60px 50px;
+}
+.model .creation .service-title .info-inputs{
+ width:400px;
+ height: 42px;
+ display: inline-block;
+}
+.model .creation .service-title span{
+ height: 42px;
+ line-height: 42px;
+ vertical-align: middle;
+}
+.model .creation .service-title .lable{
+ display: inline-block;
+ width: 100px;
+ font: 700 14px "Arial";
+ color: #3C4F8C;
+ height: 42px;
+ line-height: 42px;
+ vertical-align: middle;
+ margin-left: 5px;
+}
+.model .creation .service-title input {
+ width: 230px;
+ height: 42px;
+ border-radius:4px;
+ outline: none;
+ margin-right: 50px;
+}
+/* Site List */
+/* addsite model */
+.model .sitemodel,.model .sotnnpnmodel{
+ position: absolute;
+ z-index: 1001;
+ left: 50px;
+ top: 60px;
+ background-color: #fff;
+ width:1500px;
+ height: 81%;
+ border-radius:2px;
+ overflow:auto;
+}
+.model .sotnnpnmodel{
+ width: 1000px;
+ height: 53%;
+ top:200px;
+ left: 50%;
+ margin-left: -500px;
+}
+.model .sitemodel h3,.model .sotnnpnmodel h3{
+ width: 96%;
+ height: 40px;
+ line-height: 35px;
+ font-size: 18px;
+ font-weight: 500;
+ margin: 10px auto;
+ color: #06A7E2;
+ border-bottom: 2px solid;
+ border-image: -webkit-linear-gradient(#07A9E1,#30D9C4) 100 100;
+ border-image: -moz-linear-gradient(#07A9E1,#30D9C4) 100 100;
+ border-image: linear-gradient(#07A9E1,#30D9C4) 100 100;
+ border-radius:2px;
+}
+.model .sitemodel .inputs,.model .sotnnpnmodel .inputs {
+ padding: 10px 20px 0;
+}
+.model .sitemodel .inputs ul li,.model .sotnnpnmodel .inputs ul li {
+ display: inline-block;
+ height: 35px;
+ line-height: 35px;
+ width: 24.5%;
+ margin-bottom: 20px;
+}
+.model .sotnnpnmodel .inputs ul li{
+ width: 31%;
+}
+.model .sitemodel .inputs ul li span,.model .sotnnpnmodel .inputs ul li span {
+ display: inline-block;
+ line-height: 35px;
+ font-size: 14px;
+ font-weight: 500;
+ color: #3C4F8C;
+ margin-left: 10px;
+ vertical-align: middle;
+ float: left;
+}
+.model .sitemodel .inputs input,.model .sitemodel .inputs nz-select {
+ width: 186px;
+ float: right;
+ margin-right: 60px;
+}
+.model .sotnnpnmodel .inputs input{
+ width: 186px;
+ float: left;
+ margin-left: 20px;
+}
+.model .sitemodel .action,.model .sotnnpnmodel .action {
+ text-align: center;
+ margin-top: 30px;
+ margin-bottom: 20px;
+ cursor: pointer
+}
+.model .sotnnpnmodel .action{
+ margin-top: 70px;
+}
+.model .sitemodel .action button,.model .sotnnpnmodel .action button{
+ width: 126px;
+ height:40px;
+ background:#EEEEEE;
+ border-radius:2px;
+ border: none!important;
+ color: #9DA7C5;
+ font-size: 16px;
+ margin: 0 15px;
+}
+.model .sitemodel .action button:nth-child(2),.model .sotnnpnmodel .action button:nth-child(2){
+ background: #0DA9E2;
+ color: #fff;
+}
+.model .sitemodel .action button:nth-child(2):hover,.model .sotnnpnmodel .action button:nth-child(2):hover{
+ background:#09C6E2;
+}
+
+.model nz-table tbody td i.anticon:hover {
+ color: #3fa8eb;
+ cursor: pointer;
+}
+
+/* site table */
+.sitemodel h3 button,.sotnnpnmodel h3 button{
+ color: #D7D7D7;
+ width:32px;
+ height:32px;
+ background:#ffffff;
+ border-radius:4px;
+ border:1px solid #D7D7D7;
+}
+.sitemodel h3 button:hover,.sotnnpnmodel h3 button:hover{
+ background:#ffffff;
+ color: #0DA9E2;
+ border:1px solid #0DA9E2;
+}
+.sitemodel h3>button,.sotnnpnmodel h3>button{
+ float: right;
+ width: 30px;
+ height: 30px;
+ margin-right: 15px;
+}
+.model nz-table tbody th{
+ color:rgba(60,79,140,0.5);
+ font-size: 16px;
+}
+.model .site nz-table tbody td i.anticon:hover {
+ color: #3fa8eb;
+ cursor: pointer;
+}
+/* WAN Port */
+
+.mask{
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ z-index: 1000;
+ background: rgba(0, 0, 0, 0.65);
+ top:0;
+}
+
+
+/* chart */
+.model .chart {
+ width: 98%;
+ padding: 10px;
+ margin: 0 auto;
+ color: #06A7E2;
+ font-size: 16px;
+ font-weight: 500;
+ margin-bottom: 30px;
+ background: #EEF9FF;
+ border-radius:4px;
+}
+.model .chart #createChart {
+ width: 100%;
+ height: 220px;
+ margin-top: 20px;
+ position: relative;
+}
+.model .chart #createChart .siteNameP {
+ position: fixed;
+ border: 5px;
+ padding: 3px 5px;
+ color: #fff;
+ background: #999;
+ box-shadow: 0px 0px 20px #000;
+ max-width: 100px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.model .creation .sotnvpn,.model .creation .site{
+ background: #fff;
+ padding: 30px 30px 0 30px;
+}
+.siteWanTab{
+ width: 96%;
+ margin: 0 auto;
+ margin-top: 10px;
+}
+.siteWanTab th{
+ padding: 10px 8px;
+ color: #3C4F8C;
+ font-size: 16px;
+}
+.siteWanTab tr td{
+ padding: 10px 5px;
+}
+.siteWanTab .tr-border{
+ border-bottom: 1px solid #EDEDED;
+}
+.addListBtn{
+ margin-right: 30px;
+ color: #06A7E2;
+ border: none;
+ background: rgba(229,238,252,0.8);
+ cursor: pointer;
+} \ No newline at end of file
diff --git a/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.html b/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.html
new file mode 100644
index 00000000..1fc9a500
--- /dev/null
+++ b/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.html
@@ -0,0 +1,275 @@
+<!--
+ 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.
+-->
+<div class="model creation-model">
+
+ <div class="top-title">
+ <h3 class="title fl">{{createParams.commonParams.templateType}}
+ {{"i18nTextDefine_InstanceCreation" | translate}} </h3>
+ <div class="fl" style="width: 20%">
+ <button class="submit" nz-button (click)="submit()"><span> {{"i18nTextDefine_Create" | translate}} </span>
+ </button>
+ <button class="back" nz-button (click)="goback()"></button>
+ </div>
+ </div>
+ <!-- chart -->
+ <div class="chart">
+ <span style="padding: 25px;display: inline-block;">
+ {{"i18nTextDefine_InstanceTopology" | translate}}
+ </span>
+ <div id="createChart">
+ <svg width="100%" height="100%">
+ <image id="domain" xlink:href="assets/images/domain1.png" style="width: 15%" x="40%" y="0" />
+ </svg>
+ </div>
+ </div>
+ <!--Template resolution : Three major items-->
+ <div class="creation">
+ <nz-tabset [nzTabPosition]="'top'" [nzShowPagination]=false [nzTabBarGutter]="'2'" [nzTabBarStyle]=tabBarStyle>
+ <nz-tab nzTitle="Service Info">
+ <div class="service-title" style="clear: both">
+ <span style="color: red;">*</span><span class="lable" style="width: 60px">name:</span>
+ <input nz-input [(ngModel)]="this.templateParameters.service['name']" required="required">
+ <span style="color: red;">*</span><span class="lable">description:</span>
+ <input nz-input [(ngModel)]="this.templateParameters.service['description']">
+ </div>
+ </nz-tab>
+ <nz-tab nzTitle="Sdwanvpnresource List">
+ <div class="sotnvpn clearfix">
+ <div style="clear: both;height: 10px">
+ <h3 style="float: left;color: #3C4F8C">sdwanVPN List</h3>
+ <button nz-button (click)="addSotnvpn()" class="addListBtn"
+ style="float: right;margin-right: 10px"><i class="anticon anticon-plus"
+ style="transform: scale(1.2);font-weight: 700"></i> {{"i18nTextDefine_Add" | translate}}
+ </button>
+ </div>
+ <nz-table #sotnVpnTable [nzData]="sotnVpnTableData" [nzShowPagination]="false" nzSize="small">
+ <thead>
+ <tr>
+ <th width="30%"> NO.</th>
+ <th *ngFor="let key of getKeys(this.sotnInfo)">{{key.split("_")[1] || key}}</th>
+ <th width="10%"> Action</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let item of sotnVpnTable.data; let i = index; ">
+ <td>{{i+1}}</td>
+ <td *ngFor="let keys of getKeys(this.sotnInfo);let a = index;">
+ {{item[keys]}}
+ </td>
+ <td>
+ <span class="action" (click)="editSotnVpn(i+1)"><i
+ class="anticon anticon-edit"></i></span>
+ &nbsp;
+ <span class="action" (click)="deleteSotnVpn(i+1)"><i
+ class="anticon anticon-delete"></i></span>
+ </td>
+ </tr>
+ </tbody>
+ </nz-table>
+ </div>
+ </nz-tab>
+ <nz-tab nzTitle="Sdwansiteresource List">
+ <div class="site">
+ <div style="height: 10px">
+ <h3 style="float: left;color: #3C4F8C">Site List</h3>
+ <button nz-button (click)="addSite()" class="addListBtn"
+ style="float: right;margin-right: 10px"><i class="anticon anticon-plus"
+ style="transform: scale(1.2);font-weight: 700"></i>{{"i18nTextDefine_Add" | translate}}
+ </button>
+ </div>
+ <nz-table #siteTable [nzData]="siteTableData" [nzShowPagination]="false" nzSize="small">
+ <thead>
+ <tr>
+ <th nzWidth="10%"> NO.</th>
+ <th *ngFor="let key of getKeys(this.siteBaseData)">{{key.split("_")[1] || key}}</th>
+ <th nzWidth="20%" style="text-align: center"> Action</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let item of siteTable.data; let i = index; ">
+ <td>{{i+1}}</td>
+ <td *ngFor="let keys of getKeys(this.siteBaseData);let a = index;">
+ {{item[keys]}}
+ </td>
+ <td style="text-align: center">
+ <span class="action" (click)="editSite(i+1)"><i
+ class="anticon anticon-edit"></i></span>
+ &nbsp;
+ <span class="action" (click)="deleteSite(i+1)"><i
+ class="anticon anticon-delete"></i></span>
+ </td>
+ </tr>
+ </tbody>
+ </nz-table>
+ </div>
+ </nz-tab>
+ </nz-tabset>
+ </div>
+ <!-- sotnVpnmodel -->
+ <div class="sotnnpnmodel" *ngIf="sotnVpnModelShow">
+ <h3> {{"i18nTextDefine_Base" | translate}} </h3>
+ <div class="inputs">
+ <ul>
+ <li *ngFor="let item of this.templateParameters.sotnvpn.sdwanvpnresource_list">
+ <span *ngIf="item.required"
+ style="color: red;margin: 0;margin-right: -5px;">*</span><span>{{item.lableShow}}:</span>
+ <input nz-input [(ngModel)]="sotnInfo[item.lable]"
+ title="{{item.description ? item.description:null }}"
+ required="{{item.required==true ? 'required':null}}"></li>
+ </ul>
+ </div>
+ <div>
+ <h3>Sdwansitelan List</h3>
+ <div>
+ <div style="width: 100%;text-align: right">
+ <button nz-button (click)="addSotnSdwansitelan()" class="addListBtn"><i class="anticon anticon-plus"
+ style="transform: scale(1.2);font-weight: 700;"></i>{{"i18nTextDefine_Add" | translate}}
+ </button>
+ </div>
+ <table class="siteWanTab">
+ <thead>
+ <tr>
+ <th width="4%"> NO.</th>
+ <th *ngFor="let key of getKeys(this.sotnSdwansitelanParams)">{{key}}</th>
+ <th width="7%"> Action</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let item of sotnSdwansitelanData; let i = index;"
+ [ngClass]="{'tr-border':item.tabInputShowSdwansitelan ==false}">
+ <td>{{i+1}}</td>
+ <td *ngFor="let key of getKeys(item);let a = index;">
+ <span *ngIf="!tabInputShowSdwansitelan[i]"
+ title="{{this.templateParameters.sotnvpn.sdwansitelan_list[a]['lable']==getKeys(item)[a] ? this.templateParameters.site.sdwansitewan_list[a].description:null}}">{{item[key]}}</span>
+ <input nz-input [(ngModel)]="item[key]" *ngIf="tabInputShowSdwansitelan[i] "
+ title="{{this.templateParameters.sotnvpn.sdwansitelan_list[a]['lable']==getKeys(item)[a] ? this.templateParameters.site.sdwansitewan_list[a].description:null}}"
+ required="{{item.required==true ? 'required':null}}">
+ </td>
+ <td>
+ <span class="action" (click)="editSotnSdwansitelan(i+1,item,sotnSdwansitelanData)"><i
+ class="anticon anticon-edit" style="margin: 0 5px;"></i></span>
+ <span class="action" (click)="deleteSotnSdwansitelan(i+1,item,sotnSdwansitelanData)"><i
+ class="anticon anticon-delete"></i></span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+
+ <div class="action">
+ <button nz-button nzType="primary"
+ (click)="addSotnVpn_cancel()">{{"i18nTextDefine_Cancel" | translate}}</button>
+ <button nz-button nzType="primary" (click)="addSotnVpn_OK()">{{"i18nTextDefine_Add" | translate}}</button>
+ </div>
+ </div>
+ <!-- sitemodel -->
+ <div class="sitemodel" *ngIf="siteModelShow">
+ <h3> {{"i18nTextDefine_Base" | translate}} </h3>
+ <div class="inputs">
+ <ul>
+ <li *ngFor="let item of this.templateParameters.site.sdwansiteresource_list">
+ <span *ngIf="item.required"
+ style="color: red;margin: 0;margin-right: -5px;">*</span><span>{{item.lableShow}}:</span>
+ <input nz-input [(ngModel)]="siteBaseData[item.lable]" title="{{item.description}}"
+ required="{{item.required==true ? 'required':null}}"></li>
+ </ul>
+ </div>
+ <div>
+ <h3>Sdwandevice</h3>
+ <div>
+ <div style="width: 100%;text-align: right">
+ <button nz-button (click)="addSdwanDevice()" class="addListBtn"><i class="anticon anticon-plus"
+ style="transform: scale(1.2);font-weight: 700;"></i>{{"i18nTextDefine_Add" | translate}}
+ </button>
+ </div>
+ <table class="siteWanTab">
+ <thead>
+ <tr>
+ <th width="4%"> NO.</th>
+ <th *ngFor="let key of getKeys(this.siteCpeData)">{{key}}</th>
+ <th width="7%"> Action</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let item of siteSdwanDevice; let i = index;"
+ [ngClass]="{'tr-border':item.tabInputShowDevice ==false}">
+ <td>{{i+1}}</td>
+ <td *ngFor="let key of getKeys(item);let a = index;">
+ <span *ngIf="!tabInputShowDevice[i]"
+ title="{{this.templateParameters.site.sdwandevice_list[a]['lable']==getKeys(item)[a] ? this.templateParameters.site.sdwandevice_list[a].description:null}}">{{item[key]}}</span>
+ <input nz-input [(ngModel)]="item[key]" *ngIf="tabInputShowDevice[i] "
+ title="{{this.templateParameters.site.sdwandevice_list[a]['lable']==getKeys(item)[a] ? this.templateParameters.site.sdwandevice_list[a].description:null}}"
+ required="{{item.required==true ? 'required':null}}">
+ </td>
+ <td>
+ <span class="action" (click)="editDevicePort(i+1,item,siteSdwanDevice)"><i
+ class="anticon anticon-edit" style="margin: 0 5px;"></i></span>
+ <span class="action" (click)="deleteDevicePort(i+1,item,siteSdwanDevice)"><i
+ class="anticon anticon-delete"></i></span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
+
+ <h3>Sdwansitewan List</h3>
+ <div>
+ <div style="width: 100%;text-align: right">
+ <button nz-button (click)="addSiteWan()" class="addListBtn"><i class="anticon anticon-plus"
+ style="transform: scale(1.2);font-weight: 700;"></i>{{"i18nTextDefine_Add" | translate}}
+ </button>
+ </div>
+ <table class="siteWanTab">
+ <thead>
+ <tr>
+ <th width="4%"> NO.</th>
+ <th *ngFor="let key of getKeys(this.siteWanParams)">{{key}}</th>
+ <th width="7%"> Action</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let item of siteWanData; let i = index;"
+ [ngClass]="{'tr-border':item.tabInputShowWanPort ==false}">
+ <td>{{i+1}}</td>
+ <td *ngFor="let key of getKeys(item);let a = index;">
+ <span *ngIf="!tabInputShowWanPort[i]"
+ title="{{this.templateParameters.site.sdwansitewan_list[a]['lable']==getKeys(item)[a] ? this.templateParameters.site.sdwansitewan_list[a].description:null}}">{{item[key]}}</span>
+ <input nz-input [(ngModel)]="item[key]" *ngIf="tabInputShowWanPort[i] "
+ title="{{this.templateParameters.site.sdwansitewan_list[a]['lable']==getKeys(item)[a] ? this.templateParameters.site.sdwansitewan_list[a].description:null}}"
+ required="{{item.required==true ? 'required':null}}">
+ </td>
+ <td>
+ <span class="action" (click)="editWanPort(i+1,item,siteWanData)"><i
+ class="anticon anticon-edit" style="margin: 0 5px;"></i></span>
+ <span class="action" (click)="deleteWanPort(i+1,item,siteWanData)"><i
+ class="anticon anticon-delete"></i></span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+
+ <div class="action">
+ <button nz-button nzType="primary"
+ (click)="addsite_cancel()">{{"i18nTextDefine_Cancel" | translate}}</button>
+ <button nz-button nzType="primary" (click)="addsite_OK()">{{"i18nTextDefine_Add" | translate}}</button>
+ </div>
+ </div>
+ <div class="mask" *ngIf="siteModelShow || sotnVpnModelShow"></div>
+</div> \ No newline at end of file
diff --git a/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.spec.ts b/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.spec.ts
new file mode 100644
index 00000000..30402412
--- /dev/null
+++ b/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { CcvpnCreationComponent } from './ccvpn-creation.component';
+describe('CcvpnCreationComponent', () => {
+ let component: CcvpnCreationComponent;
+ let fixture: ComponentFixture<CcvpnCreationComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ CcvpnCreationComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CcvpnCreationComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.ts b/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.ts
new file mode 100644
index 00000000..214afbb7
--- /dev/null
+++ b/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.ts
@@ -0,0 +1,723 @@
+/*
+ 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, OnInit, Input, Output, EventEmitter } from '@angular/core';
+import * as d3 from 'd3';
+import * as $ from 'jquery';
+import { MyhttpService } from '../../core/services/myhttp.service';
+import { el } from "@angular/platform-browser/testing/src/browser_util";
+
+@Component({
+ selector: 'app-ccvpn-creation',
+ templateUrl: './ccvpn-creation.component.html',
+ styleUrls: ['./ccvpn-creation.component.css']
+})
+export class CcvpnCreationComponent implements OnInit {
+
+ constructor(private myhttp: MyhttpService) { }
+ @Input() createParams;
+ @Input() ccvpn_temParametersContent;
+ @Output() closeCreate = new EventEmitter();
+
+ ngOnInit() {
+ this.getccvpnTemParameters(this.ccvpn_temParametersContent);
+ }
+
+ //tabBarStyle
+ tabBarStyle = {
+ "height": "58px",
+ "width": "694px",
+ "box-shadow": "none",
+ "margin": "0",
+ "border-radius": "4px 4px 0px 0px"
+ };
+ templateParameters = {
+ service: {},
+ sotnvpn: {
+ info: {},
+ sdwanvpnresource_list: [],
+ sdwansitelan_list: []
+ },
+ site: {
+ info: {},
+ sdwansiteresource_list: [],
+ sdwandevice_list: [],
+ sdwansitewan_list: []
+ }
+ };
+
+ bodyTemplateParameter = {};
+
+ // SOTN VPN List
+ sotnVpnTableData = [];
+ sotnInfo = {};//sotnmodel The first part of sotnInfo
+ sotnSdwansitelanData = [];//sotnmodel The second part of the data sdwansitelan Table
+ sotnSdwansitelanParams = {};//sdwansitelan Table Detailed parameters of each line of data
+ tabInputShowSdwansitelan = [];//sdwansitelan Table input&span The status identifier of the label switching display
+ // Site List
+ siteTableData = [];
+ siteBaseData = {}; //sitemodel one sdwansiteresource_list
+ // cpe
+ siteSdwanDevice = []; //sitemodel SdwanDevice port Table data
+ siteCpeData = {}; //sitemodel two sdwandevice_list
+ tabInputShowDevice = [];//Device port Table input和span The status identifier of the label switching display
+ // Wan Port
+ siteWanData = []; //sitemodel three wan port Table data
+ siteWanParams = {}; //wan port Table Detailed parameters of each line of data
+ tabInputShowWanPort = [];//wan port Table input和span The status identifier of the label switching display
+ getKeys(item) {
+ return Object.keys(item);
+ }
+
+ getccvpnTemParameters(data) { //Get template parameters
+ console.log(this.createParams);
+ if (typeof data["model"] == 'string') {
+ data = JSON.parse(data["model"]);
+ }
+ console.log(data);
+ let inputss = data["inputs"];
+ let inputs = {};
+ this.templateParameters.service = {
+ name: data.metadata["name"],
+ description: data.metadata.description,
+ serviceInvariantUuid: data.metadata.invariantUUID,
+ serviceUuid: data.metadata.UUID
+ };
+
+ //Screening separation sotnvpn data
+ Object.keys(inputss).map((items) => {
+ if (items.search("vpn") != -1) {
+ this.bodyTemplateParameter[items] = [];
+ inputss[items].map((item, index) => {
+ if (item["required"] != undefined) {
+ this.templateParameters["sotnvpn"]["sdwanvpnresource_list"].push(item);
+ }
+ if (item["required"] == undefined && Object.keys(item).length == 1 && Object.keys(item)[0].search("site") != -1 && item[Object.keys(item)[0]] instanceof Array === true) {
+ this.templateParameters["sotnvpn"]["sdwansitelan_list"] = item[Object.keys(item)[0]]
+ let sitelanKey = {};
+ sitelanKey[Object.keys(item)[0]] = [];
+ this.bodyTemplateParameter[items].push(sitelanKey);
+ }
+ });
+ }
+ if (items.search("site") != -1) {
+ this.bodyTemplateParameter[items] = [];
+ inputss[items].map((item, index) => {
+ if (item["required"] != undefined) {
+ this.templateParameters["site"]["sdwansiteresource_list"].push(item);
+ }
+ if (item["required"] == undefined && Object.keys(item).length == 1 && Object.keys(item)[0].search("device") != -1 && item[Object.keys(item)[0]] instanceof Array === true) {
+ this.templateParameters["site"]["sdwandevice_list"] = item[Object.keys(item)[0]];
+ let sitelanKey = {};
+ sitelanKey[Object.keys(item)[0]] = [];
+ this.bodyTemplateParameter[items].push(sitelanKey);
+ }
+ if (item["required"] == undefined && Object.keys(item).length == 1 && Object.keys(item)[0].search("site") != -1 && Object.keys(item)[0].search("device") == -1 && item[Object.keys(item)[0]] instanceof Array === true) {
+ this.templateParameters["site"]["sdwansitewan_list"] = item[Object.keys(item)[0]];
+ let sitelanKey = {};
+ sitelanKey[Object.keys(item)[0]] = [];
+ this.bodyTemplateParameter[items].push(sitelanKey);
+ }
+ });
+ }
+ });
+ this.showTemParametersSotnVpn();
+ this.showTemParametersSite();
+ console.log(this.bodyTemplateParameter, this.templateParameters)
+ }
+
+ //sotnVpn data, after combining the structure, rendering the template data to the page
+ showTemParametersSotnVpn() {
+ //sotn Data analysis, structure assembly
+ this.templateParameters.sotnvpn.sdwanvpnresource_list.map((item, index) => {
+ let input = {};
+ for (var keys in item) {
+ if (keys != "required" && keys != "type" && keys != "description") {
+ input[keys] = item[keys];
+ item["lable"] = keys;
+ item["lableShow"] = keys.split("_")[1];
+ this.sotnInfo = Object.assign(this.sotnInfo, input);
+ }
+ }
+ });
+
+ this.templateParameters.sotnvpn.sdwansitelan_list.map((item, index) => {
+ let input = {};
+ for (var keys in item) {
+ if (keys != "required" && keys != "type" && keys != "description") {
+ input[keys] = item[keys];
+ item["lable"] = keys;
+ this.sotnSdwansitelanParams = Object.assign(this.sotnSdwansitelanParams, this.sotnSdwansitelanParams, input);
+ }
+ }
+ });
+ this.sotnSdwansitelanData.push(this.sotnSdwansitelanParams);
+ this.sotnSdwansitelanData.map((item, index) => {
+ this.tabInputShowSdwansitelan[index] = true;
+ });
+ }
+
+ //Site data, after combining the structure, rendering the template to the page
+ showTemParametersSite() {
+ //site Data analysis, structure assembly
+ this.templateParameters.site.sdwansiteresource_list.map((item, index) => {
+ let input = {};
+ for (var keys in item) {
+ if (keys != "required" && keys != "type" && keys != "description") {
+ input[keys] = item[keys];
+ item["lable"] = keys;
+ item["lableShow"] = keys.split("_")[1];
+ this.siteBaseData = Object.assign(this.siteBaseData, input);
+ }
+ }
+ });
+
+ this.templateParameters.site.sdwandevice_list.map((item, index) => {
+ let input = {};
+ for (var keys in item) {
+ if (keys != "required" && keys != "type" && keys != "description") {
+ input[keys] = item[keys];
+ item["lable"] = keys;
+ this.siteCpeData = Object.assign(this.siteCpeData, input);
+ }
+ }
+ });
+ this.templateParameters.site.sdwandevice_list.map((item, index) => {
+ if (this.getKeys(item).indexOf("lable") == -1) {
+ this.templateParameters.site.sdwandevice_list.splice(index, 1)
+ }
+ });
+ this.templateParameters.site.sdwansitewan_list.push(
+ {
+ ipMode: "",
+ description: ""
+ },
+ {
+ publicIP: "",
+ description: ""
+ }
+ );
+
+ this.templateParameters.site.sdwansitewan_list.map((item, index) => {
+ let input = {};
+ for (var keys in item) {
+ if (keys != "required" && keys != "type" && keys != "description") {
+ input[keys] = item[keys];
+ item["lable"] = keys;
+ this.siteWanParams = Object.assign(this.siteWanParams, this.siteWanParams, input);
+ }
+ }
+ });
+ this.siteSdwanDevice.push(this.siteCpeData);
+ this.siteWanData.push(this.siteWanParams);
+ this.siteWanData.map((item, index) => {
+ this.tabInputShowDevice[index] = true;
+ });
+ this.siteWanData.map((item, index) => {
+ this.tabInputShowWanPort[index] = true;
+ });
+
+ }
+
+ //add,edit,delete sotnSdwansitelan
+ addSotnSdwansitelan() {
+ if (this.tabInputShowSdwansitelan.indexOf(true) > -1) {//Adding new rows is not allowed when there is a row of data being edited
+ return false;
+ }
+ let addNum = this.sotnSdwansitelanData.length;
+ let inputsData = Object.assign({}, this.sotnSdwansitelanParams);
+ Object.keys(inputsData).forEach((item) => {//Add a new line of empty data
+ if (item != "description") {
+ inputsData[item] = null;
+ }
+ });
+ this.sotnSdwansitelanData[addNum] = inputsData;
+ this.tabInputShowSdwansitelan[addNum] = true;
+ this.sotnSdwansitelanData = [...this.sotnSdwansitelanData]; //Table refresh
+ }
+ editSotnSdwansitelan(num, item, sotnSdwansitelanData) {
+ if (this.tabInputShowSdwansitelan[num - 1] == false) {
+ this.tabInputShowSdwansitelan[num - 1] = true;
+ } else {
+ this.tabInputShowSdwansitelan[num - 1] = false;
+ }
+ }
+ deleteSotnSdwansitelan(num, item, sotnSdwansitelanData) {
+ if (this.sotnSdwansitelanData.length <= 1) {
+ return false;
+ } else {
+
+ }
+ this.sotnSdwansitelanData = this.sotnSdwansitelanData.filter((d, i) => i !== num - 1);
+ }
+
+ //add,edit,delete SdwanDevice
+ addSdwanDevice() {
+ if (this.tabInputShowDevice.indexOf(true) > -1) {//当有正在编辑的一行数据时,不允许添加新的行
+ return false;
+ }
+ let addNum = this.siteSdwanDevice.length;
+ let inputsData = Object.assign({}, this.siteCpeData);
+ Object.keys(inputsData).forEach((item) => {//新增一行空数据
+ if (item != "description") {
+ inputsData[item] = null;
+ }
+ });
+ this.siteSdwanDevice[addNum] = inputsData;
+ this.tabInputShowDevice[addNum] = true;
+ this.siteSdwanDevice = [...this.siteSdwanDevice]; //表格刷新
+ }
+
+ editDevicePort(num, item, siteSdwanDevice) {
+ if (this.tabInputShowDevice[num - 1] == false) {
+ this.tabInputShowDevice[num - 1] = true;
+ } else {
+ this.tabInputShowDevice[num - 1] = false;
+ }
+ }
+
+ deleteDevicePort(num, item, siteSdwanDevice) {
+ if (this.siteSdwanDevice.length <= 1) {
+ return false;
+ }
+ this.siteSdwanDevice = this.siteSdwanDevice.filter((d, i) => i !== num - 1);
+ }
+
+ //add,edit,delete siteWanPort
+ addSiteWan() {
+ if (this.tabInputShowWanPort.indexOf(true) > -1) {//Adding new rows is not allowed when there is a row of data being edited
+ return false;
+ }
+ let addNum = this.siteWanData.length;
+ let inputsData = Object.assign({}, this.siteWanParams);
+ Object.keys(inputsData).forEach((item) => {//Add a new line of empty data
+ if (item != "description") {
+ inputsData[item] = null;
+ }
+ });
+ this.siteWanData[addNum] = inputsData;
+ this.tabInputShowWanPort[addNum] = true;
+ this.siteWanData = [...this.siteWanData]; //Table refresh
+ }
+ editWanPort(num, item, siteWanData) {
+ if (this.tabInputShowWanPort[num - 1] == false) {
+ this.tabInputShowWanPort[num - 1] = true;
+ } else {
+ this.tabInputShowWanPort[num - 1] = false;
+ }
+ }
+ deleteWanPort(num, item, siteWanData) {
+ if (this.siteWanData.length <= 1) {
+ return false;
+ }
+ this.siteWanData = this.siteWanData.filter((d, i) => i !== num - 1);
+ }
+
+ //siteModel,sotnVpnModel Display sign
+ siteModelShow = false;
+ sotnVpnModelShow = false;
+ addSotnvpn() {
+ this.sotnVpnModelShow = true;
+ this.isEditSotnVpn = 0;
+ }
+ addSite() {
+ this.siteModelShow = true;
+ this.isEditSite = 0;
+ }
+
+ //add sotnVpn model
+ isEditSotnVpn = 0;//Edit serial number, No value, 0 means increase
+ addSotnVpn_OK() {
+ let inputs = {
+ "sdwansitelan_list": []
+ };
+ inputs = Object.assign(inputs, this.sotnInfo);
+ inputs["sdwansitelan_list"] = this.sotnSdwansitelanData.map((item) => {
+ return Object.assign({}, item);
+ });
+ if (this.isEditSotnVpn) {
+ // Edit status does not increase
+ this.sotnVpnTableData[this.isEditSotnVpn - 1] = inputs;
+ this.sotnVpnTableData = [...this.sotnVpnTableData]; //Table refresh
+ } else {
+ this.sotnVpnTableData = [...this.sotnVpnTableData, inputs];
+ }
+ Object.keys(this.sotnInfo).forEach((item) => { //Clear modal box
+ this.sotnInfo[item] = null;
+ });
+ this.sotnSdwansitelanData.forEach((item, index) => {
+ if (index > 0) {
+ this.sotnSdwansitelanData.splice(index, 1);
+ this.tabInputShowSdwansitelan.splice(index, 1);
+ } else {
+ Object.keys(item).forEach((item2) => {
+ item[item2] = null;
+ });
+ this.tabInputShowSdwansitelan[index] = true;
+ }
+
+ });
+ this.sotnVpnModelShow = false;
+ }
+
+ addSotnVpn_cancel() {
+ Object.keys(this.sotnInfo).forEach((item) => { //Clear modal box
+ this.sotnInfo[item] = null;
+ });
+ this.sotnSdwansitelanData.forEach((item, index) => {
+ if (index > 0) {
+ this.sotnSdwansitelanData.splice(index, 1);
+ } else {
+ Object.keys(item).forEach((item2) => {
+ item[item2] = null;
+ });
+ this.tabInputShowSdwansitelan[index] = true;
+ }
+
+ });
+ this.sotnVpnModelShow = false;
+ }
+
+ editSotnVpn(num) {
+ this.sotnVpnModelShow = true;
+ this.isEditSotnVpn = num;
+ Object.keys(this.sotnInfo).forEach((item) => { //Clear modal box
+ this.sotnInfo[item] = this.sotnVpnTableData[num - 1][item];
+ });
+ this.sotnSdwansitelanData = this.sotnVpnTableData[num - 1].sdwansitelan_list.map((item) => {
+ return Object.assign({}, {}, item)
+ });
+ this.sotnSdwansitelanData.forEach((item, index) => {
+ this.tabInputShowSdwansitelan[index] = false;
+ });
+ }
+
+ deleteSotnVpn(num) {
+ this.sotnVpnTableData = this.sotnVpnTableData.filter((d, i) => i !== num - 1);
+ }
+
+ // addsite model
+ isEditSite = 0; //Edit serial number, No value, 0 means increase
+ addsite_OK() {
+ let inputs = {
+ "sdwandevice_list": [],
+ "sdwansitewan_list": []
+ };
+ inputs = Object.assign(inputs, this.siteBaseData);
+ inputs["sdwandevice_list"] = this.siteSdwanDevice.map((item) => {
+ return Object.assign({}, item);
+ });
+ inputs["sdwansitewan_list"] = this.siteWanData.map((item) => {
+ return Object.assign({}, item);
+ });
+ if (this.isEditSite) {
+ // Edit status does not increase
+ this.siteTableData[this.isEditSite - 1] = inputs;
+ this.siteTableData = [...this.siteTableData]; //Table refresh
+ } else {
+ this.siteTableData = [...this.siteTableData, inputs];
+ }
+
+ Object.keys(this.siteBaseData).forEach((item) => { //Clear modal box
+ this.siteBaseData[item] = null;
+ });
+ this.siteSdwanDevice.forEach((item, index) => {
+ if (index > 0) {
+ this.siteSdwanDevice.splice(index, 1);
+ this.tabInputShowDevice.splice(index, 1);
+ } else {
+ Object.keys(item).forEach((item2) => {
+ item[item2] = null;
+ });
+ this.tabInputShowDevice[index] = true;
+ }
+ });
+ this.siteWanData.forEach((item, index) => {
+ if (index > 0) {
+ this.siteWanData.splice(index, 1);
+ this.tabInputShowWanPort.splice(index, 1);
+ } else {
+ Object.keys(item).forEach((item2) => {
+ item[item2] = null;
+ });
+ this.tabInputShowWanPort[index] = true;
+ }
+ });
+ console.log(this.siteTableData);
+ this.drawImage(this.siteTableData);
+ this.siteModelShow = false;
+ }
+
+ addsite_cancel() {
+ Object.keys(this.siteBaseData).forEach((item) => { //Clear modal box
+ this.siteBaseData[item] = null;
+ })
+ this.siteSdwanDevice.forEach((item, index) => {
+ if (index > 0) {
+ this.siteSdwanDevice.splice(index, 1);
+ } else {
+ Object.keys(item).forEach((item2) => {
+ item[item2] = null;
+ });
+ this.tabInputShowDevice[index] = true;
+ }
+
+ });
+ this.siteWanData.forEach((item, index) => {
+ if (index > 0) {
+ this.siteWanData.splice(index, 1);
+ } else {
+ Object.keys(item).forEach((item2) => {
+ item[item2] = null;
+ });
+ this.tabInputShowWanPort[index] = true;
+ }
+
+ });
+ this.siteModelShow = false;
+ }
+
+ editSite(num) { //Edit and modify the selected site information
+ this.siteModelShow = true;
+ this.isEditSite = num;
+ Object.keys(this.siteBaseData).forEach((item) => { //Clear modal box
+ this.siteBaseData[item] = this.siteTableData[num - 1][item];
+ });
+ this.siteSdwanDevice = this.siteTableData[num - 1].sdwandevice_list.map((item) => {
+ return Object.assign({}, item)
+ });
+ this.siteSdwanDevice.forEach((item, index) => {
+ this.tabInputShowDevice[index] = false;
+ });
+ this.siteWanData = this.siteTableData[num - 1].sdwansitewan_list.map((item) => {
+ return Object.assign({}, item)
+ });
+ this.siteWanData.forEach((item, index) => {
+ this.tabInputShowWanPort[index] = false;
+ });
+ }
+
+ deleteSite(num) {
+ this.siteTableData = this.siteTableData.filter((d, i) => i !== num - 1);
+ this.drawImage(this.siteTableData);
+ }
+
+ // Site node graphic depiction
+ lines = [];
+ siteImage = [];
+ tpImage = [];
+ imgmap = {
+ '1': '../../../assets/images/domain1.png',
+ '2': '../../../assets/images/site.png'
+ };
+
+ drawImage(sitelist) {
+ let cx = 550;
+ let cy = 40;
+ let innerx1 = 720; //Left site pattern coordinate position
+ let innery1 = 40;
+ let ox = 950;
+ let oy = 50;
+ let innerx2 = 780;//Right site pattern coordinate position
+ let innery2 = 50;
+ let lateX1 = Math.random() * 30 + 55;
+ let lateX2 = 10;
+ let lateY1 = 15;
+ this.lines = sitelist.map((item, index) => {
+ let step = index + 1;
+ let x = cx;
+ let y = cy;
+ let innerX = innerx1;
+ let innerY = innery1;
+ if (step % 2 != 0) { //Left site pattern coordinate position
+ x = cx;
+ y = cy;
+ innerX = innerx1;
+ innerY = innery1;
+ if (step == 1) {
+ innerX = innerx1;
+ innerY = innery1;
+ } else {
+ x = cx - lateX1 * Math.ceil((step / 2)) >= 0 ? cx - lateX1 * Math.ceil((step / 2)) : -(cx - lateX1 * Math.ceil((step / 2)));
+ y = cy + lateY1 * Math.floor((step / 2));
+ innerX = this.lines[step - 3].innerX - lateX2;
+ innerY = y;
+ }
+ } else { //Right site pattern coordinate position
+ x = ox;
+ y = oy;
+ innerX = innerx2;
+ innerY = innery2;
+ if (step / 2 == 1) {
+ innerX = innerx2;
+ innerY = innery2;
+ } else {
+ x = ox + lateX1 * (step / 2) >= 0 ? ox + lateX1 * (step / 2) : -(ox + lateX1 * (step / 2));
+ y = oy + lateY1 * (step / 2 - 1);
+ innerX = this.lines[step - 3].innerX - lateX2;
+ innerY = y;
+ }
+ }
+ return {
+ img: "line",
+ site: item.sdwandevice_list[0].name,
+ x1: x,
+ y1: y,
+ x2: innerX,
+ y2: innerY,
+ innerX: innerX,
+ innerY: innerY
+ }
+ });
+ this.render(this.imgmap, this.lines);
+ }
+
+ render(imgmap, lines) {
+
+ //enter
+ var svg = d3.select("svg"),
+ _g_lines = svg.selectAll('line.line')
+ .data(lines)
+ .enter()
+ .append('line')
+ .style('stroke', '#3fa8eb'
+ )
+ .style('stroke-width', 2)
+ .attr('class', 'line')
+ .attr("x1", function (d) {
+ return d.x1;
+ })
+ .attr("y1", function (d) {
+ return d.y1;
+ })
+ .attr("x2", function (d) {
+ return d.x2;
+ })
+ .attr("y2", function (d) {
+ return d.y2;
+ }),
+ _g_site = svg.selectAll('g.g-site')
+ .data(lines)
+ .enter()
+ .append('g')
+ .style('cursor', 'pointer')
+ .attr('class', 'g-site');
+ _g_site.append('image')
+ .style("width", "50px")
+ .attr('xlink:href', function (d) {
+ return imgmap[2];
+ })
+ .attr("x", function (d) {
+ return d.x1 - 25;
+ })
+ .attr("y", function (d) {
+ return d.y1 - 25;
+ })
+
+ //quit
+ svg.selectAll("g.g-site")
+ .data(lines)
+ .exit() //Select a picture without bound data
+ .remove();
+ svg.selectAll("line.line")
+ .data(lines)
+ .exit() //Select the connection without binding data
+ .remove();
+
+ }
+
+ modifyJosnKey(json, oddkey, newkey) {
+
+ let val = json[oddkey];
+ delete json[oddkey];
+ json[newkey] = val;
+ }
+
+ // submit createData
+ submit() {
+ let globalCustomerId = this.createParams.commonParams.customer.id;
+ let globalServiceType = this.createParams.commonParams.serviceType.name;
+ let servicebody = {
+ service: {
+ name: this.templateParameters.service["name"],
+ description: this.templateParameters.service["description"],
+ serviceInvariantUuid: this.templateParameters.service["serviceInvariantUuid"],
+ serviceUuid: this.templateParameters.service["serviceUuid"],
+ globalSubscriberId: globalCustomerId, //customer.id
+ serviceType: globalServiceType, //serviceType.value
+ parameters: {
+ locationConstraints: [],
+ resources: [],
+ requestInputs: {}
+ },
+ }
+ };
+ let siteresource = null, sitewan = null, device = null, vpnresource = null, sitelan = null;
+ Object.keys(this.bodyTemplateParameter).map((item, index) => {
+ if (item.search("site") != -1) {
+ siteresource = item;
+ this.bodyTemplateParameter[item].map((items, index) => {
+ if (Object.keys(items)[0].search("site") != -1 && Object.keys(items)[0].search("device") == -1) {
+ sitewan = Object.keys(items)[0]
+ }
+ if (Object.keys(items)[0].search("device") != -1) {
+ device = Object.keys(items)[0]
+ }
+ });
+ }
+ if (item.search("vpn") != -1) {
+ vpnresource = item;
+ this.bodyTemplateParameter[item].map((items, index) => {
+ if (Object.keys(items)[0].search("site") != -1) {
+ sitelan = Object.keys(items)[0]
+ }
+ });
+ }
+ });
+ this.sotnVpnTableData.forEach((item, index) => {
+ Object.keys(item).map((items, index) => {
+ if (items.search("site") != -1 && item[items] instanceof Array === true) {
+ this.modifyJosnKey(item, items, sitelan)
+ }
+ });
+ });
+ this.siteTableData.forEach((item, index) => {
+ Object.keys(item).map((items, index) => {
+ if (items.search("site") != -1 && Object.keys(item)[0].search("device") == -1 && item[items] instanceof Array === true) {
+ this.modifyJosnKey(item, items, sitewan)
+ }
+ if (items.search("device") != -1) {
+ this.modifyJosnKey(item, items, device)
+ }
+ });
+ });
+ Object.keys(this.bodyTemplateParameter).map((item, index) => {
+ if (item.search("site") != -1) {
+ servicebody.service.parameters.requestInputs[item] = [].concat(this.siteTableData);
+ }
+ if (item.search("vpn") != -1) {
+ servicebody.service.parameters.requestInputs[item] = [].concat(this.sotnVpnTableData);
+ }
+ });
+ console.log(servicebody);
+
+ this.closeCreate.emit(servicebody);
+
+ }
+
+ goback() {
+ this.closeCreate.emit();
+ }
+}
diff --git a/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.css b/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.css
new file mode 100644
index 00000000..d5ad960d
--- /dev/null
+++ b/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.css
@@ -0,0 +1,365 @@
+/*
+ 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.
+*/
+.title {
+ font: 700 18px/18px "思源黑体";
+ color: #4c5e70;
+ margin-bottom: 18px;
+}
+hr {
+ border: none;
+ height: 2px;
+ background-color: #dce1e7;
+ margin-bottom: 10px;
+}
+.model {
+ background-color: #F7F8FC;
+ overflow-y: auto;
+}
+.creation-model{
+ position: relative;
+ height: 100%;
+}
+.top-title{
+ width: 100%;
+ padding: 20px;
+ position: relative;
+ display: inline-block;
+}
+.model .submit{
+ position: absolute;
+ width: 90px;
+ height: 35px;
+ top: 10px;
+ right: 85px;
+ color: #fff;
+ font-size: 18px;
+ background: #0DA9E2;
+ border-radius: 4px;
+ border: none!important;
+ border-color: rgba(0,0,0,0)!important;
+}
+.model .back,.model .back:hover{
+ position: absolute;
+ top: 10px;
+ right: 20px;
+ display: inline-block;
+ width: 35px;
+ height: 35px;
+ background:url("../../../assets/images/Return-icon.png") no-repeat!important;
+ background-size: 100%!important;
+ border-radius:4px;
+ color: #D7D7D7;
+ cursor: pointer;
+}
+.model .back:hover{
+ background: url("../../../assets/images/Return-icon-active.png")!important;
+ background-size: 100%!important;
+}
+.top-title h3.title {
+ height: 35px;
+ width: 80%;
+ font-size:16px;
+ font-family:ArialMT;
+ color:#3C4F8C;
+ line-height:35px;
+ display: inline-block;
+}
+
+
+.model .detaildata {
+ width: 100%;
+ overflow-y: auto;
+ border-radius: 5px;
+ padding: 15px;
+}
+.model .detaildata h3.title {
+ height: 20px;
+ font: 700 20px/20px "Arial";
+ color: #666;
+}
+.model .detaildata h3 {
+ height: 20px;
+ font: 700 16px/20px "Arial";
+ margin: 5px 0;
+ color: #000;
+}
+.model .detaildata .service-title{
+ margin:60px 50px;
+}
+.model .detaildata .service-title .info-inputs{
+ width:400px;
+ height: 42px;
+ display: inline-block;
+}
+.model .detaildata .service-title span{
+ height: 42px;
+ line-height: 42px;
+ vertical-align: middle;
+}
+.model .detaildata .service-title .lable{
+ display: inline-block;
+ width: 100px;
+ font: 700 14px "Arial";
+ color: #3C4F8C;
+ height: 42px;
+ line-height: 42px;
+ vertical-align: middle;
+ margin-left: 5px;
+}
+.model .detaildata .service-title .service-title-input {
+ width: 230px;
+ height: 42px;
+ border-radius:4px;
+ margin-right: 30px;
+ display: inline-block;
+}
+/* SOTN VPN */
+.model .detaildata .sotnvpn ul li {
+ display: inline-block;
+ height: 40px;
+ width: 24.5%;
+ margin-bottom: 40px;
+ float: left;
+}
+.model .detaildata .sotnvpn ul li span {
+ display: inline-block;
+ font-size: 14px;
+ font-weight: 500;
+ color:rgba(60,79,140,0.5);
+ margin-left: 10px;
+ vertical-align: middle;
+ float: left;
+ width: 110px;
+}
+
+.model .sitemodel .inputs ul li span,.model .sotnnpnmodel .inputs ul li span {
+ display: inline-block;
+ line-height: 35px;
+ font-size: 14px;
+ font-weight: 500;
+ color: #3C4F8C;
+ margin-left: 10px;
+ vertical-align: middle;
+ float: left;
+}
+.model .sitemodel .inputs input,.model .sitemodel .inputs nz-select{
+ width: 186px;
+ float: right;
+ margin-right: 60px;
+}
+.model .sotnnpnmodel .inputs input{
+ width: 186px;
+ float: left;
+ margin-left: 20px;
+}
+
+/* addsite model */
+.model .sitemodel,.model .sotnnpnmodel{
+ position: absolute;
+ z-index: 1001;
+ left: 50px;
+ top: 60px;
+ background-color: #fff;
+ width:1500px;
+ height: 81%;
+ border-radius:2px;
+ overflow:auto;
+}
+.model .sotnnpnmodel{
+ width: 1000px;
+ height: 53%;
+ top:200px;
+ left: 50%;
+ margin-left: -500px;
+}
+.model .sitemodel h3,.model .sotnnpnmodel h3{
+ width: 96%;
+ height: 40px;
+ line-height: 35px;
+ font-size: 18px;
+ font-weight: 500;
+ margin: 10px auto;
+ color: #06A7E2;
+ border-bottom: 2px solid;
+ border-image: -webkit-linear-gradient(#07A9E1,#30D9C4) 100 100;
+ border-image: -moz-linear-gradient(#07A9E1,#30D9C4) 100 100;
+ border-image: linear-gradient(#07A9E1,#30D9C4) 100 100;
+ border-radius:2px;
+}
+.model .sitemodel .inputs,.model .sotnnpnmodel .inputs {
+ padding: 10px 20px 0;
+}
+.model .sitemodel .inputs ul li,.model .sotnnpnmodel .inputs ul li {
+ display: inline-block;
+ height: 35px;
+ line-height: 35px;
+ width: 24.5%;
+ margin-bottom: 20px;
+}
+.model .sotnnpnmodel .inputs ul li{
+ width: 31%;
+}
+.model .sitemodel .inputs ul li span,.model .sotnnpnmodel .inputs ul li span {
+ display: inline-block;
+ line-height: 35px;
+ font-size: 14px;
+ font-weight: 500;
+ color: #3C4F8C;
+ margin-left: 10px;
+ vertical-align: middle;
+ float: left;
+}
+.model .sitemodel .inputs input,.model .sitemodel .inputs nz-select{
+ width: 186px;
+ float: right;
+ margin-right: 60px;
+}
+.model .sotnnpnmodel .inputs div{
+ width: 186px;
+ float: left;
+ margin-left: 20px;
+}
+.model .sitemodel .action,.model .sotnnpnmodel .action {
+ text-align: center;
+ margin-top: 30px;
+ margin-bottom: 20px;
+ cursor: pointer
+}
+.model .sotnnpnmodel .action{
+ margin-top: 70px;
+}
+.model .sitemodel .action button,.model .sotnnpnmodel .action button{
+ width: 126px;
+ height:40px;
+ background:#EEEEEE;
+ border-radius:2px;
+ border: none!important;
+ color: #9DA7C5;
+ font-size: 16px;
+ margin: 0 15px;
+}
+.model .sitemodel .action button:nth-child(2),.model .sotnnpnmodel .action button:nth-child(2){
+ background: #0DA9E2;
+ color: #fff;
+}
+.model .sitemodel .action button:nth-child(2):hover,.model .sotnnpnmodel .action button:nth-child(2):hover{
+ background:#09C6E2;
+}
+
+.model nz-table tbody td i.anticon:hover {
+ color: #3fa8eb;
+ cursor: pointer;
+}
+
+/* site table */
+.sitemodel h3 button,.sotnnpnmodel h3 button{
+ color: #D7D7D7;
+ width:32px;
+ height:32px;
+ background:#ffffff;
+ border-radius:4px;
+ border:1px solid #D7D7D7;
+}
+.sitemodel h3 button:hover,.sotnnpnmodel h3 button:hover{
+ background:#ffffff;
+ color: #0DA9E2;
+ border:1px solid #0DA9E2;
+}
+.sitemodel h3>button,.sotnnpnmodel h3>button{
+ float: right;
+ width: 30px;
+ height: 30px;
+ margin-right: 15px;
+}
+
+/* site Detail */
+
+.model .detaildata .site h3 .closeDetail {
+ cursor: pointer;
+ padding: 2px 15px;
+ color: #3fa8eb;
+}
+
+.model .detaildata .sotnvpn,.model .detaildata .site{
+ background: #fff;
+ padding: 30px 30px 0 30px;
+}
+
+.mask{
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ z-index: 1000;
+ background: rgba(0, 0, 0, 0.65);
+ top:0;
+}
+
+/* charts */
+.model .chart {
+ width: 98%;
+ padding: 10px;
+ margin: 0 auto;
+ color: #06A7E2;
+ font-size: 16px;
+ font-weight: 500;
+ margin-bottom: 30px;
+ background: #EEF9FF;
+ border-radius: 4px;
+}
+.model .chart #detailChart {
+ width: 100%;
+ height: 254px;
+ margin-top: 20px;
+ position: relative;
+}
+.model .chart #detailChart .cloudcounty {
+ cursor: pointer;
+}
+
+.model .chart #detailChart .couldDetail {
+ position: absolute;
+ left: 50%;
+ top: 10px;
+ width: 80%;
+ transform: translate(-50%,0);
+ height: 160px;
+ background-color: #aaa;
+ border-radius: 5px;
+ box-shadow: 0px 0px 20px #000;
+}
+.siteWanTab{
+ width: 96%;
+ margin: 0 auto;
+ margin-top: 10px;
+}
+.siteWanTab th{
+ padding: 10px 8px;
+ color: #3C4F8C;
+ font-size: 16px;
+}
+.siteWanTab tr td{
+ padding: 10px 5px;
+}
+.siteWanTab .tr-border{
+ border-bottom: 1px solid #EDEDED;
+}
+.addListBtn{
+ margin-right: 30px;
+ color: #06A7E2;
+ border: none;
+ background: rgba(229,238,252,0.8);
+ cursor: pointer;
+}
diff --git a/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.html b/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.html
new file mode 100644
index 00000000..e2b5159e
--- /dev/null
+++ b/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.html
@@ -0,0 +1,421 @@
+<!--
+ 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.
+-->
+
+<div class="model creation-model" style="background: #F7F8FC;">
+ <!-- top title -->
+ <div class="top-title">
+ <h3 class="title fl">{{detailParams['service-instance-name']}} Instance Detail</h3>
+ <div class="fl" style="width: 20%">
+ <button class="submit" nz-button (click)="submitUpdate()" *ngIf="upDateShow"><span>
+ {{"i18nTextDefine_Update" | translate}} </span>
+ </button>
+ <button class="back" nz-button (click)="goback()"></button>
+ </div>
+ </div>
+ <!-- chart -->
+ <div class="chart">
+
+ <div id="detailChart">
+ <svg width="100%" height="100%" style="position: relative">
+ <!--local domain-->
+ <g class="clouds" *ngIf="vpns[0].domain!=''">
+ <image xlink:href="assets/images/domain1.png" id="domain1" width="14%" x="17%" y="14%"></image>
+ <text dx="24%" dy="51%" style="font-size: 14px; fill:#ffffff;width: 20px;">
+ {{vpns[0].domain}}
+ </text>
+ </g>
+ <g *ngIf="vpns[1]" class="clouds">
+ <image xlink:href="assets/images/domain1.png" id="domain2" width="14%" x="40%" y="40%"></image>
+ <text dx="43%" dy="19%" style="font-size: 14px; fill: #ffffff;width: 20px;">
+ {{vpns[1].domain}}
+ </text>
+ </g>
+ <!--domain1 tp-->
+ <g class="clouds" *ngIf="vpns[0].sitetpname!=''">
+ <image xlink:href="assets/images/tp.png" class="tp" id="tp1" height="16" width="20" x="21%" y="37%"></image>
+ <text dx="21%" dy="34%" style="font-size: 14px; fill: #666;width: 20px;">
+ {{vpns[0].sitetpname}}
+ </text>
+ </g>
+ <g class="clouds" *ngIf="vpns[0].othertpname!=''">
+ <image xlink:href="assets/images/tp.png" class="tp" id="tp2" height="16" width="20" x="29%" y="52%"></image>
+ <text dx="29%" dy="49%" style="font-size: 14px; fill: #666;width: 20px;">
+ {{vpns[0].othertpname}}
+ </text>
+ </g>
+ <!--domain2 tp-->
+ <g *ngIf="vpns[1]" class="clouds">
+ <image xlink:href="assets/images/tp.png" class="tp" id="tp3" height="16" width="20" x="44%" y="52%"></image>
+ <text dx="44%" dy="49%" style="font-size: 14px; fill: #666;width: 20px;">
+ {{vpns[1].othertpname}}
+ </text>
+ </g>
+ <g *ngIf="vpns[1]" class="clouds">
+ <image xlink:href="assets/images/tp.png" class="tp" id="tp4" height="16" width="20" x="51%" y="78%"></image>
+ <text dx="51%" dy="75%" style="font-size: 14px; fill: #666;width: 20px;">
+ {{vpns[1].sitetpname}}
+ </text>
+ </g>
+ <!--clouds-->
+ <g class="clouds">
+ <image xlink:href="assets/images/cloud-out.png" id="extent-cloud" width="14%" x="70%" y="11%"></image>
+ <text dx="75%" dy="39%" style="font-size: 14px; fill: #666;width: 20px;">
+ SP Partent Network
+ </text>
+ </g>
+ <!--local site-->
+ <g class="clouds" *ngIf="localSite.length>0">
+ <image xlink:href="assets/images/site.png" id="site1" height="59" width="100" x="6%" y="29%"></image>
+ <text dx="8%" dy="26%" style="font-size: 14px; fill: #666;width: 20px;">
+ {{localSite[0] && localSite[0]["service-instance-name"]}}
+ </text>
+ </g>
+ <g *ngIf="!detailSites && localSite.length>0" class="clouds">
+ <image xlink:href="assets/images/site.png" id="site2" height="59" width="100" x="61%" y="70%"
+ *ngIf="this.vpns.length == 2"></image>
+ <text dx="62%" dy="66%" style="font-size: 14px; fill: #666;width: 20px;" *ngIf="this.vpns.length == 2">
+ {{ localSite[1] && localSite[1]["service-instance-name"]}}
+ </text>
+ <image xlink:href="assets/images/site.png" id="site2" height="59" width="100" x="40%" y="44%"
+ *ngIf="this.vpns.length == 1"></image>
+ <text dx="41%" dy="40%" style="font-size: 14px; fill: #666;width: 20px;" *ngIf="this.vpns.length == 1">
+ {{ localSite[1] && localSite[1]["service-instance-name"]}}
+ </text>
+ </g>
+ <!--cloud site-->
+ <g *ngIf="!detailSites && outerSite.length>0" class="clouds">
+ <image xlink:href="assets/images/site.png" id="site3" height="59" width="100" x="89%" y="10%"></image>
+ <text dx="90%" dy="7%" style="font-size: 14px; fill: #666;width: 20px;">
+ {{outerSite[1] && outerSite[1]["service-instance-name"]}}
+ </text>
+ </g>
+ <g class="clouds" *ngIf="outerSite.length>0">
+ <image xlink:href="assets/images/site.png" id="site4" height="59" width="100" x="89%" y="40%"></image>
+ <text dx="90%" dy="37%" style="font-size: 14px; fill: #666;width: 20px;">
+ {{outerSite[0] && outerSite[0]["service-instance-name"]}}
+ </text>
+ </g>
+ <!--tp,site,domain---line -->
+ <line *ngFor="let item of detailLines" [attr.x1]="item.x1" [attr.y1]="item.y1" [attr.x2]="item.x2"
+ [attr.y2]="item.y2" style="stroke:#2F8BF7; stroke-width:2"></line>
+ <line *ngIf="detailSites" x1="45%" y1="30%" x2="75%" y2="20%" style="stroke:#FFC000; stroke-width:2"></line>
+ </svg>
+ </div>
+ </div>
+ <div class="detaildata">
+ <nz-tabset [nzTabPosition]="'top'" [nzShowPagination]=false [nzTabBarGutter]="'2'" [nzTabBarStyle]=tabBarStyle
+ [nzSelectedIndex]="upDateShow == false?0:1">
+ <nz-tab nzTitle="Service Info">
+ <div class="service-title" style="clear: both">
+ <span class="lable" style="width: 60px">name:</span>
+ <div class="service-title-input">{{templateParameters.service["name"]}}</div>
+ <span class="lable">description:</span>
+ <div class="service-title-input">{{templateParameters.service["description"]}}</div>
+ </div>
+ </nz-tab>
+ <nz-tab nzTitle="Sdwanvpnresource List">
+ <div class="sotnvpn clearfix">
+ <div style="clear: both;height: 10px">
+ <h3 style="float: left;color: #3C4F8C">sdwanVPN List</h3>
+ <button nz-button *ngIf="upDateShow" (click)="updateSotnvpn()" class="addListBtn"
+ style="float: right;margin-right: 10px"><i class="anticon anticon-plus"
+ style="transform: scale(1.2);font-weight: 700"></i> {{"i18nTextDefine_Add" | translate}}
+ </button>
+ </div>
+ <nz-table #sotnVpnTable [nzData]="sotnVpnTableData" [nzShowPagination]="false" nzSize="small">
+ <thead>
+ <tr>
+ <th width="30%"> NO.</th>
+ <th width="30%"> Name</th>
+ <th width="30%"> topology</th>
+ <th nzWidth="10%"> Action </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let item of sotnVpnTable.data; let i = index; ">
+ <td>{{i+1}}</td>
+ <td>{{item.sdwanvpn_name}}</td>
+ <td>{{item.sdwanvpn_topology}}</td>
+ <td>
+ <span class="action" (click)="showstonVpnDetail(i+1)"><i class="anticon anticon-bars"></i></span>
+ <span class="action" (click)="editUpdateSotnVpn(i+1)" *ngIf="sotnvpnnum[i]"><i
+ class="anticon anticon-edit"></i></span>
+ &nbsp;
+ <span class="action" (click)="deleteUpdateSotnVpn(i+1)" *ngIf="upDateShow"><i
+ class="anticon anticon-delete"></i></span>
+ </td>
+ </tr>
+ </tbody>
+ </nz-table>
+ </div>
+ </nz-tab>
+ <nz-tab nzTitle="Sdwansiteresource List">
+ <div class="site">
+ <div style="height: 10px">
+ <h3 style="float: left;color: #3C4F8C">Site List</h3>
+ <button nz-button *ngIf="upDateShow" (click)="updateSite()" class="addListBtn"
+ style="float: right;margin-right: 10px"><i class="anticon anticon-plus"
+ style="transform: scale(1.2);font-weight: 700"></i>{{"i18nTextDefine_Add" | translate}}
+ </button>
+ </div>
+ <nz-table #nzTable [nzData]="siteTableData" [nzShowPagination]="false" nzSize="small">
+ <thead>
+ <tr>
+ <th nzWidth="10%"> NO. </th>
+ <th nzWidth="15%"> Name </th>
+ <th nzWidth="20%"> Description </th>
+ <th nzWidth="15%"> Post Code </th>
+ <th nzWidth="15%"> Address </th>
+ <th nzWidth="15%"> VLAN </th>
+ <th nzWidth="10%"> Action </th>
+ </tr>
+ </thead>
+ <tbody>
+
+ <tr *ngFor="let item of nzTable.data; let i = index; ">
+ <td>{{i+1}}</td>
+ <td>{{item.sdwandevice_list[0].name}}</td>
+ <td>{{item.sdwansite_description}}</td>
+ <td>{{item.sdwansite_postcode}}</td>
+ <td>{{item.sdwansite_address}}</td>
+ <td>{{item.sdwansite_emails}}</td>
+ <td>
+ <span class="action" (click)="showSiteDetail(i+1)"><i class="anticon anticon-bars"></i></span>
+ &nbsp;
+ <span class="action" (click)="editUpdateSite(i+1)" *ngIf="sitenum[i]"><i
+ class="anticon anticon-edit"></i></span>
+ &nbsp;
+ <span class="action" (click)="deleteUpdateSite(i+1)" *ngIf="upDateShow"><i
+ class="anticon anticon-delete"></i></span>
+ </td>
+ </tr>
+
+ </tbody>
+ </nz-table>
+ </div>
+ </nz-tab>
+ </nz-tabset>
+ </div>
+ <!-- sotnVpn model -->
+ <div class="sotnnpnmodel" *ngIf="sotnVpnDetailShow">
+ <h3> {{"i18nTextDefine_Base" | translate}} </h3>
+ <div class="inputs">
+ <ul>
+ <li *ngFor="let item of this.templateParameters.sotnvpn.sdwanvpnresource_list">
+ <span>{{item.lableShow}}:</span>
+ <span class="input-info">{{sotnInfo[item.lable]}}</span>
+ </li>
+ </ul>
+ </div>
+ <div>
+ <h3>Sdwansitelan List</h3>
+ <div>
+ <div style="width: 100%;text-align: right">
+ </div>
+ <table class="siteWanTab">
+ <thead>
+ <tr>
+ <th width="4%"> NO.</th>
+ <th *ngFor="let key of getKeys(this.sotnSdwansitelanParams)">{{key}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let item of sotnSdwansitelanData; let i = index;" class="tr-border">
+ <td>{{i+1}}</td>
+ <td *ngFor="let key of getKeys(item);let a = index;">
+ <span *ngIf="key != 'lable' ">{{item[key]}}</span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ <div class="action">
+ <button nz-button nzType="primary"
+ (click)="detailSotnVpn_cancel()">{{"i18nTextDefine_Cancel" | translate}}</button>
+ </div>
+ </div>
+ <!-- site model -->
+ <div class="sitemodel" *ngIf="siteDetail">
+ <h3> {{"i18nTextDefine_Base" | translate}} </h3>
+ <div class="inputs">
+ <ul>
+ <li *ngFor="let item of this.templateParameters.site.sdwansiteresource_list">
+ <span>{{item.lableShow}}:</span>
+ <span class="input-info">{{siteBaseData[item.lable]}}</span>
+ </li>
+ </ul>
+ </div>
+ <div>
+ <h3>Sdwandevice</h3>
+ <div>
+ <table class="siteWanTab">
+ <thead>
+ <tr>
+ <th width="4%"> NO.</th>
+ <th *ngFor="let key of getKeys(this.siteCpeData)">{{key}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let item of siteSdwanDevice; let i = index;" class="tr-border">
+ <td>{{i+1}}</td>
+ <td *ngFor="let key of getKeys(item);">
+ <span *ngIf="key != 'lable' ">{{item[key]}}</span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ <h3>Sdwansitewan List</h3>
+ <div>
+ <table class="siteWanTab">
+ <thead>
+ <tr>
+ <th width="4%"> NO.</th>
+ <th *ngFor="let key of getKeys(this.siteWanParams)">{{key}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let item of siteWanData; let i = index;" class="tr-border">
+ <td>{{i+1}}</td>
+ <td *ngFor="let key of getKeys(item);">
+ <span *ngIf="key != 'lable' ">{{item[key]}}</span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+
+ <div class="action">
+ <button nz-button nzType="primary" (click)="detailsite_cancel()">{{"i18nTextDefine_Cancel" | translate}}</button>
+ </div>
+ </div>
+ <!-- sotnVpn update model -->
+ <div class="sotnnpnmodel" *ngIf="sotnVpnAddModelShow">
+ <h3> {{"i18nTextDefine_Base" | translate}} </h3>
+ <div class="inputs">
+ <ul>
+ <li *ngFor="let item of this.templateParameters.sotnvpn.sdwanvpnresource_list">
+ <span>{{item.lableShow}}:</span>
+ <input nz-input [(ngModel)]="sotnInfo[item.lable]"></li>
+ </ul>
+ </div>
+ <div>
+ <h3>Sdwansitelan List</h3>
+ <div>
+ <div style="width: 100%;text-align: right">
+ <button nz-button (click)="updateSotnSdwansitelan()" class="addListBtn"><i class="anticon anticon-plus"
+ style="transform: scale(1.2);font-weight: 700;"></i>{{"i18nTextDefine_Add" | translate}}
+ </button>
+ </div>
+ <table class="siteWanTab">
+ <thead>
+ <tr>
+ <th width="4%"> NO.</th>
+ <th *ngFor="let key of getKeys(this.sotnSdwansitelanParams)">{{key}}</th>
+ <th width="7%"> Action</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let item of sotnSdwansitelanData; let i = index;"
+ [ngClass]="{'tr-border':item.tabInputShowSdwansitelan ==false}">
+ <td>{{i+1}}</td>
+ <td *ngFor="let key of getKeys(item);let a = index;">
+ <span *ngIf="!tabInputShowSdwansitelan[i]">{{item[key]}}</span>
+ <input nz-input [(ngModel)]="item[key]" *ngIf="tabInputShowSdwansitelan[i] ">
+ </td>
+ <td>
+ <span class="action" (click)="editUpdateSotnSdwansitelan(i+1,item,sotnSdwansitelanData)"><i
+ class="anticon anticon-edit" style="margin: 0 5px;"></i></span>
+ <span class="action" (click)="deleteUpdateSotnSdwansitelan(i+1,item,sotnSdwansitelanData)"><i
+ class="anticon anticon-delete"></i></span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+
+ <div class="action">
+ <button nz-button nzType="primary"
+ (click)="updateSotnVpn_cancel()">{{"i18nTextDefine_Cancel" | translate}}</button>
+ <button nz-button nzType="primary" (click)="updateSotnVpn_OK()">{{"i18nTextDefine_Add" | translate}}</button>
+ </div>
+ </div>
+ <!-- site update Model -->
+ <div class="sitemodel" *ngIf="siteAddModelShow">
+ <h3> {{"i18nTextDefine_Base" | translate}} </h3>
+ <div class="inputs">
+ <ul>
+ <li *ngFor="let item of this.templateParameters.site.sdwansiteresource_list">
+ <span>{{item.lableShow}}:</span>
+ <input nz-input [(ngModel)]="siteBaseData[item.lable]"></li>
+ </ul>
+ </div>
+ <div>
+ <h3>Sdwandevice</h3>
+ <div class="inputs">
+ <ul>
+ <li *ngFor="let item of this.templateParameters.site.sdwandevice_list">
+ <span>{{item.lable}}:</span>
+ <input nz-input [(ngModel)]="siteCpeData[item.lable]">
+ </li>
+ </ul>
+ </div>
+ <h3>Sdwansitewan List</h3>
+ <div>
+ <div style="width: 100%;text-align: right">
+ <button nz-button (click)="updateSiteWan()" class="addListBtn"><i class="anticon anticon-plus"
+ style="transform: scale(1.2);font-weight: 700;"></i>{{"i18nTextDefine_Add" | translate}}
+ </button>
+ </div>
+ <table class="siteWanTab">
+ <thead>
+ <tr>
+ <th width="4%"> NO.</th>
+ <th *ngFor="let key of getKeys(this.siteWanParams)">{{key}}</th>
+ <th width="7%"> Action</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let item of siteWanData; let i = index;"
+ [ngClass]="{'tr-border':item.tabInputShowWanPort ==false}">
+ <td>{{i+1}}</td>
+ <td *ngFor="let key of getKeys(item);let a = index;">
+ <span *ngIf="!tabInputShowWanPort[i]">{{item[key]}}</span>
+ <input nz-input [(ngModel)]="item[key]" *ngIf="tabInputShowWanPort[i] ">
+ </td>
+ <td>
+ <span class="action" (click)="editUpdateWanPort(i+1,item,siteWanData)"><i class="anticon anticon-edit"
+ style="margin: 0 5px;"></i></span>
+ <span class="action" (click)="deleteUpdateWanPort(i+1,item,siteWanData)"><i
+ class="anticon anticon-delete"></i></span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+
+ <div class="action">
+ <button nz-button nzType="primary" (click)="updatesite_cancel()">{{"i18nTextDefine_Cancel" | translate}}</button>
+ <button nz-button nzType="primary" (click)="updatesite_OK()">{{"i18nTextDefine_Add" | translate}}</button>
+ </div>
+ </div>
+ <div class="mask" *ngIf="sotnVpnDetailShow || siteDetail || sotnVpnAddModelShow || siteAddModelShow"
+ (click)="hiddenModel()"></div>
+</div> \ No newline at end of file
diff --git a/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.spec.ts b/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.spec.ts
new file mode 100644
index 00000000..3d112bf8
--- /dev/null
+++ b/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.spec.ts
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2018 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 { NgZorroAntdModule } from 'ng-zorro-antd';
+import { HttpClientModule } from '@angular/common/http';
+import { NZ_I18N, en_US } from 'ng-zorro-antd';
+import { TranslateModule, TranslateLoader, TranslateService, TranslateFakeLoader } from '@ngx-translate/core';
+
+import { CcvpnDetailComponent } from './ccvpn-detail.component';
+import { MyhttpService } from '../../core/services/myhttp.service';
+
+describe('CcvpnDetailComponent', () => {
+ let component: CcvpnDetailComponent;
+ let fixture: ComponentFixture<CcvpnDetailComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [CcvpnDetailComponent],
+ imports: [TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: TranslateFakeLoader } }),
+ NgZorroAntdModule.forRoot(), HttpClientModule],
+ providers: [MyhttpService, { provide: NZ_I18N, useValue: en_US }]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ let detailshow = false;
+ detailData: Object;
+ let serviceDetail = (service) => {
+ service["siteSer"] = [];
+ service["sdwanSer"] = [];
+ service["customer"] = this.customerSelected;
+ service["serviceType"] = this.serviceTypeSelected;
+
+ service.childServiceInstances.forEach((item) => {
+ if (item.serviceDomain == "SITE") {
+ service.siteSer.push(item);
+ } else if (item.serviceDomain == "SDWAN") {
+ service.sdwanSer.push(item);
+ }
+ })
+ this.detailshow = true;
+ this.detailData = service;
+ component.detailParams = this.detailData
+ fixture = TestBed.createComponent(CcvpnDetailComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ };
+
+ it('should create', () => {
+ console.log(component);
+ expect(component).toBeTruthy();
+ });
+ });
+
+});
diff --git a/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.ts b/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.ts
new file mode 100644
index 00000000..109c143b
--- /dev/null
+++ b/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.ts
@@ -0,0 +1,815 @@
+/*
+ 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, OnInit, Input, Output, EventEmitter } from '@angular/core';
+import { MyhttpService } from '../../core/services/myhttp.service';
+import * as d3 from 'd3';
+
+@Component({
+ selector: 'app-ccvpn-detail',
+ templateUrl: './ccvpn-detail.component.html',
+ styleUrls: ['./ccvpn-detail.component.css']
+})
+export class CcvpnDetailComponent implements OnInit {
+
+ constructor(private myhttp: MyhttpService) { }
+
+ ngOnInit() {
+ this.dataInit();
+ this.drawImages();
+ }
+
+ @Input() detailParams;
+ @Input() upDateShow;
+ @Output() closeDetail = new EventEmitter();
+ @Output() closeUpdate = new EventEmitter();
+
+ tabBarStyle = {
+ "height": "58px",
+ "width": "694px",
+ "box-shadow": "none",
+ "margin": "0",
+ "border-radius": "4px 4px 0px 0px"
+ };
+ input_parameters: any;
+ templateParameters = {
+ service: {},
+ sotnvpn: {
+ // info: {},
+ sdwanvpnresource_list: [],
+ sdwansitelan_list: []
+ },
+ site: {
+ // info: {},
+ sdwansiteresource_list: [],
+ sdwandevice_list: [],
+ sdwansitewan_list: []
+ }
+ };
+ bodyTemplateParameter = {};
+
+ // SOTN VPN List
+ sotnVpnTableData = [];
+ sotnInfo = {};//sotnmodel The first part of sotnInfo
+ sotnSdwansitelanData = [];//sotnmodel The second part of the data sdwansitelan Table
+ sotnSdwansitelanParams = {};//sdwansitelan Table Detailed parameters of each line of data
+ tabInputShowSdwansitelan = [];//sdwansitelan table input and span
+ // Site List
+ siteTableData = [];
+ siteBaseData = {}; //sitemodel one sdwansiteresource_list
+ // cpe
+ siteSdwanDevice = []; //sitemodel SdwanDevice port Table data
+ siteCpeData = {}; //sitemodel two sdwandevice_list
+ tabInputShowDevice = [];//Device port input and span
+ // Wan Port
+ siteWanData = []; //sitemodel three wan port Table data
+ siteWanParams = {}; //wan port Table Detailed parameters of each line of data
+ tabInputShowWanPort = [];//wan port table input and span
+ sitenum = [];
+ sotnvpnnum = [];
+
+ getKeys(item) {
+ return Object.keys(item);
+ }
+ //tabBarStyle
+ dataInit() {
+ console.log(this.detailParams);
+ // this.input_parameters = JSON.stringify(this.detailParams['input-parameters'])
+ if (this.detailParams['input-parameters']) {
+ this.input_parameters = JSON.parse(this.detailParams['input-parameters']);
+ } else {
+ return false;
+ }
+ console.log(this.input_parameters);
+ this.templateParameters.service = {
+ name: this.input_parameters.service.name,
+ description: this.input_parameters.service.description,
+ serviceInvariantUuid: this.input_parameters.service["serviceInvariantUuid"],
+ serviceUuid: this.input_parameters.service["serviceUuid"]
+ };
+ let inputs = this.input_parameters.service.parameters.requestInputs;
+
+ Object.keys(inputs).map((items) => {
+ if (items.search("vpn") != -1) {
+ this.bodyTemplateParameter[items] = [];
+ inputs[items].map((item, index) => {
+ this.sotnVpnTableData.push(item);
+ this.sotnvpnnum.push(false);
+ });
+ let sdwanvpnresource_list = inputs[items][0];
+ Object.keys(sdwanvpnresource_list).forEach((its) => {
+ let input = {};
+ if (its.search("site") != -1 && sdwanvpnresource_list[its] instanceof Array === true) {
+ Object.keys(sdwanvpnresource_list[its][0]).forEach((i) => {
+ let input1 = {};
+ input1[i] = sdwanvpnresource_list[its][i];
+ this.templateParameters["sotnvpn"]["sdwansitelan_list"].push(input1);
+ })
+ let sitelanKey = {};
+ sitelanKey[its] = [];
+ this.bodyTemplateParameter[items].push(sitelanKey);
+ }
+ if (its.search("sitelan") == -1 && sdwanvpnresource_list[its] instanceof Array === false) {
+ input[its] = sdwanvpnresource_list[its];
+ this.templateParameters["sotnvpn"]["sdwanvpnresource_list"].push(input);
+ }
+ });
+ }
+ if (items.search("site") != -1) {
+ this.bodyTemplateParameter[items] = [];
+ inputs[items].map((item, index) => {
+ this.siteTableData.push(item);
+ this.sitenum.push(false);
+ });
+ let sdwansiteresource_list = inputs[items][0];
+ Object.keys(sdwansiteresource_list).forEach((its) => {
+ let input2 = {};
+ if (its.search("device") != -1 && sdwansiteresource_list[its] instanceof Array === true) {
+ this.templateParameters["site"]["sdwandevice_list"][0] = sdwansiteresource_list[its][0];
+ let sitelanKey = {};
+ sitelanKey[its] = [];
+ this.bodyTemplateParameter[items].push(sitelanKey);
+ }
+ if (its.search("site") != -1 && its.search("device") == -1 && sdwansiteresource_list[its] instanceof Array === true) {
+ this.templateParameters["site"]["sdwansitewan_list"][0] = sdwansiteresource_list[its][0];
+ let sitelanKey = {};
+ sitelanKey[its] = [];
+ this.bodyTemplateParameter[items].push(sitelanKey);
+ }
+ if (its.search("device") == -1 && sdwansiteresource_list[its] instanceof Array === false) {
+ input2[its] = sdwansiteresource_list[its];
+ this.templateParameters["site"]["sdwansiteresource_list"].push(input2);
+ }
+ });
+
+ }
+ });
+
+ console.log(this.templateParameters.site);
+ console.log(this.siteTableData);
+
+ this.showTemParametersSotnVpn();
+ this.showTemParametersSite();
+
+ }
+
+ //sotnVpn data, after combining the structure, rendering the template data to the page
+ showTemParametersSotnVpn() {
+ //sotn Data analysis, structure assembly
+ this.templateParameters.sotnvpn.sdwanvpnresource_list.map((item, index) => {
+ let input = {};
+ for (let keys in item) {
+ if (keys != "required" && keys != "type" && keys != "description") {
+ input[keys] = item[keys];
+ item["lable"] = keys;
+ item["lableShow"] = keys.split("_")[1];
+ this.sotnInfo = Object.assign(this.sotnInfo, input);
+ }
+ }
+ });
+
+ this.templateParameters.sotnvpn.sdwansitelan_list.map((item, index) => {
+ let input = {};
+ for (let keys in item) {
+ if (keys != "required" && keys != "type" && keys != "description") {
+ input[keys] = item[keys];
+ item["lable"] = keys;
+ this.sotnSdwansitelanParams = Object.assign(this.sotnSdwansitelanParams, this.sotnSdwansitelanParams, input);
+ }
+ }
+ });
+ this.sotnSdwansitelanData.push(this.sotnSdwansitelanParams);
+ this.sotnSdwansitelanData.map((item, index) => {
+ this.tabInputShowSdwansitelan[index] = true;
+ });
+ }
+
+ //Site data, after combining the structure, rendering the template to the page
+ showTemParametersSite() {
+ //site Data analysis, structure assembly
+ this.templateParameters.site.sdwansiteresource_list.map((item, index) => {
+ let input = {};
+ for (let keys in item) {
+ if (keys != "required" && keys != "type" && keys != "description") {
+ input[keys] = item[keys];
+ item["lable"] = keys;
+ item["lableShow"] = keys.split("_")[1];
+ this.siteBaseData = Object.assign(this.siteBaseData, input);
+ }
+ }
+ });
+
+ this.templateParameters.site.sdwandevice_list.map((item, index) => {
+ let input = {};
+ for (let keys in item) {
+ if (keys != "required" && keys != "type" && keys != "description") {
+ input[keys] = item[keys];
+ item["lable"] = keys;
+ this.siteCpeData = Object.assign(this.siteCpeData, input);
+ }
+ }
+ });
+ this.templateParameters.site.sdwandevice_list.map((item, index) => {
+ if (this.getKeys(item).indexOf("lable") == -1) {
+ this.templateParameters.site.sdwandevice_list.splice(index, 1)
+ }
+ });
+ this.templateParameters.site.sdwansitewan_list.map((item, index) => {
+ let input = {};
+ for (let keys in item) {
+ if (keys != "required" && keys != "type" && keys != "description") {
+ input[keys] = item[keys];
+ item["lable"] = keys;
+ this.siteWanParams = Object.assign(this.siteWanParams, this.siteWanParams, input);
+ }
+ }
+ });
+ this.siteSdwanDevice.push(this.siteCpeData);
+ this.siteSdwanDevice.map((item, index) => {
+ this.tabInputShowDevice[index] = true;
+ });
+ this.siteWanData.push(this.siteWanParams);
+ this.siteWanData.map((item, index) => {
+ this.tabInputShowWanPort[index] = true;
+ });
+ }
+
+ //sotnVpn detail show
+ sotnVpnDetailShow = false;
+ isEditSotnVpn = 0;
+ showstonVpnDetail(num) {
+ this.sotnVpnDetailShow = true;
+ this.isEditSotnVpn = num;
+ Object.keys(this.sotnInfo).forEach((item) => {
+ this.sotnInfo[item] = this.sotnVpnTableData[num - 1][item];
+ });
+ this.sotnSdwansitelanData = this.sotnVpnTableData[num - 1].sdwansitelan_list.map((item) => {
+ return Object.assign({}, {}, item)
+ });
+ }
+ detailSotnVpn_cancel() {
+ this.sotnVpnDetailShow = false;
+ }
+
+ // site detail show
+ siteDetail = false;
+ isEditSite = 0;
+ showSiteDetail(num) {
+ this.siteDetail = true;
+ this.isEditSite = num;
+ console.log(this.siteTableData[num - 1]);
+ Object.keys(this.siteBaseData).forEach((item) => {
+ this.siteBaseData[item] = this.siteTableData[num - 1][item];
+ });
+ this.siteSdwanDevice = this.siteTableData[num - 1].sdwandevice_list.map((item) => {
+ return Object.assign({}, {}, item)
+ });
+ this.siteWanData = this.siteTableData[num - 1].sdwansitewan_list.map((item) => {
+ return Object.assign({}, {}, item)
+ });
+ }
+ detailsite_cancel() {
+ this.siteDetail = false;
+ }
+ deleteUpdateSite(num) {
+ this.siteTableData = this.siteTableData.filter((d, i) => i !== num - 1);
+ this.sitenum.splice(num - 1, 1);
+ }
+
+ //sotnVpn addModel
+ sotnVpnAddModelShow = false;
+
+ updateSotnVpn_OK() {
+ let inputs = {
+ "sdwansitelan_list": []
+ };
+ inputs = Object.assign(inputs, this.sotnInfo);
+ inputs["sdwansitelan_list"] = this.sotnSdwansitelanData.map((item) => {
+ return Object.assign({}, item);
+ });
+ if (this.isEditSotnVpn) {
+
+ this.sotnVpnTableData[this.isEditSotnVpn - 1] = inputs;
+ this.sotnVpnTableData = [...this.sotnVpnTableData];
+ } else {
+ // this.siteTableData.push(inputs);
+ this.sotnVpnTableData = [...this.sotnVpnTableData, inputs];
+ this.sotnvpnnum = [...this.sotnvpnnum, true];
+ }
+ Object.keys(this.sotnInfo).forEach((item) => {
+ this.sotnInfo[item] = null;
+ });
+ this.sotnSdwansitelanData.forEach((item, index) => {
+ if (index > 0) {
+ this.sotnSdwansitelanData.splice(index, 1);
+ this.tabInputShowSdwansitelan.splice(index, 1);
+ } else {
+ Object.keys(item).forEach((item2) => {
+ item[item2] = null;
+ });
+ this.tabInputShowSdwansitelan[index] = true;
+ }
+
+ });
+ this.sotnVpnAddModelShow = false;
+ }
+
+ updateSotnVpn_cancel() {
+ Object.keys(this.sotnInfo).forEach((item) => {
+ this.sotnInfo[item] = null;
+ });
+ this.sotnSdwansitelanData.forEach((item, index) => {
+ if (index > 0) {
+ this.sotnSdwansitelanData.splice(index, 1);
+ } else {
+ Object.keys(item).forEach((item2) => {
+ item[item2] = null;
+ });
+ this.tabInputShowSdwansitelan[index] = true;
+ }
+
+ });
+ this.sotnVpnAddModelShow = false;
+ }
+
+ editUpdateSotnVpn(num) {
+ this.sotnVpnAddModelShow = true;
+ this.isEditSotnVpn = num;
+ Object.keys(this.sotnInfo).forEach((item) => {
+ this.sotnInfo[item] = this.sotnVpnTableData[num - 1][item];
+ });
+ this.sotnSdwansitelanData = this.sotnVpnTableData[num - 1].sdwansitelan_list.map((item) => {
+ return Object.assign({}, {}, item)
+ });
+ this.sotnSdwansitelanData.forEach((item, index) => {
+ this.tabInputShowSdwansitelan[index] = false;
+ });
+ }
+
+ deleteUpdateSotnVpn(num) {
+ this.sotnVpnTableData = this.sotnVpnTableData.filter((d, i) => i !== num - 1);
+ this.sotnvpnnum.splice(num - 1, 1);
+ }
+ updateSotnSdwansitelan() {
+ if (this.tabInputShowSdwansitelan.indexOf(true) > -1) {
+ return false;
+ }
+ let addNum = this.sotnSdwansitelanData.length;
+ let inputsData = Object.assign({}, this.sotnSdwansitelanParams);
+ Object.keys(inputsData).forEach((item) => {
+ if (item != "description") {
+ inputsData[item] = null;
+ }
+ });
+ this.sotnSdwansitelanData[addNum] = inputsData;
+ this.tabInputShowSdwansitelan[addNum] = true;
+ this.sotnSdwansitelanData = [...this.sotnSdwansitelanData];
+ }
+ editUpdateSotnSdwansitelan(num, item, sotnSdwansitelanData) {
+ if (this.tabInputShowSdwansitelan[num - 1] == false) {
+ this.tabInputShowSdwansitelan[num - 1] = true;
+ } else {
+ this.tabInputShowSdwansitelan[num - 1] = false;
+ }
+ }
+ deleteUpdateSotnSdwansitelan(num, item, sotnSdwansitelanData) {
+ if (this.sotnSdwansitelanData.length <= 1) {
+ return false;
+ } else {
+
+ }
+ this.sotnSdwansitelanData = this.sotnSdwansitelanData.filter((d, i) => i !== num - 1);
+ }
+
+ // site addModel
+ siteAddModelShow = false;
+
+ updateSotnvpn() {
+ this.sotnVpnAddModelShow = true;
+ this.isEditSotnVpn = 0;
+ }
+
+ updateSite() {
+ this.siteAddModelShow = true;
+ this.isEditSite = 0;
+ }
+
+ editUpdateSite(num) {
+ this.siteAddModelShow = true;
+ this.isEditSite = num;
+ Object.keys(this.siteBaseData).forEach((item) => {
+ this.siteBaseData[item] = this.siteTableData[num - 1][item];
+ });
+ this.siteSdwanDevice = this.siteTableData[num - 1].sdwandevice_list.map((item) => {
+ return Object.assign({}, item)
+ });
+ this.siteSdwanDevice.forEach((item, index) => {
+ this.tabInputShowDevice[index] = false;
+ });
+ this.siteWanData = this.siteTableData[num - 1].sdwansitewan_list.map((item) => {
+ return Object.assign({}, item)
+ });
+ this.siteWanData.forEach((item, index) => {
+ this.tabInputShowWanPort[index] = false;
+ });
+ }
+
+ updatesite_cancel() {
+ Object.keys(this.siteBaseData).forEach((item) => {
+ this.siteBaseData[item] = null;
+ })
+ this.siteSdwanDevice.forEach((item, index) => {
+ if (index > 0) {
+ this.siteSdwanDevice.splice(index, 1);
+ } else {
+ Object.keys(item).forEach((item2) => {
+ item[item2] = null;
+ });
+ this.tabInputShowDevice[index] = true;
+ }
+
+ });
+ this.siteWanData.forEach((item, index) => {
+ if (index > 0) {
+ this.siteWanData.splice(index, 1);
+ } else {
+ Object.keys(item).forEach((item2) => {
+ item[item2] = null;
+ });
+ this.tabInputShowWanPort[index] = true;
+ }
+
+ });
+ this.siteAddModelShow = false;
+ }
+
+ updatesite_OK() {
+ let inputs = {
+ "sdwandevice_list": [],
+ "sdwansitewan_list": []
+ };
+ inputs = Object.assign(inputs, this.siteBaseData);
+ inputs["sdwandevice_list"] = this.siteSdwanDevice.map((item) => {
+ return Object.assign({}, item);
+ });
+ inputs["sdwansitewan_list"] = this.siteWanData.map((item) => {
+ return Object.assign({}, item);
+ });
+ if (this.isEditSite) {
+ // Edit status does not increase
+ this.siteTableData[this.isEditSite - 1] = inputs;
+ this.siteTableData = [...this.siteTableData]; //Table refresh
+ } else {
+ // this.siteTableData.push(inputs);
+ this.siteTableData = [...this.siteTableData, inputs];
+ this.sitenum = [...this.sitenum, true];
+ }
+
+ Object.keys(this.siteBaseData).forEach((item) => { //Clear modal box
+ this.siteBaseData[item] = null;
+ });
+ this.siteSdwanDevice.forEach((item, index) => {
+ if (index > 0) {
+ this.siteSdwanDevice.splice(index, 1);
+ this.tabInputShowDevice.splice(index, 1);
+ } else {
+ Object.keys(item).forEach((item2) => {
+ item[item2] = null;
+ });
+ this.tabInputShowDevice[index] = true;
+ }
+
+ });
+ this.siteWanData.forEach((item, index) => {
+ if (index > 0) {
+ this.siteWanData.splice(index, 1);
+ this.tabInputShowWanPort.splice(index, 1);
+ } else {
+ Object.keys(item).forEach((item2) => {
+ item[item2] = null;
+ });
+ this.tabInputShowWanPort[index] = true;
+ }
+
+ });
+ console.log(this.siteTableData);
+ this.siteAddModelShow = false;
+ }
+
+ //add.edit,detele siteWanPort
+ updateSiteWan() {
+ if (this.tabInputShowWanPort.indexOf(true) > -1) {//Adding new rows is not allowed when there is a row of data being edited
+ return false;
+ }
+ let addNum = this.siteWanData.length;
+ let inputsData = Object.assign({}, this.siteWanParams);
+ Object.keys(inputsData).forEach((item) => {//Add a new line of empty data
+ if (item != "description") {
+ inputsData[item] = null;
+ }
+ });
+ this.siteWanData[addNum] = inputsData;
+ this.tabInputShowWanPort[addNum] = true;
+ this.siteWanData = [...this.siteWanData]; //Table refresh
+ console.log(this.siteWanData)
+ }
+
+ editUpdateWanPort(num, item, siteWanData) {
+ if (this.tabInputShowWanPort[num - 1] == false) {
+ this.tabInputShowWanPort[num - 1] = true;
+ } else {
+ this.tabInputShowWanPort[num - 1] = false;
+ }
+ }
+
+ deleteUpdateWanPort(num, item, siteWanData) {
+ if (this.siteWanData.length <= 1) {
+ return false;
+ }
+ this.siteWanData = this.siteWanData.filter((d, i) => i !== num - 1);
+ }
+
+ // site节点图形描绘
+ // site分类,根据site查tp pnf --> allotted-resource
+ localSite = [];//本地site
+ outerSite = [];//外部site
+
+ getSiteAResource() {
+ return new Promise((res, rej) => {
+ this.detailParams.siteSer.forEach((site) => {
+ site["relationship-list"]["relationship"].find((item) => { return item["related-to"] == "site-resource" }) ? this.localSite.push(site) : this.outerSite.push(site);
+ });
+
+ if (this.localSite[0] && this.localSite[0]["service-instance-name"].startsWith("Dc")) {
+ this.localSite.reverse();
+ }
+
+ if (this.outerSite[0] && this.outerSite[0]["service-instance-name"].startsWith("Dc")) {
+ this.outerSite.reverse();
+ }
+ if (this.localSite.length > 0) {
+ this.detailLines = [].concat(this.detailLiness);
+ this.localSite.forEach((site) => {
+ let obj = {
+ customerId: this.detailParams.customer.id,
+ serviceType: this.detailParams.serviceType,
+ serviceId: site["service-instance-id"]
+ };
+ this.myhttp.getAllottedResource(obj)
+ .subscribe((data) => {
+ let resource = data["allotted-resource"].find((item) => { return item["allotted-resource-name"] == "sotn ar" });
+ let tps_pnfs = resource["relationship-list"]["relationship"].find((item) => { return item["related-to"] == "p-interface" })["relationship-data"];
+ site.tpsitename = tps_pnfs.find((item) => { return item["relationship-key"] == "p-interface.interface-name" })["relationship-value"];
+ res("sites-domain");
+ })
+ })
+ } else {
+ return false;
+ }
+ })
+ }
+
+
+ vpns = [{ name: "", tps: [], domain: "", sitetpname: "", othertpname: "" }];
+
+
+ getSotnAresource() {
+ return new Promise((res, rej) => {
+ let connectivityId = this.detailParams["relationship-list"]["relationship"]
+ .find((item) => {
+ return item["related-to"] == "connectivity"
+ })["relationship-data"]
+ .find((item2) => {
+ return item2["relationship-key"] == "connectivity.connectivity-id"
+ })["relationship-value"];
+ this.myhttp.getSotnConnectivity(connectivityId)
+ .subscribe((data) => {
+ let vpns = data.connectivity[0]["relationship-list"]["relationship"]
+ .filter((item) => {
+ return item["related-to"] == "vpn-binding"
+ })
+ .map((item2) => {
+ return item2["relationship-data"].find((item3) => {
+ return item3["relationship-key"] == "vpn-binding.vpn-id"
+ })["relationship-value"]
+ });
+ console.log(vpns);
+ this.detailParams.vpns = vpns.map((item) => {
+ return { name: item }
+ });
+ this.detailParams.vpns.forEach((vpn, index) => {
+ this.myhttp.getVpnBinding(vpn.name)
+ .subscribe((data2) => {
+ let tps_pnfs = data2["vpn-binding"][0]["relationship-list"]["relationship"]
+ .filter((item) => {
+ return item["related-to"] == "p-interface"
+ })
+ .map((item2) => {
+ return item2["relationship-data"]
+ });
+ let pnfname = tps_pnfs.map((item) => {
+ return item.find((item2) => {
+ return item2["relationship-key"] == "pnf.pnf-name"
+ })["relationship-value"]
+ });
+ let tpnames = tps_pnfs.map((item) => {
+ return item.find((item2) => {
+ return item2["relationship-key"] == "p-interface.interface-name"
+ })["relationship-value"]
+ });
+ vpn.tps = tpnames;
+ this.myhttp.getPnfDetail(pnfname[0])
+ .subscribe((data2) => {
+ let networkRelation = data2["relationship-list"]["relationship"].find((item) => {
+ return item["related-to"] == "network-resource"
+ })["relationship-data"];
+ vpn.domain = networkRelation.find((item) => {
+ return item["relationship-key"] == "network-resource.network-id"
+ })["relationship-value"];
+ if (this.localSite[index]) {
+ vpn.sitetpname = this.localSite.find((site) => {
+ return tpnames.includes(site.tpsitename)
+ }).tpsitename;
+ console.log(tpnames);
+ console.log(vpn.sitetpname);
+ vpn.othertpname = tpnames.find((name) => {
+ return name != vpn.sitetpname
+ });
+ } else {
+ vpn.sitetpname = this.localSite[0].tpsitename;
+ vpn.othertpname = tpnames.find((name) => {
+ return name != vpn.sitetpname
+ });
+ }
+
+ this.vpns = this.detailParams.vpns;
+ console.log(this.vpns)
+ res(this.detailParams.vpns)
+ })
+ console.log(this.detailParams.vpns)
+ })
+ })
+ })
+ })
+ }
+
+
+ drawImages() {
+
+ this.getSiteAResource().then((data) => {
+ return this.getSotnAresource()
+ }).then((data) => {
+ this.detailSites = this.detailParams.serviceDomain == "CCVPN" ? false : true;
+ // When there is only one vpn
+ if (this.detailParams.serviceDomain == "CCVPN" && this.vpns.length == 1) {
+ this.detailLines.length = this.detailLines.length - 3;
+ // this.detailLines.push(line);
+ // when local site have 2
+ if (this.localSite.length == 2) {
+ let line = {
+ "x1": "30%", "y1": "55%", "x2": "42%", "y2": "55%"//tp2--tp3
+ }
+ this.detailLines.push(line);
+ }
+ // when cloud site have 2
+ if (this.outerSite.length == 2) {
+ let line = {
+ "x1": "81%", "y1": "21%", "x2": "90%", "y2": "21%"//out-domain--site3
+ };
+ this.detailLines.push(line);
+ }
+ }
+ })
+ let allnodes = [this.getSiteAResource(), this.getSotnAresource()];
+ Promise.all(allnodes).then((data) => {
+ console.log(data);
+ console.log(this.localSite);
+
+
+ })
+ }
+
+ detailSites = false;
+ detailLines = [];
+ detailLiness = [ //Details of the topology map connection coordinates
+ {
+ "x1": "9%", "y1": "40%", "x2": "21%", "y2": "40%"//site1--tp1
+ },
+
+ {
+ "x1": "83%", "y1": "51%", "x2": "91%", "y2": "51%"//out-domain--site4
+ },
+
+ {
+ "x1": "52%", "y1": "81%", "x2": "63%", "y2": "81%"//site2--tp4
+ },
+ {
+ "x1": "81%", "y1": "21%", "x2": "90%", "y2": "21%"//out-domain--site3
+ },
+ {
+ "x1": "30%", "y1": "55%", "x2": "44%", "y2": "55%"//tp2--tp3
+ }
+ ];
+
+ modifyJosnKey(json, oddkey, newkey) {
+
+ let val = json[oddkey];
+ delete json[oddkey];
+ json[newkey] = val;
+ }
+
+ // ccvpn update
+ submitUpdate() {
+ let globalCustomerId = this.detailParams.customer.id;
+ let globalServiceType = this.detailParams.serviceType.name;
+ let servicebody = {
+ service: {
+ name: this.templateParameters.service["name"],
+ description: this.templateParameters.service["description"],
+ serviceInvariantUuid: this.templateParameters.service["serviceInvariantUuid"],
+ serviceUuid: this.templateParameters.service["serviceUuid"],
+ globalSubscriberId: globalCustomerId, //customer.id
+ serviceType: globalServiceType, //serviceType.value
+ parameters: {
+ locationConstraints: [],
+ resources: [],
+ requestInputs: {
+ sdwanvpnresource_list: [],
+ sdwansiteresource_list: []
+ }
+ }
+ }
+ };
+ let siteresource = null, sitewan = null, device = null, vpnresource = null, sitelan = null;
+ Object.keys(this.bodyTemplateParameter).map((item, index) => {
+ if (item.search("site") != -1) {
+ siteresource = item;
+ this.bodyTemplateParameter[item].map((items, index) => {
+ if (Object.keys(items)[0].search("site") != -1 && Object.keys(items)[0].search("device") == -1) {
+ sitewan = Object.keys(items)[0]
+ }
+ if (Object.keys(items)[0].search("device") != -1) {
+ device = Object.keys(items)[0]
+ }
+ });
+ }
+ if (item.search("vpn") != -1) {
+ vpnresource = item;
+ this.bodyTemplateParameter[item].map((items, index) => {
+ if (Object.keys(items)[0].search("site") != -1) {
+ sitelan = Object.keys(items)[0]
+ }
+ });
+ }
+ });
+ this.sotnVpnTableData.forEach((item, index) => {
+ Object.keys(item).map((items, index) => {
+ if (items.search("site") != -1 && item[items] instanceof Array === true) {
+ this.modifyJosnKey(item, items, sitelan)
+ }
+ });
+ });
+ this.siteTableData.forEach((item, index) => {
+ Object.keys(item).map((items, index) => {
+ if (items.search("site") != -1 && items.search("device") == -1 && item[items] instanceof Array === true) {
+ this.modifyJosnKey(item, items, sitewan)
+ }
+ if (items.search("device") != -1) {
+ this.modifyJosnKey(item, items, device)
+ }
+ });
+ });
+ Object.keys(this.bodyTemplateParameter).map((item, index) => {
+ if (item.search("site") != -1) {
+ servicebody.service.parameters.requestInputs[item] = [].concat(this.siteTableData);
+ }
+ if (item.search("vpn") != -1) {
+ servicebody.service.parameters.requestInputs[item] = [].concat(this.sotnVpnTableData);
+ }
+ });
+ console.log(servicebody);
+ this.closeUpdate.emit(servicebody);
+ }
+
+ goback() {
+ this.closeDetail.emit();
+ }
+
+ hiddenModel() {
+ this.sotnVpnDetailShow = false;
+ this.siteDetail = false;
+ }
+
+}
diff --git a/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.css b/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.css
new file mode 100644
index 00000000..5055205d
--- /dev/null
+++ b/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.css
@@ -0,0 +1,119 @@
+/*
+ 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 {
+ /*margin-top:-4%;*/
+ background-color: #fff;
+ /*float: left;*/
+ 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/ccvpn-network/ccvpn-network.component.html b/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.html
new file mode 100644
index 00000000..25687f67
--- /dev/null
+++ b/usecaseui-portal/src/app/views/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/ccvpn-network/ccvpn-network.component.spec.ts b/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.spec.ts
new file mode 100644
index 00000000..9ec321c5
--- /dev/null
+++ b/usecaseui-portal/src/app/views/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/ccvpn-network/ccvpn-network.component.ts b/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.ts
new file mode 100644
index 00000000..8a56d885
--- /dev/null
+++ b/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.ts
@@ -0,0 +1,1270 @@
+/*
+ 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);
+ }
+ console.log(this.networkOption);
+ 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);
+ }
+ console.log(this.logicalLinks);
+ 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.getPInterfacesData1(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.getPInterfacesData2(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/fcaps/fcaps.component.html b/usecaseui-portal/src/app/views/fcaps/fcaps.component.html
new file mode 100644
index 00000000..edd2111a
--- /dev/null
+++ b/usecaseui-portal/src/app/views/fcaps/fcaps.component.html
@@ -0,0 +1,3 @@
+<iframe src="http://172.30.1.80:5601" frameborder="0" style="height:100vh;width:100%;"></iframe>
+<!-- <iframe src="http://dl_es:5601/app/kibana#/dashboard/a0db79a0-624e-11e9-88e5-b7b07490dd67?_g=(refreshInterval%3A(pause%3A!f%2Cvalue%3A86400000)%2Ctime%3A(from%3Anow-1y%2Cmode%3Aquick%2Cto%3Anow))" frameborder="0" style="height:100vh;width:100%;"></iframe> -->
+<!-- <iframe src="http://dl_es:5601/app/kibana#/dashboard/a0db79a0-624e-11e9-88e5-b7b07490dd67?embed=true&_g=(refreshInterval%3A(pause%3A!f%2Cvalue%3A86400000)%2Ctime%3A(from%3Anow-1y%2Cmode%3Aquick%2Cto%3Anow))" style="height:100vh;width:100%;"></iframe> -->
diff --git a/usecaseui-portal/src/app/views/fcaps/fcaps.component.less b/usecaseui-portal/src/app/views/fcaps/fcaps.component.less
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/usecaseui-portal/src/app/views/fcaps/fcaps.component.less
diff --git a/usecaseui-portal/src/app/views/fcaps/fcaps.component.spec.ts b/usecaseui-portal/src/app/views/fcaps/fcaps.component.spec.ts
new file mode 100644
index 00000000..42bdbc0f
--- /dev/null
+++ b/usecaseui-portal/src/app/views/fcaps/fcaps.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { FcapsComponent } from './fcaps.component';
+
+describe('FcapsComponent', () => {
+ let component: FcapsComponent;
+ let fixture: ComponentFixture<FcapsComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ FcapsComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(FcapsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/usecaseui-portal/src/app/views/fcaps/fcaps.component.ts b/usecaseui-portal/src/app/views/fcaps/fcaps.component.ts
new file mode 100644
index 00000000..7f9ab7f4
--- /dev/null
+++ b/usecaseui-portal/src/app/views/fcaps/fcaps.component.ts
@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'app-fcaps',
+ templateUrl: './fcaps.component.html',
+ styleUrls: ['./fcaps.component.less']
+})
+export class FcapsComponent implements OnInit {
+
+ constructor() { }
+
+ ngOnInit() {
+ }
+
+}
diff --git a/usecaseui-portal/src/app/views/home/home.component.css b/usecaseui-portal/src/app/views/home/home.component.css
new file mode 100644
index 00000000..41b3f5fe
--- /dev/null
+++ b/usecaseui-portal/src/app/views/home/home.component.css
@@ -0,0 +1,158 @@
+/*
+ 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.
+*/
+.title {
+ font: 700 18px/18px "思源黑体";
+ color: #4c5e70;
+ margin-bottom: 18px;
+}
+hr {
+ border: none;
+ height: 2px;
+ background-color: #dce1e7;
+ margin-bottom: 20px;
+}
+.content .services {
+ float: left;
+ background-color: #fff;
+ width: 30%;
+ height: 628px;
+ border-radius: 5px;
+ padding: 28px 22px;
+}
+.content .services h4 {
+ font: 600 16px/16px "Arial";
+ color: #3d4d65;
+ margin-bottom: 58px;
+}
+.content .services h3 {
+ font: 400 48px/48px "Arial";
+ color: #3fa8eb;
+ text-align: center;
+}
+.content .services h3 span {
+ font-size: 14px;
+}
+.content .services p {
+ font: 400 14px/14px "Arial";
+ color: #54657e;
+ text-align: center;
+ margin-bottom: 48px;
+}
+.content .services .tip {
+ background-color: #eceff4;
+ color: #3d4d65;
+ font-size: 16px;
+ margin: 0 20px;
+ height: 35px;
+ line-height: 35px;
+ border-radius: 5px;
+}
+.content .rightcontent {
+ float: left;
+ padding-left: 15px;
+ width: 70%;
+}
+.content .rightcontent .rt-content {
+ height: 220px;
+ margin-bottom: 18px;
+}
+.content .rightcontent .rt-content .poerformance {
+ float: left;
+ margin-left: 2%;
+ background-color: #fff;
+ height: 100%;
+ width: 50%;
+ border-radius: 5px;
+ padding: 28px 26px;
+}
+.content .rightcontent .rt-content .poerformance h4 {
+ font: 600 16px/16px "Arial";
+ color: #3d4d65;
+ margin-bottom: 34px;
+}
+.content .rightcontent .rt-content .poerformance div {
+ height: 57px;
+ position: relative;
+ margin-bottom: 10px;
+}
+.content .rightcontent .rt-content .poerformance div h3 {
+ font: 600 25px/25px "Arial";
+ color: #3d4d65;
+ margin-bottom: 10px;
+}
+.content .rightcontent .rt-content .poerformance div p {
+ font: 400 12px/12px "Arial";
+ color: #54657e;
+}
+.content .rightcontent .rt-content .poerformance div img {
+ position: absolute;
+ top: 0;
+ right: 0;
+}
+.content .rightcontent .rt-content .alarm {
+ float: left;
+ background-color: #fff;
+ height: 100%;
+ width: 48%;
+ margin-left: 2%;
+ border-radius: 5px;
+ position: relative;
+ padding: 28px 26px;
+}
+.content .rightcontent .rt-content .alarm h4 {
+ position: absolute;
+ font: 600 16px/16px "Arial";
+ color: #3d4d65;
+}
+.content .rightcontent .rb-content {
+ height: 390px;
+ background-color: #fff;
+ border-radius: 5px;
+ padding: 24px 30px;
+ position: relative;
+}
+.content .rightcontent .rb-content h4 {
+ font: 600 16px/16px "Arial";
+ color: #3d4d65;
+}
+.content .rightcontent .rb-content nz-dropdown {
+ position: absolute;
+ top: 24px;
+ right: 30px;
+}
+.content .rightcontent .rb-content nz-dropdown button {
+ width: 170px;
+ height: 35px;
+ background-color: #eceff4;
+ text-align: left;
+ border-color: #cad3df;
+}
+.content .rightcontent .rb-content nz-dropdown button span {
+ display: inline-block;
+ width: 120px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ font-size: 14px;
+}
+.content .rightcontent .rb-content nz-dropdown button i {
+ position: absolute;
+ top: 12px;
+ right: 12px;
+}
+.content .rightcontent .rb-content #pfVmChartLine {
+ width: 100%;
+ height: 318px;
+}
diff --git a/usecaseui-portal/src/app/views/home/home.component.html b/usecaseui-portal/src/app/views/home/home.component.html
new file mode 100644
index 00000000..4126f241
--- /dev/null
+++ b/usecaseui-portal/src/app/views/home/home.component.html
@@ -0,0 +1,102 @@
+<!--
+ 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.
+-->
+
+<!--<h3 class="title"> {{"Overall trend" | translate}}</h3>
+<hr> -->
+<div class="content">
+ <div class="left-content">
+ <div class="services">
+ <h4>{{"i18nTextDefine_SERVICES" | translate}}</h4>
+ <!-- <h3>{{serviceNumber}} <span>{{"services" | translate}}</span> </h3>
+ <p>{{serviceNumber}} {{"services has been created" | translate}}</p> -->
+ <app-pie [initData]="serviceChartInit" [chartData]="serviceChartData" *ngIf="serviceChart"></app-pie>
+ <div *ngIf="!serviceChart"
+ style="color: #ddd; font-weight: 700;font-size: 19px;height: 200px;text-align: center;line-height: 8;">No Service Instances </div>
+
+ <div>
+ <h5><span>{{"i18nTextDefine_Total" | translate}}:</span> {{serviceNumber}}
+ <span>{{"i18nTextDefine_cutomers_and" | translate}}</span> {{serviceNumber}}
+ <span>{{"i18nTextDefine_service_instance" | translate}}</span></h5>
+ </div>
+ <p class="tip">
+ <span style="color:#3C4F8C" (click) = "goback_services()">{{"i18nTextDefine_ViewDetails" | translate}}</span>
+ </p>
+ </div>
+ <div class="PACKAGE">
+ <h4>{{"i18nTextDefine_PACKAGE" | translate}}</h4>
+ <div class="details">
+ <li class="detailstoplinContent">
+ <div class="detailstoplin">
+ <div><span></span> NS</div>
+ <div>
+ <app-bar [initData]="serviceBarChartInit" [chartData]="servicesBarChartData"></app-bar>
+ </div>
+ <div>{{NSdata}}</div>
+ </div>
+ </li>
+ <li class="detailstoplinContent">
+ <div class="detailstoplin">
+ <div><span style="background-color:#BCECB8;"></span> VNF</div>
+ <div>
+ <app-bar [initData]="serviceBarChartInit" [chartData]="servicesBarChartData1"></app-bar>
+ </div>
+ <div>{{Vnfdata}}</div>
+ </div>
+ </li>
+ <li class="detailstoplinContent">
+ <div class="detailstoplin">
+ <div><span style="background-color:#ACCAF4;"></span> PNF</div>
+ <div>
+ <app-bar [initData]="serviceBarChartInit" [chartData]="servicesBarChartData2"></app-bar>
+ </div>
+ <div>{{PnfData}}</div>
+ </div>
+ </li>
+ </div>
+ <p class="tip">
+ <span style="color:#3C4F8C" (click) = "goback_onboard()">{{"i18nTextDefine_ViewDetails" | translate}}</span>
+ </p>
+ </div>
+ </div>
+ <div class="rightcontent" style="height: 96vh">
+ <div class="rt-content">
+ <div class="alarm">
+ <h4>{{"i18nTextDefine_ALARM" | translate}}</h4>
+ <app-pie [initData]="alarmChartInit" [chartData]="alarmChartData"></app-pie>
+ <p class="alarm-name"> {{"i18nTextDefine_VNF_Alarm" | translate}} </p>
+ </div>
+ <div class="poerformance">
+ <app-pie [initData]="VMAlarmChartInit" [chartData]="VMAlarmChartData"></app-pie>
+ <p class="alarm-name"> {{"i18nTextDefine_VM_Alarm" | translate}} </p>
+ <p class="tip">
+ <a href="#" style="color:#3C4F8C">{{"i18nTextDefine_ViewDetails" | translate}}</a>
+ </p>
+ </div>
+ </div>
+ <div class="rb-content">
+ <h4>{{"i18nTextDefine_VM_Performance" | translate}}</h4>
+ <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomRight'">
+ <button nz-button nz-dropdown><span>{{sourceNameSelected}}</span> <i class="anticon anticon-down"></i></button>
+ <ul nz-menu>
+ <li nz-menu-item (click)="sourceNameSelect(item)" *ngFor="let item of sourceNameList">
+ <a>{{item}}</a>
+ </li>
+ </ul>
+ </nz-dropdown>
+ <app-line [initData]="alarmLineChartInit" [chartData]="alarmLineChartData"></app-line>
+ </div>
+ </div>
+</div>
diff --git a/usecaseui-portal/src/app/views/home/home.component.less b/usecaseui-portal/src/app/views/home/home.component.less
new file mode 100644
index 00000000..9e768cf7
--- /dev/null
+++ b/usecaseui-portal/src/app/views/home/home.component.less
@@ -0,0 +1,265 @@
+/*
+ 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.
+*/
+// .title {
+// font: 700 18px/18px "思源黑体";
+// color: #4c5e70;
+// margin-bottom: 18px;
+// }
+// hr {
+// border: none;
+// height: 2px;
+// background-color: #dce1e7;
+// margin-bottom: 20px;
+// }
+.content {
+ padding: 20px 20px;
+ overflow: hidden;
+ .left-content{
+ float: left;
+ width:30%;
+ // height:96vh;
+ .services,.PACKAGE{
+ width: 100%;
+ background:rgba(255,255,255,1);
+ box-shadow:0px 10px 10px 2px rgba(222,222,222,0.5);
+ border-radius:6px;
+ padding: 28px 22px;
+ h4{
+ font: 600 16px/16px "Arial Bold";
+ color: #0DA9E2;
+ }
+ .tip {
+ float: right;
+ width: 110px;
+ line-height: 35px;
+ border-radius: 5px;
+ background-color: #eceff4;
+ font-size: 16px;
+ color: #3C4F8C;
+ margin-top: 20px;
+ margin-bottom: 0!important;
+ }
+ }
+ .services{
+ height:466px;
+ h4{
+ margin-bottom: 20px;
+ }
+ h5 {
+ font: 500 18px/18px "ArialMT";
+ color:#0DA9E2;
+ margin: -2em 0 1em 0 ;
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 2;
+ overflow: hidden;
+ span {
+ font-size: 14px;
+ font-family: "Arial";
+ color:#3C4F8C;
+ }
+ span:first-child {
+ font-size: 18px;
+ padding: 0 4PX 0 4px;
+ }
+ span:last-child {
+ padding-left: 4px;
+ }
+
+ }
+ }
+ .PACKAGE{
+ height:422px;
+ margin-top: 20px;
+ h4{
+ margin-bottom: 50px;
+ }
+ .details {
+ .detailstoplinContent{
+ border-bottom:0.5px solid rgba(237,237,237,1);
+ border-radius:4px;
+ line-height: 45px;
+ font-size: 14px;
+ color: #3C4F8C;
+ font-family:"ArialMT";
+ .detailstoplin {
+ width: 100%;
+ height: 50px;
+ border-top: 0.5px solid #ededed;
+ border-radius: 4px;
+ div:first-child{
+ width: 20%;
+ float: left;
+ }
+ div:nth-child(2){
+ width: 65%;
+ float: left;
+ }
+ div:last-child {
+ width: 13%;
+ float: right;
+ font-size:12px;
+ font-weight: 500;
+ color:rgba(60,79,140,0.5);
+ }
+ }
+ }
+ }
+
+ }
+ }
+ .services,.PACKAGE{
+ h3 {
+ font: 400 48px/48px "Arial";
+ color: #3fa8eb;
+ text-align: center;
+ span {
+ font-size: 14px;
+ }
+ }
+
+ p {
+ font: 400 14px/14px "Arial";
+ color: #54657e;
+ text-align: center;
+ margin-bottom: 48px;
+ }
+ }
+ .rightcontent {
+ float: left;
+ padding-left: 15px;
+ width: 70%;
+ .rt-content {
+ height: 40%;
+ margin-bottom: 18px;
+ background:rgba(255,255,255,1);
+ box-shadow:0px 10px 10px 2px rgba(222,222,222,0.5);
+ border-radius:6px;
+ .poerformance {
+ float: left;
+ background-color: #fff;
+ height: 100%;
+ width: 50%;
+ border-radius: 5px;
+ padding: 28px 26px;
+ .pfVmPm {
+ h3 {
+ color:#BD57E5;
+ }
+ }
+ h4 {
+ font: 600 16px/16px "Arial Bold";
+ color: #0DA9E2;
+ margin-bottom: 34px;
+ }
+
+ div {
+ height: 57px;
+ position: relative;
+ margin-bottom: 10px;
+ h3 {
+ font: 600 25px/25px "Arial";
+ color: #2F6AEF;
+ margin-bottom: 10px;
+ padding-left: 50%;
+ }
+ p {
+ font: 400 12px/12px "Arial";
+ color:rgba(60,79,140,0.5);
+ padding-left: 50%;
+
+ }
+ img {
+ position: absolute;
+ top: 0;
+ left: 0;
+ }
+ }
+ }
+ .alarm {
+ float: left;
+ background-color: #fff;
+ height: 100%;
+ width: 48%;
+ border-radius: 5px;
+ position: relative;
+ padding: 28px 26px;
+ h4 {
+ position: absolute;
+ font: 600 16px/16px "Arial Bold";
+ color: #0DA9E2;
+ }
+ }
+ .alarm-name{
+ text-align: center;
+ margin-top: 15px;
+ }
+ .tip{
+ width: 110px;
+ background-color: #eceff4;
+ color: #3C4F8C;
+ font-size: 16px;
+ float: right;
+ margin-top: 20px;
+ margin-bottom: 0!important;
+ line-height: 35px;
+ border-radius: 5px;
+ text-align: center;
+ }
+ }
+ .rb-content {
+ position: relative;
+ height: 58%;
+ background-color: #fff;
+ padding: 24px 30px;
+ box-shadow:0px 10px 15px 2px rgba(222,222,222,0.5);
+ border-radius:6px;
+ h4 {
+ font: 600 16px/16px "Arial Bold";
+ color: #0DA9E2;
+ }
+ nz-dropdown {
+ position: absolute;
+ top: 24px;
+ right: 30px;
+ button {
+ width: 170px;
+ height: 35px;
+ background-color: #eceff4;
+ text-align: left;
+ border-color: #cad3df;
+ span {
+ display: inline-block;
+ width: 120px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ font-size: 14px;
+ }
+ i {
+ position: absolute;
+ top: 12px;
+ right: 12px;
+ }
+ }
+ //下拉框中的样式在style.less中,下拉框是在body中额外临时生成的
+ }
+ #pfVmChartLine {
+ width: 100%;
+ height: 318px;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/usecaseui-portal/src/app/views/home/home.component.spec.ts b/usecaseui-portal/src/app/views/home/home.component.spec.ts
new file mode 100644
index 00000000..5456a323
--- /dev/null
+++ b/usecaseui-portal/src/app/views/home/home.component.spec.ts
@@ -0,0 +1,42 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { TranslateModule, TranslateLoader, TranslateService, TranslateFakeLoader} from '@ngx-translate/core';
+import { NgZorroAntdModule } from 'ng-zorro-antd';
+import { NgxEchartsModule } from 'ngx-echarts';
+import { HttpClientModule } from '@angular/common/http';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { RouterTestingModule } from '@angular/router/testing';
+
+import { HomeComponent } from './home.component';
+import { PieComponent } from '../../shared/components/charts/pie/pie.component';
+import { BarComponent } from '../../shared/components/charts/bar/bar.component';
+import { LineComponent } from '../../shared/components/charts/line/line.component';
+import { HomesService } from '../../core/services/homes.service';
+
+describe('HomeComponent', () => {
+ let component: HomeComponent;
+ let fixture: ComponentFixture<HomeComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ HomeComponent, PieComponent, BarComponent, LineComponent ],
+ imports: [TranslateModule.forRoot({loader: { provide: TranslateLoader, useClass: TranslateFakeLoader }}),
+ NgZorroAntdModule,
+ NgxEchartsModule,
+ HttpClientModule,
+ BrowserAnimationsModule,
+ RouterTestingModule],
+ providers: [HomesService, TranslateService]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(HomeComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/usecaseui-portal/src/app/views/home/home.component.ts b/usecaseui-portal/src/app/views/home/home.component.ts
new file mode 100644
index 00000000..11a0f1a8
--- /dev/null
+++ b/usecaseui-portal/src/app/views/home/home.component.ts
@@ -0,0 +1,531 @@
+/*
+ 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, OnInit, Input, Output, EventEmitter, HostBinding } from '@angular/core';
+import { HomesService } from '../../core/services/homes.service';
+import { slideToRight } from '../../animates';
+import { TranslateService } from "@ngx-translate/core";
+import { Router } from '@angular/router';
+
+@Component({
+ selector: 'app-home',
+ templateUrl: './home.component.html',
+ styleUrls: ['./home.component.less'],
+ animations: [slideToRight]
+})
+export class HomeComponent implements OnInit {
+ @HostBinding('@routerAnimate') routerAnimateState;
+
+ constructor(private myhttp: HomesService, private router: Router) { }
+
+ ngOnInit() {
+ this.getListSortMasters();
+ this.getSourceNames();
+ this.getHomeServiceData();
+ this.getHomeAlarmData();
+ this.getHomeAlarmChartData();
+ this.getHomeServiceBarNsData();
+ this.getHomeServiceBarVnfData();
+ this.getHomeServiceBarPnfData();
+ }
+
+
+ // services
+ serviceNumber: number = 0;
+ serviceChartData: Object;
+ serviceChartInit: Object = {
+ backgroundColor: '#fff',
+ height: 200,
+ option: {
+ legend: {
+ orient: 'vertical',
+ left: '0px',
+ bottom: '0px',
+ data: ['Active', 'Closed']
+ },
+ color: ["#7AC0EF", "#6A86D8", "#748CDC", "#7277D4", "#7067CE", "#B9B0F7", "#7DCFF5"],
+ series: [
+ {
+ name: "服务信息",
+ radius: ['50%', '70%'],
+ center: ['50%', '45%'],
+ avoidLabelOverlap: false,
+ label: {
+ normal: {
+ show: false,
+ position: 'center'
+ },
+ emphasis: {
+ show: true,
+ formatter: '{b}\n{c}',
+ textStyle: {
+ fontSize: '18',
+ fontWeight: 'bold'
+ }
+ }
+ },
+ labelLine: {
+ normal: {
+ show: false
+ }
+ },
+ itemStyle: {
+ normal: {
+ borderWidth: 4,
+ borderColor: "#fff"
+ },
+ emphasis: {
+ borderWidth: 0
+ }
+ },
+ }
+ ]
+ }
+ };
+ // gethomeServiceData
+ serviceChart = true;
+ getHomeServiceData() {
+ this.myhttp.getHomeServiceData()
+ .subscribe(
+ (data) => {
+ this.serviceNumber = data.serviceTotalNum;
+ if (this.serviceNumber > 0) {
+ this.serviceChart = true;
+ } else {
+ this.serviceChart = false;
+ }
+ this.serviceChartData = {
+ series: [{ data: data.customerServiceList }]
+ };
+ },
+ (err) => {
+ console.error(err);
+ }
+ )
+ }
+
+ // VM alarm
+ VMAlarmChartData: Object;
+ VMAlarmChartInit: Object = {
+ height: 180,
+ option: {
+ tooltip: {
+ trigger: 'item',
+ formatter: '{b}\n{c},{d}%'
+ },
+ color: [
+ {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [{
+ offset: 0, color: '#FB93C2' // 0% color
+ }, {
+ offset: 1, color: '#FB7788' // 100% color
+ }],
+ globalCoord: false
+ }, {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [{
+ offset: 0, color: '#A6BFE4' // 0% color
+ }, {
+ offset: 1, color: '#7A8BAE' // 100% color
+ }],
+ globalCoord: false
+ }],
+ series: [{
+ name: "告警信息",
+ radius: ['50%', '70%'],
+ center: ['50%', '45%'],
+ label: {
+ normal: {
+ show: false,
+ },
+ emphasis: {
+ show: true,
+ formatter: '{b}\n{c},{d}%',
+ color: "#3C4F8C"
+ }
+ },
+
+ }]
+ }
+ };
+
+ // alarm bar
+ alarmChartData: Object;
+ alarmChartInit: Object = {
+ height: 180,
+ option: {
+ tooltip: {
+ trigger: 'item',
+ formatter: '{b}\n{c},{d}%'
+ },
+ legend: {
+ orient: 'vertical',
+ left: '0px',
+ bottom: '0px',
+ itemWidth: 10,
+ itemHeight: 10,
+ textStyle: {
+ color: "#3C4F8C"
+ },
+ data: ['Active', 'Fixed']
+ },
+ color: [
+ {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [{
+ offset: 0, color: '#FB93C2' // 0% color
+ }, {
+ offset: 1, color: '#FB7788' // 100% color
+ }],
+ globalCoord: false
+ }, {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [{
+ offset: 0, color: '#A6BFE4' // 0%
+ }, {
+ offset: 1, color: '#7A8BAE' // 100%
+ }],
+ globalCoord: false
+ }],
+ series: [{
+ name: "告警信息",
+ radius: '55%',
+ center: ['50%', '45%'],
+ label: {
+ normal: {
+ show: false,
+ },
+ emphasis: {
+ show: true,
+ formatter: '{b}\n{c},{d}%',
+ color: "#3C4F8C"
+ }
+ }
+ }]
+ }
+ };
+
+ getHomeAlarmData() {
+ this.myhttp.getHomeAlarmData()
+ .subscribe((data) => {
+ this.alarmChartData = {
+ series: [{
+ data: [{ name: "Active", value: data[0] }, { name: "Fixed", value: data[1] }]
+ }]
+ };
+ this.VMAlarmChartData = {
+ series: [{
+ data: [{ name: "Active", value: data[0] }, { name: "Fixed", value: data[1] }]
+ }]
+ };
+ })
+ }
+
+ // alarm line
+ alarmLineChartData: Object;
+ alarmLineChartInit: Object = {
+ height: 320,
+ option: {
+ legend: {
+ bottom: '0px',
+ data: ['CPU', 'Memory', 'Disk']
+ },
+ xAxis: {
+ data: []
+ },
+ series: [
+ {
+ name: 'CPU',
+ type: 'line',
+ itemStyle: {
+ color: "#70ACEC"
+ },
+ data: []
+ },
+ {
+ name: 'Memory',
+ type: 'line',
+ itemStyle: {
+ color: "#3BCD79"
+ },
+ data: []
+ },
+ {
+ name: 'Disk',
+ type: 'line',
+ itemStyle: {
+ color: "#FDC288"
+ },
+ data: []
+ }
+ ]
+ }
+ };
+
+ // services
+ servicesBarChartData: Object;
+ servicesBarChartData1: Object;
+ servicesBarChartData2: Object;
+ serviceBarChartInit: Object = {
+ height: 40,
+ width: 160,
+ option: {
+ tooltip: {
+
+ },
+ grid: {
+
+ },
+ xAxis: {
+ type: 'value',
+ show: false,
+ min: 0,
+ max: 100,
+ axisTick: {
+ show: false
+ },
+ },
+ yAxis: {
+ type: 'category',
+ show: false,
+ axisTick: {
+ show: false
+ }
+ },
+ series: [{
+ type: 'bar',
+ name: 'a',
+ silent: true,
+ animation: false,
+ data: [],
+ stack: 'income',
+ barWidth: 12,
+ itemStyle: {
+ normal: {}
+ },
+ }, {
+ type: 'bar',
+ name: '',
+ animation: false,
+ silent: true,
+ data: [100],
+ tooltip: {
+ show: false
+ },
+ stack: 'income',
+ barWidth: 12,
+ itemStyle: {
+ normal: {
+ color: '#fff',
+ barBorderRadius: [10, 10, 10, 10]
+ }
+ },
+ label: {
+ normal: {
+ show: false,
+ }
+ },
+ }
+ ]
+ }
+ }
+
+
+ NSdata: number;
+ Vnfdata: number;
+ PnfData: number;
+ getHomeServiceBarNsData() {
+ this.myhttp.getHomeServiceBarNsData()
+ .subscribe((data) => {
+ this.NSdata = data.length;
+ this.servicesBarChartData = {
+ series: [
+ {
+ data: [this.NSdata],
+ itemStyle: {
+ normal: {
+ color: {
+ type: 'bar',
+ colorStops: [{
+ offset: 0,
+ color: '#FDAC63'
+ }, {
+ offset: 1,
+ color: '#FECE72'
+ }],
+ globalCoord: false,
+ },
+ barBorderRadius: [10, 10, 10, 10]
+ }
+ },
+ },
+ { data: [100] },
+
+ ]
+ }
+ }, (err) => {
+ console.error(err);
+ })
+ }
+
+ getHomeServiceBarVnfData() {
+ this.myhttp.getHomeServiceBarVnfData()
+ .subscribe((data) => {
+ this.Vnfdata = data.length;
+ this.servicesBarChartData1 = {
+ series: [
+ {
+ data: [this.Vnfdata],
+ itemStyle: {
+ normal: {
+ color: {
+ type: 'bar',
+ colorStops: [{
+ offset: 0,
+ color: '#9AD09F'
+ }, {
+ offset: 1,
+ color: '#BCECB8'
+ }],
+ globalCoord: false,
+
+ },
+ barBorderRadius: [10, 10, 10, 10]
+ }
+ },
+ },
+ { data: [100] },
+ ]
+ }
+ }, (err) => {
+ console.error(err);
+ })
+ }
+
+ getHomeServiceBarPnfData() {
+ this.myhttp.getHomeServiceBarPnfData()
+ .subscribe((data) => {
+ this.PnfData = data.length;
+ this.servicesBarChartData2 = {
+ series: [
+ {
+ data: [this.PnfData],
+ itemStyle: {
+ normal: {
+ color: {
+ type: 'bar',
+ colorStops: [{
+ offset: 0,
+ color: '#71ADEF'
+ }, {
+ offset: 1,
+ color: '#ACCAF4'
+ }],
+ globalCoord: false,
+
+ },
+ barBorderRadius: [10, 10, 10, 10]
+ }
+ },
+ },
+ { data: [100] },
+ ]
+ }
+ }, (err) => {
+ console.error(err);
+ })
+ }
+ // sourceName
+ sourceNameList = ['performanceNameOne'];
+ sourceNameSelected = null;
+
+
+ listSortMasters = null;
+
+ getListSortMasters() {
+ if (sessionStorage.getItem("DefaultLang") == undefined) {
+ sessionStorage.setItem("DefaultLang", "en");
+ }
+ this.myhttp.getListSortMasters()
+ .subscribe((data) => {
+ this.listSortMasters = JSON.stringify(data);
+ sessionStorage.setItem('listSortMasters', this.listSortMasters)
+ })
+ }
+
+ getSourceNames() {
+ this.myhttp.getSourceNames()
+ .subscribe((data) => {
+ this.sourceNameList = data;
+ })
+ }
+ sourceNameSelect(item) {
+ if (this.sourceNameSelected != item) {
+ this.sourceNameSelected = item;
+ this.getHomeAlarmChartData()
+ }
+ }
+ getHomeAlarmChartData() {
+ let nowTime = this.myhttp.dateformater(Date.now());
+ let startTime = this.myhttp.dateformater(Date.now() - 30 * 24 * 60 * 60 * 1000);
+ let obj = {
+ sourceName: this.sourceNameSelected,
+ startTime: startTime,
+ endTime: nowTime,
+ format: "day"
+ }
+
+ this.myhttp.getHomeAlarmChartData(obj)
+ .subscribe((data) => {
+ this.alarmLineChartData = {
+ xAxis: {
+ data: data.dataList
+ },
+ series: [
+ { data: data.allList },
+ { data: data.ActiveList },
+ { data: data.closedList }
+ ]
+ }
+ }, (err) => {
+ console.error(err);
+ })
+ }
+
+ goback_services() {
+ this.router.navigateByUrl('/services/services-list');
+ }
+ goback_onboard() {
+ this.router.navigateByUrl('/services/onboard-vnf-vm');
+ }
+
+}
diff --git a/usecaseui-portal/src/app/views/management/management.component.html b/usecaseui-portal/src/app/views/management/management.component.html
new file mode 100644
index 00000000..c96f0253
--- /dev/null
+++ b/usecaseui-portal/src/app/views/management/management.component.html
@@ -0,0 +1,39 @@
+<!--
+ 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.
+-->
+<div class="content" style="padding: 20px 20px;height: 100vh">
+ <div class="management" *ngIf="nocuster">
+ <div class="title">
+ <p> {{"i18nTextDefine_Create_initial_customer" | translate}} </p>
+ <span> {{"i18nTextDefine_Customer_not_in_ONAP" | translate}} </span>
+ <span> {{"i18nTextDefine_CreateCustomer" | translate}} </span>
+ <img src="../../../assets/images/customer01.png" alt="">
+ <input nz-input placeholder=" {{'i18nTextDefine_Input_customerName' | translate}} " nzSize="large"
+ style="height: 50px" [(ngModel)]="firstCustomer">
+ <div class="action">
+ <button nz-button nzType="primary" class="cancel" (click)="clearCustomerInput()">
+ {{"i18nTextDefine_Cancel" | translate}} </button>
+ <button nz-button nzType="primary" class="add" (click)="createNewCustomer(firstCustomer)">
+ {{"i18nTextDefine_Add" | translate}} </button>
+ </div>
+ </div>
+ <div class="image">
+ <img src="../../../assets/images/customer02.png" alt="">
+ </div>
+ </div>
+ <div *ngIf="!nocuster" style="height: 100%">
+ <app-customer></app-customer>
+ </div>
+</div> \ No newline at end of file
diff --git a/usecaseui-portal/src/app/views/management/management.component.less b/usecaseui-portal/src/app/views/management/management.component.less
new file mode 100644
index 00000000..5a3a0f42
--- /dev/null
+++ b/usecaseui-portal/src/app/views/management/management.component.less
@@ -0,0 +1,79 @@
+/*
+ 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.
+*/
+.content {
+ .management {
+ width: 100%;
+ .title {
+ width: 50%;
+ vertical-align:top;
+ display: inline-block;
+ font-family: "Arial";
+ p {
+ font-size: 33px;
+ color: #3C4F8C;
+ margin-bottom: 0.5em;
+ }
+ span {
+ font-size: 18px;
+ color: rgba(60,79,140,0.5);
+ display: block;
+ }
+ img {
+ padding-top: 8%;
+ width: 55%;
+ margin-left: 20%;
+ margin-bottom: 5%;
+ }
+ input {
+ width: 50%;
+ margin: 0 auto;
+ margin-bottom: 5%;
+ display: block;
+
+ }
+ .action{
+ width: 50%;
+ height: 40px;
+ margin: 0 auto;
+ }
+ .action button{
+ width: 40%;
+ height: 40px;
+ margin: 0 4%;
+ }
+ .cancel{
+ background-color: #eee;
+ border-color: #eee;
+ color: #9DA7C5;
+ }
+ .add {
+ color: #fff;
+ background:linear-gradient(310deg,rgba(30,158,255,1) 0%,rgba(99,200,255,1) 100%);
+ border-color: #1890ff;
+ }
+ }
+ .image {
+ width: 49%;
+ vertical-align:top;
+ display: inline-block;
+ img {
+ width: 85%;
+ margin-top: 41%;
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/usecaseui-portal/src/app/views/management/management.component.spec.ts b/usecaseui-portal/src/app/views/management/management.component.spec.ts
new file mode 100644
index 00000000..f6152432
--- /dev/null
+++ b/usecaseui-portal/src/app/views/management/management.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ManagementComponent } from './management.component';
+
+describe('ManagementComponent', () => {
+ let component: ManagementComponent;
+ let fixture: ComponentFixture<ManagementComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ManagementComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ManagementComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/usecaseui-portal/src/app/views/management/management.component.ts b/usecaseui-portal/src/app/views/management/management.component.ts
new file mode 100644
index 00000000..8b3afea7
--- /dev/null
+++ b/usecaseui-portal/src/app/views/management/management.component.ts
@@ -0,0 +1,68 @@
+/*
+ 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, OnInit , HostBinding} from '@angular/core';
+import { showHideAnimate, slideToRight } from '../../animates';
+import { ManagemencsService } from '../../core/services/managemencs.service';
+
+@Component({
+ selector: 'app-management',
+ templateUrl: './management.component.html',
+ styleUrls: ['./management.component.less'],
+ animations: [
+ showHideAnimate, slideToRight
+ ]
+})
+export class ManagementComponent implements OnInit {
+ @HostBinding('@routerAnimate') routerAnimateState; //Routing animation
+
+ constructor(private managemencs: ManagemencsService) { }
+
+ ngOnInit() {
+ this.getAllCustomers();
+ }
+
+ nocuster = true;
+ firstCustomer = null;
+ AllCustomersdata = [];
+
+ // Get all customers
+ getAllCustomers() {
+ this.managemencs.getAllCustomers().subscribe((data) => {
+ if (data.length > 0) {
+ this.nocuster = false;
+ } else {
+ this.nocuster = true;
+ }
+ })
+ }
+
+ createNewCustomer(customer) {
+ let createParams = {
+ customerId: customer
+ };
+ this.managemencs.createCustomer(customer, createParams).subscribe((data) => {
+ if (data["status"] == 'SUCCESS') {
+ this.nocuster = false;
+ } else {
+ this.nocuster = true;
+ console.log(data, "Interface returned error")
+ }
+ })
+ }
+ clearCustomerInput(){
+ this.firstCustomer=null;
+ }
+}
diff --git a/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.css b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.css
new file mode 100644
index 00000000..e9631957
--- /dev/null
+++ b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.css
@@ -0,0 +1,75 @@
+/*
+ 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.
+*/
+.title {
+ font: 700 18px/18px "思源黑体";
+ color: #4c5e70;
+ margin-bottom: 18px;
+}
+hr {
+ border: none;
+ height: 2px;
+ background-color: #dce1e7;
+ margin-bottom: 20px;
+}
+.select {
+ margin-bottom: 20px;
+}
+.select span {
+ display: inline-block;
+ font: 700 14px "Arial";
+ color: #4c5e70;
+}
+.select nz-dropdown {
+ vertical-align: middle;
+}
+.select nz-dropdown :hover {
+ border-color: #147dc2;
+}
+.select nz-dropdown button {
+ width: 165px;
+ height: 30px;
+ background-color: #eceff4;
+ text-align: left;
+ border-color: #9fa9ab;
+}
+.select nz-dropdown button span {
+ font-weight: 400;
+ display: inline-block;
+ width: 120px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ padding-top: 2px;
+}
+.select nz-dropdown button i {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+}
+.select .submit {
+ margin-left: 20px;
+ vertical-align: middle;
+ height: 30px;
+ padding: 0 10px;
+}
+.select .submit span {
+ color: #fff;
+ font-weight: 400;
+}
+.content {
+ background-color: #fff;
+ border-radius: 5px;
+ padding: 12px;
+}
diff --git a/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.html b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.html
new file mode 100644
index 00000000..06d84353
--- /dev/null
+++ b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.html
@@ -0,0 +1,79 @@
+<!--
+ 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.
+-->
+<!-- <h3 class="title">
+ <span (click)="performanceShow()" style="cursor:pointer;">Performance VM</span>
+ <span (click)="graphicShow()" *ngIf="graphicshow">> Graphic list </span>
+ <span *ngIf="detailshow">> Details </span>
+</h3>
+<hr>
+<div class="select" [@showHideAnimate]="state">
+ <span>Source Name: </span>
+ <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomLeft'">
+ <button nz-button nz-dropdown><span>{{sourceNameSelected}}</span> <i class="anticon anticon-down"></i></button>
+ <ul nz-menu>
+ <li nz-menu-item (click)="choseSourceName(item)" *ngFor="let item of sourceNameList">
+ <a>{{item}}</a>
+ </li>
+ </ul>
+ </nz-dropdown>
+ &nbsp;&nbsp;
+ <span>ReportingEntityName: </span>
+ <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomLeft'">
+ <button nz-button nz-dropdown><span>{{ReportingEntityNameSelected}}</span> <i class="anticon anticon-down"></i></button>
+ <ul nz-menu>
+ <li nz-menu-item (click)="choseReportingEntityName(item)" *ngFor="let item of ReportingEntityNameList">
+ <a>{{item}}</a>
+ </li>
+ </ul>
+ </nz-dropdown>
+ <button class="submit" nz-button [nzType]="'primary'" (click)="submit()"><i class="anticon anticon-plus-circle-o"></i><span>Submit</span></button>
+</div>
+<div class="content" [@showHideAnimate]="state">
+ <nz-table #nzTable [nzData]="dataSet" [nzPageSize]="10" nzShowSizeChanger nzShowQuickJumper [nzPageSizeOptions]="[5,10,15,20]" nzSize="middle">
+ <thead (nzSortChange)="sort($event)" nzSingleSort>
+ <tr>
+ <th nzWidth="5%">NO</th>
+ <th nzWidth="20%">Source Name</th>
+ <th nzWidth="20%">ReportingEntityName</th>
+ <th nzWidth="10%">Type</th>
+ <th nzWidth="15%">CPU</th>
+ <th nzWidth="10%">Memory</th>
+ <th nzWidth="10%">Disk</th>
+ <th nzWidth="10%">Action</th>
+ </tr>
+ </thead>
+ <tbody> -->
+ <!-- <ng-template ngFor let-data [ngForOf]="nzTable.data" let-i="index"> -->
+ <!-- <tr *ngFor="let item of nzTable.data; let i = index; ">
+ <td>{{i+1}}</td>
+ <td>{{item.name}}</td>
+ <td>{{item.address}}</td>
+ <td>{{item.age}}</td>
+ <td>{{item.address}}</td>
+ <td>{{item.age}}</td>
+ <td>{{item.age}}</td>
+ <td><a (click)="graphicShow()">Delete</a></td>
+ </tr> -->
+ <!-- </ng-template> -->
+ <!-- </tbody>
+ </nz-table>
+</div>
+<div [@showHideAnimate]="state2">
+ <app-graphiclist (detailData)="detailShow($event)"></app-graphiclist>
+</div>
+<div [@showHideAnimate]="state3">
+ <app-details [detailId]="detailId"></app-details>
+</div> -->
diff --git a/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.less b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.less
new file mode 100644
index 00000000..31623dcf
--- /dev/null
+++ b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.less
@@ -0,0 +1,76 @@
+/*
+ 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.
+*/
+.title {
+ font: 700 18px/18px "思源黑体";
+ color: #4c5e70;
+ margin-bottom: 18px;
+}
+hr {
+ border: none;
+ height: 2px;
+ background-color: #dce1e7;
+ margin-bottom: 20px;
+}
+.select {
+ margin-bottom: 20px;
+ span {
+ display: inline-block;
+ font: 700 14px "Arial";
+ color: #4c5e70;
+ }
+ nz-dropdown {
+ vertical-align: middle;
+ :hover{
+ border-color: #147dc2;
+ }
+ button {
+ width: 165px;
+ height: 30px;
+ background-color: #eceff4;
+ text-align: left;
+ border-color: #9fa9ab;
+ span {
+ font-weight: 400;
+ display: inline-block;
+ width: 120px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ padding-top: 2px;
+ }
+ i {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ }
+ }
+ //下拉框中的样式在style.less中,下拉框是在body中额外临时生成的
+ }
+ .submit {
+ margin-left: 20px;
+ vertical-align: middle;
+ height: 30px;
+ padding: 0 10px;
+ span {
+ color: #fff;
+ font-weight: 400;
+ }
+ }
+}
+.content {
+ background-color: #fff;
+ border-radius: 5px;
+ padding: 12px;
+} \ No newline at end of file
diff --git a/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.spec.ts b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.spec.ts
new file mode 100644
index 00000000..b66b2ea0
--- /dev/null
+++ b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.spec.ts
@@ -0,0 +1,68 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { PerformanceVmComponent } from './performance-vm.component';
+
+describe('PerformanceVmComponent', () => {
+ let component: PerformanceVmComponent;
+ let fixture: ComponentFixture<PerformanceVmComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ PerformanceVmComponent ],
+ imports: [
+ BrowserAnimationsModule
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(PerformanceVmComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('should test performanceShow method to set proper values', () => {
+ component.performanceShow();
+ expect(component.state).toBe('show');
+ expect(component.state2).toBe('hide');
+ expect(component.state3).toBe('hide');
+ expect(component.graphicshow).toBe(false);
+ expect(component.detailshow).toBe(false);
+ });
+
+ it('should test graphicShow method to set proper values', () => {
+ component.graphicShow();
+ expect(component.state).toBe('hide');
+ expect(component.state2).toBe('show');
+ expect(component.state3).toBe('hide');
+ expect(component.graphicshow).toBe(true);
+ expect(component.detailshow).toBe(false);
+ });
+
+ it('should test detailShow method to set proper values', () => {
+ component.detailShow({id:1});
+ expect(component.state).toBe('hide');
+ expect(component.state2).toBe('hide');
+ expect(component.state3).toBe('show');
+ expect(component.graphicshow).toBe(true);
+ expect(component.detailshow).toBe(true);
+ expect(component.detailId).toBe(1);
+ });
+
+ it('should test choseSourceName method', () => {
+ component.choseSourceName('bbbb');
+ expect(component.sourceNameSelected).toBe('bbbb');
+ });
+
+ it('should test choseSourceName method', () => {
+ component.choseReportingEntityName('bbbb');
+ expect(component.ReportingEntityNameSelected).toBe('bbbb');
+ });
+
+});
diff --git a/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.ts b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.ts
new file mode 100644
index 00000000..c179cdbb
--- /dev/null
+++ b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.ts
@@ -0,0 +1,159 @@
+import { Component, OnInit, HostBinding } from '@angular/core';
+import { slideToRight, showHideAnimate } from '../../../animates';
+
+@Component({
+ selector: 'app-performance-vm',
+ templateUrl: './performance-vm.component.html',
+ styleUrls: ['./performance-vm.component.less'],
+ animations: [ slideToRight, showHideAnimate ]
+})
+export class PerformanceVmComponent implements OnInit {
+ @HostBinding('@routerAnimate') routerAnimateState;
+ constructor() { }
+
+ ngOnInit() {
+ }
+
+ // Filter box (drop-down box)
+ sourceNameList = ['aaaa','bbbb','cccc','dddddDDDDDDDDDDDDDDD'];
+ sourceNameSelected = this.sourceNameList[0];
+ ReportingEntityNameList = ['aaaa','bbbb','cccc','ddddd'];
+ ReportingEntityNameSelected = this.ReportingEntityNameList[0];
+ choseSourceName(item){
+ console.log(item);
+ this.sourceNameSelected = item;
+ }
+ choseReportingEntityName(item){
+ console.log(item);
+ this.ReportingEntityNameSelected = item;
+ }
+
+ //Tabular data
+ dataSet = [
+ {
+ name : 'John Brown',
+ age : 32,
+ expand : false,
+ address : 'New York No. 1',
+ description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.'
+ },
+ {
+ name : 'Aim Green',
+ age : 42,
+ expand : false,
+ address : 'London No. 1',
+ description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.'
+ },
+ {
+ name : 'Bim Green',
+ age : 42,
+ expand : false,
+ address : 'London No. 1',
+ description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.'
+ },
+ {
+ name : 'Cim Green',
+ age : 42,
+ expand : false,
+ address : 'London No. 1',
+ description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.'
+ },
+ {
+ name : 'Jim Green',
+ age : 42,
+ expand : false,
+ address : 'London No. 1',
+ description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.'
+ },
+ {
+ name : 'Xim Green',
+ age : 42,
+ expand : false,
+ address : 'London No. 1',
+ description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.'
+ },
+ {
+ name : 'Jim Green',
+ age : 42,
+ expand : false,
+ address : 'London No. 1',
+ description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.'
+ },
+ {
+ name : 'Jim Green',
+ age : 42,
+ expand : false,
+ address : 'London No. 1',
+ description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.'
+ },
+ {
+ name : 'Jim Green',
+ age : 42,
+ expand : false,
+ address : 'London No. 1',
+ description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.'
+ },
+ {
+ name : 'Jim Green',
+ age : 42,
+ expand : false,
+ address : 'London No. 1',
+ description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.'
+ },
+ {
+ name : 'cim Green',
+ age : 42,
+ expand : false,
+ address : 'London No. 1',
+ description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.'
+ },
+ {
+ name : 'bim Green',
+ age : 42,
+ expand : false,
+ address : 'London No. 1',
+ description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.'
+ },
+ {
+ name : 'aoe Black',
+ age : 32,
+ expand : false,
+ address : 'Sidney No. 1',
+ description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.'
+ }
+ ];
+
+ //Detail page title display
+ graphicshow = false;
+ detailshow = false;
+ // Show hidden animation
+ state = "show";
+ state2 = "hide";
+ state3 = "hide";
+ performanceShow() {
+ this.state = 'show';
+ this.state2 = 'hide';
+ this.state3 = 'hide';
+ this.graphicshow = false;
+ this.detailshow = false;
+ }
+ graphicShow() {
+ this.state = 'hide';
+ this.state2 = 'show';
+ this.state3 = 'hide';
+ this.graphicshow = true;
+ this.detailshow = false;
+ }
+ // Selected id
+ detailId:number;
+ detailShow(prems) {
+ this.state = 'hide';
+ this.state2 = 'hide';
+ this.state3 = 'show';
+ this.graphicshow = true;
+ this.detailshow = true;
+ console.log(prems);
+ this.detailId = prems.id;
+ }
+
+}
diff --git a/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.css b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.css
new file mode 100644
index 00000000..269af7a9
--- /dev/null
+++ b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.css
@@ -0,0 +1,126 @@
+/*
+ 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.
+*/
+.title {
+ font: 700 18px/18px "思源黑体";
+ color: #4c5e70;
+ margin-bottom: 18px;
+}
+hr {
+ border: none;
+ height: 2px;
+ background-color: #dce1e7;
+ margin-bottom: 20px;
+}
+.select {
+ margin-bottom: 20px;
+}
+.select span {
+ display: inline-block;
+ font: 700 14px "Arial";
+ color: #4c5e70;
+}
+.select nz-dropdown {
+ vertical-align: middle;
+}
+.select nz-dropdown :hover {
+ border-color: #147dc2;
+}
+.select nz-dropdown button {
+ width: 165px;
+ height: 30px;
+ background-color: #eceff4;
+ text-align: left;
+ border-color: #9fa9ab;
+}
+.select nz-dropdown button span {
+ font-weight: 400;
+ display: inline-block;
+ width: 120px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ padding-top: 2px;
+}
+.select nz-dropdown button i {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+}
+.select .search {
+ margin-left: 20px;
+ vertical-align: middle;
+ height: 30px;
+ padding: 0 10px;
+}
+.select .search span {
+ color: #fff;
+ font-weight: 400;
+}
+.content {
+ background-color: #fff;
+ border-radius: 5px;
+ padding: 12px;
+}
+.content .vnfs {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-around;
+}
+.content .vnfs .vnf {
+ width: 18%;
+ height: 200px;
+ margin: 5px;
+ padding: 20px;
+ border-radius: 2px;
+ text-align: center;
+ cursor: pointer;
+ transition: all 0.3s linear;
+}
+.content .vnfs .vnf:hover {
+ background-color: #f5f5f5;
+ transform: scale(1.02);
+}
+.content .vnfs .vnf h3 {
+ font-size: 14px;
+ color: #3fa8eb;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ margin-bottom: 0;
+}
+.content .vnfs .vnf .intro {
+ text-align: left;
+ font-size: 12px;
+ overflow: hidden;
+ display: -webkit-box;
+ -webkit-line-clamp: 3;
+ -webkit-box-orient: vertical;
+ word-wrap: break-word;
+ word-break: break-all;
+}
+.content .vnfs .empty {
+ width: 18%;
+ height: 200px;
+ margin: 5px;
+ border-radius: 2px;
+}
+.content .pages {
+ height: 25px;
+ margin: 20px 10px;
+ position: relative;
+}
+.content .pages nz-pagination {
+ float: right;
+}
diff --git a/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.html b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.html
new file mode 100644
index 00000000..9e0e2ed6
--- /dev/null
+++ b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.html
@@ -0,0 +1,63 @@
+<!--
+ 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.
+-->
+<h3 class="title">
+ <span (click)="performanceShow()" style="cursor:pointer;" *ngIf="graphicshow">Performance VNF</span>
+ <span (click)="graphicShow()" *ngIf="graphicshow">/ Graphic list </span>
+ <span *ngIf="detailshow">/ Details </span>
+</h3>
+<div class="select" [@showHideAnimate]="state">
+ <span>Source Name: </span>
+ <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomLeft'">
+ <button nz-button nz-dropdown><span>{{sourceNameSelected}}</span> <i class="anticon anticon-down"></i></button>
+ <ul nz-menu>
+ <li nz-menu-item (click)="choseSourceName(item)" *ngFor="let item of sourceNameList">
+ <a>{{item}}</a>
+ </li>
+ </ul>
+ </nz-dropdown>
+ <button class="search" nz-button [nzType]="'primary'"><i
+ class="anticon anticon-search"></i><span>Search</span></button>
+ <!-- <button class="search" nz-button [nzType]="'primary'" (click)="getperformanceSsourceNames()"><i class="anticon anticon-search"></i><span>Search</span></button> -->
+</div>
+<div class="content" [@showHideAnimate]="state">
+ <div class="vnfs">
+ <div class="vnf" *ngFor="let item of totalRecords">
+ <img src="../../../../assets/images/vnf01.png" title="VNF" (click)="graphicShow2(item)">
+ <!-- <h3>{{item.name}}</h3> -->
+ <div class="intro">
+ {{item.name}}
+ </div>
+ </div>
+ <div class="vnf" *ngFor="let item of totalpnfs">
+ <img src="../../../../assets/images/pnf01.png" alt="PNF" (click)="graphicShow2(item)">
+ <div class="intro">
+ {{item.name}}
+ </div>
+ </div>
+ <div class="empty" *ngFor="let empty of emptys"></div>
+ </div>
+ <div class="pages">
+ <nz-pagination [(nzPageIndex)]="currentPage" [nzTotal]="vnfsdataTotal" [nzSize]="'small'"
+ [(nzPageSize)]="pageSize" [nzPageSizeOptions]="[10,15,20,25,30]" nzShowSizeChanger nzShowQuickJumper>
+ </nz-pagination>
+ </div>
+</div>
+<div [@showHideAnimate]="state2">
+ <app-graphiclist (detailData)="detailShow($event)" [vnfname]="vnfname"></app-graphiclist>
+</div>
+<div [@showHideAnimate]="state3">
+ <app-performance-details [detailId]="detailId"></app-performance-details>
+</div> \ No newline at end of file
diff --git a/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.less b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.less
new file mode 100644
index 00000000..cc4e1ca5
--- /dev/null
+++ b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.less
@@ -0,0 +1,136 @@
+/*
+ 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.
+*/
+.title {
+ font: 500 14px/18px "ArialMT";
+ color: #3C4F8C;
+ padding: 20px 0 0 20px;
+}
+.select {
+ height: 70px;
+ background-color: #fff;
+ margin-top: -30px;
+ padding-left: 20px;
+ box-shadow: 0 2px 23px 0 rgba(0, 0, 0, 0.1), 0 2px 49px 0 rgba(0, 0, 0, 0.06);
+ line-height: 5;
+ span {
+ display: inline-block;
+ font: 400 14px "ArialMT";
+ color: #3C4F8C;
+ }
+ nz-dropdown {
+ vertical-align: middle;
+ :hover{
+ border-color: #147dc2;
+ }
+ button {
+ width: 165px;
+ height: 30px;
+ background-color: #fff;
+ text-align: left;
+ border-color: #E5E8F2;
+ span {
+ font-weight: 400;
+ display: inline-block;
+ width: 120px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ padding-top: 2px;
+ }
+ i {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ }
+ }
+ :hover {
+ border-color: #48C6EF;
+ }
+ //下拉框中的样式在style.less中,下拉框是在body中额外临时生成的
+ }
+ .search {
+ margin-left: 20px;
+ margin-top: -6px;
+ vertical-align: middle;
+ height: 30px;
+ padding: 0 10px;
+ span {
+ color: #fff;
+ font-weight: 400;
+ }
+ }
+}
+
+.content {
+ // background-color: #fff;
+ border-radius: 5px;
+ padding: 12px;
+ .vnfs {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-around;
+ .vnf {
+ // width: 180px;
+ background-color: #fff;
+ width: 18%;
+ height: 200px;
+ margin: 5px;
+ padding: 20px;
+ border-radius: 2px;
+ text-align: center;
+ cursor: pointer;
+ transition: all 0.3s linear;
+ &:hover {
+ background-color: #fff;
+ transform: scale(1.02);
+ color: #3F9CFF;
+ }
+ h3 {
+ font-size: 14px;
+ color: #3fa8eb;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ margin-bottom: 0;
+ }
+ .intro {
+ text-align: left;
+ font-size: 12px;
+ overflow: hidden;
+ padding-top: 25px;
+ display: -webkit-box;
+ -webkit-line-clamp: 3;
+ -webkit-box-orient: vertical;
+ word-wrap:break-word;
+ word-break:break-all;
+ }
+ }
+ .empty {
+ // width: 180px;
+ width: 18%;
+ height: 200px;
+ margin: 5px;
+ border-radius: 2px;
+ }
+ }
+ .pages {
+ height: 25px;
+ margin: 20px 10px;
+ position: relative;
+ nz-pagination {
+ float: right;
+ }
+ }
+} \ No newline at end of file
diff --git a/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.spec.ts b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.spec.ts
new file mode 100644
index 00000000..25bcfd50
--- /dev/null
+++ b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.spec.ts
@@ -0,0 +1,45 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { NO_ERRORS_SCHEMA,CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { TranslateModule, TranslateLoader, TranslateService, TranslateFakeLoader} from '@ngx-translate/core';
+import { NgZorroAntdModule } from 'ng-zorro-antd';
+import { NgxEchartsModule } from 'ngx-echarts';
+import { NZ_I18N, en_US } from 'ng-zorro-antd';
+import { HttpClientModule } from '@angular/common/http';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { PerformanceDetailsComponent } from '../../../shared/components/performance-details/performance-details.component';
+import { GraphiclistComponent } from '../../../shared/components/graphiclist/graphiclist.component';
+import { PerformanceVnfComponent } from './performance-vnf.component';
+import { HomesService } from '../../../core/services/homes.service';
+
+describe('PerformanceVnfComponent', () => {
+ let component: PerformanceVnfComponent;
+ let fixture: ComponentFixture<PerformanceVnfComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ PerformanceVnfComponent, PerformanceDetailsComponent, GraphiclistComponent ],
+ imports: [ TranslateModule.forRoot({loader: { provide: TranslateLoader, useClass: TranslateFakeLoader }}),
+ NgZorroAntdModule.forRoot(),
+ NgxEchartsModule,
+ HttpClientModule,
+ BrowserAnimationsModule ],
+ providers: [TranslateService, HomesService ],
+ schemas: [
+ CUSTOM_ELEMENTS_SCHEMA,
+ NO_ERRORS_SCHEMA
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(PerformanceVnfComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+}); \ No newline at end of file
diff --git a/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.ts b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.ts
new file mode 100644
index 00000000..96b5404c
--- /dev/null
+++ b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.ts
@@ -0,0 +1,145 @@
+/*
+ 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, OnInit, HostBinding } from '@angular/core';
+import { slideToRight, showHideAnimate } from '../../../animates';
+import { HomesService } from '../../../core/services/homes.service';
+
+@Component({
+ selector: 'app-performance-vnf',
+ templateUrl: './performance-vnf.component.html',
+ styleUrls: ['./performance-vnf.component.less'],
+ animations: [slideToRight, showHideAnimate],
+})
+export class PerformanceVnfComponent implements OnInit {
+ @HostBinding('@routerAnimate') routerAnimateState;
+ public sourceNameList: Array<any> = ['---auto---'];
+ public sourceName: string = '';
+ public vnfsdataTotal: number;
+ public startTime: string = '';
+ public endTime: string = '';
+ public currentPage: number = 1;
+ public pageSize: number = 10;
+ list: any;
+
+ constructor(
+ private myhttp: HomesService) { }
+
+ ngOnInit() {
+ this.getqueryAllSourceNames();
+ // this.getperformanceSsourceNames();
+ let _this = this;
+ setTimeout(function(){
+ _this.totalRecords = [
+ {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"},
+ {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"},
+ {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"},
+ {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"},
+ {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"},
+ {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"},
+ {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"},
+ {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"},
+ {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"},
+ {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"},
+ {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"}
+ ];
+ _this.totalpnfs = [
+ {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"},
+ {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"},
+ {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"}
+ ]
+ _this.emptys = new Array(12-_this.totalRecords.length);
+ },300)
+ }
+
+
+ sourceNameSelected = this.sourceNameList[0];
+ getqueryAllSourceNames() {
+ this.myhttp.getqueryAllSourceNames().subscribe((data) => {
+ for (let i = 0; i < data.length; i++) {
+ this.sourceNameList.push(data[i]);
+ }
+ this.sourceNameSelected = this.sourceNameList[0];
+ })
+ }
+ choseSourceName(item) {
+ this.sourceNameSelected = item;
+ if (item == "---auto---") {
+ this.sourceName = '';
+ } else {
+ this.sourceName = item;
+ }
+ }
+ // vnfs data
+ totalRecords = [];
+ totalpnfs = [];
+ //Fill the box
+ emptys = [];
+
+ // getperformanceSsourceNames() {
+ // this.myhttp.getperformanceSourceNames(this.currentPage, this.pageSize, this.sourceName).subscribe((data) => {
+ // this.totalRecords = data.totalRecords;
+ // this.vnfsdataTotal = data.names;
+ // if (Number.isInteger(this.totalRecords.length / 5)) {
+ // this.emptys = new Array(0);
+ // } else {
+ // this.emptys = new Array(5 - this.totalRecords.length % 5);
+ // }
+ // })
+ // }
+ //Detail page title display
+ isHidden = true;
+ graphicshow = false;
+ detailshow = false;
+ // Show hidden animation
+ state = "show";
+ state2 = "hide";
+ state3 = "hide";
+ performanceShow() {
+ this.state = 'show';
+ this.state2 = 'hide';
+ this.state3 = 'hide';
+ this.graphicshow = false;
+ this.detailshow = false;
+ }
+ // Selected name
+
+ graphicShow() {
+ this.state = 'hide';
+ this.state2 = 'show';
+ this.state3 = 'hide';
+ this.graphicshow = true;
+ this.detailshow = false;
+ }
+ vnfname: string;
+ graphicShow2(item) {
+ this.state = 'hide';
+ this.state2 = 'show';
+ this.state3 = 'hide';
+ this.graphicshow = true;
+ this.detailshow = false;
+ this.vnfname = item;
+ }
+ // Selected id
+ detailId: string;
+ detailShow(item) {
+ this.state = 'hide';
+ this.state2 = 'hide';
+ this.state3 = 'show';
+ this.graphicshow = true;
+ this.detailshow = true;
+ this.detailId = item.id.id;
+ }
+}
diff --git a/usecaseui-portal/src/app/views/performance/performance.component.css b/usecaseui-portal/src/app/views/performance/performance.component.css
new file mode 100644
index 00000000..f2169538
--- /dev/null
+++ b/usecaseui-portal/src/app/views/performance/performance.component.css
@@ -0,0 +1,26 @@
+/*
+ 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.
+*/
+.title {
+ font: 700 18px/18px "思源黑体";
+ color: #4c5e70;
+ margin-bottom: 18px;
+}
+hr {
+ border: none;
+ height: 2px;
+ background-color: #dce1e7;
+ margin-bottom: 20px;
+}
diff --git a/usecaseui-portal/src/app/views/performance/performance.component.html b/usecaseui-portal/src/app/views/performance/performance.component.html
new file mode 100644
index 00000000..cd92b659
--- /dev/null
+++ b/usecaseui-portal/src/app/views/performance/performance.component.html
@@ -0,0 +1,17 @@
+<!--
+ 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.
+-->
+<h3 class="title"> Performance </h3>
+<hr>
diff --git a/usecaseui-portal/src/app/views/performance/performance.component.less b/usecaseui-portal/src/app/views/performance/performance.component.less
new file mode 100644
index 00000000..2b1949a5
--- /dev/null
+++ b/usecaseui-portal/src/app/views/performance/performance.component.less
@@ -0,0 +1,11 @@
+.title {
+ font: 700 18px/18px "思源黑体";
+ color: #4c5e70;
+ margin-bottom: 18px;
+}
+hr {
+ border: none;
+ height: 2px;
+ background-color: #dce1e7;
+ margin-bottom: 20px;
+}
diff --git a/usecaseui-portal/src/app/views/performance/performance.component.spec.ts b/usecaseui-portal/src/app/views/performance/performance.component.spec.ts
new file mode 100644
index 00000000..1bdc919d
--- /dev/null
+++ b/usecaseui-portal/src/app/views/performance/performance.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PerformanceComponent } from './performance.component';
+
+describe('PerformanceComponent', () => {
+ let component: PerformanceComponent;
+ let fixture: ComponentFixture<PerformanceComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ PerformanceComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(PerformanceComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/usecaseui-portal/src/app/views/performance/performance.component.ts b/usecaseui-portal/src/app/views/performance/performance.component.ts
new file mode 100644
index 00000000..12405e9e
--- /dev/null
+++ b/usecaseui-portal/src/app/views/performance/performance.component.ts
@@ -0,0 +1,16 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'app-performance',
+ templateUrl: './performance.component.html',
+ styleUrls: ['./performance.component.less']
+})
+export class PerformanceComponent implements OnInit {
+
+ constructor() { }
+
+ ngOnInit() {
+
+ }
+
+}
diff --git a/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.css b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.css
new file mode 100644
index 00000000..4e80750c
--- /dev/null
+++ b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.css
@@ -0,0 +1,67 @@
+/*
+ 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.
+*/
+.title {
+ font: 700 18px/18px "思源黑体";
+ color: #4c5e70;
+ margin-bottom: 18px;
+}
+hr {
+ border: none;
+ height: 2px;
+ background-color: #dce1e7;
+ margin-bottom: 20px;
+}
+.list {
+ background-color: #fff;
+ border-radius: 5px;
+ padding: 10px;
+}
+.list nz-table tbody td span.onboarding {
+ font-size: 12px;
+ color: #147dc2;
+}
+.list nz-table tbody td span.onboarded {
+ font-size: 14px;
+ color: #147dc2;
+}
+.list nz-table tbody td span.updating {
+ font-size: 12px;
+ color: blue;
+}
+.list nz-table tbody td span.deleting {
+ font-size: 12px;
+ color: red;
+}
+.list nz-table tbody td span.invalid {
+ font-size: 14px;
+ color: purple;
+}
+.list nz-table tbody td i.anticon {
+ cursor: pointer;
+ font-size: 18px;
+ padding: 2px;
+}
+.list nz-table tbody td i.anticon:hover {
+ color: #147dc2;
+}
+.list nz-table tbody td .cannotclick {
+ pointer-events: none;
+ color: #aaa;
+ opacity: 0.6;
+}
+.list nz-table tbody td .fileIcon{
+ display: none;
+} \ No newline at end of file
diff --git a/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.html b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.html
new file mode 100644
index 00000000..70ee81c0
--- /dev/null
+++ b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.html
@@ -0,0 +1,333 @@
+<!--
+ 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-tabset [nzTabPosition]="'top'" [nzType]="'card'">
+ <nz-tab *ngFor="let tab of tabs" [nzTitle]="tab" (nzClick)="handleTabChange(tab)">
+ <!-- nsList -->
+ <div class="list" *ngIf="tab === 'NS'">
+ <!-- <h3 class="title"> Onboard {{tabTitle}} </h3> -->
+ <div style="width:100%;height: 30%;margin-bottom: 1%">
+ <div class="listupload">
+ <nz-upload nzType="drag" [(nzFileList)]="fileListNS" [nzBeforeUpload]="beforeUploadNS">
+ <p class="ant-upload-drag-icon">
+ <i nz-icon type="inbox" class="anticon anticon-inbox"></i>
+ </p>
+ <p class="ant-upload-text"> {{"i18nTextDefine_Click_CSAR_File" | translate}} </p>
+ <p class="ant-upload-hint"></p>
+ </nz-upload>
+ <button nz-button [nzLoading]="nsuploading" (click)="onClick(tab)" [disabled]="fileListNS.length == 0"
+ style="margin-top: 16px;margin-left: 55px;color: #FFFFFF;font-size: 13px;background-color: #3E9BFF;font-family: ArialMT;">
+ {{ nsuploading ? 'Uploading' : 'Start Upload' }}
+ </button>
+ </div>
+ <div class="listlin"></div>
+ <div class="listfile">
+ <div style="color: rgba(66,84,143,1);font-family:ArialMT;padding-bottom: 15px;height: 15%"> {{"i18nTextDefine_Uploaded_files" | translate}} </div>
+ <div class="nouploadfile">{{"i18nTextDefine_Nofileuploading" | translate}}</div>
+ <div style="height:80%;overflow: auto">
+ <div class="listfilebgc" *ngFor="let itemns of nsRightList">
+ <div>
+ <i class="anticon anticon-link"></i>
+ </div>
+ <div class="color" [ngClass]="{'progress':itemns.status == true}">{{itemns.name}}</div>
+ <div class="color" *ngIf="itemns.status">
+ <nz-progress [nzPercent]="itemns.progress" [nzShowInfo]="false"></nz-progress>
+ </div>
+ <div class="color" *ngIf="!itemns.status">
+ <span *ngIf="itemns.success == 0">{{"i18nTextDefine_File_upload_completed" | translate}}</span>
+ <span *ngIf="itemns.success == 1">{{"i18nTextDefine_File_upload_failed" | translate}}</span>
+ </div>
+ <div *ngIf="!itemns.status">
+ <i class="anticon anticon-check-circle" *ngIf="itemns.success == 0" style="color:#7BC7F3!important;"></i>
+ <i class="anticon anticon-exclamation-circle" *ngIf="itemns.success == 1" style="color:#fb5c5c!important;"></i>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <nz-spin [nzSpinning]="isSpinning" style="height: 69%">
+ <div class="mask" *ngIf="isSpinning"></div>
+ <nz-table #nzTable [nzData]="nstableData" nzShowSizeChanger [nzFrontPagination]="true"
+ [nzShowQuickJumper]="true" [nzPageSizeOptions]="[5,10,15,20]" [nzTotal]='total' [(nzPageSize)]="nspageSize"
+ [(nzPageIndex)]='nspageIndex' [nzLoading]="loading" nzSize="middle">
+ <thead (nzSortChange)="sort($event)" nzSingleSort>
+ <tr>
+ <th nzWidth="15%"> {{"i18nTextDefine_NO" | translate}} </th>
+ <th nzWidth="15%" nzShowSort nzSortKey="name"> {{"i18nTextDefine_Name" | translate}} </th>
+ <th nzWidth="15%"> {{"i18nTextDefine_Version" | translate}} </th>
+ <th nzWidth="15%"> {{"i18nTextDefine_OnboardingState" | translate}} </th>
+ <th nzWidth="15%"> {{"i18nTextDefine_OperationalState" | translate}} </th>
+ <th nzWidth="10%"> {{"i18nTextDefine_UsageState" | translate}} </th>
+ <th nzWidth="15%"> {{"i18nTextDefine_Operationbutton" | translate}} </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let item of nzTable.data; let i = index; ">
+ <td>{{i+1}}</td>
+ <!--<td *ngIf="item.uuid">{{item.uuid}}</td>-->
+
+ <td *ngIf="item.nsdName">{{item.nsdName}}</td>
+ <td *ngIf="item.nsdName === null || item.nsdName === ''">&nbsp;</td>
+ <td *ngIf="item.name">{{item.name}}</td>
+ <td *ngIf="item.name===null || item.name=== ''">&nbsp;</td>
+ <td *ngIf="item.nsdVersion">{{item.nsdVersion}}</td>
+ <td *ngIf="item.nsdVersion === null || item.nsdVersion === ''">&nbsp;</td>
+ <td *ngIf="item.version">{{item.version}}</td>
+ <td *ngIf="item.version === null || item.version === ''">&nbsp;</td>
+ <td>
+ <span *ngIf="item.nsdOnboardingState">{{item.nsdOnboardingState}}</span>
+ <span *ngIf="item.nsdOnboardingState === null || item.nsdOnboardingState === ''">&nbsp;</span>
+ <span *ngIf="item.uuid">{{status}}</span>
+
+ <!-- <span *ngIf="item.uuid" [ngClass]="{'active':data.status=='Active','closed':data.status=='Closed','onboarding':data.status=='Onboarding',
+ 'updating':data.status=='Updating','deleting':data.status=='Deleting','creating':data.status=='Creating',
+ 'scaling':data.status=='Scaling','healing':data.status=='Healing'}">{{data.status || "Active"}}</span>
+ <nz-progress *ngIf="item.uuid" *ngIf="data.status == 'Creating' || data.status == 'Deleting' || data.status == 'Scaling' || data.status == 'Healing' " [nzPercent]="data.rate"></nz-progress> -->
+ </td>
+ <td>{{item.nsdOperationalState}}</td>
+ <td>{{item.nsdUsageState}}</td>
+ <td>
+ <i [ngClass]="{'cannotclick':onboardData.status == 'onboarding' && i == currentIndex}"
+ class="anticon anticon-upload upicon" #upload_icon (click)="updataNsService(item.uuid,i,notificationModel)"
+ *ngIf="item.uuid"></i>
+ <i class="anticon anticon-delete" nzType="info" (click)="showConfirm(i,item.id,tab,notificationModel)"
+ *ngIf="item.id"></i>
+ <!--<span *ngIf="item.id" [ngClass]="{'fileIcon':OnboardFile == 'disNone'}">-->
+ <!--<span *ngIf="item.id && item.sameid == undefined">-->
+ <!--<nz-upload [(nzFileList)]="fileList" [nzBeforeUpload]="beforeUpload">-->
+ <!--<i class="anticon anticon-file" type="upload" (click)="onClickId(item.id,tab)"></i>-->
+ <!--</nz-upload>-->
+ <!--<button nz-button [nzLoading]="nsuploading" (click)="onClick(tab)" [disabled]="fileList.length == 0"-->
+ <!--style="margin-top: 16px" *ngIf="item.id==nsdInfoId">-->
+ <!--{{ nsuploading ? 'Uploading' : 'Start Upload' }}-->
+ <!--</button>-->
+ <!--</span>-->
+
+ </td>
+ </tr>
+ </tbody>
+ </nz-table>
+ </nz-spin>
+ <!-- <div style="margin-top:8px;">
+ Loading state:
+ <nz-switch [(ngModel)]="isSpinning"></nz-switch>
+ </div> -->
+
+ </div>
+ <!-- VNFList -->
+ <div class="list" *ngIf="tab === 'VNF'">
+ <!-- <h3 class="title"> Onboard {{tabTitle}} </h3> -->
+ <div style="width:100%;height: 30%;margin-bottom: 1%">
+ <div class="listupload">
+ <nz-upload nzType="drag" [(nzFileList)]="fileListVNF" [nzBeforeUpload]="beforeUploadVNF">
+ <p class="ant-upload-drag-icon">
+ <i nz-icon type="inbox" class="anticon anticon-inbox"></i>
+ </p>
+ <p class="ant-upload-text">Click or drag CSAR File here</p>
+ <p class="ant-upload-hint"></p>
+ </nz-upload>
+ <button nz-button [nzLoading]="vnfuploading" (click)="onClick(tab)" [disabled]="fileListVNF.length == 0"
+ style="margin-top: 16px;margin-left: 55px;color: #FFFFFF;font-size: 13px;background-color: #3E9BFF;font-family: ArialMT;">
+ {{ vnfuploading ? 'Uploading' : 'Start Upload' }}
+ </button>
+ </div>
+ <div class="listlin"></div>
+ <div class="listfile">
+ <div style="color: rgba(66,84,143,1);font-family:ArialMT;padding-bottom: 15px;height: 15%"> {{"i18nTextDefine_Uploaded_files" | translate}} </div>
+ <div class="nouploadfile">{{"i18nTextDefine_Nofileuploading" | translate}}</div>
+ <div style="height:80%;overflow: auto">
+ <div class="listfilebgc" *ngFor="let itemns of vnfRightList">
+ <div>
+ <i class="anticon anticon-link"></i>
+ </div>
+ <div class="color" [ngClass]="{'progress':itemns.status == true}">{{itemns.name}}</div>
+ <div class="color" *ngIf="itemns.status">
+ <nz-progress [nzPercent]="itemns.progress" [nzShowInfo]="false"></nz-progress>
+ </div>
+ <div class="color" *ngIf="!itemns.status">
+ <span *ngIf="itemns.success == 0">{{"i18nTextDefine_File_upload_completed" | translate}}</span>
+ <span *ngIf="itemns.success == 1">{{"i18nTextDefine_File_upload_failed" | translate}}</span>
+ </div>
+ <div *ngIf="!itemns.status">
+ <i class="anticon anticon-check-circle" *ngIf="itemns.success == 0" style="color:#7BC7F3!important;"></i>
+ <i class="anticon anticon-exclamation-circle" *ngIf="itemns.success == 1" style="color:#fb5c5c!important;"></i>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <nz-spin [nzSpinning]="isSpinning" style="height: 69%">
+ <div class="mask" *ngIf="isSpinning"></div>
+ <nz-table #nzTable [nzData]="vnftableData" nzShowSizeChanger [nzFrontPagination]="true"
+ [nzShowQuickJumper]="true" [nzPageSizeOptions]="[5,10,15,20]" [nzTotal]='total' [(nzPageSize)]="vnfpageSize"
+ [(nzPageIndex)]='vnfpageIndex' [nzLoading]="loading" nzSize="middle">
+ <thead (nzSortChange)="sort($event)" nzSingleSort>
+ <tr>
+ <th nzWidth="15%"> {{"i18nTextDefine_NO" | translate}} </th>
+ <th nzWidth="15%" nzShowSort nzSortKey="name"> {{"i18nTextDefine_Name" | translate}} </th>
+ <th nzWidth="15%"> {{"i18nTextDefine_Version" | translate}} </th>
+ <th nzWidth="15%"> {{"i18nTextDefine_OnboardingState" | translate}} </th>
+ <th nzWidth="15%"> {{"i18nTextDefine_OperationalState" | translate}} </th>
+ <th nzWidth="10%"> {{"i18nTextDefine_UsageState" | translate}} </th>
+ <th nzWidth="15%"> {{"i18nTextDefine_Operationbutton" | translate}} </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let item of nzTable.data; let i = index; ">
+ <td>{{i+1}}</td>
+ <!--<td *ngIf="item.uuid">{{item.uuid}}</td>-->
+ <td *ngIf="item.vnfProductName">{{item.vnfProductName}}</td>
+ <td *ngIf="item.vnfProductName === null || item.vnfProductName === ''">&nbsp;</td>
+ <td *ngIf="item.name">{{item.name}}</td>
+ <td *ngIf="item.vnfdVersion">{{item.vnfdVersion}}</td>
+ <td *ngIf="item.vnfdVersion === null || item.vnfdVersion === ''">&nbsp;</td>
+ <td *ngIf="item.version">{{item.version}}</td>
+ <td>{{item.onboardingState}}</td>
+ <td>{{item.operationalState}}</td>
+ <td>{{item.usageState}}</td>
+ <td>
+ <i [ngClass]="{'cannotclick':onboardData.status == 'onboarding' && i == currentIndex}"
+ class="anticon anticon-upload upicon" #upload_icon (click)="updataVnfService(item.uuid,i,notificationModel)"
+ *ngIf="item.uuid"></i>
+ <i class="anticon anticon-delete" nzType="info" (click)="showConfirm(i,item.id,tab,notificationModel)"
+ *ngIf="item.id"></i>
+ <!--<span *ngIf="item.id && item.sameid == undefined">-->
+ <!--<nz-upload [(nzFileList)]="fileList" [nzBeforeUpload]="beforeUpload">-->
+ <!--&lt;!&ndash; <button nz-button> &ndash;&gt;-->
+ <!--<i class="anticon anticon-file" type="upload" (click)="onClickId(item.id,tab)"></i>-->
+ <!--&lt;!&ndash; <span >upload</span> &ndash;&gt;-->
+ <!--&lt;!&ndash; </button> &ndash;&gt;-->
+
+ <!--</nz-upload>-->
+ <!--<button nz-button [nzLoading]="nsuploading" (click)="onClick(tab)" [disabled]="fileList.length == 0"-->
+ <!--style="margin-top: 16px;margin-left: 55px;color: #FFFFFF;font-size: 13px;background-color: #3E9BFF;font-family: ArialMT;"-->
+ <!--*ngIf="item.id==vnfPkgId">-->
+ <!--{{ nsuploading ? 'Uploading' : 'Start Upload' }}-->
+ <!--</button>-->
+ <!--</span>-->
+ </td>
+ </tr>
+ </tbody>
+ </nz-table>
+ </nz-spin>
+
+ </div>
+ <!-- PNFList -->
+ <div class="list" *ngIf="tab === 'PNF'">
+ <!-- <h3 class="title"> Onboard {{tabTitle}} </h3> -->
+ <div style="width:100%;height: 30%;margin-bottom: 1%">
+ <div class="listupload">
+ <nz-upload nzType="drag" [(nzFileList)]="fileListPNF" [nzBeforeUpload]="beforeUploadPNF">
+ <p class="ant-upload-drag-icon">
+ <i nz-icon type="inbox" class="anticon anticon-inbox"></i>
+ </p>
+ <p class="ant-upload-text">Click or drag CSAR File here</p>
+ <p class="ant-upload-hint"></p>
+ </nz-upload>
+ <button nz-button [nzLoading]="pnfuploading" (click)="onClick(tab)" [disabled]="fileListPNF.length == 0"
+ style="margin-top: 16px;margin-left: 55px;color: #FFFFFF;font-size: 13px;background-color: #3E9BFF;font-family: ArialMT;">
+ {{ pnfuploading ? 'Uploading' : 'Start Upload' }}
+ </button>
+ </div>
+ <div class="listlin"></div>
+ <div class="listfile">
+ <div style="color: rgba(66,84,143,1);font-family:ArialMT;padding-bottom: 15px;height: 15%"> {{"i18nTextDefine_Uploaded_files" | translate}} </div>
+ <div class="nouploadfile">{{"i18nTextDefine_Nofileuploading" | translate}}</div>
+ <div style="height:80%;overflow: auto">
+ <div class="listfilebgc" *ngFor="let itemns of pnfRightList">
+ <div>
+ <i class="anticon anticon-link"></i>
+ </div>
+ <div class="color" [ngClass]="{'progress':itemns.status == true}">{{itemns.name}}</div>
+ <div class="color" *ngIf="itemns.status">
+ <nz-progress [nzPercent]="itemns.progress" [nzShowInfo]="false"></nz-progress>
+ </div>
+ <div class="color" *ngIf="!itemns.status">
+ <span *ngIf="itemns.success == 0">{{"i18nTextDefine_File_upload_completed" | translate}}</span>
+ <span *ngIf="itemns.success == 1">{{"i18nTextDefine_File_upload_failed" | translate}}</span>
+ </div>
+ <div *ngIf="!itemns.status">
+ <i class="anticon anticon-check-circle" *ngIf="itemns.success == 0" style="color:#7BC7F3!important;"></i>
+ <i class="anticon anticon-exclamation-circle" *ngIf="itemns.success == 1" style="color:#fb5c5c!important;"></i>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <nz-spin [nzSpinning]="isSpinning" style="height: 69%">
+ <div class="mask" *ngIf="isSpinning"></div>
+ <nz-table #nzTable [nzData]="pnftableData" nzShowSizeChanger [nzFrontPagination]="true"
+ [nzShowQuickJumper]="true" [nzPageSizeOptions]="[5,10,15,20]" [nzTotal]='total' [(nzPageSize)]="pnfpageSize"
+ [(nzPageIndex)]='pnfpageIndex' [nzLoading]="loading" nzSize="middle">
+ <thead (nzSortChange)="sort($event)" nzSingleSort>
+ <tr>
+ <th nzWidth="15%"> {{"i18nTextDefine_NO" | translate}} </th>
+ <th nzWidth="15%" nzShowSort nzSortKey="name"> {{"i18nTextDefine_Name" | translate}} </th>
+ <th nzWidth="15%"> {{"i18nTextDefine_Version" | translate}} </th>
+ <th nzWidth="15%"> {{"i18nTextDefine_OnboardingState" | translate}} </th>
+ <th nzWidth="10%"> {{"i18nTextDefine_UsageState" | translate}} </th>
+ <th nzWidth="15%"> {{"i18nTextDefine_Operationbutton" | translate}} </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let item of nzTable.data; let i = index; ">
+ <td>{{i+1}}</td>
+ <td>{{item.pnfdName}}</td>
+ <td>{{item.pnfdVersion}}</td>
+ <td>{{item.pnfdOnboardingState}}</td>
+ <td>{{item.pnfdUsageState}}</td>
+ <td>
+ <i class="anticon anticon-delete" nzType="info" (click)="showConfirm(i,item.id,tab,notificationModel)"></i>
+ <!--<span *ngIf="item.id" [ngClass]="{'fileIcon':OnboardFile == 'disNone'}">-->
+ <!--<nz-upload [(nzFileList)]="fileList" [nzBeforeUpload]="beforeUpload">-->
+ <!--<i class="anticon anticon-file" type="upload" (click)="onClickId(item.id,tab)"></i>-->
+ <!--</nz-upload>-->
+ <!--<button nz-button [nzLoading]="nsuploading" (click)="onClick(tab)" [disabled]="fileList.length == 0"-->
+ <!--style="margin-top: 16px;margin-left: 55px;color: #FFFFFF;font-size: 13px;background-color: #3E9BFF;font-family: ArialMT;"-->
+ <!--*ngIf="item.id==vnfPkgId">-->
+ <!--{{ nsuploading ? 'Uploading' : 'Start Upload' }}-->
+ <!--</button>-->
+ <!--</span>-->
+ </td>
+ </tr>
+ </tbody>
+ </nz-table>
+ </nz-spin>
+
+ </div>
+ </nz-tab>
+ <!--2019.08.14 add notification-->
+ <ng-template #notificationModel >
+ <div class="ant-notification-notice-content">
+ <div class="ant-notification-notice-with-icon">
+ <span class="ant-notification-notice-icon">
+ <img src="{{notificationAttributes.imgPath}}" alt="{{notificationAttributes.status}}">
+ </span>
+ <div class="ant-notification-notice-message">
+ {{notificationAttributes.title}}&nbsp;
+ {{"i18nTextDefine_"+notificationAttributes.action | translate}}&nbsp;&nbsp;{{"i18nTextDefine_"+notificationAttributes.status | translate}}
+ </div>
+ <div class="ant-notification-notice-description">
+ <div class="notificationlist">
+ <p>{{notificationAttributes.title}} id:&nbsp;</p>
+ <span>{{ notificationAttributes.id }}</span>
+ </div>
+ </div>
+ <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div>
+ </div>
+ </div>
+ </ng-template>
+</nz-tabset>
+
diff --git a/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.less b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.less
new file mode 100644
index 00000000..c31409c9
--- /dev/null
+++ b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.less
@@ -0,0 +1,182 @@
+/*
+ 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.
+*/
+.title {
+ font: 700 18px/18px "思源黑体";
+ color: #4c5e70;
+ margin-bottom: 18px;
+}
+hr {
+ border: none;
+ height: 2px;
+ background-color: #dce1e7;
+ margin-bottom: 20px;
+}
+.switch_btn {
+ position: absolute;
+ right: 6%;
+ top: 18px;
+ border: 1px solid #3fa8eb;
+ width: 8%;
+ border-radius: 10px;
+ margin-bottom: 18px;
+ span {
+ display: block;
+ float: left;
+ text-align: center;
+ width: 50%;
+ color: #3fa8eb;
+ font-weight: 700;
+ cursor: pointer;
+ }
+ span:first-child {
+ border-radius: 10px 0 0 10px;
+ }
+ span:last-child {
+ border-radius: 0 10px 10px 0;
+ }
+ span.left_b {
+ border-left: 1px solid #3fa8eb;
+ }
+ span.active {
+ color: #fff;
+ background: #3fa8eb;
+ }
+}
+
+.list {
+ // background-color: #fff;
+ border-radius: 5px;
+ // padding: 10px;
+ .listupload {
+ width: 22%;
+ vertical-align: top;
+ display: inline-block;
+ margin-left: 13%;
+ }
+ .listlin {
+ vertical-align: top;
+ display: inline-block;
+ width: 1%;
+ margin-left: 10%;
+ height: 177px;
+ margin-bottom: 30px;
+ border-right: 2px solid #EEEEEE;
+ }
+ .listfile {
+ width: 43%;
+ height: 100%;
+ vertical-align: top;
+ display: inline-block;
+ margin-left: 10%;
+ .nouploadfile{
+ height: 80%;
+ width: 100%;
+ text-align: center;
+ font-size: 22px;
+ margin-top: 5%;
+ }
+ .listfilebgc {
+ background-color: #fff;
+ border-bottom: 8px solid #F7F8FC;
+ }
+ .listfilebgc {
+ background-color: #fff;
+ height: 30px;
+ border-radius: 2px;
+ line-height: 2;
+ color: #42548F;
+ border-bottom: 4px solid #F7F8FC;
+ >div {
+ float: left;
+ }
+ :first-child {
+ width: 6%;
+ margin-left: 5px;
+ }
+ :nth-child(2){
+ width:20%;
+ }
+ :nth-child(3){
+ width: 60%;
+ text-align: center;
+ }
+ :nth-child(4){
+ padding-left: 4%;
+ }
+ .color {
+ color:rgba(66,84,143,1);
+ span{
+ color:rgba(66,84,143,0.7);
+ }
+ }
+ .progress{
+ color:rgba(66,84,143,0.7);
+ }
+ }
+ }
+ nz-table {
+ tbody {
+ td {
+ span.onboarding {
+ font-size: 12px;
+ color: #147dc2;
+ }
+ span.onboarded {
+ font-size: 14px;
+ color: #147dc2;
+ }
+ span.updating {
+ font-size: 12px;
+ color: blue;
+ }
+ span.deleting {
+ font-size: 12px;
+ color: red;
+ }
+ span.invalid {
+ font-size: 14px;
+ color: purple;
+ }
+ i.anticon {
+ cursor: pointer;
+ font-size: 18px;
+ padding: 2px;
+ &:hover{
+ color: #147dc2;
+ }
+ }
+ .cannotclick {
+ pointer-events: none;
+ color: #aaa;
+ opacity: 0.6;
+ }
+ .fileIcon{
+ display: none;
+ }
+ }
+ }
+ }
+}
+.mask {
+ top: 0;
+ left: 0;
+ position: fixed;
+ width: 100%;
+ height: 100%;
+ opacity: 0.1;
+ background: black;
+ z-index: 1049;
+} \ No newline at end of file
diff --git a/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.spec.ts b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.spec.ts
new file mode 100644
index 00000000..0e49f656
--- /dev/null
+++ b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { OnboardVnfVmComponent } from './onboard-vnf-vm.component';
+
+describe('OnboardVnfVmComponent', () => {
+ let component: OnboardVnfVmComponent;
+ let fixture: ComponentFixture<OnboardVnfVmComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ OnboardVnfVmComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(OnboardVnfVmComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.ts b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.ts
new file mode 100644
index 00000000..4899aed8
--- /dev/null
+++ b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.ts
@@ -0,0 +1,668 @@
+/*
+ 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 { HttpClient, HttpRequest, HttpResponse } from '@angular/common/http';
+import { Component, OnInit, HostBinding, TemplateRef } from '@angular/core';
+import { NzNotificationService } from 'ng-zorro-antd';
+// import { MyhttpService } from '../../myhttp.service';
+import { onboardService } from '../../../core/services/onboard.service';
+import { slideToRight } from '../../../animates';
+import { NzMessageService, UploadFile, NzModalRef, NzModalService } from 'ng-zorro-antd';
+import { filter } from 'rxjs/operators';
+import { Title } from '@angular/platform-browser';
+
+@Component({
+ selector: 'app-onboard-vnf-vm',
+ templateUrl: './onboard-vnf-vm.component.html',
+ styleUrls: ['./onboard-vnf-vm.component.less'],
+ animations: [slideToRight]
+})
+export class OnboardVnfVmComponent implements OnInit {
+ @HostBinding('@routerAnimate') routerAnimateState;
+
+ // delete Modal
+ confirmModal: NzModalRef;
+ nsdInfoId = '';
+ vnfPkgId = '';
+ pnfdInfoId = '';
+ tabTitle = "NS";
+ nsuploading = false;
+ vnfuploading = false;
+ pnfloading = false;
+ fileList: UploadFile[] = [];
+ fileListNS: UploadFile[] = [];
+ fileListVNF: UploadFile[] = [];
+ fileListPNF: UploadFile[] = [];
+ // onboard initial value
+ status = "Onboard Available";
+ jobId = '';
+ //url
+ url = {
+ // line up
+ ns: '/api/nsd/v1/ns_descriptors/*_*/nsd_content',
+ vnf: '/api/vnfpkgm/v1/vnf_packages/*_*/package_content',
+ pnf: '/api/nsd/v1/pnf_descriptors/*_*/pnfd_content'
+ // line local
+ //ns: 'https://jsonplaceholder.typicode.com/posts/',
+ //vnf: 'https://jsonplaceholder.typicode.com/posts/',
+ //pnf: 'https://jsonplaceholder.typicode.com/posts/',
+ };
+ constructor(
+ private myhttp: onboardService,
+ private http: HttpClient,
+ private msg: NzMessageService,
+ private titleService: Title,
+ private modal: NzModalService,
+ private modalService: NzModalService,
+ private notification: NzNotificationService
+ ) { }
+ //default Call ns data by default
+ ngOnInit() {
+ this.getTableData();
+ }
+
+ //Tabular data
+ nstableData: any;
+ vnftableData: any;
+ pnftableData: any;
+ nssdcData: any;
+ nsvfcData: any;
+
+ vnfsdcData: any;
+ vnfvfcData: any;
+ nspageIndex = 1;
+ nspageSize = 10;
+ vnfpageIndex = 1;
+ vnfpageSize = 10;
+ pnfpageIndex = 1;
+ pnfpageSize = 10;
+ total;
+ nsloading = false;
+ sortName = null;
+ sortValue = null;
+ tabs = ['NS', 'VNF', 'PNF'];
+ isSpinning = false;
+
+ //2019.08.14 add
+ notificationAttributes = {
+ "title": this.tabs[0],
+ "imgPath": "../../../../assets/images/execute-inproess.png",
+ "action": "OnboardingState",
+ "status": "InProgress",
+ "id": null
+ };
+ notificationModelShow(template: TemplateRef<{}>): void {
+ this.notification.template(template);
+ }
+ notificationSuccess(notificationModel) {
+ this.notificationAttributes.imgPath = "../../../../assets/images/execute-success.png";
+ this.notificationAttributes.status = "Success";
+ this.notificationModelShow(notificationModel);
+ }
+ notificationFailed(notificationModel) {
+ this.notificationAttributes.imgPath = "../../../../assets/images/execute-faild.png";
+ this.notificationAttributes.status = "Failed";
+ this.notificationModelShow(notificationModel);
+ }
+ // Handling tab switching request data
+ handleTabChange(tab) {
+ this.tabTitle = tab;
+ switch (tab) {
+ case 'NS':
+ this.nstableData = [];
+ this.getTableData();
+ this.fileList = []; //Empty uploaded files when switching
+ break
+ case 'VNF':
+ this.vnftableData = [];
+ this.getTableVnfData()
+ this.fileList = [];
+ break
+ case 'PNF':
+ this.pnftableData = [];
+ this.getTablePnfData()
+ this.fileList = [];
+ break
+ }
+ }
+
+
+ //before put create--Drag and drop files to the page before uploading
+ requestBody = {
+ "userDefinedData": {
+ "additionalProp1": "",
+ "additionalProp2": "",
+ "additionalProp3": ""
+ }
+ }
+
+ //NS/VNF List add file
+ beforeUpload = (file: UploadFile): boolean => {
+ this.fileList.push(file);
+ return false;
+ }
+
+ // ns beforeUpload
+ beforeUploadNS = (file: UploadFile): boolean => {
+ this.fileListNS.push(file);
+ this.myhttp.getCreatensData("createNetworkServiceData", this.requestBody)//on-line
+ // this.myhttp.getCreatensData("creatensDataNS") //local
+ .subscribe((data) => {
+ this.nsdInfoId = data["id"];
+ }, (err) => {
+ console.log(err);
+ })
+ return false;
+ }
+
+ //vnf beforeUpload
+ beforeUploadVNF = (file: UploadFile): boolean => {
+ this.fileListVNF.push(file);
+ this.myhttp.getCreatensData("createVnfData", this.requestBody)//on-line
+ // this.myhttp.getCreatensData("creatensDataVNF") //local
+ .subscribe((data) => {
+ this.vnfPkgId = data["id"];
+ }, (err) => {
+ console.log(err);
+ })
+ return false;
+ }
+
+ // //pnf eforeUpload
+ beforeUploadPNF = (file: UploadFile): boolean => {
+ this.fileListPNF.push(file);
+ this.myhttp.getCreatensData("createPnfData", this.requestBody) //on-line
+ // this.myhttp.getCreatensData("creatensDataPNF") //local
+ .subscribe((data) => {
+ this.pnfdInfoId = data["id"];
+ }, (err) => {
+ console.log(err);
+ })
+ return false;
+ }
+
+ //Get list list id
+ onClickId(id, tab) {
+ switch (tab) {
+ case 'NS':
+ this.nsdInfoId = id;
+ break
+ case 'VNF':
+ this.vnfPkgId = id;
+ break
+ case 'PNF':
+ this.pnfdInfoId = id;
+ break
+ }
+ }
+
+ //Drag and drop and click the upload button
+ onClick(tab) {
+ switch (tab) {
+ case 'NS':
+ // this.handleUpload('/api/nsd/v1/ns_descriptors/'+this.nsdInfoId+'/nsd_content',tab);
+ this.handleUpload(this.url.ns.replace("*_*", this.nsdInfoId), tab);
+ this.getTableData();
+ break
+ case 'VNF':
+ // this.handleUpload('/api/vnfpkgm/v1/vnf_packages/'+this.vnfPkgId+'/package_content',tab);
+ this.handleUpload(this.url.vnf.replace("*_*", this.vnfPkgId), tab);
+ this.getTableVnfData()
+ break
+ case 'PNF':
+ // this.handleUpload('/api/nsd/v1/pnf_descriptors/'+this.pnfdInfoId+'/pnfd_content',tab);
+ this.handleUpload(this.url.pnf.replace("*_*", this.pnfdInfoId), tab);
+ this.getTablePnfData();
+ break
+ }
+ }
+
+ nsRightList = [];
+ nsNum = 0;
+ vnfRightList = [];
+ vnfNum = 0;
+ pnfRightList = [];
+ pnfNum = 0;
+ //put Upload Upload
+ handleUpload(url, tab): void {
+ const formData = new FormData();
+ // tslint:disable-next-line:no-any
+ switch (tab) {
+ case "NS":
+ this.fileListNS.forEach((file: any) => {
+ formData.append('file', file);
+ });
+ this.nsuploading = true;
+ let lastNs = this.fileListNS[this.fileListNS.length - 1];
+ let nsfile = {
+ name: lastNs.name,
+ uid: lastNs.uid,
+ progress: 0,
+ status: true,
+ success: 0
+ };
+ this.nsNum += 1;
+ this.nsRightList.push(nsfile);
+ let requeryNs = (nsfile) => {
+ setTimeout(() => {
+ nsfile.progress += 2;
+ if (nsfile.progress < 100) {
+ requeryNs(nsfile)
+ } else {
+ nsfile.progress = 100;
+ nsfile.status = false;
+ }
+ }, 100)
+ };
+ requeryNs(nsfile);
+ break
+ case "VNF":
+ this.fileListVNF.forEach((file: any) => {
+ formData.append('file', file);
+ });
+ this.vnfuploading = true;
+ let lastVnf = this.fileListVNF[this.fileListVNF.length - 1];
+ let vnffile = {
+ name: lastVnf.name,
+ uid: lastVnf.uid,
+ progress: 0,
+ status: true,
+ success: 0
+ };
+ this.vnfNum += 1;
+ this.vnfRightList.push(vnffile);
+ let requeryVnf = (vnffile) => {
+ setTimeout(() => {
+ vnffile.progress += 2;
+ if (vnffile.progress < 100) {
+ requeryVnf(vnffile)
+ } else {
+ vnffile.progress = 100;
+ vnffile.status = false;
+ }
+ }, 100)
+ };
+ requeryVnf(vnffile);
+ break
+ case "PNF":
+ this.fileListPNF.forEach((file: any) => {
+ formData.append('file', file);
+ });
+ this.pnfloading = true;
+ let lastPnf = this.fileListPNF[this.fileListPNF.length - 1];
+ let pnffile = {
+ name: lastPnf.name,
+ uid: lastPnf.uid,
+ progress: 0,
+ status: true,
+ success: 0
+ };
+ this.pnfNum += 1;
+ this.pnfRightList.push(pnffile);
+ let requeryPnf = (pnffile) => {
+ setTimeout(() => {
+ pnffile.progress += 2;
+ if (pnffile.progress < 100) {
+ requeryPnf(pnffile)
+ } else {
+ pnffile.progress = 100;
+ pnffile.status = false;
+ }
+ }, 100)
+ };
+ requeryPnf(pnffile);
+ break
+ }
+ // line PUT
+ const req = new HttpRequest('PUT', url, formData, {
+ reportProgress: true,
+ withCredentials: true
+ });
+ //Upload pre-empty array
+ this.fileList = [];
+ this.fileListNS = [];
+ this.fileListVNF = [];
+ this.fileListPNF = [];
+ this.http.request(req)
+ .pipe(filter(e => e instanceof HttpResponse))
+ .subscribe(
+ (event: {}) => {
+ if (tab == "NS") {
+ this.nsRightList[this.nsNum - 1].progress = 100;
+ this.nsRightList[this.nsNum - 1].status = false;
+ this.nsRightList[this.nsNum - 1].success = 0;
+ }
+ if (tab == "VNF") {
+ this.vnfRightList[this.vnfNum - 1].progress = 100;
+ this.vnfRightList[this.vnfNum - 1].status = false;
+ this.vnfRightList[this.vnfNum - 1].success = 0;
+ }
+ if (tab == "PNF") {
+ this.pnfRightList[this.pnfNum - 1].progress = 100;
+ this.pnfRightList[this.pnfNum - 1].status = false;
+ this.pnfRightList[this.pnfNum - 1].success = 0;
+ }
+ this.changeUploadingSta(tab);
+ this.msg.success('upload successfully.');
+ },
+ err => {
+ if (tab == "NS") {
+ this.nsRightList[this.nsNum - 1].progress = 100;
+ this.nsRightList[this.nsNum - 1].status = false;
+ this.nsRightList[this.nsNum - 1].success = 1;
+ }
+ if (tab == "VNF") {
+ this.vnfRightList[this.vnfNum - 1].progress = 100;
+ this.vnfRightList[this.vnfNum - 1].status = false;
+ this.vnfRightList[this.vnfNum - 1].success = 1;
+ }
+ if (tab == "PNF") {
+ this.pnfRightList[this.pnfNum - 1].progress = 100;
+ this.pnfRightList[this.pnfNum - 1].status = false;
+ this.pnfRightList[this.pnfNum - 1].success = 1;
+ }
+ this.changeUploadingSta(tab);
+ this.msg.error('upload failed.');
+ }
+ );
+ }
+
+ // Control the status of uploading
+ changeUploadingSta(tab) {
+ switch (tab) {
+ case "NS":
+ this.nsuploading = false;
+ break
+ case "VNF":
+ this.vnfuploading = false;
+ break
+ case "PNF":
+ this.pnfloading = false;
+ }
+ }
+
+ //----------------------------------------------------------------------------------------------
+
+ // Get the NS list
+ getTableData() {
+ this.isSpinning = true;
+ //ns vfc lists
+ this.myhttp.getOnboardTableData()
+ .subscribe((data) => {
+ this.nsvfcData = data;
+ this.nstableData = this.nsvfcData;
+ //ns sdc list
+ this.myhttp.getSDC_NSTableData()
+ .subscribe((data) => {
+ this.isSpinning = false; //loading hide
+ this.nssdcData = data;
+ this.nsvfcData.map((nsvfc) => { nsvfc.sameid = this.nssdcData.find((nssdc) => { return nsvfc.id == nssdc.uuid }) && nsvfc.id; return nsvfc; });
+ let sameData = this.nssdcData.filter((nssdc) => { return !this.nsvfcData.find((nsvfc) => { return nsvfc.id == nssdc.uuid }) });
+ this.nstableData = this.nstableData.concat(sameData);
+ }, (err) => {
+ console.log(err);
+ this.isSpinning = false;
+ })
+ }, (err) => {
+ console.log(err);
+ this.isSpinning = false;
+ })
+
+ }
+
+ // Get the vnf list
+ getTableVnfData() {
+ this.isSpinning = true;
+ //vnf vfc lists
+ this.myhttp.getOnboardTableVnfData()
+ .subscribe((data) => {
+ this.vnfvfcData = data;
+ this.vnftableData = this.vnfvfcData;
+ //vnf sdc lists
+ this.myhttp.getSDC_VNFTableData()
+ .subscribe((data) => {
+ this.isSpinning = false; //loading hide
+ this.vnfsdcData = data;
+ this.vnfvfcData.map((vnfvfc) => { vnfvfc.sameid = this.vnfsdcData.find((nssdc) => { return vnfvfc.id == nssdc.uuid }) && vnfvfc.id; return vnfvfc; });
+ let sameData = this.vnfsdcData.filter((vnfsdc) => { return !this.vnfvfcData.find((vnfvfc) => { return vnfvfc.id == vnfsdc.uuid }) });
+ this.vnftableData = this.vnftableData.concat(sameData);
+ }, (err) => {
+ console.log(err);
+ })
+
+ }, (err) => {
+ console.log(err);
+ })
+ }
+
+ // Get pnf list
+ getTablePnfData() {
+ this.isSpinning = true;
+ this.myhttp.getOnboardTablePnfData()
+ .subscribe((data) => {
+ this.pnftableData = data;
+ this.isSpinning = false; //loading hide
+ }, (err) => {
+ console.log(err);
+ })
+ }
+
+ //-----------------------------------------------------------------------------------
+ /* onboard */
+ //Successful frame
+ success(tab): void {
+ const modal = this.modalService.success({
+ nzTitle: 'This is an success message',
+ nzContent: 'Package Onboard Completed.'
+ });
+ switch (tab) {
+ case "NS":
+ this.getTableData();
+ break
+ case "VNF":
+ this.getTableVnfData();
+ break
+ }
+ }
+
+ //Failure frame
+ error(): void {
+ this.modalService.error({
+ nzTitle: 'This is an error message',
+ nzContent: 'Package Onboard Failed!'
+ });
+ }
+
+ //onboard status
+ onboardData = {
+ status: "onboard",
+ progress: 0,
+ }
+ currentIndex = 0;
+ // ns onboard Upload button
+ updataNsService(id, index, notificationModel) {
+ this.currentIndex = index;
+ this.onboardData.status = "onboarding"; //Disabled
+ this.onboardData.progress = 0;
+ let requestBody = {
+ "csarId": id
+ };
+ this.notificationAttributes = {
+ "title": this.tabs[0],
+ "imgPath": "../../../../assets/images/execute-inproess.png",
+ "action": "OnboardingState",
+ "status": "InProgress",
+ "id": id
+ };
+ this.notificationModelShow(notificationModel);
+ this.myhttp.getNsonboard(requestBody)
+ .subscribe((data) => {
+ if (data.status == "failed") {
+ this.onboardData.status = "Failed";
+ this.notificationFailed(notificationModel);
+ this.error();
+ return false
+ } else if (data.status == "success") {
+ this.success("NS");
+ this.onboardData.status = "onboarded";
+ this.notificationSuccess(notificationModel);
+ }
+ }, (err) => {
+ console.log(err);
+ })
+ }
+
+ // vnf onboard Upload button
+ updataVnfService(id, index, notificationModel) {
+ this.currentIndex = index;
+ this.onboardData.status = "onboarding"; //Disabled button
+ this.onboardData.progress = 0;
+
+
+ let requestBody = {
+ "csarId": id
+ };
+ this.notificationAttributes = {
+ "title": this.tabs[1],
+ "imgPath": "../../../../assets/images/execute-inproess.png",
+ "action": "OnboardingState",
+ "status": "InProgress",
+ "id": id
+ };
+ this.notificationModelShow(notificationModel);
+ this.myhttp.getVnfonboard(requestBody)
+ .subscribe((data) => {
+ this.jobId = data.jobId;
+ this.queryProgress(this.jobId, 0, notificationModel); //vnf Need to query progress interface
+ }, (err) => {
+ console.log(err);
+ })
+ }
+
+ //Progress Progress inquiry
+ queryProgress(jobId, responseId, notificationModel) {
+ let mypromise = new Promise((res) => {
+ this.myhttp.getProgress(jobId, responseId)
+ .subscribe((data) => {
+ if (data.responseDescriptor == null || data.responseDescriptor == "null" || data.responseDescriptor.progress == undefined || data.responseDescriptor.progress == null) {
+ this.onboardData.status = "onboarding";
+ setTimeout(() => {
+ this.queryProgress(this.jobId, 0, notificationModel);
+ }, 10000)
+ return false
+ }
+ if (data.responseDescriptor.progress > 100) {
+ this.onboardData.status = "Failed";
+ this.notificationFailed(notificationModel);
+ this.error();
+ return false
+ }
+ if (data.responseDescriptor.progress < 100) {
+ this.onboardData.status = "onboarding";
+ setTimeout(() => {
+ this.queryProgress(this.jobId, 0, notificationModel);
+ }, 5000)
+ } else if (data.responseDescriptor.progress == 100) {
+ res(data);
+ this.success("VNF");
+ this.onboardData.status = "onboarded";
+ this.notificationSuccess(notificationModel);
+ }
+ return false
+ })
+ })
+ return mypromise;
+ }
+
+ //--------------------------------------------------------------------------------
+ /* delete button */
+ showConfirm(index, pkgid, tab, notificationModel): void {
+ this.notificationAttributes = {
+ "title": this.tabs[0],
+ "imgPath": "../../../../assets/images/execute-inproess.png",
+ "action": "OnboardingState",
+ "status": "InProgress",
+ "id": pkgid
+ };
+ this.confirmModal = this.modal.confirm({
+ nzTitle: 'Do you Want to delete these items?',
+ nzContent: 'Do you Want to delete these items?',
+ nzOkText: 'Yes',
+ nzCancelText: 'No',
+ nzOnOk: () => new Promise((resolve, reject) => {
+ switch (tab) {
+ case 'NS':
+ this.notificationAttributes.title = this.tabs[0];
+ this.notificationModelShow(notificationModel);
+ this.deleteNsService(index, pkgid, notificationModel);
+ setTimeout(Math.random() > 0.5 ? resolve : reject, 2000);
+ break
+ case 'VNF':
+ this.notificationAttributes.title = this.tabs[1];
+ this.notificationModelShow(notificationModel);
+ this.deleteVnfService(index, pkgid, notificationModel);
+ setTimeout(Math.random() > 0.5 ? resolve : reject, 2000);
+ break
+ case 'PNF':
+ this.notificationAttributes.title = this.tabs[2];
+ this.notificationModelShow(notificationModel);
+ this.deletePnfService(index, pkgid, notificationModel);
+ setTimeout(Math.random() > 0.5 ? resolve : reject, 2000);
+ break
+ }
+ }).catch(() => console.log('Oops errors!'))
+ });
+ }
+
+ //delete nsItem
+ deleteNsService(index, pkgid, notificationModel) {
+ this.myhttp.deleteNsIdData(pkgid)
+ .subscribe((data) => {
+ this.notificationSuccess(notificationModel);
+ //refresh list after successful deletion
+ this.getTableData();
+ }, (err) => {
+ console.log(err);
+ this.notificationFailed(notificationModel);
+ })
+ }
+
+ //delete vnfItem
+ deleteVnfService(index, pkgid, notificationModel) {
+ this.myhttp.deleteVnfIdData(pkgid)
+ .subscribe((data) => {
+ this.notificationSuccess(notificationModel);
+ //refresh list after successful deletion
+ this.getTableVnfData()
+ }, (err) => {
+ console.log(err);
+ this.notificationFailed(notificationModel);
+ })
+ }
+
+ //delete PnfItem
+ deletePnfService(index, pkgid, notificationModel) {
+ this.myhttp.deletePnfIdData(pkgid)
+ .subscribe((data) => {
+ //refresh list after successful deletion
+ this.notificationSuccess(notificationModel);
+ this.getTablePnfData()
+ }, (err) => {
+ console.log(err);
+ this.notificationFailed(notificationModel);
+ })
+ }
+
+}
diff --git a/usecaseui-portal/src/app/views/services/services-list/services-list.component.css b/usecaseui-portal/src/app/views/services/services-list/services-list.component.css
new file mode 100644
index 00000000..0a7f92eb
--- /dev/null
+++ b/usecaseui-portal/src/app/views/services/services-list/services-list.component.css
@@ -0,0 +1,145 @@
+/*
+ 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.
+*/
+.title {
+ font: 700 18px/18px "思源黑体";
+ color: #4c5e70;
+ margin-bottom: 18px;
+}
+hr {
+ border: none;
+ height: 2px;
+ background-color: #dce1e7;
+ margin-bottom: 20px;
+}
+.action {
+ margin-bottom: 20px;
+}
+.action span {
+ display: inline-block;
+ font: 700 14px "Arial";
+ color: #4c5e70;
+}
+.action nz-dropdown {
+ vertical-align: middle;
+}
+.action nz-dropdown :hover {
+ border-color: #147dc2;
+}
+.action nz-dropdown button {
+ width: 165px;
+ height: 30px;
+ background-color: #eceff4;
+ text-align: left;
+ border-color: #9fa9ab;
+}
+.action nz-dropdown button span {
+ font-weight: 400;
+ display: inline-block;
+ width: 120px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ padding-top: 2px;
+}
+.action nz-dropdown button i {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+}
+.action .create {
+ float: right;
+ height: 30px;
+ padding: 0 10px;
+}
+.action .create span {
+ color: #fff;
+ font-weight: 400;
+}
+.list {
+ background-color: #fff;
+ border-radius: 5px;
+ padding: 10px;
+}
+.list nz-table tbody td span.active {
+ font-size: 14px;
+ color: #147dc2;
+}
+.list nz-table tbody td span.closed {
+ font-size: 14px;
+ color: red;
+}
+.list nz-table tbody td span.onboarding {
+ font-size: 12px;
+ color: #147dc2;
+}
+.list nz-table tbody td span.updating {
+ font-size: 12px;
+ color: blue;
+}
+.list nz-table tbody td span.deleting {
+ font-size: 12px;
+ color: red;
+}
+.list nz-table tbody td span.creating {
+ font-size: 12px;
+ color: green;
+}
+.list nz-table tbody td span.scaling {
+ font-size: 12px;
+ color: purple;
+}
+.list nz-table tbody td span.healing {
+ font-size: 12px;
+ color: orangered;
+}
+.list nz-table tbody td i.anticon {
+ cursor: pointer;
+ font-size: 18px;
+ padding: 2px;
+}
+.list nz-table tbody td i.anticon:hover {
+ color: #147dc2;
+}
+.list nz-table tbody td .cannotclick {
+ pointer-events: none;
+ color: #aaa;
+ opacity: 0.6;
+}
+.list nz-table tbody tr.childtr td {
+ font-size: 12px;
+ color: #147dc2;
+}
+.detailComponent {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100vh;
+ background-color: #f3f3f3;
+ overflow-y: auto;
+ padding: 20px 32px;
+ z-index: 3;
+}
+.createComponent {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100vh;
+ background-color: #f3f3f3;
+ overflow-y: auto;
+ padding: 20px 32px;
+ z-index: 3;
+}
diff --git a/usecaseui-portal/src/app/views/services/services-list/services-list.component.html b/usecaseui-portal/src/app/views/services/services-list/services-list.component.html
new file mode 100644
index 00000000..6f6d8f74
--- /dev/null
+++ b/usecaseui-portal/src/app/views/services/services-list/services-list.component.html
@@ -0,0 +1,745 @@
+<!--
+ 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.
+-->
+<div class="action ant-tabs-bar">
+
+ <span><i style="margin-right: 10px"><img src="assets/images/customer.png" alt=""></i>
+ {{"i18nTextDefine_Customer" | translate}} : </span>
+ <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomLeft'">
+ <button nz-button nz-dropdown><span>{{customerSelected.name}}</span> <i class="anticon anticon-down"></i>
+ </button>
+ <ul nz-menu style="min-height:40px;max-height: 200px; overflow: auto;">
+ <li nz-menu-item (click)="choseCustomer(item)" *ngFor="let item of customerList">
+ <a title="{{item.name}}"
+ style="max-width: 165px; overflow: hidden; text-overflow: ellipsis;">{{item.name}}</a>
+ </li>
+ </ul>
+ </nz-dropdown>
+
+ <span style="margin-left:40px"><i style="margin-right: 10px"><img src="assets/images/service-type.png" alt=""></i>
+ {{"i18nTextDefine_ServiceType" | translate}} : </span>
+ <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomLeft'">
+ <button nz-button nz-dropdown><span>{{serviceTypeSelected.name}}</span> <i class="anticon anticon-down"></i>
+ </button>
+ <ul nz-menu style="min-height:40px;max-height: 200px; overflow: auto;">
+ <li nz-menu-item (click)="choseServiceType(item)" *ngFor="let item of serviceTypeList">
+ <a title="{{item.name}}"
+ style="max-width: 165px; overflow: hidden; text-overflow: ellipsis;">{{item.name}}</a>
+ </li>
+ </ul>
+ </nz-dropdown>
+
+ <button class="create" nz-button [nzType]="'primary'" (click)="createModal()"><i class="anticon anticon-plus"
+ style="transform: scale(1.5);line-height: 15px;margin-right: 5px;"></i><span>
+ {{"i18nTextDefine_Create" | translate}} </span>
+ </button>
+ <nz-modal nzWidth="428" [(nzVisible)]="isVisible" nzTitle=" {{'i18nTextDefine_ServiceCreation' | translate}} "
+ (nzOnCancel)="handleCancel()" (nzOnOk)="handleOk()" nzClassName="serviceCreationModel"
+ nzCancelText=" {{'i18nTextDefine_Cancel' | translate}} " nzOkText=" {{'i18nTextDefine_modelOk' | translate}} ">
+ <div class="select-list">
+ <span style="display:inline-block;"> {{"i18nTextDefine_Customer" | translate}} : </span>
+ <nz-select style="width: 176px;float: right;" [(ngModel)]="customerSelected2.name" nzAllowClear
+ (ngModelChange)="customerChange()">
+ <nz-option *ngFor="let item of customerList2" [nzValue]="item.name" [nzLabel]="item.name"></nz-option>
+ </nz-select>
+ </div>
+ <div class="select-list">
+ <span style="display:inline-block;"> {{"i18nTextDefine_ServiceType" | translate}} : </span>
+ <nz-select style="width: 176px;float: right;" [(ngModel)]="serviceTypeSelectedName" nzAllowClear
+ (ngModelChange)="serviceTypeChange()">
+ <nz-option *ngFor="let item of serviceTypeList2" [nzValue]="item.name" [nzLabel]="item.name">
+ </nz-option>
+ </nz-select>
+ </div>
+ <div class="select-list">
+ <span style="display:inline-block;"> {{"i18nTextDefine_UseCase" | translate}} : </span>
+ <nz-select style="width: 176px;float: right;" [(ngModel)]="templateTypeSelected" nzAllowClear
+ (ngModelChange)="choseTemplateType()">
+ <!-- <nz-option *ngFor="let item of templateType" [nzValue]="item" [nzLabel]="item"></nz-option> -->
+ <nz-option nzValue="SOTN" nzLabel="SOTN"></nz-option>
+ <nz-option nzValue="CCVPN" nzLabel="CCVPN"></nz-option>
+ <nz-option nzValue="E2E Service" nzLabel="E2E Service"></nz-option>
+ <nz-option nzValue="Network Service" nzLabel="Network Service"></nz-option>
+ </nz-select>
+ </div>
+
+ <div class="select-list">
+ <span style="display:inline-block;width:70px;"> {{"i18nTextDefine_Template" | translate}} : </span>
+ <nz-select style="width: 176px;float: right;" [(ngModel)]="template1" nzAllowClear>
+ <nz-option *ngFor="let item of templates" [nzValue]="item" [nzLabel]="item.name"></nz-option>
+ </nz-select>
+ </div>
+ <div *ngIf="templateTypeSelected == 'E2E Service'">
+ <div class="select-list">
+ <span style="display:inline-block;width:70px;"> {{"i18nTextDefine_Orchestrator" | translate}} : </span>
+ <nz-select style="width: 176px;float: right;" [(ngModel)]="orchestratorSelected" nzAllowClear>
+ <nz-option *ngFor="let item of orchestratorList" [nzValue]="item" [nzLabel]="item.name"></nz-option>
+ </nz-select>
+ </div>
+ </div>
+ <div *ngIf="templateTypeSelected == 'E2E Service'">
+ <div class="check-box" style="margin:30px; height: 50px">
+ <input class="check-box-style" style="zoom: 1.8; width: 70px" type="checkbox"
+ [(ngModel)]="isSol005Interface" value="true" nzAllowClear>
+ <label class="label" style="font-size: 20px; color: rgb(60,79,140,0.5)">Sol005</label>
+ </div>
+ </div>
+ <div class="select-list" style="color: red;margin-left: 66px;" *ngIf="temParametersTips">
+ {{"i18nTextDefine_Templateparsingfailed" | translate}}
+ </div>
+ </nz-modal>
+</div>
+<nz-layout style=" padding: 20px 32px; ">
+ <ul class="top-num">
+ <li *ngFor="let item of serviceMunber" class="top-list">
+ <span class="round">{{item.serviceDomain}}</span>
+ <div class="top-list-text">
+ <p>
+ <span>{{item.failed}}</span>
+ <span> {{"i18nTextDefine_Failed" | translate}} </span>
+ </p>
+ <p>
+ <span>{{item.Success}}</span>
+ <span> {{"i18nTextDefine_Success" | translate}} </span>
+ </p>
+ <p>
+ <span>{{item.InProgress}}</span>
+ <span> {{"i18nTextDefine_InProgress" | translate}} </span>
+ </p>
+ </div>
+ <p class="service-description"> {{item.detailName | translate}} </p>
+ </li>
+ </ul>
+ <div class="list" id="services-list" [ngClass]="{'listdisplay':listDisplay == true}">
+ <nz-table *ngIf="1" #nzTable [nzData]="tableData" nzShowSizeChanger [nzFrontPagination]="false"
+ [nzShowQuickJumper]="true" [nzPageSizeOptions]="[5,10,15,20]" [nzTotal]='total' [(nzPageSize)]="pageSize"
+ [(nzPageIndex)]='pageIndex' [nzLoading]="loading" [nzSize]="'middle'" [nzScroll]="{ y: '58vh' }"
+ (nzPageIndexChange)="searchData()" (nzPageSizeChange)="searchData(true)">
+ <thead>
+ <tr>
+ <th nzWidth="5%"> {{"i18nTextDefine_NO" | translate}}</th>
+ <th nzWidth="5%"></th>
+ <th nzWidth="20%"> {{"i18nTextDefine_Name" | translate}}</th>
+ <th nzWidth="20%"> {{"i18nTextDefine_InstanceID" | translate}}</th>
+ <th nzWidth="15%"> {{"i18nTextDefine_UseCase" | translate}}</th>
+ <th nzWidth="20%"> {{"i18nTextDefine_Status" | translate}}</th>
+ <th nzWidth="15%"> {{"i18nTextDefine_Action" | translate}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <ng-template ngFor let-data [ngForOf]="nzTable.data" let-i="index">
+ <tr>
+ <td>{{pageSize*(pageIndex-1) + i+1}}</td>
+ <td [nzShowExpand]="data.childServiceInstances[0]" [(nzExpand)]="data.expand"></td>
+ <td>{{data["service-instance-name"] || data.nsName}}</td>
+ <td>{{data["service-instance-id"] || data.nsInstanceId}}</td>
+ <td>
+ <p
+ [ngClass]="{'e2eColor':data.serviceDomain=='E2E Service','nsColor':data.serviceDomain=='Network Service','ccvpnColor':data.serviceDomain=='CCVPN','sotnColor':data.serviceDomain=='SOTN','voLTEColor':data.serviceDomain=='voLTE type'}">
+ {{data.serviceDomain}}
+ </p>
+ </td>
+ <td>
+ <span [ngClass]="{'active':data.statusClass=='2001','closed':data.statusClass=='Closed','onboarding':data.statusClass=='Onboarding',
+ 'updating':data.statusClass=='Updating','deleting':data.statusClass=='1002','creating':data.statusClass=='1001',
+ 'scaling':data.statusClass=='1003','healing':data.statusClass=='1004'}"
+ *ngIf="data.tips != 'Available' && data.tips != 'Unavailable'">{{data.tips}}</span>
+ <span *ngIf="data.tips == 'Available' " style="margin-left: 10px">
+ <img src="assets/images/wancheng-icon.png" alt="Available">
+ </span>
+ <span *ngIf="data.tips == 'Unavailable' " style="margin-left: 10px">
+ <img src="assets/images/shibai-icon.png" alt="Unavailable">
+ </span>
+ <nz-progress *ngIf="data.status == 'In Progress'" [nzPercent]="data.rate"
+ [nzShowInfo]="false" nzStatus="active"></nz-progress>
+ </td>
+ <td>
+ <i [ngClass]="{'cannotclick':data.status == 'In Progress'||(data.status=='Failed' && data.operationType=='1001')||(data.status=='Failed' && data.operationType=='1002')}"
+ class="anticon anticon-bars" (click)="serviceDetail(data,1)"></i>
+ <i [ngClass]="{'cannotclick':data.status == 'In Progress'}" class="anticon anticon-delete"
+ (click)="deleteModel(data)"></i>
+ <i [ngClass]="{'cannotclick':data.status == 'In Progress'}" class="anticon anticon-ellipsis"
+ (click)="iconMoreShow(data,tableData)" style="transform: rotate(90deg);"></i>
+
+ <ul *ngIf="data.iconMore==true " class="icon-more">
+ <li (click)="scaleService(data)"
+ [ngClass]="{'cannotclick':data.serviceDomain!='E2E Service' || data.status == 'In Progress'||(data.status=='Failed' && data.operationType=='1001')||(data.status=='Failed' && data.operationType=='1002')}">
+ <i class="anticon anticon-scale"></i>
+ <span> {{"i18nTextDefine_Scale" | translate}} </span>
+ </li>
+ <li (click)="serviceDetail(data,2)"
+ [ngClass]="{'cannotclick':data.serviceDomain!='CCVPN' || data.status == 'In Progress'||(data.status=='Failed' && data.operationType=='1001')||(data.status=='Failed' && data.operationType=='1002')}">
+ <i class="anticon anticon-update"></i>
+ <span> {{"i18nTextDefine_Update" | translate}} </span>
+ </li>
+ </ul>
+ <!-- <i *ngIf="data.serviceDomain=='E2E Service'||data.serviceDomain=='Network Service' " class="anticon anticon-cloud-upload-o" (click)="updataService(data)"></i> -->
+ <!-- <i [ngClass]="{'cannotclick':data.status == 'processing'||data.status=='Deleting'||data.status=='Creating'||data.status=='Healing'}"
+ *ngIf="data.serviceDomain=='Network Service' " class="anticon anticon-reload" (click)="healService(data)"></i> -->
+ </td>
+ </tr>
+ <tr class="childtr" [nzExpand]="data.expand" *ngFor="let item of data.childServiceInstances">
+ <td></td>
+ <td></td>
+ <td>{{item["service-instance-id"] || item.nsInstanceId || item.vnfInstanceId}}</td>
+ <td>{{item["service-instance-name"] || item.nsName || item.vnfInstanceName}}</td>
+ <td>
+ <p
+ [ngClass]="{'vnfColor':item.serviceDomain=='vnf','siteColor':item.serviceDomain=='SITE','SDWANColor':item.serviceDomain=='SDWAN'}">
+ {{item.serviceDomain}}
+ </p>
+ </td>
+ <td>
+ <span [ngClass]="{'healing':data.statusClass=='1004'}">{{item.tips}}</span>
+ <nz-progress *ngIf=" item.status == 'In Progress' " [nzPercent]="item.rate"></nz-progress>
+ </td>
+ <td>
+ <i [ngClass]="{'cannotclick':data.serviceDomain!='Network Service' || data.status == 'In Progress'||(data.status=='Failed' && data.operationType=='1001')||(data.status=='Failed' && data.operationType=='1002')}"
+ class="anticon anticon-reload" (click)="healService(item)"></i>
+ </td>
+ </tr>
+ </ng-template>
+ </tbody>
+ </nz-table>
+
+ <nz-modal nzWidth="428" [nzVisible]="scaleModelVisible" nzTitle=" {{'i18nTextDefine_Scale' | translate}} "
+ (nzOnCancel)="scaleCancel()" (nzOnOk)="scaleOk(templatescalestarting,templateScaleSuccessFaild)"
+ nzClassName="scaleModel" nzCancelText=" {{'i18nTextDefine_Cancel' | translate}} "
+ nzOkText=" {{'i18nTextDefine_modelOk' | translate}} ">
+ <h3><span style="color: red">*&nbsp;</span> {{"i18nTextDefine_SureScale" | translate}} </h3>
+ <div class="question">
+ <h4> {{"i18nTextDefine_InstanceID" | translate}} :</h4>
+ <div class="scaleModelContent" style="width: 100%">{{ thisService["service-instance-id"] ||
+ thisService["nsInstanceId"] ||
+ thisService["vnfInstanceId"]}}
+ </div>
+ </div>
+ <div *ngFor="let item of e2e_nsData" style="margin-top: 20px">
+ <h3>{{ item.netWorkServiceName }}</h3>
+ <div class="e2eScaleContent">
+ <span class="e2eScaleLable"> {{"i18nTextDefine_ScaleType" | translate}} :</span>
+ <nz-select style="width: 165px;" [(ngModel)]="item.scaleType">
+ <nz-option nzValue="SCALE_NS" nzLabel="SCALE_NS"></nz-option>
+ <nz-option nzValue="SCALE_VNF" nzLabel="SCALE_VNF"></nz-option>
+ </nz-select>
+ </div>
+ <div class="e2eScaleContent">
+ <span class="e2eScaleLable"> {{"i18nTextDefine_AspectId" | translate}} :</span>
+ <input style="width: 165px;" nz-input [(ngModel)]="item.aspectId" placeholder="string">
+ </div>
+ <div class="e2eScaleContent">
+ <span class="e2eScaleLable"> {{"i18nTextDefine_Number_Of_Steps" | translate}} :</span>
+ <nz-input-number style="width: 165px;" [(ngModel)]="item.numberOfSteps" [nzMin]="1" [nzMax]="100"
+ nzPrecision=0 [nzStep]="1" nzPlaceHolder="number"></nz-input-number>
+ </div>
+ <div class="e2eScaleContent">
+ <span class="e2eScaleLable"> {{"i18nTextDefine_ScalingDirection" | translate}} :</span>
+ <nz-select style="width: 165px;" nzPlaceHolder="Chose" [(ngModel)]="item.scalingDirection">
+ <nz-option nzValue="SCALE_IN" nzLabel="SCALE_IN"></nz-option>
+ <nz-option nzValue="SCALE_OUT" nzLabel="SCALE_OUT"></nz-option>
+ </nz-select>
+ </div>
+ </div>
+
+ <ng-template #templatescalestarting>
+ <div class="ant-notification-notice-content">
+ <div class="ant-notification-notice-with-icon">
+ <span class="ant-notification-notice-icon">
+ <img src="assets/images/execute-inproess.png" alt="instance temination is starting">
+ </span>
+ <div class="ant-notification-notice-message">E2E &nbsp;
+ {{"i18nTextDefine_InstanceTeminationStarting" | translate}}
+ </div>
+ <div class="ant-notification-notice-description">
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_InstanceName" | translate}} :</p>
+ <span>{{ thisService["service-instance-name"] ||
+ thisService["nsInstanceName"] }}
+ </span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_Customer" | translate}} :</p>
+ <span>{{ customerSelected.name }}</span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_UseCase" | translate}} :</p>
+ <span>{{ thisService["serviceDomain"] }}</span>
+ </div>
+ </div>
+ <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div>
+ </div>
+ </div>
+ </ng-template>
+ </nz-modal>
+
+ <nz-modal nzWidth="428" [(nzVisible)]="deleteModelVisible" nzTitle=" {{'i18nTextDefine_delete' | translate}} "
+ (nzOnCancel)="deleteCancel()" (nzOnOk)="deleteOk(templatedeletestarting,templateDeleteSuccessFaild)"
+ nzClassName="{{thisService['serviceDomain'] == 'Network Service'?'nsdeleteModel':'deleteModel'}}"
+ nzCancelText=" {{'i18nTextDefine_Cancel' | translate}} "
+ nzOkText=" {{'i18nTextDefine_modelOk' | translate}} ">
+ <h3><span style="color: red">*&nbsp;</span> {{"i18nTextDefine_SureDelete" | translate}} </h3>
+ <div class="question">
+ <h4> {{"i18nTextDefine_InstanceName" | translate}} :</h4>
+ <div class="deleteModelContent">{{ thisService["service-instance-name"] ||
+ thisService["nsInstanceName"] }}
+ </div>
+ </div>
+ <div class="question">
+ <h4> {{"i18nTextDefine_InstanceID" | translate}} :</h4>
+ <div class="deleteModelContent">{{ thisService["service-instance-id"] ||
+ thisService["nsInstanceId"] }}
+ </div>
+ </div>
+ <div *ngIf="thisService['serviceDomain'] == 'Network Service'">
+ <div class="question">
+ <h4> {{"i18nTextDefine_terminationType" | translate}} :</h4>
+ <nz-select style="width: 306px;" [(ngModel)]="terminationType">
+ <nz-option nzValue="graceful" nzLabel=" {{'i18nTextDefine_graceful' | translate}} "></nz-option>
+ <nz-option nzValue="forceful" nzLabel=" {{'i18nTextDefine_forceful' | translate}} "></nz-option>
+ </nz-select>
+ </div>
+ <div class="question">
+ <h4 *ngIf="terminationType=='graceful'"> {{"i18nTextDefine_gracefulTerminationTimeout" | translate}}
+ :</h4>
+ <input *ngIf="terminationType=='graceful'" style="width: 306px;" nz-input
+ [(ngModel)]="gracefulTerminationTimeout">
+ </div>
+ </div>
+
+ <ng-template #templatedeletestarting>
+ <div class="ant-notification-notice-content">
+ <div class="ant-notification-notice-with-icon">
+ <span class="ant-notification-notice-icon">
+ <img src="assets/images/execute-inproess.png" alt="instance temination is starting">
+ </span>
+ <div class="ant-notification-notice-message"
+ *ngIf="thisService['serviceDomain'] == 'CCVPN' || thisService['serviceDomain'] == 'SOTN'">
+ {{ thisService['serviceDomain'] }} &nbsp; {{"i18nTextDefine_InstanceTeminationStarting" |
+ translate}}
+ </div>
+ <div class="ant-notification-notice-message"
+ *ngIf="thisService['serviceDomain'] == 'E2E Service'">E2E &nbsp;
+ {{"i18nTextDefine_InstanceTeminationStarting" | translate}}
+ </div>
+ <div class="ant-notification-notice-message"
+ *ngIf="thisService['serviceDomain'] == 'Network Service'">NS &nbsp;
+ {{"i18nTextDefine_InstanceTeminationStarting" | translate}}
+ </div>
+ <div class="ant-notification-notice-description">
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_InstanceName" | translate}} :</p>
+ <span>{{ thisService["service-instance-name"] ||
+ thisService["nsInstanceName"] }}
+ </span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_Customer" | translate}} :</p>
+ <span>{{ customerSelected.name }}</span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_UseCase" | translate}} :</p>
+ <span>{{ thisService["serviceDomain"] }}</span>
+ </div>
+ </div>
+ <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div>
+ </div>
+ </div>
+ </ng-template>
+ </nz-modal>
+
+ <nz-modal nzWidth="428" [nzVisible]="healModelVisible" nzTitle=" {{'i18nTextDefine_Heal' | translate}} "
+ (nzOnCancel)="healCancel()" (nzOnOk)="healOk(templatehealstarting,templatehealSuccessFaild)"
+ nzClassName="healModel" nzCancelText=" {{'i18nTextDefine_Cancel' | translate}} "
+ nzOkText=" {{'i18nTextDefine_modelOk' | translate}} ">
+ <h3><span style="color: red">*&nbsp;</span> {{"i18nTextDefine_SureHeal" | translate}} </h3>
+ <div class="heal-question">
+ <p class="heal-label"> {{"i18nTextDefine_InstanceID" | translate}} : </p>
+ <div class="healModelContent" title="{{ thisService['service-instance-id'] || thisService['nsInstanceId'] ||
+ thisService['vnfInstanceId']}}"> {{ thisService["service-instance-id"] ||
+ thisService["nsInstanceId"] ||
+ thisService["vnfInstanceId"]}}
+ </div>
+ </div>
+ <!-- NS -->
+ <div *ngIf="thisService['serviceDomain'] == 'Network Service'">
+ <div class="question">
+ <p class="heal-label"> {{"i18nTextDefine_degreeHealing" | translate}} :</p>
+ <nz-select style="width: 200px;height:42px;margin-left: 15px;border-radius: 6px"
+ [(ngModel)]="nsParams.degreeHealing">
+ <nz-option nzValue="HEAL_RESTORE" nzLabel="HEAL_RESTORE"></nz-option>
+ <nz-option nzValue="HEAL_QOS" nzLabel="HEAL_QOS"></nz-option>
+ <nz-option nzValue="HEAL_RESET" nzLabel="HEAL_RESET"></nz-option>
+ <nz-option nzValue="PARTIAL_HEALING" nzLabel="PARTIAL_HEALING"></nz-option>
+ </nz-select>
+ </div>
+ <div>
+ <span style="display:inline-block;"> {{"i18nTextDefine_actionsHealing" | translate}} :</span>
+ <button nz-button [nzType]="'default'" (click)="addActionsHealing()"><i
+ class="anticon anticon-plus-circle-o"></i></button>
+ <br>
+ <div *ngFor="let item of healActions;let i = index;" style="display:inline-block;">
+ <input style="width: 165px;" nz-input [(ngModel)]="item.value">
+ <button nz-button [nzType]="'dashed'" (click)="minusActionsHealing(i)"><i
+ class="anticon anticon-minus-circle-o"></i></button>
+ &nbsp;
+ </div>
+ </div>
+ <span style="display:inline-block;width:50%;"> {{"i18nTextDefine_healScript" | translate}} :</span>
+ <input style="width: 165px;" nz-input [(ngModel)]="nsParams.healScript">
+ <div>
+ <span style="display:inline-block;"> {{"i18nTextDefine_additionalParamsforNs" | translate}} :</span>
+ <button nz-button [nzType]="'default'" (click)="addNsAdditional()"><i
+ class="anticon anticon-plus-circle-o"></i></button>
+ <br>
+ <div *ngFor="let item of nsAdditional;let i = index;">
+ Key: <input style="width: 165px;" nz-input [(ngModel)]="item.key"> &nbsp;
+ Value: <input style="width: 165px;" nz-input [(ngModel)]="item.value">
+ <button nz-button [nzType]="'dashed'" (click)="minusNsAdditional(i)"><i
+ class="anticon anticon-minus-circle-o"></i></button>
+ </div>
+ </div>
+ </div>
+ <!-- vnf -->
+ <div *ngIf="thisService['serviceDomain'] == 'vnf'" style="clear: both">
+ <div class="heal-question">
+ <p class="heal-label"> {{"i18nTextDefine_cause" | translate}} :</p>
+ <input nz-input [(ngModel)]="vnfParams.cause" class="heal-input">
+ </div>
+ <div class="heal-question">
+ <p class="heal-label"> {{"i18nTextDefine_action" | translate}} :</p>
+ <input nz-input [(ngModel)]="vnfParams.additionalParams.action" class="heal-input">
+ </div>
+ <div class="heal-question">
+ <p class="heal-label"> {{"i18nTextDefine_actionvminfo" | translate}}:</p>
+ <nz-select
+ style=" float: right;width: 200px;margin-left: 15px;border-radius: 6px;margin-right: 30px"
+ [(ngModel)]="vmSelected">
+ <nz-option *ngFor="let item of vnfVms" [nzValue]="item" [nzLabel]="item.vmName"></nz-option>
+ </nz-select>
+ </div>
+ </div>
+
+ <ng-template #templatehealstarting>
+ <div class="ant-notification-notice-content">
+ <div class="ant-notification-notice-with-icon">
+ <span class="ant-notification-notice-icon">
+ <img src="assets/images/execute-inproess.png" alt="instance temination is starting">
+ </span>
+ <div class="ant-notification-notice-message">NS &nbsp;
+ {{"i18nTextDefine_InstanceHealingStarting" | translate}}
+ </div>
+ <div class="ant-notification-notice-description">
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_InstanceName" | translate}} :</p>
+ <span>{{ thisService["service-instance-name"] ||
+ thisService["nsInstanceName"] }}
+ </span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_Customer" | translate}} :</p>
+ <span>{{ customerSelected.name }}</span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_UseCase" | translate}} :</p>
+ <span>{{ thisService["serviceDomain"] }}</span>
+ </div>
+ </div>
+ <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div>
+ </div>
+ </div>
+ </ng-template>
+ </nz-modal>
+
+ <!-- add notification-->
+ <ng-template #templateCreatestarting>
+ <div class="ant-notification-notice-content">
+ <div class="ant-notification-notice-with-icon">
+ <span class="ant-notification-notice-icon">
+ <img src="assets/images/execute-inproess.png" alt="instance temination is starting">
+ </span>
+ <div class="ant-notification-notice-message"
+ *ngIf="thisCreateService['serviceDomain'] == 'CCVPN' || thisService['serviceDomain'] == 'SOTN'">
+ {{ thisService['serviceDomain'] }} &nbsp; {{"i18nTextDefine_InstanceCreationStarting" |
+ translate}}
+ </div>
+ <div class="ant-notification-notice-message"
+ *ngIf="thisCreateService['serviceDomain'] == 'E2E Service'">E2E &nbsp;
+ {{"i18nTextDefine_InstanceCreationStarting" | translate}}
+ </div>
+ <div class="ant-notification-notice-message"
+ *ngIf="thisCreateService['serviceDomain'] == 'Network Service'">NS &nbsp;
+ {{"i18nTextDefine_InstanceCreationStarting" | translate}}
+ </div>
+ <div class="ant-notification-notice-description">
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_InstanceName" | translate}} :</p>
+ <span>{{ thisCreateService["service-instance-name"] }}
+ </span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_Customer" | translate}} :</p>
+ <span>{{ customerSelected2.name }}</span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_UseCase" | translate}} :</p>
+ <span>{{ thisCreateService['serviceDomain'] }}</span>
+ </div>
+ </div>
+ <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div>
+ </div>
+ </div>
+ </ng-template>
+ <ng-template #templateCreateSuccessFaild>
+ <div class="ant-notification-notice-content">
+ <div class="ant-notification-notice-with-icon">
+ <span class="ant-notification-notice-icon">
+ <img src="assets/images/execute-success.png" alt="instance temination is starting"
+ *ngIf="thisCreateService.status == 'Successful'">
+ <img src="assets/images/execute-faild.png" alt="instance temination is starting"
+ *ngIf="thisCreateService.status == 'Failed'">
+ </span>
+ <div class="ant-notification-notice-message"
+ *ngIf="(thisCreateService['serviceDomain'] == 'CCVPN' || thisCreateService['serviceDomain'] == 'SOTN') && thisCreateService.status == 'Successful'">
+ {{ thisCreateService['serviceDomain'] }} &nbsp; {{"i18nTextDefine_InstanceCreatedSuccessfully" |
+ translate}}
+ </div>
+ <div class="ant-notification-notice-message"
+ *ngIf="(thisCreateService['serviceDomain'] == 'E2E Service') && thisCreateService.status == 'Successful'">
+ E2E &nbsp; {{"i18nTextDefine_InstanceCreatedSuccessfully" | translate}}
+ </div>
+ <div class="ant-notification-notice-message"
+ *ngIf="(thisCreateService['serviceDomain'] == 'Network Service') && thisCreateService.status == 'Successful'">
+ NS &nbsp; {{"i18nTextDefine_InstanceCreatedSuccessfully" | translate}}
+ </div>
+ <div class="ant-notification-notice-message"
+ *ngIf="(thisCreateService['serviceDomain'] == 'CCVPN' || thisCreateService['serviceDomain'] == 'SOTN') && thisCreateService.status == 'Failed'">
+ {{ thisCreateService['serviceDomain'] }} &nbsp; {{"i18nTextDefine_InstanceCreationFailed" |
+ translate}}
+ </div>
+ <div class="ant-notification-notice-message"
+ *ngIf="(thisCreateService['serviceDomain'] == 'E2E Service') && thisCreateService.status == 'Failed'">
+ E2E &nbsp; {{"i18nTextDefine_InstanceCreationFailed" | translate}}
+ </div>
+ <div class="ant-notification-notice-message"
+ *ngIf="(thisCreateService['serviceDomain'] == 'Network Service') && thisCreateService.status == 'Failed'">
+ NS &nbsp; {{"i18nTextDefine_InstanceCreationFailed" | translate}}
+ </div>
+ <div class="ant-notification-notice-description">
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_InstanceName" | translate}} :</p>
+ <span>{{ thisCreateService["service-instance-name"] ||
+ thisCreateService["nsInstanceName"] }}
+ </span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_Customer" | translate}} :</p>
+ <span>{{ customerSelected2.name }}</span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_UseCase" | translate}} :</p>
+ <span>{{ thisCreateService["serviceDomain"] }}</span>
+ </div>
+ </div>
+ <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div>
+ </div>
+ </div>
+ </ng-template>
+ <ng-template #templateDeleteSuccessFaild>
+ <div class="ant-notification-notice-content">
+ <div class="ant-notification-notice-with-icon">
+ <span class="ant-notification-notice-icon">
+ <img src="assets/images/execute-success.png" alt="instance temination is starting"
+ *ngIf="thisService.status == 'Successful'">
+ <img src="assets/images/execute-faild.png" alt="instance temination is starting"
+ *ngIf="thisService.status == 'Failed'">
+ </span>
+ <div class="ant-notification-notice-message"
+ *ngIf="(thisService['serviceDomain'] == 'CCVPN' || thisService['serviceDomain'] == 'SOTN') && thisService.status == 'Successful'">
+ {{ thisService['serviceDomain'] }} &nbsp; {{"i18nTextDefine_InstanceTeminatedSuccessfully" |
+ translate}}
+ </div>
+ <div class="ant-notification-notice-message"
+ *ngIf="(thisService['serviceDomain'] == 'E2E Service') && thisService.status == 'Successful'">
+ E2E &nbsp; {{"i18nTextDefine_InstanceTeminatedSuccessfully" | translate}}
+ </div>
+ <div class="ant-notification-notice-message"
+ *ngIf="(thisService['serviceDomain'] == 'Network Service') && thisService.status == 'Successful'">
+ NS &nbsp; {{"i18nTextDefine_InstanceTeminatedSuccessfully" | translate}}
+ </div>
+ <div class="ant-notification-notice-message"
+ *ngIf="(thisService['serviceDomain'] == 'CCVPN' || thisService['serviceDomain'] == 'SOTN') && thisService.status == 'Failed'">
+ {{ thisService['serviceDomain'] }} &nbsp; {{"i18nTextDefine_InstanceTeminationFailed" |
+ translate}}
+ </div>
+ <div class="ant-notification-notice-message"
+ *ngIf="(thisService['serviceDomain'] == 'E2E Service') && thisService.status == 'Failed'">E2E
+ &nbsp; {{"i18nTextDefine_InstanceTeminationFailed" | translate}}
+ </div>
+ <div class="ant-notification-notice-message"
+ *ngIf="(thisService['serviceDomain'] == 'Network Service') && thisService.status == 'Failed'">
+ NS &nbsp; {{"i18nTextDefine_InstanceTeminationFailed" | translate}}
+ </div>
+ <div class="ant-notification-notice-description">
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_InstanceName" | translate}} :</p>
+ <span>{{ thisService["service-instance-name"] ||
+ thisService["nsInstanceName"] }}
+ </span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_Customer" | translate}} :</p>
+ <span>{{ customerSelected.name }}</span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_UseCase" | translate}} :</p>
+ <span>{{ thisService["serviceDomain"] }}</span>
+ </div>
+ </div>
+ <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div>
+ </div>
+ </div>
+ </ng-template>
+ <ng-template #templateScaleSuccessFaild>
+ <div class="ant-notification-notice-content">
+ <div class="ant-notification-notice-with-icon">
+ <span class="ant-notification-notice-icon">
+ <img src="assets/images/execute-success.png" alt="instance temination is starting"
+ *ngIf="thisService.status == 'Successful'">
+ <img src="assets/images/execute-faild.png" alt="instance temination is starting"
+ *ngIf="thisService.status == 'Failed'">
+ </span>
+ <div class="ant-notification-notice-message" *ngIf="thisService.status == 'Successful'">E2E &nbsp;
+ {{"i18nTextDefine_InstanceScaledSuccessfully" | translate}}
+ </div>
+ <div class="ant-notification-notice-message" *ngIf="thisService.status == 'Failed'">E2E &nbsp;
+ {{"i18nTextDefine_InstanceScaleFailed" | translate}}
+ </div>
+ <div class="ant-notification-notice-description">
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_InstanceName" | translate}} :</p>
+ <span>{{ thisService["service-instance-name"] ||
+ thisService["nsInstanceName"] }}
+ </span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_Customer" | translate}} :</p>
+ <span>{{ customerSelected.name }}</span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_UseCase" | translate}} :</p>
+ <span>{{ thisService["serviceDomain"] }}</span>
+ </div>
+ </div>
+ <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div>
+ </div>
+ </div>
+ </ng-template>
+ <ng-template #templatehealSuccessFaild>
+ <div class="ant-notification-notice-content">
+ <div class="ant-notification-notice-with-icon">
+ <span class="ant-notification-notice-icon">
+ <img src="assets/images/execute-success.png" alt="instance temination is starting"
+ *ngIf="thisService.status == 'Successful'">
+ <img src="assets/images/execute-faild.png" alt="instance temination is starting"
+ *ngIf="thisService.status == 'Failed'">
+ </span>
+ <div class="ant-notification-notice-message" *ngIf="thisService.status == 'Successful'">NS &nbsp;
+ {{"i18nTextDefine_InstanceHealedSuccessfully" | translate}}
+ </div>
+ <div class="ant-notification-notice-message" *ngIf="thisService.status == 'Failed'">NS &nbsp;
+ {{"i18nTextDefine_InstanceHealingFailed" | translate}}
+ </div>
+ <div class="ant-notification-notice-description">
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_InstanceName" | translate}} :</p>
+ <span>{{ thisService["service-instance-name"] ||
+ thisService["nsInstanceName"] }}
+ </span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_Customer" | translate}} :</p>
+ <span>{{ customerSelected.name }}</span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_UseCase" | translate}} :</p>
+ <span>{{ thisService["serviceDomain"] }}</span>
+ </div>
+ </div>
+ <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div>
+ </div>
+ </div>
+ </ng-template>
+ <ng-template #templateUpdateSuccessFaild>
+ <div class="ant-notification-notice-content">
+ <div class="ant-notification-notice-with-icon">
+ <span class="ant-notification-notice-icon">
+ <img src="assets/images/execute-success.png" alt="instance temination is starting"
+ *ngIf="thisService.status == 'Successful'">
+ <img src="assets/images/execute-faild.png" alt="instance temination is starting"
+ *ngIf="thisService.status == 'Failed'">
+ </span>
+ <div class="ant-notification-notice-message" *ngIf="thisService.status == 'Successful'">CCVPN &nbsp;
+ {{"i18nTextDefine_InstanceUpdatedSuccessfully" | translate}}
+ </div>
+ <div class="ant-notification-notice-message" *ngIf="thisService.status == 'Failed'">CCVPN &nbsp;
+ {{"i18nTextDefine_InstanceUpdateFailed" | translate}}
+ </div>
+ <div class="ant-notification-notice-description">
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_InstanceName" | translate}} :</p>
+ <span>{{ thisService["service-instance-name"] ||
+ thisService["nsInstanceName"] }}
+ </span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_Customer" | translate}} :</p>
+ <span>{{ customerSelected.name }}</span>
+ </div>
+ <div class="notificationlist">
+ <p> {{"i18nTextDefine_UseCase" | translate}} :</p>
+ <span>{{ thisService["serviceDomain"] }}</span>
+ </div>
+ </div>
+ <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div>
+ </div>
+ </div>
+ </ng-template>
+ </div>
+ <div class="detailComponent" *ngIf="detailshow">
+ <app-ccvpn-detail [detailParams]="detailData" [upDateShow]="upDateShow"
+ (closeUpdate)="closeCCVPNUpdate($event,templateUpdateSuccessFaild)"
+ (closeDetail)="detailshow = false;listDisplay = false;"></app-ccvpn-detail>
+ </div>
+ <div class="detailComponent" *ngIf="detailshow2">
+ <app-e2e-detail [detailParams]="detailData" (closeDetail)="detailshow2 = false;listDisplay = false;">
+ </app-e2e-detail>
+ </div>
+ <div class="createComponent" *ngIf="createshow">
+ <app-ccvpn-creation [createParams]="createData" [ccvpn_temParametersContent]="ccvpn_temParametersContent"
+ (closeCreate)="closeCreate($event,templateCreatestarting,templateCreateSuccessFaild)">
+ </app-ccvpn-creation>
+ </div>
+ <div class="createComponent" *ngIf="createshow2">
+ <app-e2e-creation [createParams]="createData" [e2e_ns_temParametersContent]="e2e_ns_temParametersContent"
+ (nsCloseCreate)="nsCloseCreate($event,templateCreatestarting,templateCreateSuccessFaild)"
+ (e2eCloseCreate)="e2eCloseCreate($event,templateCreatestarting,templateCreateSuccessFaild)">
+ </app-e2e-creation>
+ </div>
+ <!--</div>-->
+</nz-layout>
+<div class="loading" *ngIf="loadingAnimateShow">
+ <img src="assets/images/loading-animate2.gif" alt="loading">
+ <p>Please wating……</p>
+</div> \ No newline at end of file
diff --git a/usecaseui-portal/src/app/views/services/services-list/services-list.component.less b/usecaseui-portal/src/app/views/services/services-list/services-list.component.less
new file mode 100644
index 00000000..392d1b3a
--- /dev/null
+++ b/usecaseui-portal/src/app/views/services/services-list/services-list.component.less
@@ -0,0 +1,380 @@
+/*
+ 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.
+*/
+.title {
+ font: 700 18px/18px "思源黑体";
+ color: #4c5e70;
+ margin-bottom: 18px;
+}
+hr {
+ border: none;
+ height: 2px;
+ background-color: #dce1e7;
+ margin-bottom: 20px;
+}
+.ant-tabs-bar{
+ margin-bottom: 0!important;
+}
+.mask{
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ z-index: 999;
+ background: rgba(0, 0, 0, 0.65);
+ top:0;
+}
+.loading{
+ width: 100%;
+ height: 100%;
+ position: fixed;
+ top: 0;
+ margin-top: -50px;
+ margin-left: -50px;
+ z-index: 1001;
+ text-align: center;
+ background: transparent;
+ p{
+ color: #0DA9E2;
+ text-align: center;
+ position: absolute;
+ width: 300px;
+ height: 30px;
+ line-height: 30px;
+ top: 71%;
+ left: 36%;
+ margin-top: -150px;
+ margin-left: -150px;
+ }
+ img{
+ width: 300px;
+ height: 300px;
+ position: absolute;
+ top: 50%;
+ left: 36%;
+ margin-top: -150px;
+ margin-left: -150px;
+ }
+}
+.action {
+ margin-bottom: 15px;
+ padding: 28px;
+ background: #ffffff;
+ position: relative;
+ span {
+ display: inline-block;
+ font: 700 14px "Arial";
+ color: #3C4F8C;
+ margin-right: 5px;
+ }
+ nz-dropdown {
+ vertical-align: middle;
+ background-color:#ffffff;
+ :hover{
+ border-color: #48C6EF;
+ }
+ button {
+ width: 165px;
+ height: 42px;
+ background-color:#ffffff;
+ text-align: left;
+ border-color: #EEEEEE;
+ span {
+ font-weight: 400;
+ color: #3C4F8C;
+ display: inline-block;
+ width: 120px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ padding-top: 2px;
+ }
+ i {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ }
+ }
+ }
+ //The style in the drop-down box is in style.less, and the drop-down box is extra temporary generated in the body.
+ .create {
+ position: absolute;
+ right: 3%;
+ top:50%;
+ width:116px;
+ height:42px;
+ background:#0DA9E2;
+ border-radius:6px;
+ margin-top: -15px;
+ span {
+ color: #fff;
+ font-weight: 400;
+ font-size: 18px;
+ }
+ .anticon-plus-circle-o{
+ font-size: 18px;
+ }
+ }
+ .create.ant-btn.ant-btn-primary{
+ border: none;
+ }
+ .create:hover{
+ background:#09C6E2;
+ }
+
+}
+.top-num{
+ overflow: auto;
+ width: 100%;
+}
+.top-list{
+ position: relative;
+ width:29%;
+ height:170px;
+ margin: 10px 1%;
+ float: left;
+ background:url("../../../../assets/images/servicelist-e2e.png") no-repeat;
+ background-size: 100% 100%;
+ border-radius:2px;
+}
+.top-num .top-list:nth-child(2){
+ background:url("../../../../assets/images/servicelist-e2e.png") no-repeat;
+ background-size: 100% 100%;
+}
+.top-num .top-list:nth-child(3){
+ background:url("../../../../assets/images/servicelist-e2e.png") no-repeat;
+ background-size: 100% 100%;
+}
+.top-num .top-list:nth-child(4){
+ background:url("../../../../assets/images/servicelist-sotn.png") no-repeat;
+ background-size: 100% 100%;
+}
+.top-list .round{
+ position: absolute;
+ width: 60px;
+ height: 60px;
+ line-height: 60px;
+ text-align: center;
+ top:45%;
+ left: 50px;
+ margin-top: -30px;
+ background:#E0EDFF;
+ border:2px solid rgba(224,237,255,1);
+ border-radius: 50%;
+ font-size:16px;
+ font-family:ArialMT;
+ color:#3C4F8C;
+}
+.top-list {
+ .top-list-text {
+ position: absolute;
+ text-align: right;
+ height: 40px;
+ line-height: 20px;
+ right: 50px;
+ color: #fff;
+ p {
+ font-size: 14px;
+ width: 250px;
+ margin: 15px 0 0 0;
+ height: 13px;
+ clear: both;
+ span {
+ display: inline-block;
+ font-weight: 500;
+ text-align: right;
+ float: right;
+ }
+ span:nth-child(1) {
+ font-size: 18px;
+ width: 40px;
+ min-width: 40px;
+ }
+ span:nth-child(2) {
+ width: 85px;
+ font-size: 16px;
+ }
+ }
+ p:nth-child(1) {
+ margin-top: 25px;
+ }
+ }
+ .service-description{
+ font-size: 14px;
+ width: 250px;
+ height: 13px;
+ position: absolute;
+ bottom: 30px;
+ left: 50px;
+ color: #3C4F8C;
+ }
+}
+.list {
+ background-color: #fff;
+ border-radius: 5px;
+ padding: 10px;
+ nz-table {
+ tbody {
+ td {
+ position: relative;
+ span.active {
+ font-size: 14px;
+ color: #147dc2;
+ }
+ span.closed {
+ font-size: 14px;
+ color: red;
+ }
+ span.onboarding{
+ font-size: 12px;
+ color: #147dc2;
+ }
+ span.updating{
+ font-size: 12px;
+ color: blue;
+ }
+ span.deleting {
+ font-size: 12px;
+ color: red;
+ }
+ span.creating {
+ font-size: 12px;
+ color: green;
+ }
+ span.scaling {
+ font-size: 12px;
+ color: purple;
+ }
+ span.healing {
+ font-size: 12px;
+ color: orangered;
+ }
+ i.anticon {
+ cursor: pointer;
+ font-size: 18px;
+ padding: 2px;
+ &:hover{
+ color: #147dc2;
+ }
+ }
+ .cannotclick {
+ pointer-events: none;
+ color: #aaa;
+ opacity: 0.6;
+ }
+ .icon-more{
+ position: absolute;
+ width: 115px;
+ height: 90px;
+ top:50px;
+ padding:15px 0 0 15px;
+ background: #ffffff;
+ z-index: 2;
+ border-radius: 5px;
+ box-shadow: 0px 10px 15px 2px rgba(247, 247, 247, 0.5);
+ li{
+ margin-bottom:10px;
+ line-height: 20px;
+ text-align: left;
+ cursor: pointer;
+ .anticon{
+ width: 18px;
+ height: 18px;
+ background: url("../../../../assets/images/scale.png") no-repeat;
+ }
+ .anticon.anticon-update{
+ background: url("../../../../assets/images/update.png") no-repeat;
+ }
+ span{
+ margin-left: 5px;
+ }
+ }
+ li:hover{
+ color: #0DA9E2;
+ .anticon{
+ background: url("../../../../assets/images/scale-active.png") no-repeat;
+ }
+ .anticon.anticon-update{
+ background: url("../../../../assets/images/update-active.png") no-repeat;
+ }
+ }
+ }
+ }
+ tr.childtr {
+ td {
+ font-size: 12px;
+ color: #147dc2;
+ }
+ }
+ }
+ }
+}
+
+
+.detailComponent {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100vh;
+ background-color: #f3f3f3;
+ overflow-y: auto;
+ z-index: 3;
+}
+.createComponent {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100vh;
+ background-color: #F7F8FC;
+ overflow-y: auto;
+ z-index: 3;
+}
+
+.e2eColor,.nsColor,.ccvpnColor,.sotnColor,.voLTEColor{
+ width:120px;
+ height: 34px;
+ line-height: 34px;
+ margin-bottom: 0!important;
+ text-align: center;
+ background:rgba(158, 158, 158, 0.38);
+ border-radius:4px
+}
+
+.vnfColor,.siteColor,.SDWANColor{
+ color:rgba(60,79,140,0.5);
+ width:120px;
+ height: 34px;
+ line-height: 34px;
+ margin-bottom: 0!important;
+ text-align: center;
+ background:rgba(238,238,238,1);
+ border-radius:4px;
+}
+
+.select-list{
+ width: 320px;
+ height: 32px;
+ line-height: 32px;
+ margin: 35px auto;
+}
+.select-list>span{
+ text-align: right;
+ width: 110px!important;
+ line-height: 32px;
+}
+
+.listdisplay{
+ display: none;
+} \ No newline at end of file
diff --git a/usecaseui-portal/src/app/views/services/services-list/services-list.component.spec.ts b/usecaseui-portal/src/app/views/services/services-list/services-list.component.spec.ts
new file mode 100644
index 00000000..61440dc3
--- /dev/null
+++ b/usecaseui-portal/src/app/views/services/services-list/services-list.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ServicesListComponent } from './services-list.component';
+
+describe('ServicesListComponent', () => {
+ let component: ServicesListComponent;
+ let fixture: ComponentFixture<ServicesListComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ServicesListComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ServicesListComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/usecaseui-portal/src/app/views/services/services-list/services-list.component.ts b/usecaseui-portal/src/app/views/services/services-list/services-list.component.ts
new file mode 100644
index 00000000..c15e9f11
--- /dev/null
+++ b/usecaseui-portal/src/app/views/services/services-list/services-list.component.ts
@@ -0,0 +1,1410 @@
+/*
+ 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, OnInit, HostBinding, TemplateRef } from '@angular/core';
+import { MyhttpService } from '../../../core/services/myhttp.service';
+import { slideToRight } from '../../../animates';
+import { NzModalService } from 'ng-zorro-antd';
+import { NzNotificationService } from 'ng-zorro-antd';
+
+@Component({
+ selector: 'app-services-list',
+ templateUrl: './services-list.component.html',
+ styleUrls: ['./services-list.component.less'],
+ animations: [slideToRight]
+})
+export class ServicesListComponent implements OnInit {
+ @HostBinding('@routerAnimate') routerAnimateState;
+
+ constructor(private myhttp: MyhttpService, private modalService: NzModalService, private notification: NzNotificationService) {
+ }
+
+ ngOnInit() {
+ this.getallCustomers();
+ }
+
+ // customer servicetype
+ isSol005Interface = false;
+ orchestratorList = [];
+ customerList = [];
+ customerList2 = [];
+ customerSelected = { name: null, id: null };
+ customerSelected2 = { name: null, id: null };
+ serviceTypeList = [];
+ serviceTypeList2 = [];
+ serviceTypeSelected = { name: '' };
+ serviceTypeSelected2 = { name: '' };
+ serviceTypeSelectedName = "";
+ templateTypeSelected = "CCVPN";
+ orchestratorSelected = { name: null, id: null };
+ listSortMasters = JSON.parse(sessionStorage.getItem('listSortMasters'));
+ language = sessionStorage.getItem("DefaultLang");
+ iconMore = false;
+ loadingAnimateShow = false;
+ serviceMunber = [ // top: E2E/NS/CCVPN data
+ {
+ "serviceDomain": "E2E",
+ "Success": 0,
+ "failed": 0,
+ "InProgress": 0,
+ "detailName": "i18nTextDefine_End_To_End_Service"
+ },
+ {
+ "serviceDomain": "NS",
+ "Success": 0,
+ "failed": 0,
+ "InProgress": 0,
+ "detailName": "i18nTextDefine_Network_Service"
+ },
+ {
+ "serviceDomain": "CCVPN",
+ "Success": 0,
+ "failed": 0,
+ "InProgress": 0,
+ "detailName": "i18nTextDefine_Cross_Domain_and_Cross_Layer_VPN"
+ }
+ ];
+
+ //The icon behind each row of data in the table expands
+ iconMoreShow(data, tableData) {
+ tableData.map((its) => {
+ if (its["service-instance-id"] == data["service-instance-id"]) {
+ if (its["iconMore"] == false) {
+ data.iconMore = true;
+ } else if (its["iconMore"] == true) {
+ data.iconMore = false;
+ }
+ } else {
+ its["iconMore"] = false;
+ }
+ })
+ }
+
+ //Get all the customers
+ getallCustomers() {
+ console.log(this.language, "this.language");
+ this.myhttp.getAllCustomers()
+ .subscribe((data) => {
+ this.customerList = data.map((item) => {
+ return { name: item["subscriber-name"], id: item["global-customer-id"] }
+ });
+ if (this.customerList.length == 0) {
+ console.log("customerList.length == 0", this.customerList);
+ return false;
+ }
+ this.customerList2 = data.map((item) => {
+ return { name: item["subscriber-name"], id: item["global-customer-id"] }
+ });
+ if (this.customerList2.length == 0) {
+ return false;
+ }
+ this.customerSelected = this.customerList[0];
+ this.choseCustomer(this.customerSelected);
+ })
+ }
+
+ getallOrchestrators() {
+ this.myhttp.getAllOrchestrators()
+ .subscribe((data) => {
+ this.orchestratorList = data.map((item) => {
+ return { name: item["name"], id: item["name"] }
+ });
+ if (this.orchestratorList.length == 0) {
+ console.log("orchestratorList.length == 0", this.orchestratorList);
+ return false;
+ }
+ this.orchestratorSelected = this.orchestratorList[0];
+ })
+ }
+
+ choseCustomer(item) {
+ this.customerSelected = item;
+ this.myhttp.getServiceTypes(this.customerSelected)
+ .subscribe((data) => {
+ this.serviceTypeList = data.map((item) => {
+ return { name: item["service-type"] }
+ });
+
+ if (this.serviceTypeList.length == 0) {
+ console.log("serviceTypeList.length == 0", this.serviceTypeList);
+ return false;
+ }
+
+ this.serviceTypeSelected = this.serviceTypeList[0];
+
+ this.choseServiceType(this.serviceTypeSelected);
+ })
+ }
+
+ choseServiceType(item) {
+ this.serviceTypeSelected = item;
+ this.getTableData();
+ }
+
+
+ // Create modal box 2 (dialog box) create -------------------------------
+ isVisible = false;
+
+ customerChange(): void {
+ this.getServiceType(this.customerSelected2);
+ }
+
+ getServiceType(customerSelected2) {
+ this.myhttp.getServiceTypes(customerSelected2)
+ .subscribe((data) => {
+ this.serviceTypeList2 = data.map((item) => {
+ return { name: item["service-type"] }
+ });
+ if (this.serviceTypeList2.length == 0) {
+ console.log("serviceTypeList.length == 0", this.serviceTypeList2);
+ return false;
+ }
+ this.getAlltemplates();
+ })
+ }
+
+ serviceTypeChange(): void {
+ this.serviceTypeSelected2.name = this.serviceTypeSelectedName
+ }
+
+ createModal(): void {
+ this.isVisible = true;
+ this.getallOrchestrators();
+ this.customerSelected2 = this.customerSelected;
+ this.serviceTypeSelectedName = this.serviceTypeSelected.name;
+ this.serviceTypeSelected2 = Object.assign({}, this.serviceTypeSelected);
+ this.getServiceType(this.customerSelected2);
+ }
+
+ choseTemplateType() {
+ this.getallOrchestrators();
+ this.getAlltemplates();
+ }
+
+ templates = [];
+ template1 = { name: null };
+
+ getAlltemplates() {
+ this.myhttp.getAllServiceTemplates(this.templateTypeSelected)
+ .subscribe((data) => {
+ this.templates = data;
+ if (this.templateTypeSelected == "Network Service") {
+ this.templates = data.filter((d) => {
+ return typeof d.packageInfo.csarName == "string";
+ }).map((item) => {
+ let cName = item.packageInfo.csarName.split("/").reverse()[0];
+ return { name: cName, id: item.csarId, packageInfo: item.packageInfo }
+ });
+ }
+ this.template1 = this.templates[0];
+ }, (err) => {
+ console.log(err);
+ })
+ }
+
+ createshow = false;
+ createshow2 = false;
+ listDisplay = false;
+ createData: Object = {};
+
+ handleOk(): void {
+ if (this.templateTypeSelected == "SOTN" || this.templateTypeSelected == "CCVPN") {
+ this.createData = {
+ commonParams: {
+ customer: this.customerSelected,
+ serviceType: this.serviceTypeSelected2,
+ templateType: this.templateTypeSelected
+ }, template: this.template1
+ };
+ } else if (this.templateTypeSelected == "E2E Service" || this.templateTypeSelected == "Network Service") {
+ this.createData = {
+ commonParams: {
+ customer: this.customerSelected,
+ serviceType: this.serviceTypeSelected2,
+ templateType: this.templateTypeSelected
+ },
+ template: this.template1,
+ orchestrator: this.orchestratorSelected,
+ isSol005Interface: this.isSol005Interface
+ };
+ }
+ this.getTemParameters();
+ }
+
+ handleCancel(): void {
+ this.isVisible = false;
+ this.loadingAnimateShow = false;
+ }
+
+ temParametersTips = false;
+ ccvpn_temParametersContent: any;
+ e2e_ns_temParametersContent: any;
+
+ getTemParameters() {
+ let chosedtemplates = this.createData["template"];
+ let types = this.createData["commonParams"].templateType;
+ if (types == "E2E Service") {
+ types = "e2e";
+ } else if (types == "Network Service") {
+ types = "ns";
+ }
+ this.loadingAnimateShow = true;
+ this.myhttp.getTemplateParameters(types, chosedtemplates)
+ .subscribe((data) => {
+ this.loadingAnimateShow = false;
+ if (data.status == "FAILED") {
+ this.temParametersTips = true;
+ this.isVisible = true;
+ console.log("Template parsing Failed");
+ } else {
+ this.isVisible = false;
+ this.temParametersTips = false;
+ if (this.templateTypeSelected == "SOTN" || this.templateTypeSelected == "CCVPN") {
+ this.ccvpn_temParametersContent = data;
+ this.createshow = true;
+ this.listDisplay = true;
+ } else if (this.templateTypeSelected == "E2E Service" || this.templateTypeSelected == "Network Service") {
+ this.e2e_ns_temParametersContent = data;
+ this.createshow2 = true;
+ this.listDisplay = true;
+ }
+ }
+ })
+ }
+
+ //tableData
+ tableData = [];
+ pageIndex = 1;
+ pageSize = 10;
+ total = 100;
+ loading = false;
+
+ getTableData() {
+ this.loading = true;
+ // Query parameter: customer serviceType Current page number, number of pages per page
+ let paramsObj = {
+ customerId: this.customerSelected.id,
+ serviceType: this.serviceTypeSelected.name,
+ currentPage: this.pageIndex,
+ pageSize: this.pageSize
+ }
+ this.myhttp.getServicesTableData(paramsObj)
+ .subscribe((data) => {
+ this.total = data.body.total;
+ this.tableData = data.body.tableList.map((item) => {
+ if (typeof item == "string") {
+ item = JSON.parse(item);
+ }
+
+ item["iconMore"] = this.iconMore;
+ if (item["serviceDomain"] == "Network Service") {
+ if (item["vnfInfo"]) {
+ item["childServiceInstances"] = item["vnfInfo"].map((vnf) => {
+ vnf["serviceDomain"] = "vnf";
+ return vnf;
+ });
+ } else if (item["relationship-list"] && item["relationship-list"]["relationship"]) {
+ item["childServiceInstances"] = item["relationship-list"]["relationship"].filter((relate) => {
+ return relate["related-to"] == "generic-vnf";
+ }).map((vnf) => {
+ let vnfInfo = {
+ vnfNsInstanceId: "",
+ vnfInstanceId: "",
+ vnfInstanceName: "",
+ serviceDomain: "vnf"
+ };
+ vnfInfo.vnfNsInstanceId = item["nsInstanceId"] || item["service-instance-id"];
+ vnfInfo.vnfInstanceId = vnf["relationship-data"].find((vnfid) => {
+ return vnfid["relationship-key"] == "generic-vnf.vnf-id"
+ })["relationship-value"];
+ vnfInfo.vnfInstanceName = vnf["related-to-property"].find((vnfname) => {
+ return vnfname["property-key"] == "generic-vnf.vnf-name"
+ })["property-value"];
+ return vnfInfo;
+ })
+ }
+ } else {
+ item["childServiceInstances"] = [];
+ }
+
+ //
+ if (item["operationResult"] == "2001") { //operationResult==2001
+ item["status"] = "Available";
+ item["tips"] = "Available";
+ item["statusClass"] = item["operationResult"];
+ }
+ // 2018.12.13
+ else if (item["operationResult"] == "2002") { //operationResult==2002
+ if (item["operationType"] == "1001" || item["operationType"] == "1002") {
+ // item["status"] = this.accordingState["operationResult"][item["operationResult"]];
+ item["status"] = this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == item["operationResult"] && its["language"] == this.language
+ })["sortValue"];
+ item["tips"] = "Unavailable";
+ item["statusClass"] = item["operationType"];
+ } else if (item["operationType"] != "1001" && item["operationType"] != "1002") {
+ // item["status"] = this.accordingState["operationResult"][item["operationResult"]];
+ item["status"] = this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == item["operationResult"] && its["language"] == this.language
+ })["sortValue"];
+ item["tips"] = "Available";
+ item["statusClass"] = item["operationType"];
+ }
+
+ }
+ else if (item["operationResult"] == "2003") { //operationResult==2003
+ // item["status"] = this.accordingState["operationResult"][item["operationResult"]];
+ item["status"] = this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == item["operationResult"] && its["language"] == this.language
+ })["sortValue"];
+ item["statusClass"] = item["operationType"];
+ if (item["serviceDomain"] == "Network Service") {
+ let updata = (prodata) => {
+ item["rate"] = prodata.progress;
+ item["tips"] = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == item["operationType"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + prodata.progress + "%";
+ if (item["rate"] > 100) {
+ item["status"] = prodata.status;
+ item["tips"] = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == item["operationType"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + item["status"];
+ }
+ }
+ let id = item["nsInstanceId"] || item["service-instance-id"];
+ let jobid = item["jobId"] || item["operationId"];
+ let operationType = item["operationType"];
+ this.queryNsProgress(jobid, id, updata, operationType).then(() => {
+ item["rate"] = 100;
+ item["status"] = this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == 2001 && its["language"] == this.language
+ })["sortValue"];
+ item["tips"] = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == item["operationType"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + item["status"];
+ })
+ } else {
+ let updata = (prodata) => {
+ item["rate"] = prodata.progress || item["rate"];
+ item["tips"] = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == item["operationType"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + prodata.progress + "%";
+ if (item["rate"] > 100) {
+ item["status"] = prodata.status;
+ item["tips"] = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == item["operationType"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + item["status"];
+ }
+ }
+ let obj = {
+ serviceId: item["service-instance-id"],
+ operationId: item["operationId"],
+ operationType: item["operationType"]
+ }
+ this.queryProgress(obj, updata).then(() => {
+ item["rate"] = 100;
+ item["status"] = this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == 2001 && its["language"] == this.language
+ })["sortValue"];
+ item["tips"] = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == item["operationType"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + item["status"];
+ })
+ }
+ }
+ return item;
+ })
+ this.tableData.map((item, index) => {
+ if (item.serviceDomain == 'E2E Service') {
+ if (item.operationResult == 2001) {
+ this.serviceMunber[0]["Success"] += 1;
+ } else if (item.operationResult == 2002) {
+ this.serviceMunber[0]["failed"] += 1;
+ } else if (item.operationResult == 2003) {
+ this.serviceMunber[0]["InProgress"] += 1;
+ }
+ }
+ else if (item.serviceDomain == 'Network Service') {
+ if (item.operationResult == 2001) {
+ this.serviceMunber[1]["Success"] += 1;
+ } else if (item.operationResult == 2002) {
+ this.serviceMunber[1]["failed"] += 1;
+ } else if (item.operationResult == 2003) {
+ this.serviceMunber[1]["InProgress"] += 1;
+ }
+ }
+ else if (item.serviceDomain == 'CCVPN') {
+ if (item.operationResult == 2001) {
+ this.serviceMunber[2]["Success"] += 1;
+ } else if (item.operationResult == 2002) {
+ this.serviceMunber[2]["failed"] += 1;
+ } else if (item.operationResult == 2003) {
+ this.serviceMunber[2]["InProgress"] += 1;
+ }
+ }
+ })
+ this.loading = false;
+ }, (err) => {
+ console.log(err);
+ this.loading = false;
+ })
+ }
+
+ searchData(reset: boolean = false) {
+ this.getTableData();
+ }
+
+ thisService = {}; //The current service of the operation
+ e2e_nsData: Object[];
+ scaleModelVisible = false;
+
+ scaleService(service) {
+ this.thisService = service;
+ this.scaleModelVisible = true;
+ let paramsObj = {
+ customerId: this.customerSelected.id,
+ serviceType: this.serviceTypeSelected.name,
+ serviceId: service["service-instance-id"]
+ }
+ this.myhttp.getE2e_nsData(paramsObj)
+ .subscribe((data) => {
+ this.e2e_nsData = data;
+ })
+ }
+
+ scaleOk(templatescalestarting, templateScaleSuccessFaild) {
+ this.scaleModelVisible = false;
+ let requestBody = {
+ "service": {
+ "serviceInstanceName": this.thisService["service-instance-name"],
+ "serviceType": this.serviceTypeSelected.name,
+ "globalSubscriberId": this.customerSelected.id,
+ "resources": this.e2e_nsData.map((item) => {
+ return {
+ "resourceInstanceId": item["netWorkServiceId"],
+ "scaleType": item["scaleType"],
+ "scaleNsData": {
+ "scaleNsByStepsData": {
+ "aspectId": item["aspectId"],
+ "numberOfSteps": item["numberOfSteps"],
+ "scalingDirection": item["scalingDirection"]
+ }
+ }
+ }
+ })
+ }
+ }
+ this.scaleE2eService(this.thisService, requestBody, templateScaleSuccessFaild);
+ this.scaleNotification(templatescalestarting);
+ }
+
+ scaleCancel() {
+ this.scaleModelVisible = false;
+ }
+
+ scaleNotification(template: TemplateRef<{}>): void {
+ this.notification.template(template);
+ }
+
+ scaleSuccessNotification(template: TemplateRef<{}>): void {
+ this.notification.template(template);
+ }
+
+ //heal
+ healModelVisible = false;
+ healActions = [];
+ nsAdditional = [];
+ nsParams = {
+ degreeHealing: "HEAL_RESTORE",
+ actionsHealing: [],
+ healScript: "",
+ additionalParamsforNs: ""
+ }
+ vnfVms = [];
+ vmSelected = {};
+ vnfParams = {
+ vnfInstanceId: "",
+ cause: "",
+ additionalParams: {
+ action: "",
+ actionvminfo: {
+ vmid: "",
+ vduid: "",
+ vmname: ""
+ }
+ }
+ }
+
+ addActionsHealing() {
+ this.healActions.push({ value: "" })
+ }
+
+ minusActionsHealing(index) {
+ this.healActions.splice(index, 1);
+ }
+
+ addNsAdditional() {
+ this.nsAdditional.push({ key: "", value: "" })
+ }
+
+ minusNsAdditional(index) {
+ this.nsAdditional.splice(index, 1);
+ }
+
+ healService(service) {
+ this.thisService = service;
+ this.healModelVisible = true;
+ if (service.serviceDomain == "vnf") {
+ this.vnfParams.vnfInstanceId = service.vnfInstanceId;
+ this.myhttp.getVnfInfo(service.vnfInstanceId)
+ .subscribe((data) => {
+ this.vnfVms = data.vnfVms;
+ this.vmSelected = this.vnfVms[0];
+ })
+ }
+ }
+
+ healOk(templatehealstarting, templatehealSuccessFaild) {
+ this.healModelVisible = false;
+ // nsParams
+ this.nsParams.actionsHealing = this.healActions.map((item) => {
+ return item.value
+ });
+ let additional = {};
+ this.nsAdditional.forEach((item) => {
+ additional[item.key] = item.value;
+ });
+ this.nsParams.additionalParamsforNs = JSON.stringify(additional);
+ // vnfParams
+ this.vnfParams.additionalParams.actionvminfo.vmid = this.vmSelected["vmId"];
+ this.vnfParams.additionalParams.actionvminfo.vmname = this.vmSelected["vmName"];
+
+ let requestBody = this.thisService["serviceDomain"] == "Network Service" ? { healNsData: this.nsParams } : { healVnfData: this.vnfParams };
+ this.healNsVnfService(this.thisService, requestBody, templatehealSuccessFaild);
+ this.healNotification(templatehealstarting);
+ }
+
+ healCancel() {
+ this.healModelVisible = false;
+ }
+
+ healNotification(template: TemplateRef<{}>): void {
+ this.notification.template(template);
+ }
+
+ healSuccessNotification(template: TemplateRef<{}>): void {
+ this.notification.template(template);
+ }
+
+ // show detail
+ detailshow = false;
+ detailshow2 = false;
+ upDateShow = false;
+ detailData: Object;
+
+ serviceDetail(service, typeNum) {
+ service["siteSer"] = [];
+ service["sdwanSer"] = [];
+ service["customer"] = this.customerSelected;
+ service["serviceType"] = this.serviceTypeSelected;
+
+ service.childServiceInstances.forEach((item) => {
+ if (item.serviceDomain == "SITE") {
+ service.siteSer.push(item);
+ } else if (item.serviceDomain == "SDWAN") {
+ service.sdwanSer.push(item);
+ }
+ })
+ if (service["serviceDomain"] == 'CCVPN' || service["serviceDomain"] == 'SOTN') {
+ this.detailshow = true;
+ if (typeNum == 1) {
+ this.upDateShow = false;
+ } else {
+ this.upDateShow = true;
+ }
+ } else if (service["serviceDomain"] == 'E2E Service' || service["serviceDomain"] == 'Network Service') {
+ this.detailshow2 = true;
+ }
+ this.listDisplay = true;
+ this.detailData = service;
+ console.log(service);
+ }
+
+ deleteModelVisible = false;
+ terminationType = "graceful";
+ gracefulTerminationTimeout = 120;
+
+ // delete Model show
+ deleteModel(service) {
+ this.thisService = service;
+ this.deleteModelVisible = true;
+ }
+
+ deleteOk(templatedeletestarting, templateDeleteSuccessFaild) {
+ this.deleteModelVisible = false;
+ this.loadingAnimateShow = true;
+ if (this.thisService["serviceDomain"] == "Network Service") {
+ this.deleteNsService(this.thisService, templateDeleteSuccessFaild);
+ } else {
+ this.deleteService(this.thisService, templateDeleteSuccessFaild);
+ }
+ this.deleteNotification(templatedeletestarting);
+ }
+
+ deleteCancel() {
+ this.deleteModelVisible = false;
+ }
+
+ deleteNotification(template: TemplateRef<{}>): void {
+ this.notification.template(template);
+ }
+
+ deleteSuccessNotification(template: TemplateRef<{}>): void {
+ this.notification.template(template);
+ }
+
+ createNotification(template: TemplateRef<{}>): void {
+ this.notification.template(template);
+ }
+
+ createSuccessNotification(template: TemplateRef<{}>): void {
+ this.notification.template(template);
+ }
+
+ //ccvpn sotn createservice
+ parentServiceInstanceId = "";
+ thisCreateService = {};
+
+ closeCreate(obj, templateCreatestarting, templateCreateSuccessFaild) {
+ if (!obj) {
+ this.createshow = false; //close
+ this.listDisplay = false; //close
+ return false;
+ }
+ this.createshow = false;
+ this.listDisplay = false;
+ this.loadingAnimateShow = true;
+ console.log(obj);
+ let newData; //Newly created service data for the main table
+
+ let createParams = "?customerId=" + this.customerSelected2.id +
+ "&serviceType=" + this.serviceTypeSelected2.name +
+ "&serviceDomain=" + this.templateTypeSelected;
+ this.createService(obj, createParams, templateCreatestarting, templateCreateSuccessFaild).then((data) => {
+ console.log(data);
+ this.loadingAnimateShow = false;
+ newData = { //Newly created service data in the main form
+ 'service-instance-id': data["serviceId"],
+ 'service-instance-name': obj.service.name,
+ serviceDomain: this.templateTypeSelected,
+ childServiceInstances: [],
+ status: "In Progress",
+ rate: 0,
+ statusClass: 1001,
+ tips: ""
+ };
+ this.thisCreateService = newData;
+ this.tableData = [newData, ...this.tableData];
+ this.createNotification(templateCreatestarting);
+ let updata = (prodata) => {
+ newData.rate = prodata.progress;
+ newData.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == newData["statusClass"] && its["language"] == this.language
+ })["sortValue"] + newData.rate + "%";
+ if (newData["rate"] > 100) {
+ newData["status"] = prodata.status;
+ newData.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == newData["statusClass"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + newData["status"];
+ }
+ };
+ let queryParams = { serviceId: data["serviceId"], operationId: data["operationId"], operationType: "1001" };
+ return this.queryProgress(queryParams, updata);
+ }).then((data) => {
+ console.log(data);
+ newData.rate = 100;
+ newData.status = "Successful";
+ this.createSuccessNotification(templateCreateSuccessFaild);
+ newData.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == newData["statusClass"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == 2001 && its["language"] == this.language
+ })["sortValue"];
+ let hasUndone = this.tableData.some((item) => {
+ return item.rate < 100;
+ });
+ if (!hasUndone) {
+ setTimeout(() => {
+ this.getTableData();
+ }, 1000)
+ }
+ })
+ }
+
+ e2eCloseCreate(obj, templateCreatestarting, templateCreateSuccessFaild) {
+ if (!obj) {
+ this.createshow2 = false; //
+ this.listDisplay = false; //
+ return false;
+ }
+ this.createshow2 = false; //
+ this.listDisplay = false; //
+ this.loadingAnimateShow = true;
+ console.log(obj);
+ let newData; //
+ let createParams = "?customerId=" + this.customerSelected.id +
+ "&serviceType=" + this.serviceTypeSelected2.name +
+ "&serviceDomain=" + this.templateTypeSelected +
+ "&parentServiceInstanceId=" +
+ "&uuid=" + obj.service.serviceUuid +
+ "&invariantUuuid=" + obj.service.serviceInvariantUuid;
+ this.createService(obj, createParams, templateCreatestarting, templateCreateSuccessFaild).then((data) => {
+ console.log(data);
+ this.loadingAnimateShow = false;
+ newData = { //
+ 'service-instance-id': data["serviceId"],
+ 'service-instance-name': obj.service.name,
+ serviceDomain: this.templateTypeSelected,
+ childServiceInstances: [],
+ status: "In Progress",
+ statusClass: 1001,
+ rate: 0,
+ tips: ""
+ }
+ this.thisCreateService = newData;
+ this.tableData = [newData, ...this.tableData];
+ this.createNotification(templateCreatestarting);
+ let updata = (prodata) => {
+ newData.rate = prodata.progress;
+ newData.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == newData["statusClass"] && its["language"] == this.language
+ })["sortValue"] + newData.rate + "%";
+ if (newData["rate"] > 100) {
+ newData["status"] = prodata.status;
+ newData.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == newData["statusClass"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + newData["status"];
+ }
+ }
+ let queryParams = { serviceId: data["serviceId"], operationId: data["operationId"], operationType: "1001" };
+ return this.queryProgress(queryParams, updata);
+ }).then((data) => {
+ console.log(data);
+ newData.rate = 100;
+ newData.status = "Successful";
+ this.createSuccessNotification(templateCreateSuccessFaild);
+ newData.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == newData["statusClass"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == 2001 && its["language"] == this.language
+ })["sortValue"];
+ let hasUndone = this.tableData.some((item) => {
+ return item.rate < 100;
+ })
+ if (!hasUndone) {
+ setTimeout(() => {
+ this.getTableData();
+ }, 1000)
+ }
+ })
+
+ }
+
+ nsCloseCreate(obj, templateCreatestarting, templateCreateSuccessFaild) {
+ if (!obj) {
+ this.createshow2 = false; //
+ this.listDisplay = false; //
+ return false;
+ }
+ this.createshow2 = false; //
+ this.listDisplay = false; //
+ this.loadingAnimateShow = true;
+ console.log(obj);
+ let newData; //
+ // step1
+ this.myhttp.nsCreateInstance(obj.step1)
+ .subscribe((data) => {
+ // console.log(data);
+ this.loadingAnimateShow = false;
+ newData = { //
+ 'service-instance-id': data.nsInstanceId,
+ 'service-instance-name': obj.step1.nsName,
+ serviceDomain: this.templateTypeSelected,
+ childServiceInstances: [],
+ status: "In Progress",
+ statusClass: 1001,
+ rate: 0,
+ tips: ""
+ }
+ this.thisCreateService = newData;
+ this.tableData = [newData, ...this.tableData];
+ this.createNotification(templateCreatestarting);
+ if (data.status == "FAILED") {
+ console.log("create ns service Failed :" + JSON.stringify(data));
+ newData.status = "Failed";
+ this.createSuccessNotification(templateCreateSuccessFaild);
+ return false;
+ }
+ let createParams = "?ns_instance_id=" + data.nsInstanceId +
+ "&customerId=" + this.customerSelected2.id +
+ "&serviceType=" + this.serviceTypeSelected2.name +
+ "&serviceDomain=" + this.templateTypeSelected +
+ "&parentServiceInstanceId=";
+ // step2
+ this.createNsService(createParams, obj.step2).then((jobid) => {
+ if (jobid == "Failed") {
+ newData.status = "Failed";
+ console.log(jobid, "ns two jobid")
+ this.thisCreateService = newData;
+ console.log(this.thisCreateService)
+ this.createSuccessNotification(templateCreateSuccessFaild);
+ newData.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == newData["statusClass"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == 2002 && its["language"] == this.language
+ })["sortValue"];
+ return false;
+ }
+ let operationType = "1001";
+ let updata = (prodata) => {
+ newData.rate = prodata.progress;
+ newData.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == newData["statusClass"] && its["language"] == this.language
+ })["sortValue"] + newData.rate + "%";
+ if (newData["rate"] > 100) {
+ newData["status"] = prodata.status;
+ newData.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == newData["statusClass"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + newData["status"];
+ }
+ }
+
+ return this.queryNsProgress(jobid, newData["service-instance-id"], updata, operationType);
+ }).then((data) => {
+ console.log(data);
+ newData.rate = 100;
+ newData.status = "Successful";
+ this.thisCreateService = newData;
+ console.log(this.thisCreateService)
+ this.createSuccessNotification(templateCreateSuccessFaild);
+ newData.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == newData["statusClass"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == 2001 && its["language"] == this.language
+ })["sortValue"];
+ let hasUndone = this.tableData.some((item) => {
+ return item.rate < 100;
+ })
+ if (!hasUndone) {
+ setTimeout(() => {
+ this.getTableData();
+ }, 1000)
+ }
+ })
+ })
+ }
+
+ createService(requestBody, createParams, templateCreatestarting, templateCreateSuccessFaild) {
+ let mypromise = new Promise((res, rej) => {
+ this.myhttp.createInstance(requestBody, createParams)
+ .subscribe((data) => {
+ if (data.status == "FAILED") {
+ this.loadingAnimateShow = false;
+ res("Failed");
+ console.log("create e2e service Failed :" + JSON.stringify(data));
+ return false;
+ }
+ res(data.service);
+ })
+ })
+ return mypromise;
+ }
+
+ createNsService(id, obj) {
+ let mypromise = new Promise((res, rej) => {
+ this.myhttp.nsCreateInstance2(id, obj)
+ .subscribe((data) => {
+ if (data.status == "FAILED") {
+ this.loadingAnimateShow = false;
+ console.log("instantiate ns service Failed :" + JSON.stringify(data));
+ res("Failed");
+ return false;
+ }
+ res(data.jobId);
+ })
+ })
+ return mypromise;
+ }
+
+ scaleE2eService(service, requestBody, templateScaleSuccessFaild) {
+ let id = service["service-instance-id"];
+ service.rate = 0;
+ service.status = "In Progress";
+ service.statusClass = "1003";
+ service.tips = "";
+ this.myhttp.scaleE2eService(id, requestBody)
+ .subscribe((data) => {
+ if (data.status == "FAILED") {
+ console.log("scale E2e service Failed :" + JSON.stringify(data));
+ service.status = "Failed";
+ service.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == service.statusClass && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == 2002 && its["language"] == this.language
+ })["sortValue"];
+ this.scaleSuccessNotification(templateScaleSuccessFaild);
+ return false;
+ }
+ let obj = {
+ serviceId: id,
+ operationId: data.operationId,
+ operationType: "1003"
+ }
+ let updata = (prodata) => {
+ service.rate = prodata.progress;
+ service.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == service.statusClass && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + service["rate"] + "%";
+ if (service["rate"] > 100) {
+ service["status"] = prodata.status;
+ service.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == service["statusClass"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + service["status"];
+ }
+ }
+ this.queryProgress(obj, updata).then(() => {
+ service.rate = 100;
+ service.status = "Successful";
+ service.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == service["statusClass"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == 2001 && its["language"] == this.language
+ })["sortValue"];
+ this.scaleSuccessNotification(templateScaleSuccessFaild);
+ })
+ })
+ }
+
+ healNsVnfService(service, requestBody, templatehealSuccessFaild) {
+ console.log(service);
+ service.rate = 0;
+ service.status = "In Progress";
+ service.tips = "";
+ service.statusClass = "1004";
+ let id = service.nsInstanceId || service["service-instance-id"] || service["vnfNsInstanceId"];
+ this.myhttp.healNsService(id, requestBody)
+ .subscribe((data) => {
+ if (data.status == "FAILED") {
+ console.log("heal nsvnf service Failed :" + JSON.stringify(data));
+ service.status = "Failed";
+ service.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == service.statusClass && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == 2002 && its["language"] == this.language
+ })["sortValue"];
+ this.healSuccessNotification(templatehealSuccessFaild);
+ return false;
+ }
+ let jobid = data.jobId;
+ let operationType = "1004";
+ let updata = (prodata) => {
+ service.rate = prodata.progress;
+ service.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == service.statusClass && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + service.rate + "%";
+ console.log(service.rate)
+ if (service["rate"] > 100) {
+ service["status"] = prodata.status;
+ service.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == service.statusClass && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + service["status"];
+ }
+ }
+ this.queryNsProgress(jobid, null, updata, operationType).then((data1) => {
+ console.log(data1);
+ service.rate = 100;
+ service.status = "Successful";
+ service.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == service.statusClass && its["language"] == this.language
+ })["sortValue"] + this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == 2001 && its["language"] == this.language
+ })["sortValue"];
+ this.healSuccessNotification(templatehealSuccessFaild);
+ });
+ })
+ }
+
+ updateCcvpnNotification(template: TemplateRef<{}>): void {
+ this.notification.template(template);
+ }
+
+ updateCcvpnSuccessNotification(template: TemplateRef<{}>): void {
+ this.notification.template(template);
+ }
+
+ closeCCVPNUpdate(obj, templateUpdateSuccessFaild) {
+ console.log(obj);
+ this.detailshow = false;
+ this.listDisplay = false;
+ this.upDateShow = false;
+ this.detailData["rate"] = 0;
+ this.detailData["status"] = "In Progress";
+ this.detailData['tips'] = "";
+ this.detailData["statusClass"] = "1005";
+ let id = this.detailData["service-instance-id"];
+ this.myhttp.updateccvpn(id, obj)
+ .subscribe((data) => {
+ if (data.status == "FAILED") {
+ console.log("scale E2e service Failed :" + JSON.stringify(data));
+ this.detailData["status"] = "Failed";
+ this.detailData["tips"] = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == this.detailData["statusClass"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == 2002 && its["language"] == this.language
+ })["sortValue"];
+ this.updateCcvpnSuccessNotification(templateUpdateSuccessFaild);
+ return false;
+ }
+ let obj = {
+ serviceId: id,
+ operationId: data.operationId
+ }
+ let updata = (prodata) => {
+ this.detailData["rate"] = prodata.progress;
+ this.detailData["tips"] = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == this.detailData["statusClass"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + this.detailData["rate"] + "%";
+ if (this.detailData["rate"] > 100) {
+ this.detailData["status"] = prodata.status;
+ this.detailData["tips"] = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == this.detailData["statusClass"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + this.detailData["status"];
+ }
+ };
+ this.queryProgress(obj, updata).then(() => {
+ this.detailData["rate"] = 100;
+ this.detailData["status"] = "Successful";
+ this.detailData["tips"] = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == this.detailData["statusClass"] && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == 2001 && its["language"] == this.language
+ })["sortValue"];
+ this.updateCcvpnSuccessNotification(templateUpdateSuccessFaild);
+ })
+ })
+ }
+
+ deleteService(service, templateDeleteSuccessFaild) {
+ let allprogress = {}; //
+ let querypros = []; //
+ service.rate = 0;
+ service.status = "In Progress";
+ service.tips = "";
+ service.statusClass = "1002";
+ service["childServiceInstances"].push({ "service-instance-id": service["service-instance-id"] });
+ let deletePros = service["childServiceInstances"].map((item) => {
+ let params = {
+ globalSubscriberId: this.customerSelected.id,
+ serviceType: this.serviceTypeSelected,
+ serviceInstanceId: item["service-instance-id"]
+ }
+ return new Promise((res, rej) => {
+ this.myhttp.deleteInstance(params)
+ .subscribe((data) => {
+ this.loadingAnimateShow = false;
+ if (data.status == "FAILED") {
+ console.log("delete service Failed :" + JSON.stringify(data));
+ service.status = "Failed";
+ service.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == service.statusClass && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == 2002 && its["language"] == this.language
+ })["sortValue"];
+ return false;
+ }
+ let obj = {
+ serviceId: params.serviceInstanceId,
+ operationId: data.operationId,
+ operationType: "1002"
+ }
+ let updata = (prodata) => {
+ allprogress[prodata.operationId] = prodata.progress;
+ let average = ((arr) => {
+ return eval(arr.join("+")) / arr.length
+ })(Object.values(allprogress));
+ service["rate"] = average;
+ service.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == service.statusClass && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + service["rate"] + "%";
+ if (service["rate"] > 100) {
+ service["status"] = prodata.status;
+ service.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == service.statusClass && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + service["status"];
+ }
+ };
+ querypros.push(this.queryProgress(obj, updata));
+ res();
+ })
+ })
+ });
+ Promise.all(deletePros).then(() => {
+ Promise.all(querypros).then((data) => {
+ console.log(data);
+ service.rate = 100;
+ service.status = "Successful";
+ service.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == service.statusClass && its["language"] == this.language
+ })["sortValue"] + this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == 2001 && its["language"] == this.language
+ })["sortValue"];
+ this.deleteSuccessNotification(templateDeleteSuccessFaild);
+ let hasUndone = this.tableData.some((item) => {
+ return item.rate < 100;
+ })
+ if (!hasUndone) {
+ setTimeout(() => {
+ this.getTableData();
+ }, 1000)
+ }
+ })
+ })
+ }
+
+ deleteNsService(service, templateDeleteSuccessFaild) {
+ service.rate = 0;
+ service.status = "In Progress";
+ service.tips = "";
+ service.statusClass = "1002";
+ let id = service.nsInstanceId || service["service-instance-id"];
+ let operationType = "1002";
+ let requestBody = {
+ terminationType: this.terminationType,
+ gracefulTerminationTimeout: this.gracefulTerminationTimeout
+ }
+ this.stopNsService(id, requestBody).then((jobid) => {
+ if (jobid == "Failed") {
+ service.status = "Failed";
+ this.deleteSuccessNotification(templateDeleteSuccessFaild);
+ service.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == service.statusClass && its["language"] == this.language
+ })["sortValue"] + this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == 2002 && its["language"] == this.language
+ })["sortValue"];
+ return false;
+ }
+ let updata = (prodata) => {
+ service.rate = prodata.progress;
+ service.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == service.statusClass && its["language"] == this.language
+ })["sortValue"] + '\xa0\xa0\xa0' + service.rate + "%";
+ if (service["rate"] > 100) {
+ service["status"] = prodata.status;
+ service.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == service.statusClass && its["language"] == this.language
+ })["sortValue"] + service["status"];
+ }
+ }
+ return this.queryNsProgress(jobid, null, updata, operationType);
+ }).then(() => {
+ this.myhttp.nsDeleteInstance(id)
+ .subscribe((data) => {
+ console.log(data);
+ service.rate = 100;
+ service.status = "Successful";
+ service.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == service.statusClass && its["language"] == this.language
+ })["sortValue"] + this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == 2001 && its["language"] == this.language
+ })["sortValue"];
+ this.deleteSuccessNotification(templateDeleteSuccessFaild);
+ if (data.status == "FAILED") {
+ console.log("delete ns service Failed :" + JSON.stringify(data));
+ service.status = "Failed";
+ service.tips = this.listSortMasters["operationTypes"].find((its) => {
+ return its["sortCode"] == service.statusClass && its["language"] == this.language
+ })["sortValue"] + this.listSortMasters["operationResults"].find((its) => {
+ return its["sortCode"] == 2002 && its["language"] == this.language
+ })["sortValue"];
+ this.deleteSuccessNotification(templateDeleteSuccessFaild);
+ return false;
+ }
+ console.log(service, "deleteservice");
+ console.log(this.thisService, "thisService");
+ let hasUndone = this.tableData.some((item) => {
+ return item.rate < 100;
+ })
+ if (!hasUndone) {
+ setTimeout(() => {
+ this.getTableData();
+ }, 1000)
+ }
+ })
+ })
+ }
+
+ stopNsService(id, obj) {
+ let mypromise = new Promise((res, rej) => {
+ this.myhttp.stopNsService(id, obj)
+ .subscribe((data) => {
+ this.loadingAnimateShow = false;
+ if (data.status == "FAILED") {
+ console.log("stop ns service Failed :" + JSON.stringify(data));
+ res("Failed");
+ return false;
+ }
+ res(data.jobId);
+ })
+ })
+ return mypromise;
+ }
+
+ queryProgress(obj, callback) {
+ let mypromise = new Promise((res, rej) => {
+ // let data = {
+ // operationStatus:{
+ // "operationId": "XXXXXX",
+ // "operation": "create|delete|update|scale",
+ // "result": "finished|error|processing",
+ // "reason": "",
+ // "userId": "",
+ // "operationContent": "Be creating pop.",
+ // "progress": 0,
+ // "operateAt": "",
+ // "finishedAt": ""
+ // }
+ // }
+ let errorNums = 180;
+ let requery = () => {
+ this.myhttp.getProgress(obj)
+ .subscribe((data) => {
+ if (data.status == "FAILED") {
+ callback({ progress: 255, status: "Failed" });
+ return false;
+ }
+ if (data.operationStatus == null || data.operationStatus.progress == undefined) {
+ // console.log(data);
+ errorNums--;
+ if (errorNums == 0) {
+ callback({ progress: 255, status: "time over" });
+ return false;
+ }
+ setTimeout(() => {
+ requery();
+ }, 10000)
+ return false;
+ }
+ if (data.operationStatus.progress > 100) {
+ callback({ progress: 255, status: "time over" });
+ return false;
+ }
+ if (data.operationStatus.progress < 100) {
+ callback(data.operationStatus);
+ setTimeout(() => {
+ requery();
+ }, 5000)
+ } else {
+ res(data.operationStatus);
+ }
+ })
+ // setTimeout(()=>{
+ // console.log(data.operationStatus.progress)
+ // data.operationStatus.progress++;
+ // if(data.operationStatus.progress<100){
+ // callback(data.operationStatus);
+ // requery()
+ // }else{
+ // callback(data.operationStatus);
+ // res(data.operationStatus)
+ // }
+ // },100)
+ }
+ requery();
+ })
+ return mypromise;
+ }
+
+ queryNsProgress(jobid, id, callback, operationType) {
+ let mypromise = new Promise((res, rej) => {
+ // let data = {
+ // "jobId": "string",
+ // "responseDescriptor": {
+ // "status": "string",
+ // "progress": 0,
+ // "statusDescription": "string",
+ // "errorCode": "string",
+ // "responseId": "string",
+ // "responseHistoryList": [
+ // {
+ // "status": "string",
+ // "progress": "string",
+ // "statusDescription": "string",
+ // "errorCode": "string",
+ // "responseId": "string"
+ // }
+ // ]
+ // }
+ // }
+ let errorNums = 180;
+ let requery = () => {
+ this.myhttp.getNsProgress(jobid, id, operationType)
+ .subscribe((data) => {
+ if (data.status == "FAILED") {
+ callback({ progress: 255, status: "Failed" });
+ return false;
+ }
+ if (data.responseDescriptor == null || data.responseDescriptor.progress == undefined) {
+ // console.log(data);
+ errorNums--;
+ if (errorNums == 0) {
+ callback({ progress: 255, status: "time over" });
+ return false;
+ }
+ setTimeout(() => {
+ requery();
+ }, 10000)
+ return false;
+ }
+ if (data.responseDescriptor.progress > 100 && data.responseDescriptor.status == "error") {
+ callback({ progress: 255, status: data.responseDescriptor.statusDescription });
+ return false;
+ }
+ if (data.responseDescriptor.progress < 100) {
+ callback(data.responseDescriptor);
+ setTimeout(() => {
+ requery();
+ }, 5000)
+ } else {
+ res(data);
+ }
+ })
+ // setTimeout(()=>{
+ // console.log(data.responseDescriptor.progress)
+ // data.responseDescriptor.progress++;
+ // if(data.responseDescriptor.progress<100){
+ // callback(data.responseDescriptor);
+ // requery()
+ // }else{
+ // callback(data);
+ // res(data)
+ // }
+ // },100)
+ };
+ requery();
+ });
+ return mypromise;
+ }
+
+}
diff --git a/usecaseui-portal/src/app/views/services/services.component.html b/usecaseui-portal/src/app/views/services/services.component.html
new file mode 100644
index 00000000..10142833
--- /dev/null
+++ b/usecaseui-portal/src/app/views/services/services.component.html
@@ -0,0 +1,18 @@
+<!--
+ 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.
+-->
+<p>
+ services works!
+</p>
diff --git a/usecaseui-portal/src/app/views/services/services.component.less b/usecaseui-portal/src/app/views/services/services.component.less
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/usecaseui-portal/src/app/views/services/services.component.less
diff --git a/usecaseui-portal/src/app/views/services/services.component.spec.ts b/usecaseui-portal/src/app/views/services/services.component.spec.ts
new file mode 100644
index 00000000..2e76b9f9
--- /dev/null
+++ b/usecaseui-portal/src/app/views/services/services.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ServicesComponent } from './services.component';
+
+describe('ServicesComponent', () => {
+ let component: ServicesComponent;
+ let fixture: ComponentFixture<ServicesComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ServicesComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ServicesComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/usecaseui-portal/src/app/views/services/services.component.ts b/usecaseui-portal/src/app/views/services/services.component.ts
new file mode 100644
index 00000000..eec235b4
--- /dev/null
+++ b/usecaseui-portal/src/app/views/services/services.component.ts
@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'app-services',
+ templateUrl: './services.component.html',
+ styleUrls: ['./services.component.less']
+})
+export class ServicesComponent implements OnInit {
+
+ constructor() { }
+
+ ngOnInit() {
+ }
+
+}