mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-29 21:54:13 +01:00
Implement metrics gauge
This commit is contained in:
parent
64bcbfde00
commit
301a9c57c2
284
src/ui_ng/src/app/shared/gauge/gauge.component.css
Normal file
284
src/ui_ng/src/app/shared/gauge/gauge.component.css
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
.esxc-gauge-container {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gauge track color
|
||||||
|
*
|
||||||
|
* TODO: we should make this configurable in the directive
|
||||||
|
*/
|
||||||
|
|
||||||
|
.esxc-gauge-circle-bg {
|
||||||
|
background-color: #EEE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gauge bar
|
||||||
|
*/
|
||||||
|
|
||||||
|
.esxc-gauge-circle-fill {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: transparent;
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gauge center area
|
||||||
|
*/
|
||||||
|
|
||||||
|
.esxc-gauge-circle-inner {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gauge caption
|
||||||
|
*/
|
||||||
|
|
||||||
|
.esxc-gauge-circle-caption {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-bar-one {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Small size gauge sizing
|
||||||
|
*/
|
||||||
|
|
||||||
|
.esxc-gauge-small .esxc-gauge-container {
|
||||||
|
width: 100px;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-small .esxc-gauge-circle-fill {
|
||||||
|
height: 100px;
|
||||||
|
border-radius: 50px;
|
||||||
|
clip: rect(50px, 100px, 100px, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-small .esxc-gauge-circle-bg {
|
||||||
|
height: 100px;
|
||||||
|
border-radius: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-small .esxc-gauge-circle-inner {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
border-radius: 40px;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-small .esxc-gauge-circle-caption {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Medium size gauge sizing
|
||||||
|
*/
|
||||||
|
|
||||||
|
.esxc-gauge-medium .esxc-gauge-container {
|
||||||
|
width: 130px;
|
||||||
|
height: 65px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-medium .esxc-gauge-circle-fill {
|
||||||
|
height: 130px;
|
||||||
|
border-radius: 130px;
|
||||||
|
clip: rect(65px, 130px, 130px, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-medium .esxc-gauge-circle-bg {
|
||||||
|
height: 130px;
|
||||||
|
border-radius: 65px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-medium .esxc-gauge-circle-inner {
|
||||||
|
height: 120px;
|
||||||
|
width: 120px;
|
||||||
|
border-radius: 60px;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Large size gauge sizing
|
||||||
|
*/
|
||||||
|
|
||||||
|
.esxc-gauge-large .esxc-gauge-container {
|
||||||
|
width: 260px;
|
||||||
|
height: 130px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-large .esxc-gauge-circle-fill {
|
||||||
|
height: 260px;
|
||||||
|
border-radius: 130px;
|
||||||
|
clip: rect(130px, 260px, 260px, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-large .esxc-gauge-circle-bg {
|
||||||
|
height: 260px;
|
||||||
|
border-radius: 130px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-large .esxc-gauge-circle-inner {
|
||||||
|
width: 240px;
|
||||||
|
height: 240px;
|
||||||
|
border-radius: 120px;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-large .esxc-gauge-circle-caption {
|
||||||
|
margin-top: 95px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-small .esxc-gauge-circle-caption .esxc-value {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-small .esxc-gauge-circle-caption .esxc-unit {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-small .esxc-gauge-circle-caption .esxc-loading {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-small .esxc-title {
|
||||||
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-small .esxc-title .esxc-bar-title {
|
||||||
|
float: left;
|
||||||
|
text-align: right;
|
||||||
|
width: 70px;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-small .esxc-limit {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-small .esxc-limit .esxc-value {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-small .esxc-limit .esxc-unit {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-small .esxc-limit .esxc-label {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-small .esxc-limit .esxc-bar-limit {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-medium .esxc-gauge-circle-caption {
|
||||||
|
margin-top: 40px;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-medium .esxc-gauge-circle-caption .esxc-value {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-medium .esxc-gauge-circle-caption .esxc-unit {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-medium .esxc-gauge-circle-caption .esxc-loading {
|
||||||
|
font-size: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-medium .esxc-limit {
|
||||||
|
text-align: center;
|
||||||
|
color: #565656;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-medium .esxc-limit .esxc-value {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-medium .esxc-limit .esxc-unit {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-medium .esxc-limit .esxc-label {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-medium .esxc-title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #565656;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: -8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-large .esxc-gauge-circle-caption .esxc-value {
|
||||||
|
font-size: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-large .esxc-gauge-circle-caption .esxc-unit {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-large .esxc-gauge-circle-caption .esxc-loading {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-large .esxc-limit {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-large .esxc-limit .esxc-value {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #565656;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-large .esxc-limit .esxc-unit {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-large .esxc-limit .esxc-label {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-large .esxc-limit .esxc-bar-limit {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-large .esxc-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #565656;
|
||||||
|
line-height: 18px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esxc-gauge-large .esxc-title .esxc-bar-title {
|
||||||
|
float: left;
|
||||||
|
text-align: right;
|
||||||
|
width: 70px;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
18
src/ui_ng/src/app/shared/gauge/gauge.component.html
Normal file
18
src/ui_ng/src/app/shared/gauge/gauge.component.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<div class="{{sizeClass}}">
|
||||||
|
<div class="esxc-gauge-container esxc-gauge">
|
||||||
|
<div class="esxc-gauge-circle-bg"></div>
|
||||||
|
<div #barOne class="esxc-gauge-circle-fill esxc-gauge-bar-one"></div>
|
||||||
|
<div #barTwo class="esxc-gauge-circle-fill esxc-gauge-bar-two"></div>
|
||||||
|
<div class="esxc-gauge-circle-inner" [ngStyle]="{'background-color': backgroundColor}">
|
||||||
|
<div class="esxc-gauge-circle-caption">
|
||||||
|
<span class="esxc-value">{{used}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="esxc-limit">
|
||||||
|
<span class="esxc-value">{{threasHold}}</span>
|
||||||
|
<span class="esxc-unit">GB</span>
|
||||||
|
<span class="esxc-label">{{'STATISTICS.LIMIT' | translate}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="esxc-title">{{title | translate}}</div>
|
||||||
|
</div>
|
272
src/ui_ng/src/app/shared/gauge/gauge.component.ts
Normal file
272
src/ui_ng/src/app/shared/gauge/gauge.component.ts
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
import {
|
||||||
|
Component,
|
||||||
|
Input,
|
||||||
|
AfterViewInit,
|
||||||
|
ViewChild,
|
||||||
|
ElementRef
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
import * as $ from 'jquery';
|
||||||
|
|
||||||
|
const RESOURCE_COLOR_GREEN_NORMAL: string = '#5DB700';
|
||||||
|
const RESOURCE_COLOR_ORANGE_NORMAL: string = '#FBBF00';
|
||||||
|
const RESOURCE_COLOR_RED_NORMAL: string = '#EA400D';
|
||||||
|
const RESOURCE_COLOR_GREY500: string = '#D7DEE2';
|
||||||
|
const RESOURCE_COLOR_GREY600: string = '#C7D1D6';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Guage to visualize percent usage.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'esxc-gauge',
|
||||||
|
templateUrl: 'gauge.component.html',
|
||||||
|
styleUrls: ['gauge.component.css']
|
||||||
|
})
|
||||||
|
|
||||||
|
export class GaugeComponent implements AfterViewInit {
|
||||||
|
private _backgroundColor: string;
|
||||||
|
private _colorOne: string;
|
||||||
|
private _colorTwo: string;
|
||||||
|
private _size: string = "small"; //Support small, medium, large
|
||||||
|
private _title: string = "UNKNOWN"; //Lang key
|
||||||
|
private _used: number = 0;
|
||||||
|
private _threasHold: number = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Background color of the component. Default is white.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
get backgroundColor() {
|
||||||
|
if (this._backgroundColor) {
|
||||||
|
return this._backgroundColor;
|
||||||
|
}
|
||||||
|
return '#FAFAFA';
|
||||||
|
}
|
||||||
|
|
||||||
|
set backgroundColor(value: string) {
|
||||||
|
this._backgroundColor = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _positionOne: number;
|
||||||
|
/**
|
||||||
|
* Keep these two properties
|
||||||
|
* Percentage of the total width for the first portion of the bar.
|
||||||
|
* Bar one is rendered above bar two, so bar two's position should always
|
||||||
|
* be greater than bar one if you want bar two to be visible.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
get positionOne(): number {
|
||||||
|
return this._positionOne;
|
||||||
|
}
|
||||||
|
|
||||||
|
set positionOne(value: number) {
|
||||||
|
this._positionOne = value;
|
||||||
|
this.setBars();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _positionTwo: number;
|
||||||
|
/**
|
||||||
|
* Percentage of the total width for the second portion of the bar
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
get positionTwo(): number {
|
||||||
|
return this._positionTwo;
|
||||||
|
}
|
||||||
|
|
||||||
|
set positionTwo(value: number) {
|
||||||
|
this._positionTwo = this._positionOne + value;
|
||||||
|
this.setBars();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _animate: boolean;
|
||||||
|
/**
|
||||||
|
* Whether to animate transitions in the bars
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
get animate(): boolean {
|
||||||
|
return this._animate;
|
||||||
|
}
|
||||||
|
|
||||||
|
set animate(value: boolean) {
|
||||||
|
if (typeof value !== 'undefined') {
|
||||||
|
this._animate = value;
|
||||||
|
}
|
||||||
|
this.setAnimate();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Define the gauge size
|
||||||
|
@Input()
|
||||||
|
get size(): string {
|
||||||
|
return this._size;
|
||||||
|
}
|
||||||
|
|
||||||
|
set size(sz: string) {
|
||||||
|
if (typeof sz !== 'undefined') {
|
||||||
|
if (sz === 'small' || sz === 'medium' || sz === 'large') {
|
||||||
|
this._size = sz;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._size = "small";
|
||||||
|
}
|
||||||
|
|
||||||
|
get sizeClass(): string {
|
||||||
|
return "esxc-gauge-" + this._size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
get title(): string {
|
||||||
|
return this._title;
|
||||||
|
}
|
||||||
|
|
||||||
|
set title(t: string) {
|
||||||
|
if (typeof t !== 'undefined') {
|
||||||
|
this._title = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
get used(): number {
|
||||||
|
return this._used;
|
||||||
|
}
|
||||||
|
|
||||||
|
set used(u: number) {
|
||||||
|
this._used = u;
|
||||||
|
this.determineColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
get threasHold(): number {
|
||||||
|
return this._threasHold;
|
||||||
|
}
|
||||||
|
|
||||||
|
set threasHold(th: number) {
|
||||||
|
this._threasHold = th;
|
||||||
|
this.determineColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
this.determineColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewChild('barOne') private barOne: ElementRef;
|
||||||
|
@ViewChild('barTwo') private barTwo: ElementRef;
|
||||||
|
|
||||||
|
private determineColors() {
|
||||||
|
console.info(this._used, this._threasHold);
|
||||||
|
let percent: number = 0;
|
||||||
|
if (this._threasHold !== 0) {
|
||||||
|
percent = (this._used / this._threasHold) * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (percent > 100) {
|
||||||
|
percent = percent - 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (percent <= 70) {
|
||||||
|
this._colorOne = RESOURCE_COLOR_GREEN_NORMAL;
|
||||||
|
} else if (percent > 70 && percent <= 90) {
|
||||||
|
this._colorOne = RESOURCE_COLOR_ORANGE_NORMAL;
|
||||||
|
} else if (percent > 90 && percent <= 100) {
|
||||||
|
this._colorOne = RESOURCE_COLOR_RED_NORMAL;
|
||||||
|
} else {
|
||||||
|
this._colorOne = RESOURCE_COLOR_GREY600;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._positionOne = percent;
|
||||||
|
this.setBars();
|
||||||
|
this.setColors();
|
||||||
|
this.setAnimate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private setBars() {
|
||||||
|
if (!this.barOne || !this.barTwo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let barOne = $(this.barOne.nativeElement);
|
||||||
|
let barTwo = $(this.barTwo.nativeElement);
|
||||||
|
|
||||||
|
if (!barOne || !barTwo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let posOne, posTwo;
|
||||||
|
|
||||||
|
if (isNaN(this.positionOne)) {
|
||||||
|
posOne = posTwo = 0;
|
||||||
|
} else {
|
||||||
|
posOne = (this.positionOne / 100) * 180;
|
||||||
|
posTwo = (this.positionTwo / 100) * 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
barOne.css({
|
||||||
|
'-webkit-transform': 'rotate(' + posOne + 'deg)',
|
||||||
|
'-moz-transform': 'rotate(' + posOne + 'deg)',
|
||||||
|
'-ms-transform': 'rotate(' + posOne + 'deg)',
|
||||||
|
'-o-transform': 'rotate(' + posOne + 'deg)',
|
||||||
|
'transform': 'rotate(' + posOne + 'deg)'
|
||||||
|
});
|
||||||
|
|
||||||
|
barTwo.css({
|
||||||
|
'-webkit-transform': 'rotate(' + posTwo + 'deg)',
|
||||||
|
'-moz-transform': 'rotate(' + posTwo + 'deg)',
|
||||||
|
'-ms-transform': 'rotate(' + posTwo + 'deg)',
|
||||||
|
'-o-transform': 'rotate(' + posTwo + 'deg)',
|
||||||
|
'transform': 'rotate(' + posTwo + 'deg)'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private setColors() {
|
||||||
|
if (!this.barOne || !this.barTwo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let barOne = $(this.barOne.nativeElement);
|
||||||
|
let barTwo = $(this.barTwo.nativeElement);
|
||||||
|
|
||||||
|
if (!barOne || !barTwo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
barOne.css({
|
||||||
|
'background-color': this._colorOne
|
||||||
|
});
|
||||||
|
|
||||||
|
barTwo.css({
|
||||||
|
'background-color': this._colorTwo
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private setAnimate() {
|
||||||
|
if (!this.barOne || !this.barTwo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let barOne = $(this.barOne.nativeElement);
|
||||||
|
let barTwo = $(this.barTwo.nativeElement);
|
||||||
|
|
||||||
|
if (!barOne || !barTwo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let transition = 'transform 1s ease';
|
||||||
|
let prefixes = ['webkit', 'moz', 'ms', 'o'];
|
||||||
|
let css = {
|
||||||
|
'transition': transition
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!this._animate) {
|
||||||
|
transition = 'none';
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let prefix of prefixes) {
|
||||||
|
css['-' + prefix + '-transition'] = transition;
|
||||||
|
}
|
||||||
|
|
||||||
|
barOne.css(css);
|
||||||
|
barTwo.css(css);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -39,6 +39,7 @@ import { ListRepositoryROComponent } from './list-repository-ro/list-repository-
|
|||||||
|
|
||||||
import { MessageHandlerService } from './message-handler/message-handler.service';
|
import { MessageHandlerService } from './message-handler/message-handler.service';
|
||||||
import { EmailValidatorDirective } from './email.directive';
|
import { EmailValidatorDirective } from './email.directive';
|
||||||
|
import { GaugeComponent } from './gauge/gauge.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -62,7 +63,8 @@ import { EmailValidatorDirective } from './email.directive';
|
|||||||
StatisticsPanelComponent,
|
StatisticsPanelComponent,
|
||||||
ListProjectROComponent,
|
ListProjectROComponent,
|
||||||
ListRepositoryROComponent,
|
ListRepositoryROComponent,
|
||||||
EmailValidatorDirective
|
EmailValidatorDirective,
|
||||||
|
GaugeComponent
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
CoreModule,
|
CoreModule,
|
||||||
@ -82,7 +84,8 @@ import { EmailValidatorDirective } from './email.directive';
|
|||||||
StatisticsPanelComponent,
|
StatisticsPanelComponent,
|
||||||
ListProjectROComponent,
|
ListProjectROComponent,
|
||||||
ListRepositoryROComponent,
|
ListRepositoryROComponent,
|
||||||
EmailValidatorDirective
|
EmailValidatorDirective,
|
||||||
|
GaugeComponent
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
SessionService,
|
SessionService,
|
||||||
|
@ -35,10 +35,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="statistic-item-divider" [hidden]="!isValidSession"></div>
|
<div class="statistic-item-divider" [hidden]="!isValidSession || !isValidStorage"></div>
|
||||||
<div class="statistic-block" [hidden]="!isValidSession">
|
<div class="statistic-block" [hidden]="!isValidSession || !isValidStorage">
|
||||||
<div>{{freeStorage}}GB | {{totalStorage}}GB</div>
|
<esxc-gauge [used]="freeStorage" [threasHold]="totalStorage" [size]="small" [title]='"STATISTICS.STORAGE"' [animate]="true">
|
||||||
<div>[STORAGE]</div>
|
</esxc-gauge>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -64,6 +64,10 @@ export class StatisticsPanelComponent implements OnInit {
|
|||||||
return user && user.has_admin_role > 0;
|
return user && user.has_admin_role > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get isValidStorage(): boolean {
|
||||||
|
return this.volumesInfo.storage.total != 0;
|
||||||
|
}
|
||||||
|
|
||||||
private getGBFromBytes(bytes: number): number {
|
private getGBFromBytes(bytes: number): number {
|
||||||
return Math.round((bytes / (1024 * 1024 * 1024)));
|
return Math.round((bytes / (1024 * 1024 * 1024)));
|
||||||
}
|
}
|
||||||
|
@ -413,7 +413,9 @@
|
|||||||
"REPO_ITEM": "REPOSITORIES",
|
"REPO_ITEM": "REPOSITORIES",
|
||||||
"INDEX_MY": "MY",
|
"INDEX_MY": "MY",
|
||||||
"INDEX_PUB": "PUBLIC",
|
"INDEX_PUB": "PUBLIC",
|
||||||
"INDEX_TOTAL": "TOTAL"
|
"INDEX_TOTAL": "TOTAL",
|
||||||
|
"STORAGE": "STORAGE",
|
||||||
|
"LIMIT": "Limit"
|
||||||
},
|
},
|
||||||
"SEARCH": {
|
"SEARCH": {
|
||||||
"IN_PROGRESS": "Search...",
|
"IN_PROGRESS": "Search...",
|
||||||
|
@ -413,7 +413,9 @@
|
|||||||
"REPO_ITEM": "镜像库",
|
"REPO_ITEM": "镜像库",
|
||||||
"INDEX_MY": "私有",
|
"INDEX_MY": "私有",
|
||||||
"INDEX_PUB": "公开",
|
"INDEX_PUB": "公开",
|
||||||
"INDEX_TOTAL": "总计"
|
"INDEX_TOTAL": "总计",
|
||||||
|
"STORAGE": "存储",
|
||||||
|
"LIMIT": "容量"
|
||||||
},
|
},
|
||||||
"SEARCH": {
|
"SEARCH": {
|
||||||
"IN_PROGRESS": "搜索中...",
|
"IN_PROGRESS": "搜索中...",
|
||||||
|
Loading…
Reference in New Issue
Block a user