diff options
Diffstat (limited to 'usecaseui-portal/src/app/views/services')
45 files changed, 5744 insertions, 1730 deletions
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 index 4f865ff3..c48d68f9 100644 --- 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 @@ -13,274 +13,111 @@ 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'"> - <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.nsdName">{{item.nsdName}}</td> - <td *ngIf="item.nsdName === null || item.nsdName === ''"> </td> - <td *ngIf="item.name">{{item.name}}</td> - <td *ngIf="item.name===null || item.name=== ''"> </td> - <td *ngIf="item.nsdVersion">{{item.nsdVersion}}</td> - <td *ngIf="item.nsdVersion === null || item.nsdVersion === ''"> </td> - <td *ngIf="item.version">{{item.version}}</td> - <td *ngIf="item.version === null || item.version === ''"> </td> - <td> - <span *ngIf="item.nsdOnboardingState">{{item.nsdOnboardingState}}</span> - <span *ngIf="item.nsdOnboardingState === null || item.nsdOnboardingState === ''"> </span> - <span *ngIf="item.uuid">{{status}}</span> - - </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> - - </td> - </tr> - </tbody> - </nz-table> - </nz-spin> - - </div> - <!-- VNFList --> - <div class="list" *ngIf="tab === 'VNF'"> - <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.vnfProductName">{{item.vnfProductName}}</td> - <td *ngIf="item.vnfProductName === null || item.vnfProductName === ''"> </td> - <td *ngIf="item.name">{{item.name}}</td> - <td *ngIf="item.vnfdVersion">{{item.vnfdVersion}}</td> - <td *ngIf="item.vnfdVersion === null || item.vnfdVersion === ''"> </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> - </td> - </tr> - </tbody> - </nz-table> - </nz-spin> +<!-- tab --> +<nz-tabset [nzTabPosition]="'top'" [nzType]="'card'"> + <nz-tab *ngFor="let tab of tabs" [nzTitle]="tab" (nzClick)="handleTabChange(tab)"></nz-tab> +</nz-tabset> +<div class="list"> + <!-- upload --> + <div class="listUploadContainer"> + <div class="listupload"> + <nz-upload nzType="drag" [(nzFileList)]="fileList" [nzBeforeUpload]="beforeUpload"> + <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]="uploading" (click)="onClick()" [disabled]="fileList.length == 0" class="upload"> + {{ uploading ? 'Uploading' : 'Start Upload' }} + </button> </div> - <!-- PNFList --> - <div class="list" *ngIf="tab === 'PNF'"> - <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 class="listlin"></div> + <div class="listfile"> + <div class="listFileTitle"> {{"i18nTextDefine_Uploaded_files" | translate}} </div> + <div class="nouploadfile" [style.display]="display">{{"i18nTextDefine_Nofileuploading" | translate}}</div> + <div class="listfilebgc" *ngIf="file"> + <i class="anticon anticon-link icon"></i> + <div class="color" [ngClass]="{'progress':file.status}">{{file.name}}</div> + <div class="color" *ngIf="file.status"> + <nz-progress [nzPercent]="file.progress" [nzShowInfo]="false"></nz-progress> </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> - </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}} - {{"i18nTextDefine_"+notificationAttributes.action | translate}} {{"i18nTextDefine_"+notificationAttributes.status | translate}} + <div class="color" *ngIf="!file.status"> + <span *ngIf="file.success === 0">{{"i18nTextDefine_File_upload_completed" | translate}}</span> + <span *ngIf="file.success === 1">{{"i18nTextDefine_File_upload_failed" | translate}}</span> </div> - <div class="ant-notification-notice-description"> - <div class="notificationlist"> - <p>{{notificationAttributes.title}} id: </p> - <span>{{ notificationAttributes.id }}</span> - </div> + <div *ngIf="!file.status"> + <i class="anticon anticon-check-circle success" *ngIf="file.success === 0"></i> + <i class="anticon anticon-exclamation-circle fail" *ngIf="file.success === 1"></i> </div> - <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div> </div> </div> - </ng-template> -</nz-tabset> - + </div> + <!-- table --> + <nz-spin [nzSpinning]="isSpinning" class="listContainer"> + <div class="mask" *ngIf="isSpinning"></div> + <nz-table #nzTable [nzData]="currentTab === 'NS'? nsTableData: (currentTab === 'VNF'? vnfTableData : pnfTableData)" nzShowSizeChanger [nzFrontPagination]="true" + [nzShowQuickJumper]="true" [nzPageSizeOptions]="[5,10,15,20]" [(nzPageSize)]="pageSize" + [(nzPageIndex)]='pageIndex' nzSize="middle"> + <thead> + <tr class="theadColor"> + <th nzWidth="15%"> {{"i18nTextDefine_NO" | translate}} </th> + <th nzWidth="15%"> {{"i18nTextDefine_Name" | translate}} </th> + <th nzWidth="15%"> {{"i18nTextDefine_Version" | translate}} </th> + <th nzWidth="15%"> {{"i18nTextDefine_OnboardingState" | translate}} </th> + <th nzWidth="15%" *ngIf="currentTab !== 'PNF'"> {{"i18nTextDefine_OperationalState" | translate}} </th> + <th nzWidth="10%"> {{"i18nTextDefine_UsageState" | translate}} </th> + <th nzWidth="15%"> {{"i18nTextDefine_Operationbutton" | translate}} </th> + </tr> + </thead> + <tbody *ngIf="currentTab === 'NS'"> + <tr *ngFor="let item of nzTable.data;let i = index;"> + <td>{{i+1}}</td> + <td>{{item.nsdName || item.name }}</td> + <td>{{item.nsdVersion || item.version}}</td> + <td>{{item.nsdOnboardingState ? item.nsdOnboardingState : status}}</td> + <td>{{item.nsdOperationalState}}</td> + <td>{{item.nsdUsageState}}</td> + <td> + <i [ngClass]="{'cannotclick': isUpdate}" + class="anticon anticon-upload upicon" #upload_icon (click)="updataService(item.uuid)" + *ngIf="item.uuid"></i> + <i class="anticon anticon-delete" (click)="showDeleteConfirm(item.id)" + *ngIf="item.id"></i> + </td> + </tr> + </tbody> + <tbody *ngIf="currentTab === 'VNF'"> + <tr *ngFor="let item of nzTable.data;let i = index;"> + <td>{{i+1}}</td> + <td>{{item.vnfProductName || item.name }}</td> + <td>{{item.vnfdVersion || item.version}}</td> + <td>{{item.onboardingState}}</td> + <td>{{item.operationalState}}</td> + <td>{{item.usageState}}</td> + <td> + <i [ngClass]="{'cannotclick': isUpdate}" + class="anticon anticon-upload upicon" #upload_icon (click)="updataService(item.uuid)" + *ngIf="item.uuid"></i> + <i class="anticon anticon-delete" (click)="showDeleteConfirm(item.id)" + *ngIf="item.id"></i> + </td> + </tr> + </tbody> + <tbody *ngIf="currentTab === 'PNF'" > + <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" (click)="showDeleteConfirm(item.id)"></i> + </td> + </tr> + </tbody> + </nz-table> + </nz-spin> +</div> +<app-notification #notification [isServicesList]="false"></app-notification>
\ No newline at end of file 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 index 5ba479de..f877e1ca 100644 --- 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 @@ -13,141 +13,112 @@ See the License for the specific language governing permissions and limitations under the License. */ -.title { - font: 700 18px/18px "思源黑体"; - color: #4c5e70; - margin-bottom: 18px; +th{ + background-color: rgba(241,243,244,.9) !important; } -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 { - border-radius: 5px; - .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%; + padding: 20px; + .listUploadContainer{ + display: flex; + align-items: flex-start; + width: 100%; + height: 30%; + margin-bottom: 1%; + .listupload { + position: relative; + width: 22%; + margin-left: 13%; + .upload{ + position: absolute; + left: 50%; + bottom: -48px; + transform: translateX(-50%); + color: #FFFFFF; + font-size: 13px; + background-color: #3E9BFF; + font-family: ArialMT; + } } - .listfilebgc { - background-color: #fff; - border-bottom: 8px solid #F7F8FC; + .listlin { + width: 1%; + margin-left: 10%; + height: 177px; + margin-bottom: 30px; + border-right: 2px solid #EEEEEE; } - .listfilebgc { - background-color: #fff; - height: 30px; - border-radius: 2px; - line-height: 2; - color: #42548F; - border-bottom: 4px solid #F7F8FC; - >div { - float: left; + .listfile { + width: 43%; + height: 100%; + margin-left: 10%; + .listFileTitle{ + height: 15%; + padding-bottom: 15px; + color: rgba(66,84,143,1); + font-family: ArialMT; } - :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); + .nouploadfile{ + height: 80%; + width: 100%; + text-align: center; + font-size: 22px; + margin: 5% 0 10px; } + .listfilebgc { + display: flex; + justify-content: space-around; + align-items: center; + width:100%; + height: 80%; + padding: 5px; + background-color: #fff; + border-radius: 2px; + color: #42548F; + .icon{ + width: 15px; + } + :nth-child(3){ + width: 50%; + } + :nth-child(4){ + width: 5%; + height:100%; + .success{ + color:#7BC7F3!important; + } + .fail{ + color:#fb5c5c!important; + } + } + .color { + color:rgba(66,84,143,1); + span{ + color:rgba(66,84,143,0.7); + } + .progress{ + color:rgba(66,84,143,0.7); + } + } + } + + } + + } + .listContainer{ + height: 69%; + .mask { + top: 0; + left: 0; + position: fixed; + width: 100%; + height: 100%; + opacity: 0.1; + background: black; + z-index: 1049; } } 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; @@ -161,20 +132,7 @@ hr { 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.ts b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.ts index 33385e32..3d312c5c 100644 --- 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 @@ -14,14 +14,11 @@ 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 { Component, OnInit, HostBinding, TemplateRef, ViewChild } from '@angular/core'; import { onboardService } from '../../../core/services/onboard.service'; import { slideToRight } from '../../../shared/utils/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', @@ -31,114 +28,75 @@ import { Title } from '@angular/platform-browser'; }) export class OnboardVnfVmComponent implements OnInit { @HostBinding('@routerAnimate') routerAnimateState; + @ViewChild('notification') notification: any; - // delete Modal - confirmModal: NzModalRef; - nsdInfoId = ''; - vnfPkgId = ''; - pnfdInfoId = ''; - tabTitle = "NS"; - nsuploading = false; - vnfuploading = false; - pnfloading = false; + // upload + tabs: string[] = ['NS', 'VNF', 'PNF']; + currentTab: string = 'NS' fileList: UploadFile[] = []; - fileListNS: UploadFile[] = []; - fileListVNF: UploadFile[] = []; - fileListPNF: UploadFile[] = []; - // onboard initial value - status = "Onboard Available"; - jobId = ''; + uploading:boolean = false; + infoId: string; + display: string = 'block'; + + // table + isSpinning: boolean = false; + nsTableData: any[]; + vnfTableData: any[]; + pnfTableData: any[]; + status: string = "Onboard Available"; + pageIndex: number = 1; + pageSize: number = 10; + + // update or delete + isUpdate: boolean = false; + jobId: string; + //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/', }; + + file: { + name: string, + uid: string, + progress: number, + status: boolean, + success: number + }; + constructor( private myhttp: onboardService, private http: HttpClient, private msg: NzMessageService, - private titleService: Title, - private modal: NzModalService, - private modalService: NzModalService, - private notification: NzNotificationService + private modalService: NzModalService ) { } + //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; + handleTabChange(tab: string): void { + this.currentTab = tab; + this.fileList = []; + this.display = 'block'; + delete this.file; 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": { @@ -148,302 +106,128 @@ export class OnboardVnfVmComponent implements OnInit { } } - //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 + this.fileList.splice(0,1,file); + let API: string; + if(this.currentTab === 'NS'){ + API = 'createNetworkServiceData'; + }else if(this.currentTab === 'VNF'){ + API = 'createVnfData'; + }else { + API = 'createPnfData'; + } + this.myhttp.getCreatensData(API, this.requestBody)//on-line .subscribe((data) => { - this.pnfdInfoId = data["id"]; + this.infoId = 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 - } + // Drag and drop and click the upload button + onClick(): void { + this.display = 'none'; + let tab = this.currentTab === 'NS' ? 'ns' : (this.currentTab === 'VNF' ? 'vnf' : 'pnf') + this.handleUpload(this.url[tab].replace("*_*", this.infoId)); } - nsRightList = []; - nsNum = 0; - vnfRightList = []; - vnfNum = 0; - pnfRightList = []; - pnfNum = 0; - //put Upload Upload - handleUpload(url, tab): void { + handleUpload(url: string): 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 + this.fileList.forEach((file: any) => { + formData.set('file', file); + }); + this.uploading = true; + this.file = { + name: this.fileList[0].name, + uid: this.fileList[0].uid, + progress: 0, + status: true, + success: 0 + }; + let requery = (file) => { + file.progress += 3; + setTimeout(() => { + if (file.progress < 100) { + requery(file) + } + }, 100) + }; + requery(this.file); 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.file.progress = 100; + this.file.status = false; + this.uploading = false; this.msg.success('upload successfully.'); + this.currentTab === 'NS' ? this.getTableData() : (this.currentTab === 'VNF' ? this.getTableVnfData() : this.getTablePnfData()); }, 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.file.progress = 100; + this.file.status = false; + this.file.success = 1; + this.uploading = false; 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() { + getTableData(): void{ this.isSpinning = true; //ns vfc lists this.myhttp.getOnboardTableData() .subscribe((data) => { - this.nsvfcData = data; - this.nstableData = this.nsvfcData; + this.nsTableData = data; //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); + let nsData = data; + // this.NSTableData.map((nsvfc) => { nsvfc.sameid = nsData.find((nssdc) => { return nsvfc.id == nssdc.uuid }) && nsvfc.id; return nsvfc; }); + let sameData = nsData.filter((nssdc) => { return !this.nsTableData.find((nsvfc) => { return nsvfc.id == nssdc.uuid }) }); + this.nsTableData = this.nsTableData.concat(sameData); }, (err) => { - console.log(err); + console.error(err); this.isSpinning = false; }) }, (err) => { - console.log(err); + console.error(err); this.isSpinning = false; }) - } // Get the vnf list - getTableVnfData() { + getTableVnfData(): void{ this.isSpinning = true; //vnf vfc lists this.myhttp.getOnboardTableVnfData() .subscribe((data) => { - this.vnfvfcData = data; - this.vnftableData = this.vnfvfcData; + this.vnfTableData = data; //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); + let vnfData = data; + // this.VNFTableData.map((vnfvfc) => { vnfvfc.sameid = this.vnfData.find((nssdc) => { return vnfvfc.id == nssdc.uuid }) && vnfvfc.id; return vnfvfc; }); + let sameData = vnfData.filter((vnfsdc) => { return !this.vnfTableData.find((vnfvfc) => { return vnfvfc.id == vnfsdc.uuid }) }); + this.vnfTableData = this.vnfTableData.concat(sameData); }, (err) => { - console.log(err); + console.error(err); + this.isSpinning = false; }) - }, (err) => { - console.log(err); + console.error(err); + this.isSpinning = false; }) } @@ -452,133 +236,76 @@ export class OnboardVnfVmComponent implements OnInit { this.isSpinning = true; this.myhttp.getOnboardTablePnfData() .subscribe((data) => { - this.pnftableData = data; + this.pnfTableData = data; this.isSpinning = false; //loading hide }, (err) => { - console.log(err); + console.error(err); + this.isSpinning = false; }) } - //----------------------------------------------------------------------------------- - /* 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 - } + // confirm + showConfirm(requestBody: object, id: string): void{ + let API = this.currentTab === 'NS'? 'getNsonboard' : 'getVnfonboard'; + this.modalService.confirm({ + nzTitle: '<p>Are you sure you want to do this?</p>', + nzOnOk: () => { + this.myhttp[API](requestBody) + .subscribe((data) => { + if (data.status == "success") { + if(this.currentTab === 'NS'){ + this.isUpdate = false; + this.notification.notificationSuccess(this.currentTab, "OnboardingState", id); + this.getTableData(); + }else{ + this.jobId = data.jobId; + this.queryProgress(this.jobId, id); + this.getTableVnfData(); + } + } else { + this.isUpdate = false; + this.notification.notificationFailed(this.currentTab, "OnboardingState", id); + return false + } + }, (err) => { + console.log(err); + }) + } + }) } - //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); - }) - } + updataService(id: string) { + this.isUpdate = true; + let requestBody = { "csarId": id }; + this.showConfirm(requestBody, id) + } //Progress Progress inquiry - queryProgress(jobId, responseId, notificationModel) { + queryProgress(jobId: string, id: string): any{ let mypromise = new Promise((res) => { - this.myhttp.getProgress(jobId, responseId) + this.myhttp.getProgress(jobId, 0) .subscribe((data) => { if (data.responseDescriptor == null || data.responseDescriptor == "null" || data.responseDescriptor.progress == undefined || data.responseDescriptor.progress == null) { - this.onboardData.status = "onboarding"; + this.isUpdate = true; setTimeout(() => { - this.queryProgress(this.jobId, 0, notificationModel); + this.queryProgress(this.jobId, id); }, 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"; + this.isUpdate = false; + this.notification.notificationFailed(this.currentTab, 'OnboardingState', id); + }else if (data.responseDescriptor.progress < 100) { + this.isUpdate = true; setTimeout(() => { - this.queryProgress(this.jobId, 0, notificationModel); + this.queryProgress(this.jobId, id); }, 5000) - } else if (data.responseDescriptor.progress == 100) { + } else { res(data); - this.success("VNF"); - this.onboardData.status = "onboarded"; - this.notificationSuccess(notificationModel); + this.isUpdate = false; + this.notification.notificationSuccess(this.currentTab, 'OnboardingState', id); } return false }) @@ -586,83 +313,48 @@ export class OnboardVnfVmComponent implements OnInit { 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({ + showDeleteConfirm(pkgid: string): void { + this.modalService.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 - } + nzOnOk: () => new Promise((resolve) => { + this.deleteService(pkgid, resolve); }).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) + deleteService(pkgid, resolve) { + let API: string; + if(this.currentTab === 'NS'){ + API = 'deleteNsIdData'; + }else if(this.currentTab === 'VNF'){ + API = 'deleteVnfIdData'; + }else{ + API = 'deletePnfIdData'; + } + this.myhttp[API](pkgid) .subscribe((data) => { + this.notification.notificationSuccess(this.currentTab, 'OnboardingState', pkgid); + resolve() //refresh list after successful deletion - this.notificationSuccess(notificationModel); - this.getTablePnfData() + switch(this.currentTab){ + case 'NS': + this.getTableData(); + break + case 'VNF': + this.getTableVnfData(); + break + case 'PNF': + this.getTablePnfData(); + break + } }, (err) => { console.log(err); - this.notificationFailed(notificationModel); + this.notification.notificationFailed(this.currentTab, 'OnboardingState', pkgid); }) } - } diff --git a/usecaseui-portal/src/app/views/services/services-list/ccvpn-creation/ccvpn-creation.component.css b/usecaseui-portal/src/app/views/services/services-list/ccvpn-creation/ccvpn-creation.component.css new file mode 100644 index 00000000..8ea1b621 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/ccvpn-creation/ccvpn-creation.component.css @@ -0,0 +1,315 @@ +/* + 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; + font: 700 14px "Arial"; + color: #3C4F8C; + height: 42px; + line-height: 42px; + vertical-align: middle; + margin-left: 5px; + margin-right: 10px; +} +.model .creation .service-title input { + width: 20%; + height: 42px; + border-radius:4px; + outline: none; + margin-right: 50px; +} +/* Site List */ +/* addsite model */ +.model .sitemodel,.model .sotnnpnmodel{ + position: absolute; + z-index: 1001; + left: 50%; + top: 50%; + background-color: #fff; + width:90%; + min-width: 725px; + border-radius:2px; + overflow:auto; + transform: translate(-50%, -50%); +} +.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: 42%; + float: right; + margin-right: 2%; +} +.model .sotnnpnmodel .inputs input{ + width: 42%; + float: right; + margin-right: 2%; +} +.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/services/services-list/ccvpn-creation/ccvpn-creation.component.html b/usecaseui-portal/src/app/views/services/services-list/ccvpn-creation/ccvpn-creation.component.html new file mode 100644 index 00000000..6a05ff11 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/ccvpn-creation/ccvpn-creation.component.html @@ -0,0 +1,276 @@ +<!-- + 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> + + <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" nzVirtualScroll> + <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" nzVirtualScroll [nzScroll]="siteTableWidth"> + <thead> + <tr> + <th nzWidth="10%" nzLeft="0px"> NO.</th> + <th *ngFor="let key of getKeys(this.siteBaseData)">{{key.split("_")[1] || key}}</th> + <th nzWidth="20%" style="text-align: center" nzRight="0px"> 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> + + <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> + <nz-table class="siteWanTab" nzVirtualScroll #nzTable [nzData]="siteWanData" [nzScroll]="{ x: '2500px'}"> + <thead> + <tr> + <th width="4%" nzLeft="0px"> NO.</th> + <th *ngFor="let key of getKeys(this.siteWanParams)">{{key}}</th> + <th width="7%" nzRight="0px"> Action</th> + </tr> + </thead> + <tbody> + <ng-template ngFor let-item [ngForOf]="nzTable.data" let-i="index"> + <tr [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> + </ng-template> + </tbody> + </nz-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/services/services-list/ccvpn-creation/ccvpn-creation.component.spec.ts b/usecaseui-portal/src/app/views/services/services-list/ccvpn-creation/ccvpn-creation.component.spec.ts new file mode 100644 index 00000000..30402412 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/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/services/services-list/ccvpn-creation/ccvpn-creation.component.ts b/usecaseui-portal/src/app/views/services/services-list/ccvpn-creation/ccvpn-creation.component.ts new file mode 100644 index 00000000..752fddd6 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/ccvpn-creation/ccvpn-creation.component.ts @@ -0,0 +1,724 @@ +/* + 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 { ServiceListService } from '../../../../core/services/serviceList.service'; +import {Observable} from "../../../../../../node_modules/rxjs"; + +@Component({ + selector: 'app-ccvpn-creation', + templateUrl: './ccvpn-creation.component.html', + styleUrls: ['./ccvpn-creation.component.css'] +}) +export class CcvpnCreationComponent implements OnInit { + + constructor(private myhttp: ServiceListService) { } + @Input() createParams; + @Input() ccvpn_temParametersContent; + @Output() closeCreate = new EventEmitter(); + + + ngOnInit() { + this.getccvpnTemParameters(this.ccvpn_temParametersContent); + Observable.fromEvent(window, 'resize').subscribe((event) => { + this.siteTableWidth["x"] = document.documentElement.clientWidth > 1400 ?"78%":"961px"; + }); + } + + //tabBarStyle + tabBarStyle: object = { + "height": "58px", + "width": "694px", + "box-shadow": "none", + "margin": "0", + "border-radius": "4px 4px 0px 0px" + }; + siteTableWidth: object = { + x:"" + }; + templateParameters: any = { + service: {}, + sotnvpn: { + info: {}, + sdwanvpnresource_list: [], + sdwansitelan_list: [] + }, + site: { + info: {}, + sdwansiteresource_list: [], + sdwandevice_list: [], + sdwansitewan_list: [] + } + }; + + bodyTemplateParameter: object = {}; + + // SOTN VPN List + sotnVpnTableData: any[] = []; + sotnInfo: object = {};//sotnmodel The first part of sotnInfo + sotnSdwansitelanData: any[] = [];//sotnmodel The second part of the data sdwansitelan Table + sotnSdwansitelanParams: object = {};//sdwansitelan Table Detailed parameters of each line of data + tabInputShowSdwansitelan: any[] = [];//sdwansitelan Table input&span The status identifier of the label switching display + // Site List + siteTableData: any[] = []; + siteBaseData: object = {}; //sitemodel one sdwansiteresource_list + // cpe + siteSdwanDevice: any[] = []; //sitemodel SdwanDevice port Table data + siteCpeData: object = {}; //sitemodel two sdwandevice_list + tabInputShowDevice: any[] = [];//Device port Table input和span The status identifier of the label switching display + // Wan Port + siteWanData: any[] = []; //sitemodel three wan port Table data + siteWanParams: object = {}; //wan port Table Detailed parameters of each line of data + tabInputShowWanPort: any[] = [];//wan port Table input和span The status identifier of the label switching display + getKeys(item) { + return Object.keys(item); + } + + getccvpnTemParameters(data) { //Get template parameters + if (data.hasOwnProperty("model") && typeof data["model"] == 'string') { + data = JSON.parse(data["model"]); + } + 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(); + } + + //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) {//Adding new rows is not allowed when there is a row of data being edited + return false; + } + let addNum = this.siteSdwanDevice.length; + let inputsData = Object.assign({}, this.siteCpeData); + Object.keys(inputsData).forEach((item) => {//Add a new line of empty data + if (item != "description") { + inputsData[item] = null; + } + }); + this.siteSdwanDevice[addNum] = inputsData; + this.tabInputShowDevice[addNum] = true; + this.siteSdwanDevice = [...this.siteSdwanDevice]; //Table refresh + } + + 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; + } + }); + 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); + } + }); + + this.closeCreate.emit(servicebody); + + } + + goback() { + this.closeCreate.emit(); + } +} diff --git a/usecaseui-portal/src/app/views/services/services-list/ccvpn-detail/ccvpn-detail.component.css b/usecaseui-portal/src/app/views/services/services-list/ccvpn-detail/ccvpn-detail.component.css new file mode 100644 index 00000000..8d005d40 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/ccvpn-detail/ccvpn-detail.component.css @@ -0,0 +1,359 @@ +/* + 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: 42%; + float: right; + margin-right: 2%; +} +.model .sotnnpnmodel .inputs input{ + width: 42%; + float: right; + margin-right: 2%; +} + +/* addsite model */ +.model .sitemodel,.model .sotnnpnmodel{ + position: absolute; + z-index: 1001; + left: 50%; + top: 50%; + background-color: #fff; + width:90%; + min-width: 725px; + border-radius:2px; + overflow:auto; + transform: translate(-50%, -50%); +} +.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: 42%; + float: right; + margin-right: 2%; +} +.model .sotnnpnmodel .inputs div{ + width: 42%; + float: right; + margin-right: 2%; +} +.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/services/services-list/ccvpn-detail/ccvpn-detail.component.html b/usecaseui-portal/src/app/views/services/services-list/ccvpn-detail/ccvpn-detail.component.html new file mode 100644 index 00000000..e2b5159e --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/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> + + <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> + + <span class="action" (click)="editUpdateSite(i+1)" *ngIf="sitenum[i]"><i + class="anticon anticon-edit"></i></span> + + <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/services/services-list/ccvpn-detail/ccvpn-detail.component.spec.ts b/usecaseui-portal/src/app/views/services/services-list/ccvpn-detail/ccvpn-detail.component.spec.ts new file mode 100644 index 00000000..b6f3171f --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/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 { ServiceListService } from '../../core/services/serviceList.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: [ServiceListService, { 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/services/services-list/ccvpn-detail/ccvpn-detail.component.ts b/usecaseui-portal/src/app/views/services/services-list/ccvpn-detail/ccvpn-detail.component.ts new file mode 100644 index 00000000..a253b044 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/ccvpn-detail/ccvpn-detail.component.ts @@ -0,0 +1,797 @@ +/* + 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 { ServiceListService } from '../../../../core/services/serviceList.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: ServiceListService) { } + + 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() { + // 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; + } + 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); + } + }); + + } + }); + + 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; + 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 + } + + 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 node graphic depiction + // site sort,Check tp add pnf according to site --> allotted-resource + localSite = [];//local site + outerSite = [];//outer 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"] + }); + 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; + 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; + res(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) => { + }) + } + + 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); + } + }); + this.closeUpdate.emit(servicebody); + } + + goback() { + this.closeDetail.emit(); + } + + hiddenModel() { + this.sotnVpnDetailShow = false; + this.siteDetail = false; + } + +} diff --git a/usecaseui-portal/src/app/views/services/services-list/create-model/create-model.component.html b/usecaseui-portal/src/app/views/services/services-list/create-model/create-model.component.html new file mode 100644 index 00000000..e093b3b8 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/create-model/create-model.component.html @@ -0,0 +1,59 @@ +<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> {{"i18nTextDefine_Customer" | translate}} : </span> + <nz-select [(ngModel)]="currentCustomer.name" nzAllowClear + (ngModelChange)="customerChange()"> + <nz-option *ngFor="let item of customerList" [nzValue]="item.name" [nzLabel]="item.name"></nz-option> + </nz-select> + </div> + <div class="select-list"> + <span> {{"i18nTextDefine_ServiceType" | translate}} : </span> + <nz-select [(ngModel)]="currentServiceType.name" nzAllowClear> + <nz-option *ngFor="let item of serviceTypes" [nzValue]="item.name" [nzLabel]="item.name"> + </nz-option> + </nz-select> + </div> + <div class="select-list"> + <span> {{"i18nTextDefine_UseCase" | translate}} : </span> + <nz-select [(ngModel)]="templateTypeSelected" nzAllowClear + (ngModelChange)="choseTemplateType()"> + <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> {{"i18nTextDefine_Template" | translate}} : </span> + <nz-select [(ngModel)]="currentTemplate" 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> {{"i18nTextDefine_Orchestrator" | translate}} : </span> + <nz-select [(ngModel)]="orchestratorSelected" nzAllowClear> + <nz-option *ngFor="let item of orchestratorList" [nzValue]="item" [nzLabel]="item.name"></nz-option> + </nz-select> + </div> + <div class="checkbox select-list"> + <span>Sol005 :</span> + <input type="checkbox" + [(ngModel)]="isSol005Interface" value="true" nzAllowClear> + + </div> + </div> + <div class="select-list" *ngIf="temParametersTips"> + {{"i18nTextDefine_Templateparsingfailed" | translate}} + </div> +</nz-modal> +<div class="loading" *ngIf="loadingAnimateShow"> + <img src="assets/images/loading-animate2.gif" alt="loading"> + <p>Please wating……</p> +</div> + diff --git a/usecaseui-portal/src/app/views/services/services-list/create-model/create-model.component.less b/usecaseui-portal/src/app/views/services/services-list/create-model/create-model.component.less new file mode 100644 index 00000000..fdee93c8 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/create-model/create-model.component.less @@ -0,0 +1,59 @@ +.select-list{
+ width: 320px;
+ height: 32px;
+ line-height: 32px;
+ margin: 35px auto;
+ .select-list>span{
+ display:inline-block;
+ text-align: right;
+ line-height: 32px;
+ }
+ nz-select{
+ width: 176px;
+ float: right;
+ }
+ &.checkbox{
+ margin: 0 auto;
+ line-height: 32px;
+ input[type="checkbox"]{
+ zoom: 1.3;
+ width: 140px;
+ }
+ }
+}
+::ng-deep nz-modal button.ant-btn {
+ margin-top:20px !important;
+}
+
+.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;
+ }
+}
diff --git a/usecaseui-portal/src/app/views/services/services-list/create-model/create-model.component.spec.ts b/usecaseui-portal/src/app/views/services/services-list/create-model/create-model.component.spec.ts new file mode 100644 index 00000000..fd57b3a7 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/create-model/create-model.component.spec.ts @@ -0,0 +1,26 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CreateModelComponent } from './create-model.component'; + +describe('CreateModelComponent', () => { + let component: CreateModelComponent; + let fixture: ComponentFixture<CreateModelComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CreateModelComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CreateModelComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); + diff --git a/usecaseui-portal/src/app/views/services/services-list/create-model/create-model.component.ts b/usecaseui-portal/src/app/views/services/services-list/create-model/create-model.component.ts new file mode 100644 index 00000000..f7cce450 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/create-model/create-model.component.ts @@ -0,0 +1,144 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import { ServiceListService } from '../../../../core/services/serviceList.service'; + +@Component({ + selector: 'app-create-model', + templateUrl: './create-model.component.html', + styleUrls: ['./create-model.component.less'], +}) +export class CreateModelComponent implements OnInit { + @Input()isVisible: boolean; + @Input()customerList; + @Input()serviceTypeList; + @Input()customerSelected; + @Input()serviceTypeSelected; + + @Output() cancel = new EventEmitter<boolean>(); + @Output() createdModalShow = new EventEmitter<any>(); + + serviceTypes: any[]; + currentCustomer: any; + currentServiceType: any; + templateTypeSelected:string = "CCVPN"; + templates: any[] = []; + currentTemplate: object = { name: null }; + orchestratorList: any[] = []; + orchestratorSelected: object = { name: null, id: null }; + isSol005Interface: boolean = false; + temParametersTips: boolean = false; + createData: Object = {}; + loadingAnimateShow: boolean = false; + + constructor( private http: ServiceListService) {} + + ngOnInit() { + this.serviceTypes = this.serviceTypeList; + this.currentCustomer = JSON.parse(JSON.stringify(this.customerSelected)); + this.currentServiceType = JSON.parse(JSON.stringify(this.serviceTypeSelected)); + this.getAlltemplates(); + } + + getServiceType(): void{ + this.http.getServiceTypes(this.currentCustomer) + .subscribe((data) => { + this.serviceTypes = data.map((item) => { + return { name: item["service-type"] } + }); + }) + } + + getAlltemplates() { + this.http.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.currentTemplate = this.templates[0]; + }, (err) => { + console.log(err); + }) + } + + getallOrchestrators() { + this.http.getAllOrchestrators() + .subscribe((data) => { + if(data.length > 0){ + this.orchestratorList = data.map((item) => { + return { name: item["name"], id: item["name"] } + }); + this.orchestratorSelected = this.orchestratorList[0]; + } + }) + } + + handleCancel(): void { + this.isVisible = false; + this.cancel.emit(false); + this.loadingAnimateShow = false; + } + + customerChange(): void { + this.getServiceType(); + } + + choseTemplateType() { + if(this.templateTypeSelected === 'E2E Service'){ + this.getallOrchestrators(); + } + this.getAlltemplates(); + } + + handleOk(): void { + if (this.templateTypeSelected === "SOTN" || this.templateTypeSelected === "CCVPN") { + this.createData = { + commonParams: { + customer: this.currentCustomer, + serviceType: this.currentServiceType, + templateType: this.templateTypeSelected + }, + template: this.currentTemplate + }; + } else if (this.templateTypeSelected === "E2E Service" || this.templateTypeSelected === "Network Service") { + this.createData = { + commonParams: { + customer: this.currentCustomer, + serviceType: this.currentServiceType, + templateType: this.templateTypeSelected + }, + template: this.currentTemplate, + orchestrator: this.orchestratorSelected, + isSol005Interface: this.isSol005Interface + }; + } + this.getTemParameters(); + } + + 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.http.getTemplateParameters(types, chosedtemplates) + .subscribe((data) => { + this.loadingAnimateShow = false; + if (data.status == "FAILED") { + this.temParametersTips = true; + this.isVisible = true; + } else { + this.cancel.emit(false); + this.temParametersTips = false; + this.createdModalShow.emit({templateType: this.templateTypeSelected, data, createData: this.createData}) + } + }) + } +}
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/services/services-list/delete-model/delete-model.component.html b/usecaseui-portal/src/app/views/services/services-list/delete-model/delete-model.component.html new file mode 100644 index 00000000..5b516a0f --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/delete-model/delete-model.component.html @@ -0,0 +1,34 @@ +<nz-modal nzWidth="428" [(nzVisible)]="deleteModalVisible" nzTitle=" {{'i18nTextDefine_delete' | translate}}" + (nzOnCancel)="deleteCancel()" (nzOnOk)="deleteOk()" + nzClassName="{{thisService['serviceDomain'] == 'Network Service'?'nsdeleteModel':'deleteModel'}}" + nzCancelText=" {{'i18nTextDefine_Cancel' | translate}} " + nzOkText=" {{'i18nTextDefine_modelOk' | translate}} "> + <h3><span style="color: red">* </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> +</nz-modal> diff --git a/usecaseui-portal/src/app/views/services/services.component.less b/usecaseui-portal/src/app/views/services/services-list/delete-model/delete-model.component.less index e69de29b..e69de29b 100644 --- a/usecaseui-portal/src/app/views/services/services.component.less +++ b/usecaseui-portal/src/app/views/services/services-list/delete-model/delete-model.component.less diff --git a/usecaseui-portal/src/app/views/services/services-list/delete-model/delete-model.component.spec.ts b/usecaseui-portal/src/app/views/services/services-list/delete-model/delete-model.component.spec.ts new file mode 100644 index 00000000..e5e94c94 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/delete-model/delete-model.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DeleteModelComponent } from './delete-model.component'; + +describe('DeleteModelComponent', () => { + let component: DeleteModelComponent; + let fixture: ComponentFixture<DeleteModelComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DeleteModelComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DeleteModelComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/usecaseui-portal/src/app/views/services/services-list/delete-model/delete-model.component.ts b/usecaseui-portal/src/app/views/services/services-list/delete-model/delete-model.component.ts new file mode 100644 index 00000000..f9bf9a9c --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/delete-model/delete-model.component.ts @@ -0,0 +1,42 @@ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; + +@Component({ + selector: 'app-delete-model', + templateUrl: './delete-model.component.html', + styleUrls: ['./delete-model.component.less'] +}) +export class DeleteModelComponent implements OnInit { + @Input()deleteModalVisible: boolean; + @Input()thisService; + @Input()terminationType; + @Input()loadingAnimateShow; + @Input()templateDeleteSuccessFaild; + @Input()gracefulTerminationTimeout; + + @Output() cancel = new EventEmitter<boolean>(); + @Output() deleteModalOK = new EventEmitter<any>(); + + constructor() { } + + ngOnInit() { + } + + deleteOk() { + this.deleteModalVisible = false; + this.loadingAnimateShow = true; + + if (this.thisService["serviceDomain"] === "Network Service") { + this.deleteModalOK.emit({ + terminationType: this.terminationType, + gracefulTerminationTimeout: this.gracefulTerminationTimeout + }) + } else { + this.deleteModalOK.emit() + } + } + deleteCancel() { + this.deleteModalVisible = false; + } + + +} diff --git a/usecaseui-portal/src/app/views/services/services-list/e2e-creation/e2e-creation.component.css b/usecaseui-portal/src/app/views/services/services-list/e2e-creation/e2e-creation.component.css new file mode 100644 index 00000000..5dce6c92 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/e2e-creation/e2e-creation.component.css @@ -0,0 +1,77 @@ +/* + 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: #fff; + height: 90%; + overflow-y: auto; +} +.model .back { + position: absolute; + top: 10px; + right: 20px; +} +.model .creation { + position: relative; + width: 60%; + height: 100%; + overflow-y: auto; + border-radius: 5px; + padding: 20px; +} +.model .creation .baseparms h3 { + color: #3fa8eb; + font: 700 16px "Arial"; +} +.model .creation .baseparms h4 { + font: 700 16px "Arial"; +} +.model .creation .baseparms ul li { + margin: 3px 0; +} +.model .creation .baseparms ul li span { + display: inline-block; + width: 40%; + font: 700 14px "Arial"; + vertical-align: middle; + overflow: hidden; + text-overflow: ellipsis; + text-align: right; +} +.model .creation .baseparms ul li input { + width: 165px; +} +.model .creation .submit { + position: absolute; + top: 10px; + right: 20px; +} +.model .chart { + width: 40%; + padding: 10px; + height: 100%; + border-left: 10px solid #f3f3f3; +} diff --git a/usecaseui-portal/src/app/views/services/services-list/e2e-creation/e2e-creation.component.html b/usecaseui-portal/src/app/views/services/services-list/e2e-creation/e2e-creation.component.html new file mode 100644 index 00000000..da673bf0 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/e2e-creation/e2e-creation.component.html @@ -0,0 +1,139 @@ +<!-- + 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"> Services List </h3>--> +<div class="model creation-model"> + <!-- Create data --> + <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> + <div class="e2ecreate-content"> + <div class="creation fl"> + <div *ngIf="createParams.commonParams.templateType=='E2E Service'" class="baseparms clearfix"> + <div class="vnf-box"> + <h3> {{"i18nTextDefine_Base" | translate}} </h3> + <ul class="clearfix"> + <li> + <span>Name:</span> + <input nz-input [(ngModel)]="service.name"> + </li> + <li> + <span>Description:</span> + <input nz-input [(ngModel)]="service.description"> + </li> + <li> + <span>COS:</span> + <input nz-input [(ngModel)]="service.COS"> + </li> + <li> + <span>EBS:</span> + <input nz-input [(ngModel)]="service.EBS"> + </li> + </ul> + </div> + <div class="vnf-box" *ngIf="templateParameters.inputs.length>0"> + <h3>{{"i18nTextDefine_templateInputs" | translate}}</h3> + <ul> + <li *ngFor="let parameter of templateParameters.inputs; let i = index;"> + <span *ngIf="parameter.type !== 'vf_location' && parameter.type !== 'sdn_controller'" title="{{parameter.name}}">{{parameter.name}}:</span> + <input *ngIf="parameter.type !== 'vf_location' && parameter.type !== 'sdn_controller'" nz-input [(ngModel)]="parameter.value"> + + <h5 *ngIf="parameter.type === 'vf_location'" style="padding-left:10px;">id: {{parameter.name}} + </h5> + <span *ngIf="parameter.type === 'vf_location'"> vf_location: </span> + <nz-select *ngIf="parameter.type === 'vf_location'" [(ngModel)]="parameter.value" nzAllowClear> + <nz-option *ngFor="let vim of vimInfos" [nzValue]="vim" [nzLabel]="vim.name"></nz-option> + </nz-select> + </li> + </ul> + </div> + <div class="vnf-box" *ngFor="let template of templateParameters.nestedTemplates;"> + <h3>{{template.name}}</h3> + <ul> + <li *ngFor="let input of template.inputs; let i = index;"> + <span *ngIf="input.type !== 'vf_location' && input.type !== 'sdn_controller'" title="{{input.name}}"> {{input.name}}: </span> + <input *ngIf="input.type !== 'vf_location' && input.type !== 'sdn_controller'" nz-input [(ngModel)]="input.value"> + + <h5 *ngIf="input.type === 'vf_location'" style="padding-left:10px;">id: {{input.name}}</h5> + <span *ngIf="input.type === 'vf_location'"> vf_location: </span> + <nz-select *ngIf="input.type === 'vf_location'" [(ngModel)]="input.value" nzAllowClear> + <nz-option *ngFor="let vim of vimInfos" [nzValue]="vim" [nzLabel]="vim.name"></nz-option> + </nz-select> + </li> + </ul> + </div> + </div> + + <div *ngIf="createParams.commonParams.templateType=='Network Service'" class="baseparms clearfix"> + <div class="vnf-box"> + <h3> {{"i18nTextDefine_Base" | translate}} </h3> + <ul class="clearfix"> + <li> + <span>Name:</span> + <input nz-input [(ngModel)]="ns_service.nsName"> + </li> + <li> + <span>Description:</span> + <input nz-input [(ngModel)]="ns_service.description"> + </li> + </ul> + </div> + <div class="vnf-box" *ngIf="nsTemplateParameters.inputs2.length>0"> + <h4>{{"i18nTextDefine_templateInputs" | translate}}</h4> + <ul> + <li *ngFor="let parameter of nsTemplateParameters.inputs2; let i = index;"> + <span *ngIf="parameter.type !== 'vf_location' && parameter.type !== 'sdn_controller'" title="{{parameter.name}}">{{parameter.name}}:</span> + <input *ngIf="parameter.type !== 'vf_location' && parameter.type !== 'sdn_controller'" nz-input [(ngModel)]="parameter.value"> + + <h5 *ngIf="parameter.type === 'vf_location'" style="padding-left:10px;">id: {{parameter.name}} + </h5> + <span *ngIf="parameter.type === 'vf_location'"> vf_location: </span> + <nz-select *ngIf="parameter.type === 'vf_location'" [(ngModel)]="parameter.value" nzAllowClear> + <nz-option *ngFor="let vim of vimInfos" [nzValue]="vim" [nzLabel]="vim.name"></nz-option> + </nz-select> + </li> + </ul> + </div> + <div class="vnf-box"> + <h4 *ngIf="nsTemplateParameters.vnfs.length>0">vnfs Inputs</h4> + <ul> + <li *ngFor="let vnf of nsTemplateParameters.vnfs;"> + <h5 style="padding-left:10px;">id: {{vnf.vnf_id}}</h5> + <span> vf_location: </span> + <nz-select [(ngModel)]="vnf.value" nzAllowClear> + <nz-option *ngFor="let vim of vimInfos" [nzValue]="vim" [nzLabel]="vim.name"></nz-option> + </nz-select> + </li> + </ul> + </div> + </div> + </div> + <div class="dividing-line fl"></div> + <!-- chart --> + <div class="chart fr"> + <div id="createChart"> + <svg width="100%" height="100%"> + </svg> + </div> + </div> + </div> + +</div>
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/services/services-list/e2e-creation/e2e-creation.component.less b/usecaseui-portal/src/app/views/services/services-list/e2e-creation/e2e-creation.component.less new file mode 100644 index 00000000..3679079e --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/e2e-creation/e2e-creation.component.less @@ -0,0 +1,161 @@ +/* + 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; + height: 100%; + overflow-y: auto; + position: relative; + .top-title{ + width: 100%; + padding: 20px; + position: relative; + display: inline-block; + } + .submit{ + position: absolute; + width:84px; + height: 35px; + top: 10px; + right: 85px; + color: #fff; + font-size: 18px; + background:linear-gradient(90deg,rgba(99,194,246,1) 0%,rgba(62,155,255,1) 100%) !important; + border-radius:4px; + border: none!important; + border-color:rgba(0,0,0,0)!important; + } + .submit:hover{ + background:linear-gradient(90deg, rgb(103, 207, 246) 0%, rgb(69, 175, 255) 100%) !important; + border: none; + } + .back,.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; + } + .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; + } + .e2ecreate-content{ + position: relative; + width: 98%; + height: 100%; + margin-left: 30px; + box-shadow:0px 10px 15px 2px rgba(222,222,222,0.5); + background: #fff; + border-radius:2px; + } + .creation{ + position: relative; + width: 58%; + height: 100%; + overflow-y: auto; + padding: 20px; + background: #fff; + .baseparms { + h3,h4{ + color: #06A7E2; + width: 96%; + height: 40px; + line-height: 35px; + font-size: 18px; + font-weight: 500; + margin: 10px auto; + 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; + } + h4 { + font: 700 16px "Arial"; + margin-left: 25px; + } + .vnf-box{ + clear: both; + } + ul{ + margin-left: 30px; + } + ul li { + margin: 10px 0; + width: 42%; + margin-right: 5%; + float: left; + text-align: left; + span { + display: inline-block; + width: 30%; + min-width: 80px; + font: 700 14px "Arial"; + overflow: hidden; + text-align: left; + word-break: break-all; + vertical-align: top; + } + input,nz-select{ + width: 49%; + margin-left:3% + } + } + } + } + .dividing-line{ + width: 0; + height: 85%; + margin: 4% 0; + border-left: 1px #cccccc dashed; + } + .chart { + width: 38%; + padding: 10px; + height: 95%; + margin: 0 auto; + #createChart{ + height: 100%; + width: 100%; + } + } +} diff --git a/usecaseui-portal/src/app/views/services/services-list/e2e-creation/e2e-creation.component.spec.ts b/usecaseui-portal/src/app/views/services/services-list/e2e-creation/e2e-creation.component.spec.ts new file mode 100644 index 00000000..de00c43f --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/e2e-creation/e2e-creation.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { E2eCreationComponent } from './e2e-creation.component'; + +describe('E2eCreationComponent', () => { + let component: E2eCreationComponent; + let fixture: ComponentFixture<E2eCreationComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ E2eCreationComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(E2eCreationComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/usecaseui-portal/src/app/views/services/services-list/e2e-creation/e2e-creation.component.ts b/usecaseui-portal/src/app/views/services/services-list/e2e-creation/e2e-creation.component.ts new file mode 100644 index 00000000..f1df9636 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/e2e-creation/e2e-creation.component.ts @@ -0,0 +1,357 @@ +/* + 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 { ServiceListService } from '../../../../core/services/serviceList.service'; +import * as d3 from 'd3'; + +@Component({ + selector: 'app-e2e-creation', + templateUrl: './e2e-creation.component.html', + styleUrls: ['./e2e-creation.component.less'] +}) +export class E2eCreationComponent implements OnInit { + + constructor(private myhttp: ServiceListService) { } + + ngOnInit() { + this.gete2eTemParameters(this.e2e_ns_temParametersContent); + this.getVimInfo(); + this.getSdnControllers(); + console.log(this.createParams); + } + + @Output() e2eCloseCreate = new EventEmitter(); + @Output() nsCloseCreate = new EventEmitter(); + @Input() createParams; + @Input() e2e_ns_temParametersContent; + + + // e2e serviceTemplateParameters + templateParameters = { + invariantUUID: "", + uuid: "", + name: "", + type: "", + version: "", + description: "", + category: "", + subcategory: "", + customizationUuid: "", + inputs: [], + nestedTemplates: [] + }; + // ns serviceTemplateParameters + nsTemplateParameters = { + inputs: {}, + inputs2: [], + vnfs: [] + } + roote2e = { + "name": "e2e", + "type": "e2e", + "children": [] + }; + + rootns = { + "name": "ns", + "type": "ns", + "children": [] + }; + + imgmap = { + '1': '../../../../assets/images/create-e2e.png', + '2': '../../../../assets/images/create-ns.png', + '3': '../../../../assets/images/create-vnf.png', + }; + gete2eTemParameters(data) { //Get template parameters + let type = this.createParams.commonParams.templateType == "E2E Service" ? "e2e" : "ns"; + console.log(this.createParams); + console.log(data); + if (type == "e2e") { + this.templateParameters = data; + this.templateParameters.nestedTemplates.forEach((item) => { + item.inputs = item.inputs.filter((input) => { return input.type !== "sdn_controller" }); + }) + this.templateParameters.nestedTemplates.map((item, index) => { + let nsIndex = { + "name": "ns", + "type": "ns", + "children": [] + }; + nsIndex.children = item.nestedTemplates.map((item, index) => { + return { + "name": "vnf", + "type": "vnf", + } + }); + this.roote2e.children.push(nsIndex); + }); + console.log(this.templateParameters); + console.log(this.roote2e) + } else if (type == "ns") { + if (data["model"] != undefined && typeof data["model"] == 'string') { + this.nsTemplateParameters = JSON.parse(data["model"]); + console.log(data["model"]); + } else { + this.nsTemplateParameters = data; + } + console.log(this.nsTemplateParameters); + this.nsTemplateParameters["inputs2"] = []; + let inputs = this.nsTemplateParameters.inputs; + for (let key in inputs) { + this.nsTemplateParameters["inputs2"].push({ name: key, type: inputs[key].type, value: inputs[key].value }) + } + this.rootns.children = this.nsTemplateParameters.vnfs.map((item, index) => { + return { + "name": "vnf", + "type": "vnf", + } + }); + console.log(this.nsTemplateParameters); + } + + this.drawImage(type) + + } + vimInfos = []; + getVimInfo() { + this.myhttp.getVimInfo() + .subscribe((data) => { + this.vimInfos = data.map((item) => { return { name: item['cloud-owner'], id: item['cloud-region-id'] } }); + }) + }; + sdnControllers = []; + getSdnControllers() { + this.myhttp.getSdnControllers() + .subscribe((data) => { + this.sdnControllers = data.map((item) => { return { name: item['thirdparty-sdnc-id'], id: item['thirdparty-sdnc-id'] } }); + }) + } + + // e2e requstbody + service = { + name: "", + description: "", + COS: "", + EBS: "", + serviceInvariantUuid: "", + serviceUuid: "", // uuid ?? + globalSubscriberId: "", // "customer.id", + serviceType: "", // "serviceType.value", + parameters: { + locationConstraints: [ + + ], + resources: [], + requestInputs: {}, + } + + } + + // ns requstbody + ns_service = { + csarId: "", + nsName: "", + description: "", + context: { + globalCustomerId: "", + serviceType: "" + } + } + ns_service2 = { + locationConstraints: [ + + ], + additionalParamForNs: { + } + } + submit() { + let type = this.createParams.commonParams.templateType == "E2E Service" ? "e2e" : "ns"; + if (type == "e2e") { + this.service.serviceInvariantUuid = this.templateParameters.invariantUUID; + this.service.serviceUuid = this.templateParameters.uuid; + this.service.globalSubscriberId = this.createParams.commonParams.customer.id; + this.service.serviceType = this.createParams.commonParams.serviceType.name; + + this.templateParameters.inputs.forEach((ipnut) => { + this.service.parameters.requestInputs[ipnut.name] = ipnut.value == undefined ? ipnut.defaultValue : ipnut.value; + }) + + this.templateParameters.nestedTemplates.forEach((item) => { + let nsService = { + resourceName: item.name, + resourceInvariantUuid: item.invariantUUID, + resourceUuid: item.uuid, + resourceCustomizationUuid: item.customizationUuid, + parameters: { + locationConstraints: [], + resources: [], + requestInputs: {} + } + } + item.inputs.forEach((input) => { + if (input.type == "vf_location") { + let location = { + vnfProfileId: input.name, + locationConstraints: { + cloudOwner: input.value.name, + cloudRegionId: input.value.id + } + } + nsService.parameters.locationConstraints.push(location); + } else { + nsService.parameters.requestInputs[input.name] = input.value == undefined ? input.defaultValue : input.value; + } + }) + this.service.parameters.resources.push(nsService); + }) + console.log(this.service) + this.service.parameters.requestInputs['orchestrator'] = this.createParams.orchestrator.name; + if (this.createParams.isSol005Interface) { + this.service.parameters.requestInputs['isSol005Interface'] = this.createParams.isSol005Interface; + } + this.e2eCloseCreate.emit({ service: this.service }); + + } else if (type == "ns") { + //create ns instance + this.ns_service.csarId = this.createParams.template.id; + this.ns_service.context.globalCustomerId = this.createParams.commonParams.customer.id; + this.ns_service.context.serviceType = this.createParams.commonParams.serviceType.name; + + this.nsTemplateParameters.inputs2.forEach((input) => { + this.ns_service2.additionalParamForNs[input.name] = input.value == undefined ? input.defaultValue : input.value; + }) + this.nsTemplateParameters.vnfs.forEach((vnf) => { + let vnfparams = { + vnfProfileId: vnf.properties.id, + locationConstraints: { + cloudOwner: vnf.value.name, + cloudRegionId: vnf.value.id + } + } + this.ns_service2.locationConstraints.push(vnfparams); + }) + console.log(this.ns_service2); + + let requstbody = { + step1: this.ns_service, + step2: this.ns_service2 + } + this.nsCloseCreate.emit(requstbody); + } + + } + goback() { + this.e2eCloseCreate.emit(); + } + + + + drawImage(type) { + if (type == "e2e") { + this.render(this.roote2e, this.imgmap) + } else if (type == "ns") { + this.render(this.rootns, this.imgmap) + } + + + } + + render(data, imgmap) { + var width = document.getElementById("createChart").clientWidth, + height = document.getElementById("createChart").clientHeight; + var cluster = d3.layout.tree() + .size([width, height]); + var diagonal = d3.svg.diagonal() + .projection(function (d) { + return [d.x - 18, d.y + 40]; + }); + var svg = d3.select("svg"); + + //marker + var marker = + svg.append("marker") + .attr("id", "resolved") + .attr("markerUnits", "strokeWidth") + .attr("markerUnits", "userSpaceOnUse") + .attr("viewBox", "0 -5 10 10") + .attr("refX", 22) + .attr("refY", 0) + .attr("markerWidth", 20) + .attr("markerHeight", 20) + .attr("orient", "auto") + .attr("stroke-width", 1) + .append("circle") + .attr("cx", 5) + .attr("cy", 0) + .attr("r", 2) + .attr("stroke-width", 1) + .style("stroke", "#2F8BF7") + .attr('fill', 'white'); + var i = 0; + var nodes = cluster.nodes(data).reverse(); + nodes.forEach(function (d) { + d.y = d.depth * 200 + 100; + + }); + + var links = cluster.links(nodes); + + var linkEnter = svg.selectAll("path.link") + .data(links); + + linkEnter.enter().append("path") + .attr("class", "link") + .attr("d", diagonal) + .style("stroke", "#2F8BF7") + .style('stroke-width', '1px') + .attr("marker-end", "url(#resolved)") + .style("fill", "none") + // .style("fill-opacity", 1) + .attr("id", function (d, i) { + return "mypath" + i; + }); + + var node = svg.selectAll(".node") + .data(nodes) + .enter() + .append("g") + .attr("class", "node") + .attr("transform", function (d) { + return "translate(" + (d.x + -50) + "," + (d.y) + ")"; + }); + + node.append('image') + .attr('xlink:href', function (d) { + if (d.type == "e2e") { + return imgmap[1]; + } else if (d.type == "ns") { + return imgmap[2]; + } else if (d.type == "vnf") { + return imgmap[3]; + } + + }) + .style('width', '12%') + .style("cursor", "pointer") + .attr("x", 0) + .attr("y", 0) + .attr("rx", 3); + + + } + +} diff --git a/usecaseui-portal/src/app/views/services/services-list/e2e-detail/e2e-detail.component.html b/usecaseui-portal/src/app/views/services/services-list/e2e-detail/e2e-detail.component.html new file mode 100644 index 00000000..976a9f6c --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/e2e-detail/e2e-detail.component.html @@ -0,0 +1,109 @@ +<!-- + 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"> Services List </h3>--> +<div class="model creation-model"> + + <div class="top-title"> + <h3 class="title fl">{{serviceInstanceName}} Instance Detail</h3> + <div class="fl" style="width: 20%"> + <button class="back" nz-button (click)="goback()"></button> + </div> + </div> + <div class="detaildata fl"> + <div *ngIf="detailParams.serviceDomain == 'E2E Service'" class="baseparms clearfix"> + <div class="vnf-box"> + <h3> {{"i18nTextDefine_Base" | translate}} </h3> + <ul class="clearfix"> + <li> + <span style="width:15%">Name:</span> + <span class="input-content">{{service.name}}</span> + </li> + <li> + <span style="width:25%">Description:</span> + <span class="input-content">{{service.description}}</span> + </li> + </ul> + </div> + <div class="vnf-box" *ngIf="getKeys(e2e_requestInputs).length>0"> + <h3>{{"i18nTextDefine_templateInputs" | translate}}</h3> + <ul class="clearfix"> + <li *ngFor="let key of getKeys(e2e_requestInputs);"> + <span title="{{key}}">{{key}}:</span> + <span class="input-content">{{e2e_requestInputs[key]}}</span> + </li> + </ul> + </div> + <div class="vnf-box" *ngFor="let template of e2e_nestedTemplates;"> + <h3>{{template.name}}</h3> + <ul class="clearfix"> + <li *ngFor="let input of template.vnfs; let i = index;"> + <span style="width: 26%;min-width: 80px!important"> vf_location: </span> + <span class="input-content">{{input["vf_location"]}}</span> + </li> + </ul> + </div> + </div> + + <div *ngIf="detailParams.serviceDomain=='Network Service'" class="baseparms clearfix"> + <div class="vnf-box"> + <h3> {{"i18nTextDefine_Base" | translate}} </h3> + <ul class="clearfix"> + <li> + <span style="width:15%">Name:</span> + <span class="input-content">{{ns_service.name}}</span> + </li> + <li> + <span style="width:25%">Description:</span> + <span class="input-content">{{ns_service.description}}</span> + </li> + </ul> + </div> + <div class="vnf-box" *ngIf="getKeys(ns_requestInputs).length>0"> + <h4>{{"i18nTextDefine_templateInputs" | translate}}</h4> + <ul> + <li *ngFor="let key of getKeys(ns_requestInputs);"> + <span title="{{key}}">{{key}}:</span> + <span class="input-content">{{ns_requestInputs[key]}}</span> + </li> + </ul> + </div> + <div class="vnf-box" *ngIf="ns_nestedTemplates.length>0"> + <h4>vnfs Inputs</h4> + <ul> + <li *ngFor="let vnf of ns_nestedTemplates;"> + <h5> + <span style="width: 26%;min-width: 80px!important"> id: </span> + <span class="input-content"> {{vnf.vnfInstanceId}}</span> + </h5> + <h5> + <span style="width: 26%;min-width: 80px!important"> vf_location: </span> + <span class="input-content">{{vnf["vnfInstanceName"]}}</span> + </h5> + </li> + </ul> + </div> + </div> + </div> + + <!-- chart --> + <div class="chart fr"> + <div id="createChart"> + <svg width="100%" height="100%"> + </svg> + </div> + </div> + +</div>
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/services/services-list/e2e-detail/e2e-detail.component.less b/usecaseui-portal/src/app/views/services/services-list/e2e-detail/e2e-detail.component.less new file mode 100644 index 00000000..ad28a518 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/e2e-detail/e2e-detail.component.less @@ -0,0 +1,142 @@ +/* + 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; +} +.creation-model{ + position: relative; +} +.model { + background-color: #F7F8FC; + height: 100%; + overflow-y: auto; + position: relative; + .top-title{ + width: 100%; + padding: 20px; + position: relative; + display: inline-block; + } + .back,.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; + } + .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; + } + .detaildata{ + position: relative; + width: 58%; + height: 100%; + overflow-y: auto; + border-radius: 5px; + padding: 20px; + background: #fff; + margin-left: 30px; + box-shadow:0px 10px 15px 2px rgba(222,222,222,0.5); + .baseparms { + h3,h4{ + color: #06A7E2; + width: 96%; + height: 40px; + line-height: 35px; + font-size: 18px; + font-weight: 500; + margin: 10px auto; + 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; + } + h4 { + font: 700 16px "Arial"; + margin-left: 25px; + } + .vnf-box{ + clear: both; + } + ul{ + margin-left: 30px; + } + ul li { + margin: 10px 0; + width: 49%; + float: left; + text-align: left; + color:rgba(60,79,140,1); + font-size: 14px; + span { + display: inline-block; + width: 50%; + font: 700 14px "Arial"; + vertical-align: top; + overflow: hidden; + text-align: left; + color:rgba(60,79,140,0.5); + word-break: break-all; + } + span.input-content{ + width: 42%; + color: #3C4F8C; + margin-left: 5%; + word-break: break-all; + vertical-align: top; + } + } + } + } + .chart { + width: 35%; + padding: 10px; + height: 95%; + box-shadow: 0px 10px 35px 10px rgba(222, 222, 222, 0.5); + margin-right: 1%; + background:linear-gradient(180deg,rgba(183, 230, 247, 1) 0%,rgba(214, 240, 254, 1) 100%); + border-radius: 4px; + #createChart{ + height: 100%; + width: 100%; + } + } +} diff --git a/usecaseui-portal/src/app/views/services/services-list/e2e-detail/e2e-detail.component.spec.ts b/usecaseui-portal/src/app/views/services/services-list/e2e-detail/e2e-detail.component.spec.ts new file mode 100644 index 00000000..ad24a477 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/e2e-detail/e2e-detail.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { E2eDetailComponent } from './e2e-detail.component'; + +describe('E2eDetailComponent', () => { + let component: E2eDetailComponent; + let fixture: ComponentFixture<E2eDetailComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ E2eDetailComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(E2eDetailComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/usecaseui-portal/src/app/views/services/services-list/e2e-detail/e2e-detail.component.ts b/usecaseui-portal/src/app/views/services/services-list/e2e-detail/e2e-detail.component.ts new file mode 100644 index 00000000..50f63b3e --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/e2e-detail/e2e-detail.component.ts @@ -0,0 +1,246 @@ +/* + 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 { ServiceListService } from '../../../../core/services/serviceList.service'; +import * as d3 from 'd3'; + +@Component({ + selector: 'app-e2e-detail', + templateUrl: './e2e-detail.component.html', + styleUrls: ['./e2e-detail.component.less'] +}) +export class E2eDetailComponent implements OnInit { + + constructor(private myhttp: ServiceListService) { + } + + ngOnInit() { + // this.getDetails(); + this.dataInit(); + } + + @Input() detailParams; + + @Output() closeDetail = new EventEmitter(); + serviceInstanceName: any; + serviceType: any; + input_parameters: any; + nsinput_parameters: any; + + // e2e + service = { + name: "", + description: "", + }; + e2e_nestedTemplates = []; + e2e_requestInputs: any; + + ns_service = { + name: "", + description: "" + } + ns_nestedTemplates = []; + ns_requestInputs = {}; + roote2e = { + "name": "e2e", + "type": "e2e", + "children": [] + }; + + rootns = { + "name": "ns", + "type": "ns", + "children": [] + }; + + imgmap = { + '1': '../../../../assets/images/create-e2e.png', + '2': '../../../../assets/images/create-ns.png', + '3': '../../../../assets/images/create-vnf.png', + }; + + getKeys(item) { + return Object.keys(item); + } + + dataInit() { + console.log(this.detailParams); + this.serviceInstanceName = this.detailParams['service-instance-name'] || this.detailParams["nsName"]; + if (this.detailParams.serviceDomain == 'E2E Service') { + this.input_parameters = JSON.stringify(this.detailParams['input-parameters']); + this.input_parameters = JSON.parse(this.input_parameters); + console.log(this.input_parameters); + this.service = { + name: this.input_parameters.service.name, + description: this.input_parameters.service.description, + }; + if (this.input_parameters.service.parameters.requestInputs != undefined && Object.keys(this.input_parameters.service.parameters.requestInputs).length > 0) { + this.e2e_requestInputs = this.input_parameters.service.parameters.requestInputs; + } + if (this.input_parameters.service.parameters.resources != undefined && this.input_parameters.service.parameters.resources.length > 0) { + this.input_parameters.service.parameters.resources.map((item, i) => { + let nestedTemplates = { + name: null, + vnfs: [] + }; + nestedTemplates.name = item.resourceName; + item.parameters.locationConstraints.map((its, k) => { + nestedTemplates.vnfs.push({ + "vf_location": its.locationConstraints.cloudOwner + }) + }); + this.e2e_nestedTemplates.push(nestedTemplates); + + let nsIndex = { + "name": "ns", + "type": "ns", + "children": [] + }; + nsIndex.children = item.parameters.locationConstraints.map((itemits, index) => { + return { + "name": "vnf", + "type": "vnf", + } + }); + this.roote2e.children.push(nsIndex); + }); + console.log(this.e2e_nestedTemplates); + console.log(this.e2e_requestInputs); + console.log(this.roote2e) + } + } else if (this.detailParams.serviceDomain == 'Network Service') { + this.ns_service = { + name: this.detailParams.name || this.detailParams['service-instance-name'], + description: this.detailParams.description || null + }; + if (this.detailParams.requestInputs != undefined && Object.keys(this.detailParams.requestInputs).length > 0) { + this.ns_requestInputs = this.detailParams.requestInputs; + } + this.ns_nestedTemplates = this.detailParams.childServiceInstances; + this.rootns.children = this.ns_nestedTemplates.map((item, index) => { + return { + "name": "vnf", + "type": "vnf" + } + }); + console.log(this.ns_nestedTemplates); + console.log(this.ns_requestInputs); + console.log(this.rootns) + } + this.drawImage(this.detailParams.serviceDomain) + } + + goback() { + this.closeDetail.emit(); + } + + drawImage(type) { + if (type == "E2E Service") { + this.render(this.roote2e, this.imgmap) + } else if (type == "Network Service") { + this.render(this.rootns, this.imgmap) + } + + + } + + render(data, imgmap) { + var width = document.getElementById("createChart").clientWidth, + height = document.getElementById("createChart").clientHeight; + var cluster = d3.layout.tree() + .size([width, height]); + var diagonal = d3.svg.diagonal() + .projection(function (d) { + return [d.x - 18, d.y + 40]; + }); + var svg = d3.select("svg"); + + //marker + var marker = + svg.append("marker") + .attr("id", "resolved") + .attr("markerUnits", "strokeWidth") + .attr("markerUnits", "userSpaceOnUse") + .attr("viewBox", "0 -5 10 10") + .attr("refX", 22) + .attr("refY", 0) + .attr("markerWidth", 20) + .attr("markerHeight", 20) + .attr("orient", "auto") + .attr("stroke-width", 1) + .append("circle") + .attr("cx", 5) + .attr("cy", 0) + .attr("r", 2) + .attr("stroke-width", 1) + .style("stroke", "#2F8BF7") + .attr('fill', 'white'); + var i = 0; + var nodes = cluster.nodes(data).reverse(); + nodes.forEach(function (d) { + d.y = d.depth * 200 + 100; + + }); + + var links = cluster.links(nodes); + + var linkEnter = svg.selectAll("path.link") + .data(links); + + linkEnter.enter().append("path") + .attr("class", "link") + .attr("d", diagonal) + .style("stroke", "#2F8BF7") + .style('stroke-width', '1px') + .attr("marker-end", "url(#resolved)") + .style("fill", "none") + // .style("fill-opacity", 1) + .attr("id", function (d, i) { + return "mypath" + i; + }); + + var node = svg.selectAll(".node") + .data(nodes) + .enter() + .append("g") + .attr("class", "node") + .attr("transform", function (d) { + return "translate(" + (d.x + -50) + "," + (d.y) + ")"; + }); + + node.append('image') + .attr('xlink:href', function (d) { + if (d.type == "e2e") { + return imgmap[1]; + } else if (d.type == "ns") { + return imgmap[2]; + } else if (d.type == "vnf") { + return imgmap[3]; + } + + }) + .style('width', '12%') + .style("cursor", "pointer") + .attr("x", 0) + .attr("y", 0) + .attr("rx", 3); + + + } + + +} diff --git a/usecaseui-portal/src/app/views/services/services-list/heal-model/heal-model.component.html b/usecaseui-portal/src/app/views/services/services-list/heal-model/heal-model.component.html new file mode 100644 index 00000000..0117669f --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/heal-model/heal-model.component.html @@ -0,0 +1,72 @@ +<nz-modal nzWidth="428" [nzVisible]="healModelVisible" nzTitle=" {{'i18nTextDefine_Heal' | translate}} " + (nzOnCancel)="healCancel()" (nzOnOk)="healOk()" + nzClassName="healModel" nzCancelText=" {{'i18nTextDefine_Cancel' | translate}} " + nzOkText=" {{'i18nTextDefine_modelOk' | translate}} "> + <h3><span style="color: red">* </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> + + </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"> + 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> +</nz-modal>
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/services/services-list/heal-model/heal-model.component.less b/usecaseui-portal/src/app/views/services/services-list/heal-model/heal-model.component.less new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/heal-model/heal-model.component.less diff --git a/usecaseui-portal/src/app/views/services/services-list/heal-model/heal-model.component.spec.ts b/usecaseui-portal/src/app/views/services/services-list/heal-model/heal-model.component.spec.ts new file mode 100644 index 00000000..af1c07bd --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/heal-model/heal-model.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HealModelComponent } from './heal-model.component'; + +describe('HealModelComponent', () => { + let component: HealModelComponent; + let fixture: ComponentFixture<HealModelComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HealModelComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HealModelComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/usecaseui-portal/src/app/views/services/services-list/heal-model/heal-model.component.ts b/usecaseui-portal/src/app/views/services/services-list/heal-model/heal-model.component.ts new file mode 100644 index 00000000..a7ffe663 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/heal-model/heal-model.component.ts @@ -0,0 +1,68 @@ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; + +@Component({ + selector: 'app-heal-model', + templateUrl: './heal-model.component.html', + styleUrls: ['./heal-model.component.less'] +}) +export class HealModelComponent implements OnInit { + @Input()healModelVisible: boolean; + @Input()thisService; + @Input()nsParams; + @Input()healActions; + @Input()nsAdditional; + @Input()vnfParams; + @Input()vmSelected; + @Input()vnfVms; + @Input()templatehealstarting; + @Input()templatehealSuccessFaild; + + @Output() cancel = new EventEmitter<boolean>(); + @Output() healModalOK = new EventEmitter<any>(); + + constructor() { } + + ngOnInit() { + } + + + 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); + } + + healOk() { + 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.healModalOK.emit(requestBody) + } + + healCancel() { + this.healModelVisible = false; + } + +} diff --git a/usecaseui-portal/src/app/views/services/services-list/scale-model/scale-model.component.html b/usecaseui-portal/src/app/views/services/services-list/scale-model/scale-model.component.html new file mode 100644 index 00000000..cb873149 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/scale-model/scale-model.component.html @@ -0,0 +1,40 @@ +<nz-modal nzWidth="428" [nzVisible]="scaleModelVisible" nzTitle=" {{'i18nTextDefine_Scale' | translate}} " + (nzOnCancel)="scaleCancel()" (nzOnOk)="scaleOk()" + nzClassName="scaleModel" nzCancelText=" {{'i18nTextDefine_Cancel' | translate}} " + nzOkText=" {{'i18nTextDefine_modelOk' | translate}} "> + <h3><span style="color: red">* </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> + +</nz-modal>
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/services/services-list/scale-model/scale-model.component.less b/usecaseui-portal/src/app/views/services/services-list/scale-model/scale-model.component.less new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/scale-model/scale-model.component.less diff --git a/usecaseui-portal/src/app/views/services/services-list/scale-model/scale-model.component.spec.ts b/usecaseui-portal/src/app/views/services/services-list/scale-model/scale-model.component.spec.ts new file mode 100644 index 00000000..5d069ee4 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/scale-model/scale-model.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ScaleModelComponent } from './scale-model.component'; + +describe('ScaleModelComponent', () => { + let component: ScaleModelComponent; + let fixture: ComponentFixture<ScaleModelComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ScaleModelComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ScaleModelComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/usecaseui-portal/src/app/views/services/services-list/scale-model/scale-model.component.ts b/usecaseui-portal/src/app/views/services/services-list/scale-model/scale-model.component.ts new file mode 100644 index 00000000..c1b9a86e --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/scale-model/scale-model.component.ts @@ -0,0 +1,53 @@ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; + +@Component({ + selector: 'app-scale-model', + templateUrl: './scale-model.component.html', + styleUrls: ['./scale-model.component.less'] +}) +export class ScaleModelComponent implements OnInit { + @Input()scaleModelVisible: boolean; + @Input()templatescalestarting; + @Input()templateScaleSuccessFaild; + @Input()thisService; + @Input()e2e_nsData; + @Input()customerSelected; + @Input()serviceTypeSelected; + + @Output() cancel = new EventEmitter<boolean>(); + @Output() scaleModalOK = new EventEmitter<any>(); + constructor() { } + + ngOnInit() { + } + + scaleOk() { + 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.scaleModalOK.emit(requestBody) + } + + scaleCancel() { + this.scaleModelVisible = false; + } + +} 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 index a995b485..216e92df 100644 --- 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 @@ -14,7 +14,6 @@ limitations under the License. --> <div class="action ant-tabs-bar"> - <span> <i class="icon"> <img src="assets/images/customer.png" alt=""> @@ -51,88 +50,26 @@ <i *ngIf="width>1200" class="anticon anticon-plus"></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 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> + <app-create-model *ngIf="isVisible" [isVisible]="isVisible" (cancel)="isVisible=$event" (createdModalShow)="createdModalShow($event)" + [customerList]="customerList" [serviceTypeList]="serviceTypeList" [customerSelected]="customerSelected" [serviceTypeSelected]="serviceTypeSelected"> + </app-create-model> + </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> - <p class="service-description"> {{item.detailName | translate}} </p> - </div> - </li> - </ul> - <div class="list" id="services-list" [ngClass]="{'listdisplay':listDisplay == true}"> - <nz-table *ngIf="1" #nzTable [nzData]="tableData" nzShowSizeChanger [nzFrontPagination]="false" +<nz-layout> + <div class="top-num"> + <app-top-card + *ngFor="let item of serviceNunber" + [serviceDomain]="item.serviceDomain" + [successNum]="item.Success" + [failedNum]="item.failed" + [inProgressNum]="item.InProgress" + [serviceDetailName]="item.detailName"> + </app-top-card> + </div> + <div class="list" id="services-list" [ngClass]="{'listdisplay':listDisplay === true}"> + <nz-table #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' }" + [(nzPageIndex)]='pageIndex' [nzLoading]="loading" [nzSize]="'middle'" (nzPageIndexChange)="searchData()" (nzPageSizeChange)="searchData(true)"> <thead> <tr> @@ -153,31 +90,30 @@ <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'}"> + <p class="usecase"> {{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"> + <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' " class="marginLeft10"> <img src="assets/images/wancheng-icon.png" alt="Available"> </span> - <span *ngIf="data.tips == 'Unavailable' " style="margin-left: 10px"> + <span *ngIf="data.tips === 'Unavailable' " class="marginLeft10"> <img src="assets/images/shibai-icon.png" alt="Unavailable"> </span> - <nz-progress *ngIf="data.status == 'In Progress'" [nzPercent]="data.rate" + <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')}" + <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" + <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" + <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"> @@ -218,255 +154,50 @@ </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">* </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 - {{"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">* </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'] }} {{"i18nTextDefine_InstanceTeminationStarting" | - translate}} - </div> - <div class="ant-notification-notice-message" - *ngIf="thisService['serviceDomain'] == 'E2E Service'">E2E - {{"i18nTextDefine_InstanceTeminationStarting" | translate}} - </div> - <div class="ant-notification-notice-message" - *ngIf="thisService['serviceDomain'] == 'Network Service'">NS - {{"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">* </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> - - </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"> - 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 - {{"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> + <app-delete-model + *ngIf="deleteModalVisible" + [deleteModalVisible]="deleteModalVisible" + [thisService]="thisService" + [terminationType]="terminationType" + [loadingAnimateShow]="loadingAnimateShow" + [gracefulTerminationTimeout]="gracefulTerminationTimeout" + [templateDeleteSuccessFaild]="templateDeleteSuccessFaild" + (cancel)="deleteModalVisible=$event" + (deleteModalOK)="deleteModalOK($event,templateDeleteSuccessFaild)" + > + </app-delete-model> + <app-scale-model + *ngIf="scaleModelVisible" + [scaleModelVisible]="scaleModelVisible" + [thisService]="thisService" + [e2e_nsData]="e2e_nsData" + [customerSelected]="customerSelected" + [serviceTypeSelected]="serviceTypeSelected" + [templatescalestarting]="templatescalestarting" + [templateScaleSuccessFaild]="templateScaleSuccessFaild" + (cancel)="scaleModelVisible=$event" + (scaleModalOK)="scaleModalOK($event,templatescalestarting,templateScaleSuccessFaild)" + > + </app-scale-model> + <app-heal-model + *ngIf="healModelVisible" + [healModelVisible]="healModelVisible" + [thisService]="thisService" + [nsParams]="nsParams" + [healActions]="healActions" + [nsAdditional]="nsAdditional" + [vnfParams]="vnfParams" + [vmSelected]="vmSelected" + [vnfVms]="vnfVms" + [templatehealstarting]="templatehealstarting" + [templatehealSuccessFaild]="templatehealSuccessFaild" + (cancel)="healModelVisible=$event" + (healModalOK)="healModalOK($event,templatehealstarting,templatehealSuccessFaild)" + ></app-heal-model> + <app-notification #notification [isServicesList]="true" [customerSelected]="customerSelected"></app-notification> <!-- add notification--> + <ng-template #templateCreatestarting> <div class="ant-notification-notice-content"> <div class="ant-notification-notice-with-icon"> @@ -474,7 +205,7 @@ <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'"> + *ngIf="thisCreateService['serviceDomain'] === 'CCVPN' || thisService['serviceDomain'] === 'SOTN'"> {{ thisService['serviceDomain'] }} {{"i18nTextDefine_InstanceCreationStarting" | translate}} </div> @@ -582,6 +313,7 @@ *ngIf="(thisService['serviceDomain'] == 'Network Service') && thisService.status == 'Successful'"> NS {{"i18nTextDefine_InstanceTeminatedSuccessfully" | translate}} </div> + <div class="ant-notification-notice-message" *ngIf="(thisService['serviceDomain'] == 'CCVPN' || thisService['serviceDomain'] == 'SOTN') && thisService.status == 'Failed'"> {{ thisService['serviceDomain'] }} {{"i18nTextDefine_InstanceTeminationFailed" | @@ -615,6 +347,35 @@ </div> </div> </ng-template> + <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 + {{"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> <ng-template #templateScaleSuccessFaild> <div class="ant-notification-notice-content"> <div class="ant-notification-notice-with-icon"> @@ -650,6 +411,35 @@ </div> </div> </ng-template> + <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 + {{"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> <ng-template #templatehealSuccessFaild> <div class="ant-notification-notice-content"> <div class="ant-notification-notice-with-icon"> @@ -728,7 +518,7 @@ </div> <div class="detailComponent" *ngIf="detailshow2"> <app-e2e-detail [detailParams]="detailData" (closeDetail)="detailshow2 = false;listDisplay = false;"> - </app-e2e-detail> + </app-e2e-detail> </div> <div class="createComponent" *ngIf="createshow"> <app-ccvpn-creation [createParams]="createData" [ccvpn_temParametersContent]="ccvpn_temParametersContent" 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 index aeddf257..454e3bc8 100644 --- 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 @@ -207,69 +207,9 @@ nz-layout{ width: 100%; display: flex; justify-content: space-around; - .top-list{ - position: relative; - width:32%; - max-width:400px; - height:170px; - background:url("/assets/images/servicelist-e2e.png") no-repeat; - background-size: 100% 100%; - border-radius:2px; - .round{ - position: absolute; - width: 60px; - height: 60px; - line-height: 60px; - text-align: center; - background:#E0EDFF; - border:2px solid rgba(224,237,255,1); - border-radius: 50%; - font-size:16px; - font-family:ArialMT; - color:#3C4F8C; - transition: .5s; - } - .top-list-text{ - position: absolute; - text-align: right; - line-height: 20px; - right: 12%; - color: #fff; - p{ - height: 28px; - margin-bottom: 0; - padding-left: 5px; - font-size: 14px; - clear: both; - span{ - display: inline-block; - float: right; - font-weight: 500; - text-align: right; - } - span:nth-child(1){ - font-size: 18px; - margin-left: 15px; - } - span:nth-child(2){ - width: 85px; - font-size: 16px; - } - } - p:nth-child(1){ - margin-top: 25px; - } - .service-description{ - - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - color: #3C4F8C; - - } - } + app-top-card{ + width: 32%; } - } } .list { @@ -312,6 +252,9 @@ nz-layout{ font-size: 12px; color: orangered; } + span.marginLeft10{ + margin-left: 10px; + } i.anticon { cursor: pointer; font-size: 18px; @@ -395,7 +338,7 @@ nz-layout{ z-index: 3; } -.e2eColor,.nsColor,.ccvpnColor,.sotnColor,.voLTEColor{ +.usecase{ width:120px; height: 34px; line-height: 34px; @@ -416,18 +359,6 @@ nz-layout{ 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.ts b/usecaseui-portal/src/app/views/services/services-list/services-list.component.ts index 72cacc7e..da027028 100644 --- 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 @@ -13,8 +13,8 @@ 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 { Component, OnInit, HostBinding, TemplateRef, ViewChild } from '@angular/core'; +import { ServiceListService } from '../../../core/services/serviceList.service'; import { slideToRight } from '../../../shared/utils/animates'; import { NzModalService } from 'ng-zorro-antd'; import { NzNotificationService } from 'ng-zorro-antd'; @@ -28,10 +28,11 @@ import { Observable } from 'rxjs/Rx'; }) export class ServicesListComponent implements OnInit { @HostBinding('@routerAnimate') routerAnimateState; + @ViewChild('notification') notification1: any; public width:number = document.documentElement.clientWidth; - constructor(private myhttp: MyhttpService, private modalService: NzModalService, private notification: NzNotificationService) { + constructor(private myhttp: ServiceListService, private modalService: NzModalService, private notification: NzNotificationService) { } ngOnInit() { @@ -41,16 +42,19 @@ export class ServicesListComponent implements OnInit { this.width = document.documentElement.clientWidth }); } - + ngOnDestroy() { + clearInterval(this.progressCcvpnOutTimer); + clearInterval(this.progressingCcvpnTimer); + clearInterval(this.progressNsOutTimer); + clearInterval(this.progressingNsTimer); + } // customer servicetype isSol005Interface = false; orchestratorList = []; customerList = []; - customerList2 = []; customerSelected = { name: null, id: null }; customerSelected2 = { name: null, id: null }; serviceTypeList = []; - serviceTypeList2 = []; serviceTypeSelected = { name: '' }; serviceTypeSelected2 = { name: '' }; serviceTypeSelectedName = ""; @@ -60,7 +64,7 @@ export class ServicesListComponent implements OnInit { language = sessionStorage.getItem("DefaultLang"); iconMore = false; loadingAnimateShow = false; - serviceMunber = [ // top: E2E/NS/CCVPN data + serviceNunber = [ // top: E2E/NS/CCVPN data { "serviceDomain": "E2E", "Success": 0, @@ -84,6 +88,11 @@ export class ServicesListComponent implements OnInit { } ]; + progressCcvpnOutTimer :any; // ccvpn��NS progress Timer + progressingCcvpnTimer :any; + progressNsOutTimer :any; + progressingNsTimer :any; + //The icon behind each row of data in the table expands iconMoreShow(data, tableData) { tableData.map((its) => { @@ -104,59 +113,40 @@ export class ServicesListComponent implements OnInit { 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.customerList = data.map(item => ({ name: item["subscriber-name"], id: item["global-customer-id"] }) ); + if(data.length !== 0){ + this.customerSelected = this.customerList[0]; + this.choseCustomer(); } - 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; + if(data.length > 0){ + this.orchestratorList = data.map((item) => { + return { name: item["name"], id: item["name"] } + }); + this.orchestratorSelected = this.orchestratorList[0]; } - this.orchestratorSelected = this.orchestratorList[0]; }) } - choseCustomer(item) { - this.customerSelected = item; + choseCustomer(item = this.customerSelected) { + if(this.customerSelected !== 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.serviceTypeList = data.map( item => ({ name: item["service-type"] })); + if(data.length !== 0){ + this.serviceTypeSelected = this.serviceTypeList[0]; + this.choseServiceType(); } - - this.serviceTypeSelected = this.serviceTypeList[0]; - - this.choseServiceType(this.serviceTypeSelected); }) } - choseServiceType(item) { - this.serviceTypeSelected = item; + choseServiceType(item = this.serviceTypeSelected) { + if(this.serviceTypeSelected !== item) this.serviceTypeSelected = item; this.getTableData(); } @@ -164,131 +154,28 @@ export class ServicesListComponent implements OnInit { // 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; + createshow: boolean = false; + createshow2: boolean = false; + listDisplay: boolean = 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"; + createdModalShow(obj: any): void{ + this.createData = obj.createData; + console.log(obj.createData) + if (obj.templateType === "SOTN" || obj.templateType === "CCVPN") { + this.ccvpn_temParametersContent = obj.data; + this.createshow = true; + } else if (obj.templateType === "E2E Service" || obj.templateType === "Network Service") { + this.e2e_ns_temParametersContent = obj.data; + this.createshow2 = true; } - 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; - } - } - }) + this.listDisplay = true; } //tableData @@ -316,7 +203,7 @@ export class ServicesListComponent implements OnInit { } item["iconMore"] = this.iconMore; - if (item["serviceDomain"] == "Network Service") { + if (item["serviceDomain"] === "Network Service") { if (item["vnfInfo"]) { item["childServiceInstances"] = item["vnfInfo"].map((vnf) => { vnf["serviceDomain"] = "vnf"; @@ -334,10 +221,10 @@ export class ServicesListComponent implements OnInit { }; vnfInfo.vnfNsInstanceId = item["nsInstanceId"] || item["service-instance-id"]; vnfInfo.vnfInstanceId = vnf["relationship-data"].find((vnfid) => { - return vnfid["relationship-key"] == "generic-vnf.vnf-id" + 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" + return vnfname["property-key"] === "generic-vnf.vnf-name" })["property-value"]; return vnfInfo; }) @@ -347,32 +234,30 @@ export class ServicesListComponent implements OnInit { } // - if (item["operationResult"] == "2001") { //operationResult==2001 + if (item["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") { + else if (item["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 + 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"]]; + } else { item["status"] = this.listSortMasters["operationResults"].find((its) => { - return its["sortCode"] == item["operationResult"] && its["language"] == this.language + 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"]]; + else if (item["operationResult"] === "2003") { item["status"] = this.listSortMasters["operationResults"].find((its) => { return its["sortCode"] == item["operationResult"] && its["language"] == this.language })["sortValue"]; @@ -404,16 +289,11 @@ export class ServicesListComponent implements OnInit { }) } else { let updata = (prodata) => { - item["rate"] = prodata.progress || item["rate"]; + item["rate"] = prodata.progress || 0; + 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' + 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"]; - } + return its["sortCode"] === item["operationType"] && its["language"] === this.language + })["sortValue"] + '\xa0\xa0\xa0' + (item["rate"] > 100? item["status"] : prodata.progress + '%'); } let obj = { serviceId: item["service-instance-id"], @@ -433,35 +313,36 @@ export class ServicesListComponent implements OnInit { } 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; + this.tableData.forEach( item => { + if (item.serviceDomain === 'E2E Service') { + if (item.operationResult === 2001) { + this.serviceNunber[0]["Success"] += 1; + } else if (item.operationResult === 2002) { + this.serviceNunber[0]["failed"] += 1; + } else if (item.operationResult === 2003) { + this.serviceNunber[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 === 'Network Service') { + if (item.operationResult === 2001) { + this.serviceNunber[1]["Success"] += 1; + } else if (item.operationResult === 2002) { + this.serviceNunber[1]["failed"] += 1; + } else if (item.operationResult === 2003) { + this.serviceNunber[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; + else if (item.serviceDomain === 'CCVPN') { + if (item.operationResult === 2001) { + this.serviceNunber[2]["Success"] += 1; + } else if (item.operationResult === 2002) { + this.serviceNunber[2]["failed"] += 1; + } else if (item.operationResult === 2003) { + this.serviceNunber[2]["InProgress"] += 1; } } }) + console.log(this.tableData) this.loading = false; }, (err) => { console.log(err); @@ -484,43 +365,18 @@ export class ServicesListComponent implements OnInit { 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); + scaleModalOK(obj: any,templatescalestarting,templateScaleSuccessFaild) :void{ + this.scaleE2eService(this.thisService, obj, templateScaleSuccessFaild); this.scaleNotification(templatescalestarting); } - scaleCancel() { - this.scaleModelVisible = false; - } - scaleNotification(template: TemplateRef<{}>): void { this.notification.template(template); } @@ -552,23 +408,7 @@ export class ServicesListComponent implements OnInit { 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; @@ -583,30 +423,11 @@ export class ServicesListComponent implements OnInit { } } - 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); + healModalOK(obj: any,templatehealstarting,templatehealSuccessFaild) :void{ + this.healNsVnfService(this.thisService, obj, templatehealSuccessFaild); this.healNotification(templatehealstarting); } - healCancel() { - this.healModelVisible = false; - } - healNotification(template: TemplateRef<{}>): void { this.notification.template(template); } @@ -628,54 +449,45 @@ export class ServicesListComponent implements OnInit { service["serviceType"] = this.serviceTypeSelected; service.childServiceInstances.forEach((item) => { - if (item.serviceDomain == "SITE") { + if (item.serviceDomain === "SITE") { service.siteSer.push(item); - } else if (item.serviceDomain == "SDWAN") { + } else if (item.serviceDomain === "SDWAN") { service.sdwanSer.push(item); } }) - if (service["serviceDomain"] == 'CCVPN' || service["serviceDomain"] == 'SOTN') { + if (service["serviceDomain"] === 'CCVPN' || service["serviceDomain"] === 'SOTN') { this.detailshow = true; - if (typeNum == 1) { + if (typeNum === 1) { this.upDateShow = false; } else { this.upDateShow = true; } - } else if (service["serviceDomain"] == 'E2E Service' || service["serviceDomain"] == 'Network Service') { + } else if (service["serviceDomain"] === 'E2E Service' || service["serviceDomain"] === 'Network Service') { this.detailshow2 = true; } this.listDisplay = true; this.detailData = service; - console.log(service); } - deleteModelVisible = false; + deleteModalVisible = false; terminationType = "graceful"; gracefulTerminationTimeout = 120; // delete Model show deleteModel(service) { this.thisService = service; - this.deleteModelVisible = true; + this.deleteModalVisible = true; } - deleteOk(templatedeletestarting, templateDeleteSuccessFaild) { - this.deleteModelVisible = false; + deleteModalOK(obj: any,templateDeleteSuccessFaild) :void{ + this.deleteModalVisible = false; this.loadingAnimateShow = true; - if (this.thisService["serviceDomain"] == "Network Service") { - this.deleteNsService(this.thisService, templateDeleteSuccessFaild); + if (this.thisService["serviceDomain"] === "Network Service") { + this.deleteNsService(obj,this.thisService); } else { this.deleteService(this.thisService, templateDeleteSuccessFaild); } - this.deleteNotification(templatedeletestarting); - } - - deleteCancel() { - this.deleteModelVisible = false; - } - - deleteNotification(template: TemplateRef<{}>): void { - this.notification.template(template); + this.notification1.notificationStart(this.thisService['serviceDomain'],'deleteStarting',this.thisService["service-instance-name"] ||this.thisService["nsInstanceName"]) } deleteSuccessNotification(template: TemplateRef<{}>): void { @@ -1011,7 +823,10 @@ export class ServicesListComponent implements OnInit { service.tips = ""; service.statusClass = "1004"; let id = service.nsInstanceId || service["service-instance-id"] || service["vnfNsInstanceId"]; - this.myhttp.healNsService(id, requestBody) + let paramsObj = { + "ns_instance_id":id + }; + this.myhttp.healNsService(paramsObj, requestBody) .subscribe((data) => { if (data.status == "FAILED") { console.log("heal nsvnf service Failed :" + JSON.stringify(data)); @@ -1113,7 +928,7 @@ export class ServicesListComponent implements OnInit { }) } - deleteService(service, templateDeleteSuccessFaild) { + deleteService(service:any, templateDeleteSuccessFaild) { let allprogress = {}; let querypros = []; service.rate = 0; @@ -1190,21 +1005,17 @@ export class ServicesListComponent implements OnInit { }) } - deleteNsService(service, templateDeleteSuccessFaild) { + deleteNsService(obj:any,service:any) { 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") { + this.stopNsService(id, obj).then((jobid) => { + if (jobid === "Failed") { service.status = "Failed"; - this.deleteSuccessNotification(templateDeleteSuccessFaild); + this.notification1.notificationFailed(service.serviceDomain,'deleteStarting',service["service-instance-name"] ||service["nsInstanceName"]) service.tips = this.listSortMasters["operationTypes"].find((its) => { return its["sortCode"] == service.statusClass && its["language"] == this.language })["sortValue"] + this.listSortMasters["operationResults"].find((its) => { @@ -1213,58 +1024,56 @@ export class ServicesListComponent implements OnInit { return false; } let updata = (prodata) => { - service.rate = prodata.progress; + service.rate = prodata.progress || 0; + 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.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"]; - } + })["sortValue"] + (service["rate"] > 100? service["status"] : ('\xa0\xa0\xa0' + service.rate + "%")); } - 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; + this.queryNsProgress(jobid, null, updata, operationType).then(() => { + let paramsObj = { + "ns_instance_id":id + }; + this.myhttp.nsDeleteInstance(paramsObj) + .subscribe((data) => { + if(data.status == "SUCCESS"){ + 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.notification1.notificationSuccess(service.serviceDomain,'deleteStarting',service["service-instance-name"] ||service["nsInstanceName"]) + }else { + 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.notification1.notificationFailed(service.serviceDomain,'deleteStarting',service["service-instance-name"] ||service["nsInstanceName"]) + return false; + } + let hasUndone = this.tableData.some((item) => { + return item.rate < 100; + }) + if (!hasUndone) { + setTimeout(() => { + this.getTableData(); + }, 1000) + } }) - if (!hasUndone) { - setTimeout(() => { - this.getTableData(); - }, 1000) - } - }) + }) }) } stopNsService(id, obj) { - let mypromise = new Promise((res, rej) => { - this.myhttp.stopNsService(id, obj) + let paramsObj = { + "ns_instance_id":id + } + return new Promise((res, rej) => { + this.myhttp.stopNsService(paramsObj, obj) .subscribe((data) => { this.loadingAnimateShow = false; if (data.status == "FAILED") { @@ -1275,87 +1084,77 @@ export class ServicesListComponent implements OnInit { res(data.jobId); }) }) - return mypromise; } queryProgress(obj, callback) { - let mypromise = new Promise((res, rej) => { + return new Promise( res => { + let operationTypeObj = {operationType:obj.operationType}; let errorNums = 180; - let requery = () => { - this.myhttp.getProgress(obj) + let requeryCcvpn = () => { + this.myhttp.getProgress(obj,operationTypeObj) .subscribe((data) => { - if (data.status == "FAILED") { + if (data.status === "FAILED") { callback({ progress: 255, status: "Failed" }); - return false; - } - if (data.operationStatus == null || data.operationStatus.progress == undefined) { + }else if (data.operationStatus === null || data.operationStatus.progress === undefined) { errorNums--; - if (errorNums == 0) { + if (errorNums === 0) { callback({ progress: 255, status: "time over" }); return false; } - setTimeout(() => { - requery(); - }, 10000) - return false; - } - if (data.operationStatus.progress > 100) { + this.progressCcvpnOutTimer = setTimeout(()=>{ + requeryCcvpn(); + },10000); + }else if (data.operationStatus.progress > 100) { callback({ progress: 255, status: "time over" }); - return false; - } - if (data.operationStatus.progress < 100) { + }else if (data.operationStatus.progress < 100) { callback(data.operationStatus); - setTimeout(() => { - requery(); - }, 5000) + this.progressingCcvpnTimer = setTimeout(()=>{ + requeryCcvpn(); + },5000); } else { res(data.operationStatus); } }) } - requery(); + requeryCcvpn(); }) - return mypromise; } queryNsProgress(jobid, id, callback, operationType) { - let mypromise = new Promise((res, rej) => { + return new Promise((res, rej) => { let errorNums = 180; - let requery = () => { - this.myhttp.getNsProgress(jobid, id, operationType) + let paramsObj = { + "responseId":0, + "serviceInstanceId":id, + "operationType":operationType + } + let requeryNs = () => { + this.myhttp.getNsProgress(jobid,paramsObj) .subscribe((data) => { if (data.status == "FAILED") { callback({ progress: 255, status: "Failed" }); - return false; - } - if (data.responseDescriptor == null || data.responseDescriptor.progress == undefined) { + }else if (data.responseDescriptor === null || data.responseDescriptor.progress === undefined) { errorNums--; - if (errorNums == 0) { + 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") { + this.progressNsOutTimer = setTimeout(()=>{ + requeryNs(); + },10000); + }else if (data.responseDescriptor.progress > 100 && data.responseDescriptor.status === "error") { callback({ progress: 255, status: data.responseDescriptor.statusDescription }); - return false; - } - if (data.responseDescriptor.progress < 100) { + }else if (data.responseDescriptor.progress < 100) { callback(data.responseDescriptor); - setTimeout(() => { - requery(); - }, 5000) + this.progressingNsTimer = setTimeout(()=>{ + requeryNs(); + },5000); } else { res(data); } }) }; - requery(); + requeryNs(); }); - return mypromise; } - } diff --git a/usecaseui-portal/src/app/views/services/services-list/top-card/top-card.component.html b/usecaseui-portal/src/app/views/services/services-list/top-card/top-card.component.html new file mode 100644 index 00000000..98e42ae7 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/top-card/top-card.component.html @@ -0,0 +1,18 @@ +<div class="top-list"> + <span class="round">{{serviceDomain}}</span> + <div class="top-list-text"> + <p> + <span>{{failedNum}}</span> + <span> {{"i18nTextDefine_Failed" | translate}} </span> + </p> + <p> + <span>{{successNum}}</span> + <span> {{"i18nTextDefine_Success" | translate}} </span> + </p> + <p> + <span>{{inProgressNum}}</span> + <span> {{"i18nTextDefine_InProgress" | translate}} </span> + </p> + <p class="service-description"> {{serviceDetailName | translate}} </p> + </div> +</div>
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/services/services-list/top-card/top-card.component.less b/usecaseui-portal/src/app/views/services/services-list/top-card/top-card.component.less new file mode 100644 index 00000000..a235b1e6 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/top-card/top-card.component.less @@ -0,0 +1,65 @@ +.top-list{ + position: relative; + width:100%; + max-width:400px; + height:170px; + background:url("/assets/images/servicelist-e2e.png") no-repeat; + background-size: 100% 100%; + border-radius:2px; + .round{ + position: absolute; + width: 60px; + height: 60px; + line-height: 60px; + text-align: center; + background:#E0EDFF; + border:2px solid rgba(224,237,255,1); + border-radius: 50%; + font-size:16px; + font-family:ArialMT; + color:#3C4F8C; + transition: .5s; + top: 42%; + margin-top: -30px; + left: 15%; + } + .top-list-text{ + position: absolute; + text-align: right; + line-height: 20px; + right: 12%; + color: #fff; + p{ + height: 28px; + margin-bottom: 0; + padding-left: 5px; + font-size: 14px; + clear: both; + span{ + display: inline-block; + float: right; + font-weight: 500; + text-align: right; + } + span:nth-child(1){ + font-size: 18px; + margin-left: 15px; + } + span:nth-child(2){ + width: 85px; + font-size: 16px; + } + } + p:nth-child(1){ + margin-top: 25px; + } + .service-description{ + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + color: #3C4F8C; + + } + } +}
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/services/services.component.spec.ts b/usecaseui-portal/src/app/views/services/services-list/top-card/top-card.component.spec.ts index 2e76b9f9..b2d2cbb4 100644 --- a/usecaseui-portal/src/app/views/services/services.component.spec.ts +++ b/usecaseui-portal/src/app/views/services/services-list/top-card/top-card.component.spec.ts @@ -1,20 +1,20 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { ServicesComponent } from './services.component'; +import { TopCardComponent } from './top-card.component'; -describe('ServicesComponent', () => { - let component: ServicesComponent; - let fixture: ComponentFixture<ServicesComponent>; +describe('TopCardComponent', () => { + let component: TopCardComponent; + let fixture: ComponentFixture<TopCardComponent>; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ ServicesComponent ] + declarations: [ TopCardComponent ] }) .compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(ServicesComponent); + fixture = TestBed.createComponent(TopCardComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/usecaseui-portal/src/app/views/services/services-list/top-card/top-card.component.ts b/usecaseui-portal/src/app/views/services/services-list/top-card/top-card.component.ts new file mode 100644 index 00000000..6004fb8e --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/top-card/top-card.component.ts @@ -0,0 +1,19 @@ +import { Component, OnInit, Input } from '@angular/core'; + +@Component({ + selector: 'app-top-card', + templateUrl: './top-card.component.html', + styleUrls: ['./top-card.component.less'] +}) +export class TopCardComponent implements OnInit { + @Input() serviceDomain: string; + @Input() failedNum: number; + @Input() successNum: number; + @Input() inProgressNum: number; + @Input() serviceDetailName: string; + constructor() { } + + ngOnInit() { + } + +} diff --git a/usecaseui-portal/src/app/views/services/services.component.html b/usecaseui-portal/src/app/views/services/services.component.html deleted file mode 100644 index 10142833..00000000 --- a/usecaseui-portal/src/app/views/services/services.component.html +++ /dev/null @@ -1,18 +0,0 @@ -<!-- - 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.ts b/usecaseui-portal/src/app/views/services/services.component.ts deleted file mode 100644 index eec235b4..00000000 --- a/usecaseui-portal/src/app/views/services/services.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -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() { - } - -} |