Feature-5950: Management of quotas in VIM Account 06/10806/6 release-v11.0-start v11.0.0 v11.0.0rc1 v11.0.0rc2
authorSANDHYA.JS <sandhya.j@tataelxsi.co.in>
Sat, 15 May 2021 10:05:22 +0000 (15:35 +0530)
committerrbara <barath.r@tataelxsi.co.in>
Fri, 23 Jul 2021 11:57:07 +0000 (13:57 +0200)
 * Showing the pie/doughnut chart for the Openstack VIM resources
 * Available in dashboard, VIM Account section and NSInstantiate section.

Change-Id: I64bec0b724accc7ea733f509ec5aef7c0d09662e
Signed-off-by: SANDHYA.JS <sandhya.j@tataelxsi.co.in>
23 files changed:
package.json
src/app/AppModule.ts
src/app/dashboard/DashboardComponent.html
src/app/dashboard/DashboardComponent.ts
src/app/dashboard/DashboardModule.ts
src/app/packages/instantiate-ns/InstantiateNsComponent.html
src/app/packages/instantiate-ns/InstantiateNsComponent.ts
src/app/utilities/vim-accounts-action/VimAccountsActionComponent.html
src/app/utilities/vim-accounts-action/VimAccountsActionComponent.ts
src/app/vim-accounts/Resources-Overview/ResourcesOverviewComponent.html [new file with mode: 0644]
src/app/vim-accounts/Resources-Overview/ResourcesOverviewComponent.scss [new file with mode: 0644]
src/app/vim-accounts/Resources-Overview/ResourcesOverviewComponent.ts [new file with mode: 0644]
src/app/vim-accounts/Resources-Overview/SharedModule.ts [new file with mode: 0644]
src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.ts
src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.ts
src/assets/i18n/de.json
src/assets/i18n/en.json
src/assets/i18n/es.json
src/assets/i18n/pt.json
src/assets/scss/app.scss
src/models/CommonModel.ts
src/models/VimAccountModel.ts
tsconfig.json

index 6f33eb4..3f16dec 100644 (file)
@@ -40,6 +40,7 @@
     "angular-notifier": "^6.0.1",
     "bootstrap": "^4.4.1",
     "chart.js": "^2.8.0",
+    "chartjs-plugin-labels": "^1.1.0",
     "codemirror": "^5.51.0",
     "core-js": "^2.5.4",
     "d3": "^5.9.2",
index 70f10dc..f36b8bf 100644 (file)
@@ -69,6 +69,7 @@ import { ProjectLinkComponent } from 'ProjectLinkComponent';
 import { ProjectsActionComponent } from 'ProjectsAction';
 import { ScalingComponent } from 'ScalingComponent';
 import { SDNControllerActionComponent } from 'SDNControllerActionComponent';
+import { SharedModule } from 'SharedModule';
 import { ShowInfoComponent } from 'ShowInfoComponent';
 import { SwitchProjectComponent } from 'SwitchProjectComponent';
 import { UsersActionComponent } from 'UsersActionComponent';
@@ -147,7 +148,8 @@ const customNotifierOptions: NotifierOptions = {
         NgSelectModule,
         RouterModule.forRoot(appRoutes, { useHash: false, relativeLinkResolution: 'legacy' }),
         NgIdleKeepaliveModule.forRoot(),
-        LoaderModule
+        LoaderModule,
+        SharedModule
     ],
     providers: [
         {
index 5b09dc9..a54351b 100644 (file)
@@ -133,6 +133,33 @@ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.i
                 </div>
             </div>
         </div>
+        <div class="row mb-2">
+            <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
+                <div class="custom-card card mt-2 text-primary">
+                    <div class="text-center header-style pt-2">{{'PAGE.VIMDETAILS.VIMRESOURCES' | translate}}</div>
+                    <div class="row p-2">
+                        <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
+                            <div class="form-row">
+                                <div class="form-group col-md-6">
+                                    <label for="vimType">{{'PAGE.VIMDETAILS.VIMTYPE' | translate}}</label>
+                                    <ng-select (change)="getSelectedVimTypeList($event.value)" [clearable]="false"
+                                        placeholder="{{'SELECT' | translate}}" [items]="vimTypes" bindLabel="title"
+                                        bindValue="value" id="vimType"></ng-select>
+                                </div>
+                                <div class="form-group col-md-6">
+                                    <label for="vimList">{{'PAGE.VIMDETAILS.NAME' | translate}}</label>
+                                    <ng-select (change)="getSelectedVIMDetails($event)" [clearable]="false"
+                                        placeholder="{{'SELECT' | translate}}" [items]="vimList" bindLabel="name"
+                                        bindValue="name" id="vimList"></ng-select>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <app-resources-overview *ngIf="selectedVIMDetails !== null && selectedVIMDetails !== undefined"
+                        [resourcesData]="selectedVIMDetails"></app-resources-overview>
+                </div>
+            </div>
+        </div>
     </div>
     <div class="col-xs-3 col-sm-12 col-md-12 col-lg-3 col-xl-3 p-0">
         <div class="custom-card">
index 56b79a4..2feef7c 100644 (file)
  */
 import { Component, Injector, OnInit } from '@angular/core';
 import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
 import { AuthenticationService } from 'AuthenticationService';
 import { Chart } from 'chart.js';
-import { ERRORDATA } from 'CommonModel';
+import 'chartjs-plugin-labels';
+import { ERRORDATA, TYPESECTION, VIM_TYPES } from 'CommonModel';
 import { environment } from 'environment';
 import { NSDDetails } from 'NSDModel';
 import { NSInstanceDetails } from 'NSInstanceModel';
@@ -33,6 +35,7 @@ import { Observable, Subscription } from 'rxjs';
 import { SDNControllerModel } from 'SDNControllerModel';
 import { SharedService } from 'SharedService';
 import { ProjectRoleMappings, UserDetail } from 'UserModel';
+import { isNullOrUndefined } from 'util';
 import { VimAccountDetails } from 'VimAccountModel';
 import { VNFInstanceDetails } from 'VNFInstanceModel';
 
@@ -108,6 +111,18 @@ export class DashboardComponent implements OnInit {
     /** List of NS Success Instances @public */
     public nsRunningInstance: string[] = [];
 
+    /** Contains VIM Account details @public */
+    public vimData: VimAccountDetails[] = [];
+
+    /** Contains Selected VIM Details @public */
+    public selectedVIMDetails: VimAccountDetails = null;
+
+    /** List of VIM_TYPES @public */
+    public vimTypes: TYPESECTION[] = VIM_TYPES;
+
+    /** Array holds Vim data filtered with selected vimtype  */
+    public vimList: VimAccountDetails[] = [];
+
     /** List of color for Instances @private */
     private backgroundColor: string[] = [];
 
@@ -159,6 +174,9 @@ export class DashboardComponent implements OnInit {
     /** Contians hour converter @private */
     private hourConverter: number = 3600;
 
+    /** Notifier service to popup notification @private */
+    private notifierService: NotifierService;
+
     constructor(injector: Injector) {
         this.injector = injector;
         this.restService = this.injector.get(RestService);
@@ -166,6 +184,7 @@ export class DashboardComponent implements OnInit {
         this.projectService = this.injector.get(ProjectService);
         this.sharedService = this.injector.get(SharedService);
         this.translateService = this.injector.get(TranslateService);
+        this.notifierService = this.injector.get(NotifierService);
     }
 
     /**
@@ -314,6 +333,12 @@ export class DashboardComponent implements OnInit {
                         el.style.cursor = item[0] ? 'pointer' : 'default';
                     }
                 },
+                plugins: {
+                    labels: {
+                        // render 'label', 'value', 'percentage', 'image' or custom function, default is 'percentage'
+                        render: 'value'
+                    }
+                },
                 legend: { display: false },
                 scales: {
                     xAxes: [{
@@ -353,6 +378,7 @@ export class DashboardComponent implements OnInit {
         this.vimAccountCountSub = this.restService.getResource(environment.VIMACCOUNTS_URL)
             .subscribe((vimAccountData: VimAccountDetails[]): void => {
                 this.vimAccountCount = vimAccountData.length;
+                this.vimData = vimAccountData;
             }, (error: ERRORDATA): void => {
                 this.restService.handleError(error, 'get');
             });
@@ -368,6 +394,22 @@ export class DashboardComponent implements OnInit {
             });
     }
 
+    /** Get Vim data filtered by the selected Vim Type @public */
+    public getSelectedVimTypeList(selectedVIMType: string): void {
+        this.vimList = this.vimData.filter((vimData: VimAccountDetails): boolean =>
+            vimData.vim_type === selectedVIMType);
+
+    }
+
+    /** Get Selected VIM details @public */
+    public getSelectedVIMDetails(vimDetails: VimAccountDetails): void {
+        if (!isNullOrUndefined(vimDetails.resources)) {
+            this.selectedVIMDetails = vimDetails;
+        } else {
+            this.notifierService.notify('error', this.translateService.instant('RESOURCESNOTFOUND'));
+        }
+    }
+
     /**
      * Lifecyle Hooks the trigger before component is deleted
      */
index 4d882e2..82b27c0 100644 (file)
@@ -26,10 +26,12 @@ import { FlexLayoutModule } from '@angular/flex-layout';
 import { FormsModule } from '@angular/forms';
 import { RouterModule, Routes } from '@angular/router';
 import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
+import { NgSelectModule } from '@ng-select/ng-select';
 import { TranslateModule } from '@ngx-translate/core';
 import { DashboardComponent } from 'DashboardComponent';
 import { LoaderModule } from 'LoaderModule';
 import { ChartsModule } from 'ng2-charts';
+import { SharedModule } from 'SharedModule';
 
 /** To halndle project information */
 const projectInfo: {} = { title: '{project}', url: '/' };
@@ -50,8 +52,8 @@ const routes: Routes = [
  * @NgModule takes a metadata object that tells Angular how to compile and run module code.
  */
 @NgModule({
-    imports: [FormsModule, CommonModule, HttpClientModule, FlexLayoutModule, TranslateModule,
-        ChartsModule, RouterModule.forChild(routes), NgbModule, LoaderModule],
+    imports: [FormsModule, CommonModule, HttpClientModule, FlexLayoutModule, TranslateModule, NgSelectModule,
+        ChartsModule, RouterModule.forChild(routes), NgbModule, LoaderModule, SharedModule],
     declarations: [DashboardComponent]
 })
 /** Exporting a class @exports DashboardModule */
index dabd469..2bbd837 100644 (file)
@@ -57,13 +57,30 @@ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.i
         <div class="form-group row">
             <label class="col-sm-4 col-form-label"
                 for="vimAccountId">{{'PAGE.INSTANCEINSTANTIATE.VIMACCOUNT' | translate}}*</label>
-            <div class="col-sm-8">
-                <ng-select [items]="vimAccountSelect" bindLabel="name" bindValue="_id"
+            <div class="col-sm-6">
+                <ng-select  (change)="getSelectedVIMDetails($event)" [items]="vimAccountSelect" bindLabel="name" bindValue="_id"
                     placeholder="{{'SELECT' | translate}} {{'PAGE.INSTANCEINSTANTIATE.VIMACCOUNT' | translate}}"
                     formControlName="vimAccountId" [(ngModel)]="vimAccountId" id="vimAccountId"
                     [ngClass]="{ 'is-invalid': submitted && f.vimAccountId.errors }" required>
                 </ng-select>
             </div>
+            <div class="col-sm-2" *ngIf="selectedVIMDetails !== null && selectedVIMDetails !== undefined" >
+                <ng-template #graphTitle>
+                    <span class="text-primary"><strong>{{'PAGE.VIMDETAILS.VIMRESOURCES' | translate}}</strong></span>
+                    <button class="button-xs close" type="button" (click)="chart.close()">
+                        <i class="fas fa-times-circle text-danger"></i>
+                    </button>
+                </ng-template>
+                <ng-template #graphContent>
+                    <app-resources-overview *ngIf="selectedVIMDetails !== null && selectedVIMDetails !== undefined"
+                    [resourcesData]="selectedVIMDetails"></app-resources-overview>
+                </ng-template>
+                <button type="button" class="btn btn-primary" placement="left" container="body"
+                    [ngbPopover]="graphContent" triggers="manual" #chart="ngbPopover"
+                    (click)="chart.open()" [autoClose]="'outside'" [popoverTitle]="graphTitle" popoverClass="resources-chart-popover">
+                    <i class="fas fa-chart-pie"></i>
+                </button>
+            </div>
         </div>
         <div class="form-group row">
             <label class="col-sm-4 col-form-label"
index 74569f1..1043f9a 100644 (file)
@@ -75,6 +75,9 @@ export class InstantiateNsComponent implements OnInit {
   /** Give the message for the loading @public */
   public message: string = 'PLEASEWAIT';
 
+  /** Contains Selected VIM Details @public */
+  public selectedVIMDetails: VimAccountDetails = null;
+
   /** Element ref for fileInputConfig @public */
   @ViewChild('fileInputConfig', { static: true }) public fileInputConfig: ElementRef;
 
@@ -284,4 +287,11 @@ export class InstantiateNsComponent implements OnInit {
     this.fileInputConfigLabel.nativeElement.innerText = files[0].name;
     this.fileInputConfig.nativeElement.value = null;
   }
+
+  /** Get Selected VIM details @public */
+  public getSelectedVIMDetails(vimDetails: VimAccountDetails): void {
+    if (!isNullOrUndefined(vimDetails.resources)) {
+      this.selectedVIMDetails = vimDetails;
+    }
+  }
 }
index 52c9200..515066e 100644 (file)
@@ -31,6 +31,21 @@ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.i
             </li>
         </ul>
     </ng-template>
+    <ng-template #graphTitle>
+        <span class="text-primary"><strong>{{'PAGE.VIMDETAILS.VIMRESOURCES' | translate}}</strong></span>
+        <button class="button-xs close" type="button" (click)="chart.close()">
+            <i class="fas fa-times-circle text-danger"></i>
+        </button>
+    </ng-template>
+    <ng-template #graphContent>
+        <app-resources-overview [resourcesData]="value"></app-resources-overview>
+    </ng-template>
+    <button type="button" class="btn btn-primary" placement="left" container="body"
+        [ngbPopover]="graphContent" triggers="manual" #chart="ngbPopover"
+        (click)="chart.open()" [autoClose]="'outside'" [popoverTitle]="graphTitle" popoverClass="resources-chart-popover"
+        [disabled]="value.resources === null">
+        <i class="fas fa-chart-pie"></i>
+    </button>
     <button type="button" class="btn btn-primary" (click)="vimInfo()" placement="top" container="body"
         ngbTooltip="{{'INFO' | translate}}">
         <i class="fas fa-info icons"></i>
index 57f1f64..ffa0340 100644 (file)
@@ -24,8 +24,9 @@ import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
 import { MODALCLOSERESPONSEDATA } from 'CommonModel';
 import { DeleteComponent } from 'DeleteComponent';
 import { NSInstanceDetails } from 'NSInstanceModel';
+import { ResourcesOverviewComponent } from 'ResourcesOverviewComponent';
 import { SharedService } from 'SharedService';
-import { VIMData } from 'VimAccountModel';
+import { VimAccountDetails, VIMData } from 'VimAccountModel';
 
 /**
  * Creating component
@@ -101,4 +102,10 @@ export class VimAccountsActionComponent implements OnInit {
             }
         });
     }
+
+    /** Show VIM Resources Data @public */
+    public showVIMResources(vimDetails: VimAccountDetails): void {
+        const modalRef: NgbModalRef = this.modalService.open(ResourcesOverviewComponent, {backdrop: 'static'});
+        modalRef.componentInstance.resourcesData = vimDetails;
+    }
 }
diff --git a/src/app/vim-accounts/Resources-Overview/ResourcesOverviewComponent.html b/src/app/vim-accounts/Resources-Overview/ResourcesOverviewComponent.html
new file mode 100644 (file)
index 0000000..39990b5
--- /dev/null
@@ -0,0 +1,60 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+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.
+
+Author: SANDHYA JS (sandhya.j@tataelxsi.co.in)
+-->
+<div class="row">
+    <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
+        <div class="row d-flex flex-row justify-content-between px-3 py-2">
+            <div class="d-flex align-items-center header-style">{{resourcesData.name}}</div>
+            <span class="button">
+                <label class="switch ml-1">
+                    <input type="checkbox" (change)="changeChartType($event.target.checked)">
+                    <div class="slider round">
+                        <span class="on">{{ 'PAGE.VIMDETAILS.DOUGHNUT' | translate }}</span>
+                        <span class="off">{{ 'PAGE.VIMDETAILS.PIE' | translate }}</span>
+                    </div>
+                </label>
+            </span>
+        </div>
+        <ng-container *ngFor="let showData of chartData">
+            <div class="header-style ml-3 mt-2">{{showData.heading}}</div>
+            <div class="row mt-2">
+                <div class="col-xs-{{12/showData.length}} col-sm-{{12/showData.length}} col-md-{{12/showData.length}} col-lg-{{12/showData.length}} col-xl-{{12/showData.length}}"
+                    *ngFor="let list of showData.data;let i = index;">
+                    <div class="chartData-card card text-center text-primary">
+                        <canvas class="my-2"
+                            baseChart
+                            [data]="list.data"
+                            [labels]="chartLabels"
+                            [chartType]="chartType"
+                            [options]="chartOptions"
+                            [legend]="chartLegend"
+                            [colors]="list.colorValues">
+                        </canvas>
+                        <div class="card-body">
+                            <h5 class="card-title"><strong>{{list.title}}</strong></h5>
+                            <p class="card-text">
+                                {{ (list.title === 'Floating IPs' ? 'PAGE.VIMDETAILS.ALLOCATED' : 'PAGE.VIMDETAILS.USED') | translate }}
+                                {{list.values.used}}{{ list.title === 'RAM' || list.title === 'Volume Storage' ? list.values.used > 0 ? 'GB' : 'Bytes' : '' }}
+                                of {{list.values.total}}{{ list.title === 'RAM' || list.title === 'Volume Storage' ? 'GB' : '' }}
+                            </p>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </ng-container>
+    </div>
+</div>
\ No newline at end of file
diff --git a/src/app/vim-accounts/Resources-Overview/ResourcesOverviewComponent.scss b/src/app/vim-accounts/Resources-Overview/ResourcesOverviewComponent.scss
new file mode 100644 (file)
index 0000000..e042092
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ 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.
+
+ Author: SANDHYA JS (sandhya.j@tataelxsi.co.in)
+*/
+@import "../../../assets/scss/mixins/mixin";
+@import "../../../assets/scss/variable";
+.chartData-card {
+    word-wrap: break-word;
+    @include box-shadow(0px, 1px, 15px, 0px, rgba(69, 90, 100, 0.1));
+    @include transition(all, 0.2s, null, null);
+    @include roundedCorners(5);
+    @include border(all, 1, solid, rgba(238, 238, 238, 0.75));
+    color: $white;
+    .card-body {
+        @include padding-value(5, 5, 5, 10);
+    }
+}
+.switch {
+    @include position_value(relative, null, null, null, null);
+    @include flexbox(inline-block, null, null, null, null, null);
+    @include wh-value(70px, 20px);
+    @include margin-value(0, 0, 0, 0);
+    input {
+        opacity: 0;
+        @include wh-value(0px, 0px);
+        &:checked + .slider {
+            @include background(null, $gray-400, null, null, null);
+            &:before {
+                @include background(null, $primary, null, null, null);
+                left: 22px;
+                -webkit-transform: translateX(26px);
+                -ms-transform: translateX(26px);
+                transform: translateX(26px);
+            }
+            .on {
+                @include flexbox(block, null, null, null, null, null);
+            }
+            .off {
+                @include flexbox(none, null, null, null, null, null);
+            }
+        }
+    }
+    .slider {
+        @include position_value(absolute, 0, 0, 0, 0);
+        cursor: pointer;
+        @include background(null, $gray-400, null, null, null);
+        -webkit-transition: 0.4s;
+        transition: 0.4s;
+        box-shadow: 0 0 1px $gray-400;
+        &.round {
+            @include roundedCorners(30);
+            &:before {
+                @include roundedCornersPercentage(50%);
+            }
+        }
+        &:before {
+            @include position_value(absolute, null, null, -2px, 0px);
+            @include wh-value(25px, 25px);
+            @include background(null, $primary, null, null, null);
+            content: "";
+            -webkit-transition: 0.4s;
+            transition: 0.4s;
+            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
+        }
+        .on {
+            @include flexbox(none, null, null, null, null, null);
+            @include position_value(absolute, 50%, null, null, 35% !important);
+        }
+        .on,
+        .off {
+            @include position_value(absolute, 50%, null, null, 55%);
+            color: $primary;
+            transform: translate(-50%, -50%);
+            @include font(null, 10px, bold);
+        }
+    }
+}
diff --git a/src/app/vim-accounts/Resources-Overview/ResourcesOverviewComponent.ts b/src/app/vim-accounts/Resources-Overview/ResourcesOverviewComponent.ts
new file mode 100644 (file)
index 0000000..2d21ade
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ 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.
+
+ Author: SANDHYA JS (sandhya.j@tataelxsi.co.in)
+*/
+/**
+ * @file Resources Overview Component
+ */
+import { Component, Injector, Input, OnChanges } from '@angular/core';
+import { TranslateService } from '@ngx-translate/core';
+import { ChartOptions, ChartType } from 'chart.js';
+import 'chartjs-plugin-labels';
+import { CONSTANTNUMBER } from 'CommonModel';
+import {
+    CHARTRANGE,
+    CHARTVALUES,
+    Color,
+    CONFIGRESOURCESTITLE,
+    RANGECOLOR,
+    RESOURCESCHARTDATA,
+    RESOURCESDATA,
+    VimAccountDetails
+} from 'VimAccountModel';
+/**
+ * Creating component
+ * @Component takes ResourcesOverviewComponent.html as template url
+ */
+@Component({
+    selector: 'app-resources-overview',
+    templateUrl: './ResourcesOverviewComponent.html',
+    styleUrls: ['./ResourcesOverviewComponent.scss']
+})
+/** Exporting a class @exports ResourcesOverviewComponent */
+export class ResourcesOverviewComponent implements OnChanges {
+    /** To inject services @public */
+    public injector: Injector;
+    /** handle translate @public */
+    public translateService: TranslateService;
+    /** Chart Options @public */
+    public chartOptions: ChartOptions = {
+        responsive: true,
+        plugins: {
+            labels: {
+                // render 'label', 'value', 'percentage', 'image' or custom function, default is 'percentage'
+                render: 'value'
+            }
+        }
+    };
+    /** Chart Lables @public */
+    public chartLabels: String[] = [];
+    /** Chart Type @public */
+    public chartType: ChartType = 'doughnut';
+    /** Chart Legend @public */
+    public chartLegend: boolean = false;
+    /** Input data of Resources from parent @public */
+    @Input() public resourcesData: VimAccountDetails;
+    /** Resources data for generating chart @public */
+    public chartData: RESOURCESDATA[] = [];
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.translateService = this.injector.get(TranslateService);
+    }
+    /**
+     * Lifecyle Hooks the trigger while changes in the input
+     */
+    public ngOnChanges(): void {
+        this.callChartData();
+    }
+    /**
+     * Call the graphData
+     */
+    public callChartData(): void {
+        this.chartLabels = [];
+        this.chartLabels.push(this.translateService.instant('PAGE.VIMDETAILS.USED'), this.translateService.instant('PAGE.VIMDETAILS.FREE'));
+        this.createVIMResourceChartData(this.resourcesData);
+    }
+    /**
+     * Get the selected VIM Account Details
+     * @param vimAccountData: VimAccountDetails
+     */
+    public createVIMResourceChartData(vimAccountData: VimAccountDetails): void {
+        this.chartData = [];
+        if (vimAccountData.resources !== null && vimAccountData.resources !== undefined) {
+            if (vimAccountData.resources.compute !== null && vimAccountData.resources.compute !== undefined) {
+                const computeList: RESOURCESCHARTDATA[] = this.createResourcesData(vimAccountData.resources.compute, 'ram');
+                this.chartData.push(this.generateResourceObject('Compute', computeList.length, computeList));
+            }
+            if (vimAccountData.resources.storage !== null && vimAccountData.resources.storage !== undefined) {
+                const storageList: RESOURCESCHARTDATA[] = this.createResourcesData(vimAccountData.resources.storage, 'null');
+                this.chartData.push(this.generateResourceObject('Volume', storageList.length, storageList));
+            }
+            if (vimAccountData.resources.network !== null && vimAccountData.resources.network !== undefined) {
+                const networkList: RESOURCESCHARTDATA[] = this.createResourcesData(vimAccountData.resources.network, 'null');
+                this.chartData.push(this.generateResourceObject('Network', networkList.length, networkList));
+            }
+        }
+    }
+    /**
+     * Generate the Resources Data and return @public
+     * @param compute {}
+     * @param keyValidate string
+     * @returns RESOURCESCHARTDATA[]
+     */
+    public createResourcesData(compute: {}, keyValidate?: string): RESOURCESCHARTDATA[] {
+        const getCompute: string[] = Object.keys(compute);
+        const getData: RESOURCESCHARTDATA[] = [];
+        const range: CHARTRANGE = { percentage: 100, nearlyFull: 75, full: 100 };
+        getCompute.forEach((key: string): void => {
+            let usedColor: string = RANGECOLOR.used;
+            const getValuesUsedFree: number[] = Object.values(compute[key]);
+            const total: number = key === keyValidate ? getValuesUsedFree[0] / CONSTANTNUMBER.oneGB : getValuesUsedFree[0];
+            const used: number = key === keyValidate ? getValuesUsedFree[1] / CONSTANTNUMBER.oneGB : getValuesUsedFree[1];
+            const remaining: number = total - used;
+            const usedPercentage: number = (used / total) * range.percentage;
+            if (usedPercentage >= range.nearlyFull && usedPercentage < range.full) {
+                usedColor = RANGECOLOR.nearlyfull;
+            }
+            if (usedPercentage === range.full) {
+                usedColor = RANGECOLOR.full;
+            }
+            getData.push(this.generateChartData(key, { total, used, remaining }, [{ backgroundColor: [usedColor, '#b9bcc3'] }]));
+        });
+        return getData;
+    }
+    /**
+     * Generate chart data @public
+     * @param setTitle string
+     * @param setValues CHARTVALUES
+     * @returns RESOURCESCHARTDATA
+     */
+    public generateChartData(setTitle: string, setValues: CHARTVALUES, setColor: Color[]): RESOURCESCHARTDATA {
+        return {
+            title: CONFIGRESOURCESTITLE[setTitle],
+            values: this.generateChartDataValues(setValues.total, setValues.used, setValues.remaining),
+            data: [setValues.used, setValues.remaining],
+            colorValues: setColor
+        };
+    }
+    /**
+     * Generate values for the chart data @public
+     * @param setTotal number
+     * @param setUsed number
+     * @param setRemaining number
+     * @returns CHARTVALUES
+     */
+    public generateChartDataValues(setTotal: number, setUsed: number, setRemaining: number): CHARTVALUES {
+        return {
+            total: setTotal !== null ? setTotal : 0,
+            used: setUsed !== null ? setUsed : 0,
+            remaining: setRemaining !== null ? setRemaining : 0
+        };
+    }
+    /**
+     * Generate the resource data object @public
+     * @param setHeading string
+     * @param setLength number
+     * @param setData RESOURCESCHARTDATA[]
+     * @returns RESOURCESDATA
+     */
+    public generateResourceObject(setHeading: string, setLength: number, setData: RESOURCESCHARTDATA[]): RESOURCESDATA {
+        return {
+            heading: setHeading,
+            length: setLength,
+            data: setData
+        };
+    }
+    /**
+     * Chart type can be changed
+     * @param isChecked: boolean
+     */
+    public changeChartType(isChecked: boolean): void {
+        if (isChecked) {
+            this.chartType = 'pie';
+        } else {
+            this.chartType = 'doughnut';
+        }
+        this.callChartData();
+    }
+}
diff --git a/src/app/vim-accounts/Resources-Overview/SharedModule.ts b/src/app/vim-accounts/Resources-Overview/SharedModule.ts
new file mode 100644 (file)
index 0000000..1b365f3
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ 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.
+
+ Author: SANDHYA JS (sandhya.j@tataelxsi.co.in)
+*/
+/**
+ * @file Shared Module.
+ */
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { TranslateModule } from '@ngx-translate/core';
+import { ChartsModule } from 'ng2-charts';
+import { ResourcesOverviewComponent } from 'ResourcesOverviewComponent';
+/**
+ * Creating @NgModule component for Modules
+ */
+@NgModule({
+    imports: [CommonModule, TranslateModule, ChartsModule],
+    declarations: [ResourcesOverviewComponent],
+    exports: [ResourcesOverviewComponent],
+    entryComponents: [ResourcesOverviewComponent]
+})
+/** Exporting a class @exports SharedModule */
+export class SharedModule {
+    /** Variables declared to avoid state-less class */
+    private sharedModule: string;
+}
index 3f44af5..daa9332 100644 (file)
@@ -48,8 +48,7 @@ import * as jsyaml from 'js-yaml';
 import { RestService } from 'RestService';
 import { SharedService } from 'SharedService';
 import { isNullOrUndefined } from 'util';
-import { FEATURES, VIMLOCATION, VIMLOCATIONDATA } from 'VimAccountModel';
-import { VimAccountDetails, VIMData } from 'VimAccountModel';
+import { VimAccountDetails } from 'VimAccountModel';
 
 /**
  * Creating component
@@ -80,9 +79,6 @@ export class NewVimaccountComponent implements OnInit {
   /** Showing more details of collapase */
   public isCollapsed: boolean = false;
 
-  /** Vim location values @public */
-  public getVIMLocation: VIMLOCATIONDATA[] = [];
-
   /** Check the Projects loading results @public */
   public isLocationLoadingResults: boolean = false;
 
index 5621b0f..18dffa0 100644 (file)
@@ -267,7 +267,8 @@ export class VimAccountDetailsComponent implements OnInit {
             type: vimAccountData.vim_type,
             operationalState: vimAccountData._admin.operationalState,
             description: vimAccountData.description,
-            instancesData: this.nsData
+            instancesData: this.nsData,
+            resources: vimAccountData.resources !== undefined ? vimAccountData.resources : null
         };
     }
 
index 5d67b03..7489891 100644 (file)
@@ -40,7 +40,7 @@
     "PACKAGES": "Pakete",
     "MODIFIED": "Geändert",
     "NODATAMSG": "Keine Daten in der Tabelle verfügbar",
-    "PRODUCTNAME":"Produktname",
+    "PRODUCTNAME": "Produktname",
     "IDENTIFIER": "Kennung",
     "DESCRIPTION": "Beschreibung",
     "DESIGNER": "Designer",
     "SCALE": "Rahmen",
     "DEFAULT": "Standard",
     "SOURCE": "Quelle",
+    "RESOURCESNOTFOUND": "Ressourcen nicht gefunden",
     "PAGE": {
         "DASHBOARD": {
             "DASHBOARD": "Instrumententafel",
             "BACKTOVIMACCOUNTS": "Zurück zu VimAccounts",
             "LOCATIONERROR": "Das Datencenter ist bereits am ausgewählten Speicherort verfügbar",
             "LOADSAMPLECONFIG": "Beispielkonfiguration laden",
-            "CLEARCONFIG": "Konfiguration löschen"
+            "CLEARCONFIG": "Konfiguration löschen",
+            "USED": "Benutzt",
+            "ALLOCATED": "Zugewiesen",
+            "FREE": "Kostenlos",
+            "VIMRESOURCES": "Übersicht über die VIM-Ressourcen",
+            "DOUGHNUT": "Krapfen",
+            "PIE": "Kuchen"
         },
         "WIMACCOUNTS": {
             "CREATEDSUCCESSFULLY": "WIM erfolgreich erstellt",
index c412e15..c1e4cd7 100644 (file)
     "SCALE": "Scale",
     "DEFAULT": "Default",
     "SOURCE": "Source",
+    "RESOURCESNOTFOUND": "Resources not found",
     "PAGE": {
         "DASHBOARD": {
             "DASHBOARD": "Dashboard",
             "BACKTOVIMACCOUNTS": "Back to VimAccounts",
             "LOCATIONERROR": "The Datacenter is already available in the selected location",
             "LOADSAMPLECONFIG": "Load Sample Config",
-            "CLEARCONFIG": "Clear Config"
+            "CLEARCONFIG": "Clear Config",
+            "USED": "Used",
+            "ALLOCATED": "Allocated",
+            "FREE": "Free",
+            "VIMRESOURCES": "VIM Resources Overview",
+            "DOUGHNUT": "Doughnut",
+            "PIE": "Pie"
         },
         "WIMACCOUNTS": {
             "CREATEDSUCCESSFULLY": "WIM Created Successfully",
index 55c9490..5a3920d 100644 (file)
@@ -40,7 +40,7 @@
     "PACKAGES": "Paquetes",
     "MODIFIED": "Modificado",
     "NODATAMSG": "No hay datos disponibles en la tabla",
-    "PRODUCTNAME":"Nombre del producto",
+    "PRODUCTNAME": "Nombre del producto",
     "IDENTIFIER": "Identificador",
     "DESCRIPTION": "Descripción",
     "DESIGNER": "Diseñador",
     "SCALE": "Escala",
     "DEFAULT": "por defecto",
     "SOURCE": "Fuente",
+    "RESOURCESNOTFOUND": "Recursos no encontrados",
     "PAGE": {
         "DASHBOARD": {
             "DASHBOARD": "Tablero",
             "BACKTOVIMACCOUNTS": "Volver a cuentas VIM",
             "LOCATIONERROR": "El centro de datos ya está disponible en la ubicación seleccionada",
             "LOADSAMPLECONFIG": "Cargar configuración de muestra",
-            "CLEARCONFIG": "Borrar configuración"
+            "CLEARCONFIG": "Borrar configuración",
+            "USED": "Usado",
+            "ALLOCATED": "Asignado",
+            "FREE": "Libre",
+            "VIMRESOURCES": "Descripción general de los recursos de VIM",
+            "DOUGHNUT": "Rosquilla",
+            "PIE": "Pastel"
         },
         "WIMACCOUNTS": {
             "CREATEDSUCCESSFULLY": "WIM Creado correctamente",
             "LEADER": "Líder",
             "LIVELOAD": "Cargando en vivo",
             "SETSECONDS": "Configurar temporizador",
-            "SERIES": "serie"
+            "SERIES": "serie",
+            "UPDATEDSUCCESSFULLY": "Repositorio OSM actualizado correctamente"
         }
     },
     "HTTPERROR": {
index b0f7985..65c9855 100644 (file)
@@ -40,7 +40,7 @@
     "MODIFIED": "Modificada",
     "PACKAGES": "Pacotes",
     "NODATAMSG": "Sem dados disponíveis na tabela",
-    "PRODUCTNAME":"Nome do Produto",
+    "PRODUCTNAME": "Nome do Produto",
     "IDENTIFIER": "Identificador",
     "DESCRIPTION": "Descrição",
     "DESIGNER": "Designer",
     "SCALE": "Escala",
     "DEFAULT": "Padrão",
     "SOURCE": "Fonte",
+    "RESOURCESNOTFOUND": "Recursos não encontrados",
     "PAGE": {
         "DASHBOARD": {
             "DASHBOARD": "painel de controle",
             "BACKTOVIMACCOUNTS": "Voltar para VimAccounts",
             "LOCATIONERROR": "O Datacenter já está disponível no local selecionado",
             "LOADSAMPLECONFIG": "Carregar configuração de amostra",
-            "CLEARCONFIG": "Limpar configuração"
+            "CLEARCONFIG": "Limpar configuração",
+            "USED": "Usava",
+            "ALLOCATED": "Alocada",
+            "FREE": "Livre",
+            "VIMRESOURCES": "Visão geral dos recursos do VIM",
+            "DOUGHNUT": "rosquinha",
+            "PIE": "torta"
         },
         "WIMACCOUNTS": {
             "CREATEDSUCCESSFULLY": "WIM criado com sucesso",
index 8dd8399..1f7ce6c 100644 (file)
@@ -37,7 +37,8 @@ body,
 .layout-wrapper,
 .CodeMirror-vscrollbar,
 .ng-sidebar,
-.runninginstances .popover-body {
+.runninginstances .popover-body,
+.resources-chart-popover .popover-body {
   &::-webkit-scrollbar {
     @include wh-value(10px, null);
   }
@@ -263,6 +264,14 @@ body {
       overflow-y: scroll;
     }
   }
+  .resources-chart-popover{
+    max-width: 60% !important;
+    @include font-family("Roboto");
+    .popover-body{
+      max-height: 60vh;
+      overflow-y: scroll;
+    }
+  }
   /****************************************************************************/
   /************************** Smart table custom design ***********************/
   /****************************************************************************/
index 7b51e9e..96d926d 100644 (file)
@@ -43,7 +43,8 @@ export enum CONSTANTNUMBER {
     paginationDefaultValue = 10,
     splitLongitude = 1,
     splitLatitude = 2,
-    timeOutDefaultSeconds = 5
+    timeOutDefaultSeconds = 5,
+    oneGB = 1024
 }
 /**
  * handle count @enum
@@ -333,3 +334,8 @@ export interface LOGINPARAMS {
     username?: string;
     password?: string;
 }
+/** Interface for the LABELVALUE */
+export interface LABELVALUE {
+    label: string;
+    value: string;
+}
index 0e02701..159b2c9 100644 (file)
@@ -18,9 +18,8 @@
 /**
  * @file  Model for VimAccount Details related information.
  */
-
+// tslint:disable: completed-docs
 import { NSInstanceDetails } from 'NSInstanceModel';
-
 /** Interface for VimAccountDetails */
 export interface VimAccountDetails {
     description: string;
@@ -35,12 +34,13 @@ export interface VimAccountDetails {
     vim_user: string;
     vim_type: string;
     name: string;
+    resources?: RESOURCES;
 }
 
 /** Interface for _ADMIN */
 interface ADMIN {
     projects_write: string[];
-    deployed: Deployed;
+    deployed?: Deployed;
     operationalState: string;
     modified: string;
     projects_read: string[];
@@ -106,6 +106,7 @@ export interface VIMData {
     description: string;
     page?: string;
     instancesData?: NSInstanceDetails[];
+    resources?: RESOURCES;
 }
 /** Interface for VIMLOCATION */
 export interface VIMLOCATION {
@@ -129,8 +130,61 @@ interface PROPERTIES {
     name: string;
     state: string;
 }
-/** Interface for the VIMLOCATIONDATA */
-export interface VIMLOCATIONDATA {
-    label: string;
-    value: string;
+/** Interface for the RESOURCES */
+export interface RESOURCES {
+    compute: object;
+    storage: object;
+    network: object;
+}
+/** Interface for the RESOURCESDATA */
+export interface RESOURCESDATA {
+    heading: string;
+    length: number;
+    data: RESOURCESCHARTDATA[];
+}
+/** Interface for the RESOURCESCHARTDATA */
+export interface RESOURCESCHARTDATA {
+    title: string;
+    values: CHARTVALUES;
+    data: number[];
+    colorValues: Color[];
+}
+/** Interface common use for the Chart */
+export interface CHARTVALUES {
+    total: number;
+    used?: number;
+    remaining?: number;
+}
+/** Interface for the CHARTRANGE */
+export interface CHARTRANGE {
+    percentage: number;
+    nearlyFull: number;
+    full: number;
+}
+/** Interface for the COLOR */
+export interface Color {
+    backgroundColor?: string[] | string;
+    borderColor?: string[] | string;
+}
+/** Constant Values for the resources titles */
+export enum CONFIGRESOURCESTITLE {
+    ram = 'RAM',
+    instances = 'Instances',
+    vcpus = 'VCPUs',
+    snapshots = 'Volume Snapshots',
+    storage = 'Volume Storage',
+    volumes = 'Volumes',
+    floating_ips = 'Floating IPs',
+    security_group = 'Security Group',
+    subnets = 'Subnets',
+    networks = 'Networks',
+    ports = 'Ports',
+    routers = 'Routers'
+}
+
+/** constant values for color */
+export enum RANGECOLOR {
+    used = '#29c3be',
+    nearlyfull = '#f0ad4e',
+    full = '#d9534f'
 }
index 7c024ea..d31012b 100644 (file)
             "OperationalModel": ["src/models/OperationalModel"],
             "OperationalAppConfigsComponent": ["src/app/operational-view/operational-view-app-configs/OperationalViewAppConfigsComponent"],
             "OperationalAppActionsComponent": ["src/app/operational-view/operational-view-app-actions/OperationalViewAppActionsComponent"],
-            "OperationalAppExecutedActionsComponent" : ["src/app/operational-view/operational-view-app-executed-actions/OperationalViewAppExecutedActionsComponent"]
+            "OperationalAppExecutedActionsComponent" : ["src/app/operational-view/operational-view-app-executed-actions/OperationalViewAppExecutedActionsComponent"],
+            "ResourcesOverviewComponent": ["src/app/vim-accounts/Resources-Overview/ResourcesOverviewComponent"],
+            "SharedModule": ["src/app/vim-accounts/Resources-Overview/SharedModule"]
         }
     }
 }
\ No newline at end of file