mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-26 10:38:00 +01:00
Update storage display (#14807)
Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
parent
dce3522b4e
commit
3322716bc6
@ -18,7 +18,6 @@ import { ListProjectComponent } from "./list-project/list-project.component";
|
||||
import { CreateProjectComponent } from "./create-project/create-project.component";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
import { StatisticsPanelComponent } from "./statictics/statistics-panel.component";
|
||||
import { StatisticsComponent } from "./statictics/statistics.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@ -36,8 +35,7 @@ const routes: Routes = [
|
||||
ProjectsComponent,
|
||||
ListProjectComponent,
|
||||
CreateProjectComponent,
|
||||
StatisticsPanelComponent,
|
||||
StatisticsComponent
|
||||
StatisticsPanelComponent
|
||||
],
|
||||
providers: []
|
||||
})
|
||||
|
@ -1,44 +1,46 @@
|
||||
<div class="row flex-items-xs-between flex-items-xs-middle">
|
||||
<div></div>
|
||||
<div id="right_statistic_panel">
|
||||
<div class="statistic-block">
|
||||
<div class="statistic-column-block">
|
||||
<div>
|
||||
<span class="statistic-column-title statistic-column-title-pro">{{'STATISTICS.PRO_ITEM' | translate }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="statistic-column-title statistic-column-title-repo">{{'STATISTICS.REPO_ITEM' | translate }}</span>
|
||||
</div>
|
||||
<div class="clr-row flex-end">
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<h4 class="head">{{'STATISTICS.PRO_ITEM' | translate }}</h4>
|
||||
<div class="clr-row" *ngIf="isValidSession">
|
||||
<div class="clr-col">{{"STATISTICS.INDEX_PRIVATE" | translate}}</div>
|
||||
<div class="clr-col font-weight-700">{{originalCopy?.private_project_count}}</div>
|
||||
</div>
|
||||
<div class="statistic-column-block">
|
||||
<div>
|
||||
<statistics [data]='originalCopy.private_project_count' [label]='"STATISTICS.INDEX_PRIVATE" | translate'></statistics>
|
||||
</div>
|
||||
<div>
|
||||
<statistics [data]='originalCopy.private_repo_count' [label]='"STATISTICS.INDEX_PRIVATE" | translate'></statistics>
|
||||
</div>
|
||||
<div class="clr-row">
|
||||
<div class="clr-col">{{"STATISTICS.INDEX_PUB" | translate}}</div>
|
||||
<div class="clr-col font-weight-700">{{originalCopy?.public_project_count}}</div>
|
||||
</div>
|
||||
<div class="statistic-column-block">
|
||||
<div>
|
||||
<statistics [data]='originalCopy.public_project_count' [label]='"STATISTICS.INDEX_PUB" | translate'></statistics>
|
||||
</div>
|
||||
<div>
|
||||
<statistics [data]='originalCopy.public_repo_count' [label]='"STATISTICS.INDEX_PUB" | translate'></statistics>
|
||||
</div>
|
||||
</div>
|
||||
<div class="statistic-column-block">
|
||||
<div>
|
||||
<statistics [data]='originalCopy.total_project_count' [label]='"STATISTICS.INDEX_TOTAL" | translate' *ngIf="isValidSession"></statistics>
|
||||
</div>
|
||||
<div>
|
||||
<statistics [data]='originalCopy.total_repo_count' [label]='"STATISTICS.INDEX_TOTAL" | translate' *ngIf="isValidSession"></statistics>
|
||||
</div>
|
||||
<div class="clr-row" *ngIf="isValidSession">
|
||||
<div class="clr-col">{{"STATISTICS.INDEX_TOTAL" | translate}}</div>
|
||||
<div class="clr-col font-weight-700">{{originalCopy?.total_project_count}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="statistic-item-divider" [hidden]="!isValidSession || !isValidStorage"></div>
|
||||
<div class="statistic-block" [hidden]="!isValidSession || !isValidStorage">
|
||||
<esxc-gauge [free]="freeStorage" [threasHold]="totalStorage" [title]='"STATISTICS.STORAGE"' [animate]="true">
|
||||
</esxc-gauge>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<h4 class="head">{{'STATISTICS.REPO_ITEM' | translate }}</h4>
|
||||
<div class="clr-row" *ngIf="isValidSession">
|
||||
<div class="clr-col">{{"STATISTICS.INDEX_PRIVATE" | translate}}</div>
|
||||
<div class="clr-col font-weight-700">{{originalCopy?.private_repo_count}}</div>
|
||||
</div>
|
||||
<div class="clr-row">
|
||||
<div class="clr-col">{{"STATISTICS.INDEX_PUB" | translate}}</div>
|
||||
<div class="clr-col font-weight-700">{{originalCopy?.public_repo_count}}</div>
|
||||
</div>
|
||||
<div class="clr-row" *ngIf="isValidSession">
|
||||
<div class="clr-col">{{"STATISTICS.INDEX_TOTAL" | translate}}</div>
|
||||
<div class="clr-col font-weight-700">{{originalCopy?.total_repo_count}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" *ngIf="isValidSession">
|
||||
<div class="card-block container">
|
||||
<h4 class="head">{{'STATISTICS.STORAGE_USED' | translate }}</h4>
|
||||
<div class="storage-used font-weight-700">
|
||||
<div>
|
||||
<span class="size-number margin-right-5px">{{getSizeNumber()}}</span><span *ngIf="getSizeNumber()">{{getSizeUnit()}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -0,0 +1,37 @@
|
||||
.head {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
.card{
|
||||
width: 10rem;
|
||||
margin-right: 0.5rem;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.card:last-child{
|
||||
width: 10rem;
|
||||
margin-right: 0;
|
||||
}
|
||||
.flex-end {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.font-weight-700 {
|
||||
font-weight: 700;
|
||||
}
|
||||
.storage-used {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.size-number {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
.margin-right-5px {
|
||||
margin-right: 5px;
|
||||
}
|
@ -1,80 +1,89 @@
|
||||
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
||||
import { StatisticsPanelComponent } from './statistics-panel.component';
|
||||
import { StatisticsComponent } from './statistics.component';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { ClarityModule } from '@clr/angular';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { of } from 'rxjs';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { StatisticsService } from "./statistics.service";
|
||||
import { SessionService } from "../../../../shared/services/session.service";
|
||||
import { MessageHandlerService } from "../../../../shared/services/message-handler.service";
|
||||
import { StatisticHandler } from "./statistic-handler.service";
|
||||
import { AppConfigService } from "../../../../services/app-config.service";
|
||||
import { Statistics } from './statistics';
|
||||
import { Volumes } from './volumes';
|
||||
import { Statistic } from "../../../../../../ng-swagger-gen/models/statistic";
|
||||
import { SharedTestingModule } from "../../../../shared/shared.module";
|
||||
import { StatisticService } from "../../../../../../ng-swagger-gen/services/statistic.service";
|
||||
|
||||
describe('StatisticsPanelComponent', () => {
|
||||
let component: StatisticsPanelComponent;
|
||||
let fixture: ComponentFixture<StatisticsPanelComponent>;
|
||||
const mockStatisticsService = {
|
||||
getStatistics: () => of(new Statistics()),
|
||||
getVolumes: () => of(new Volumes()),
|
||||
};
|
||||
const mockSessionService = {
|
||||
getCurrentUser: () => { }
|
||||
};
|
||||
const mockAppConfigService = {
|
||||
getConfig: () => {
|
||||
return {
|
||||
registry_storage_provider_name : ""
|
||||
};
|
||||
}
|
||||
};
|
||||
const mockMessageHandlerService = {
|
||||
handleError: () => { }
|
||||
};
|
||||
const mockStatisticHandler = {
|
||||
refreshChan$: of(null)
|
||||
};
|
||||
const mockRouter = {
|
||||
navigate: () => { }
|
||||
};
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
schemas: [
|
||||
CUSTOM_ELEMENTS_SCHEMA
|
||||
],
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
ClarityModule,
|
||||
TranslateModule.forRoot(),
|
||||
FormsModule,
|
||||
RouterTestingModule,
|
||||
NoopAnimationsModule,
|
||||
HttpClientTestingModule
|
||||
],
|
||||
declarations: [StatisticsPanelComponent, StatisticsComponent],
|
||||
providers: [
|
||||
TranslateService,
|
||||
{ provide: SessionService, useValue: mockSessionService },
|
||||
{ provide: AppConfigService, useValue: mockAppConfigService },
|
||||
{ provide: StatisticsService, useValue: mockStatisticsService },
|
||||
{ provide: StatisticHandler, useValue: mockStatisticHandler },
|
||||
{ provide: MessageHandlerService, useValue: mockMessageHandlerService }
|
||||
]
|
||||
}).compileComponents();
|
||||
}));
|
||||
const mockedStatistic: Statistic = {
|
||||
"private_project_count": 2,
|
||||
"private_repo_count": 0,
|
||||
"public_project_count": 3,
|
||||
"public_repo_count": 1,
|
||||
"total_project_count": 5,
|
||||
"total_repo_count": 1,
|
||||
"total_storage_consumption": 4564
|
||||
};
|
||||
let component: StatisticsPanelComponent;
|
||||
let fixture: ComponentFixture<StatisticsPanelComponent>;
|
||||
const mockStatisticsService = {
|
||||
getStatistic: () => of(mockedStatistic),
|
||||
};
|
||||
const mockSessionService = {
|
||||
getCurrentUser: () => {
|
||||
return {
|
||||
has_admin_role: true
|
||||
};
|
||||
}
|
||||
};
|
||||
const mockAppConfigService = {
|
||||
getConfig: () => {
|
||||
return {
|
||||
registry_storage_provider_name: ""
|
||||
};
|
||||
}
|
||||
};
|
||||
const mockMessageHandlerService = {
|
||||
handleError: () => {
|
||||
}
|
||||
};
|
||||
const mockStatisticHandler = {
|
||||
refreshChan$: of(null)
|
||||
};
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
schemas: [
|
||||
CUSTOM_ELEMENTS_SCHEMA
|
||||
],
|
||||
imports: [
|
||||
SharedTestingModule
|
||||
],
|
||||
declarations: [StatisticsPanelComponent],
|
||||
providers: [
|
||||
{provide: SessionService, useValue: mockSessionService},
|
||||
{provide: AppConfigService, useValue: mockAppConfigService},
|
||||
{provide: StatisticService, useValue: mockStatisticsService},
|
||||
{provide: StatisticHandler, useValue: mockStatisticHandler},
|
||||
{provide: MessageHandlerService, useValue: mockMessageHandlerService}
|
||||
]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(StatisticsPanelComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(StatisticsPanelComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
it('should have 3 cards', async () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
const cards = fixture.nativeElement.querySelectorAll('.card');
|
||||
expect(cards.length).toEqual(3);
|
||||
});
|
||||
it('should display right size number', async () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
const sizeHtml: HTMLSpanElement = fixture.nativeElement.querySelector('.size-number');
|
||||
expect(sizeHtml.innerText).toEqual('4.46');
|
||||
});
|
||||
});
|
||||
|
@ -13,35 +13,28 @@
|
||||
// limitations under the License.
|
||||
import { Component, OnInit, OnDestroy } from "@angular/core";
|
||||
import { Subscription } from "rxjs";
|
||||
|
||||
import { StatisticsService } from "./statistics.service";
|
||||
import { Statistics } from "./statistics";
|
||||
|
||||
import { SessionService } from "../../../../shared/services/session.service";
|
||||
import { Volumes } from "./volumes";
|
||||
|
||||
import { MessageHandlerService } from "../../../../shared/services/message-handler.service";
|
||||
import { StatisticHandler } from "./statistic-handler.service";
|
||||
import { AppConfigService } from "../../../../services/app-config.service";
|
||||
import { Statistic } from "../../../../../../ng-swagger-gen/models/statistic";
|
||||
import { StatisticService } from "../../../../../../ng-swagger-gen/services/statistic.service";
|
||||
import { getSizeNumber, getSizeUnit } from "../../../../shared/units/utils";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: "statistics-panel",
|
||||
templateUrl: "statistics-panel.component.html",
|
||||
styleUrls: ["statistics.component.scss"],
|
||||
providers: [StatisticsService]
|
||||
})
|
||||
styleUrls: ["statistics-panel.component.scss"],
|
||||
})
|
||||
|
||||
export class StatisticsPanelComponent implements OnInit, OnDestroy {
|
||||
|
||||
originalCopy: Statistics = new Statistics();
|
||||
volumesInfo: Volumes = new Volumes();
|
||||
originalCopy: Statistic;
|
||||
refreshSub: Subscription;
|
||||
constructor(
|
||||
private statistics: StatisticsService,
|
||||
private statistics: StatisticService,
|
||||
private msgHandler: MessageHandlerService,
|
||||
private session: SessionService,
|
||||
private appConfigService: AppConfigService,
|
||||
private statisticHandler: StatisticHandler) {
|
||||
}
|
||||
|
||||
@ -54,10 +47,6 @@ export class StatisticsPanelComponent implements OnInit, OnDestroy {
|
||||
if (this.session.getCurrentUser()) {
|
||||
this.getStatistics();
|
||||
}
|
||||
|
||||
if (this.isValidSession) {
|
||||
this.getVolumes();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
@ -65,60 +54,27 @@ export class StatisticsPanelComponent implements OnInit, OnDestroy {
|
||||
this.refreshSub.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
public get totalStorage(): number {
|
||||
let count: number = 0;
|
||||
if (this.volumesInfo && this.volumesInfo.storage && this.volumesInfo.storage.length) {
|
||||
this.volumesInfo.storage.forEach(item => {
|
||||
count += item.total ? item.total : 0;
|
||||
});
|
||||
}
|
||||
return this.getGBFromBytes(count);
|
||||
}
|
||||
|
||||
public get freeStorage(): number {
|
||||
let count: number = 0;
|
||||
if (this.volumesInfo && this.volumesInfo.storage && this.volumesInfo.storage.length) {
|
||||
this.volumesInfo.storage.forEach(item => {
|
||||
count += item.free ? item.free : 0;
|
||||
});
|
||||
}
|
||||
return this.getGBFromBytes(count);
|
||||
}
|
||||
|
||||
public getStatistics(): void {
|
||||
this.statistics.getStatistics()
|
||||
getStatistics(): void {
|
||||
this.statistics.getStatistic()
|
||||
.subscribe(statistics => this.originalCopy = statistics
|
||||
, error => {
|
||||
this.msgHandler.handleError(error);
|
||||
});
|
||||
}
|
||||
|
||||
public getVolumes(): void {
|
||||
this.statistics.getVolumes()
|
||||
.subscribe(volumes => this.volumesInfo = volumes
|
||||
, error => {
|
||||
this.msgHandler.handleError(error);
|
||||
});
|
||||
}
|
||||
|
||||
public get isValidSession(): boolean {
|
||||
get isValidSession(): boolean {
|
||||
let user = this.session.getCurrentUser();
|
||||
return user && user.has_admin_role;
|
||||
}
|
||||
|
||||
public get isValidStorage(): boolean {
|
||||
let count: number = 0;
|
||||
if (this.volumesInfo && this.volumesInfo.storage && this.volumesInfo.storage.length) {
|
||||
this.volumesInfo.storage.forEach(item => {
|
||||
count += item.total ? item.total : 0;
|
||||
});
|
||||
getSizeNumber(): number | string {
|
||||
if (this.originalCopy) {
|
||||
return getSizeNumber(this.originalCopy.total_storage_consumption);
|
||||
}
|
||||
return count !== 0 &&
|
||||
this.appConfigService.getConfig().registry_storage_provider_name === "filesystem";
|
||||
return null;
|
||||
}
|
||||
|
||||
getGBFromBytes(bytes: number): number {
|
||||
return Math.round((bytes / (1024 * 1024 * 1024)));
|
||||
getSizeUnit(): number | string {
|
||||
if (this.originalCopy) {
|
||||
return getSizeUnit(this.originalCopy.total_storage_consumption);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
<div class="statistic-wrapper">
|
||||
<span class="statistic-data">{{data}}</span>
|
||||
<span class="statistic-text">{{label}}</span>
|
||||
</div>
|
@ -1,75 +0,0 @@
|
||||
.statistic-wrapper {
|
||||
padding: 4px;
|
||||
margin: 4px;
|
||||
text-align: right;
|
||||
vertical-align: middle;
|
||||
height: 30px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.statistic-data {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
font-family: Metropolis, "Avenir Next", "Helvetica Neue", Arial, sans-serif;
|
||||
line-height: 24px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.statistic-text {
|
||||
font-size: 14px;
|
||||
line-height: 14px;
|
||||
text-transform: uppercase;
|
||||
font-family: Metropolis, "Avenir Next", "Helvetica Neue", Arial, sans-serif;
|
||||
}
|
||||
|
||||
.statistic-column-block {
|
||||
display: inline-block;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.statistic-column-title {
|
||||
position: relative;
|
||||
text-transform: uppercase;
|
||||
font-size: 14px;
|
||||
font-family: Metropolis, "Avenir Next", "Helvetica Neue", Arial, sans-serif;
|
||||
}
|
||||
|
||||
.statistic-column-title-pro {
|
||||
top: -10px;
|
||||
}
|
||||
|
||||
.statistic-column-title-repo {
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
.statistic-item-divider {
|
||||
height: 54px;
|
||||
display: inline-block;
|
||||
width: 2px;
|
||||
background-color: #bdbdbd;
|
||||
opacity: 0.55;
|
||||
margin-left: 4px;
|
||||
margin-right: 12px;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
.statistic-block {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#right_statistic_panel {
|
||||
margin-right: 18px;
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
div:nth-of-type(2) {
|
||||
margin-left: 16px;
|
||||
}
|
||||
div:nth-of-type(3) {
|
||||
margin-left: 28px;
|
||||
}
|
||||
div:nth-of-type(4) {
|
||||
margin-left: 28px;
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { StatisticsComponent } from './statistics.component';
|
||||
|
||||
describe('StatisticsComponent', () => {
|
||||
let component: StatisticsComponent;
|
||||
let fixture: ComponentFixture<StatisticsComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [StatisticsComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(StatisticsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// 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, Input } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'statistics',
|
||||
templateUrl: "statistics.component.html",
|
||||
styleUrls: ['statistics.component.scss']
|
||||
})
|
||||
|
||||
export class StatisticsComponent {
|
||||
@Input() label: string;
|
||||
@Input() data: number = 0;
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { StatisticsService } from './statistics.service';
|
||||
|
||||
describe('StatisticsService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
HttpClientTestingModule
|
||||
],
|
||||
providers: [StatisticsService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([StatisticsService], (service: StatisticsService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
@ -1,48 +0,0 @@
|
||||
// Copyright (c) 2017 VMware, Inc. 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 { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { map, catchError } from "rxjs/operators";
|
||||
import { Observable, throwError as observableThrowError } from "rxjs";
|
||||
import { Statistics } from './statistics';
|
||||
import { Volumes } from './volumes';
|
||||
import { CURRENT_BASE_HREF, HTTP_GET_OPTIONS } from "../../../../shared/units/utils";
|
||||
|
||||
|
||||
const statisticsEndpoint = CURRENT_BASE_HREF + "/statistics";
|
||||
const volumesEndpoint = CURRENT_BASE_HREF + "/systeminfo/volumes";
|
||||
/**
|
||||
* Declare service to handle the top repositories
|
||||
*
|
||||
*
|
||||
**
|
||||
* class GlobalSearchService
|
||||
*/
|
||||
@Injectable()
|
||||
export class StatisticsService {
|
||||
|
||||
constructor(private http: HttpClient) { }
|
||||
|
||||
getStatistics(): Observable<Statistics> {
|
||||
return this.http.get(statisticsEndpoint, HTTP_GET_OPTIONS)
|
||||
.pipe(map(response => response as Statistics)
|
||||
, catchError(error => observableThrowError(error)));
|
||||
}
|
||||
|
||||
getVolumes(): Observable<Volumes> {
|
||||
return this.http.get(volumesEndpoint, HTTP_GET_OPTIONS)
|
||||
.pipe(map(response => response as Volumes)
|
||||
, catchError(error => observableThrowError(error)));
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// 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.
|
||||
export class Statistics {
|
||||
constructor() {}
|
||||
|
||||
private_project_count: number;
|
||||
private_repo_count: number;
|
||||
public_project_count: number;
|
||||
public_repo_count: number;
|
||||
total_project_count: number;
|
||||
total_repo_count: number;
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// 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.
|
||||
export class Volumes {
|
||||
constructor() {
|
||||
this.storage = [new Storage()];
|
||||
}
|
||||
|
||||
storage: Storage[];
|
||||
}
|
||||
|
||||
export class Storage {
|
||||
constructor() {
|
||||
this.total = 0;
|
||||
this.free = 0;
|
||||
}
|
||||
|
||||
total: number;
|
||||
free: number;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { delUrlParam, getQueryString, getSortingString, isSameArrayValue, isSameObject } from "./utils";
|
||||
import { delUrlParam, getQueryString, getSizeNumber, getSizeUnit, getSortingString, isSameArrayValue, isSameObject } from "./utils";
|
||||
import { ClrDatagridStateInterface } from "@clr/angular";
|
||||
|
||||
describe('functions in utils.ts should work', () => {
|
||||
@ -53,4 +53,20 @@ describe('functions in utils.ts should work', () => {
|
||||
};
|
||||
expect(getQueryString(state)).toEqual(encodeURIComponent('name=~test,url=~http://test.com'));
|
||||
});
|
||||
|
||||
it('function getSizeNumber() should work', () => {
|
||||
expect(getSizeNumber).toBeTruthy();
|
||||
expect(getSizeNumber(4564)).toEqual('4.46');
|
||||
expect(getSizeNumber(10)).toEqual(10);
|
||||
expect(getSizeNumber(456400)).toEqual('445.70');
|
||||
expect(getSizeNumber(45640000)).toEqual('43.53');
|
||||
});
|
||||
|
||||
it('function getSizeUnit() should work', () => {
|
||||
expect(getSizeUnit).toBeTruthy();
|
||||
expect(getSizeUnit(4564)).toEqual('KB');
|
||||
expect(getSizeUnit(10)).toEqual('B');
|
||||
expect(getSizeUnit(4564000)).toEqual('MB');
|
||||
expect(getSizeUnit(4564000000)).toEqual('GB');
|
||||
});
|
||||
});
|
||||
|
@ -579,6 +579,38 @@ export function formatSize(tagSize: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get size number of target size (in byte)
|
||||
* @param size
|
||||
*/
|
||||
export function getSizeNumber(size: number): string | number {
|
||||
if (Math.pow(1024, 1) <= size && size < Math.pow(1024, 2)) {
|
||||
return (size / Math.pow(1024, 1)).toFixed(2);
|
||||
} else if (Math.pow(1024, 2) <= size && size < Math.pow(1024, 3)) {
|
||||
return (size / Math.pow(1024, 2)).toFixed(2);
|
||||
} else if (Math.pow(1024, 3) <= size && size < Math.pow(1024, 4)) {
|
||||
return (size / Math.pow(1024, 3)).toFixed(2);
|
||||
} else {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get size unit of target size (in byte)
|
||||
* @param size
|
||||
*/
|
||||
export function getSizeUnit(size: number): string {
|
||||
if (Math.pow(1024, 1) <= size && size < Math.pow(1024, 2)) {
|
||||
return "KB";
|
||||
} else if (Math.pow(1024, 2) <= size && size < Math.pow(1024, 3)) {
|
||||
return "MB";
|
||||
} else if (Math.pow(1024, 3) <= size && size < Math.pow(1024, 4)) {
|
||||
return "GB";
|
||||
} else {
|
||||
return "B";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple object check.
|
||||
* @param item
|
||||
|
@ -991,16 +991,14 @@
|
||||
},
|
||||
"TOP_REPO": "Beliebte Repositories",
|
||||
"STATISTICS": {
|
||||
"TITLE": "STATISTIKEN",
|
||||
"PRO_ITEM": "PROJEKTE",
|
||||
"REPO_ITEM": "REPOSITORIES",
|
||||
"INDEX_PRIVATE": "PRIVAT",
|
||||
"INDEX_MY_PROJECTS": "MEINE PROJEKTE",
|
||||
"INDEX_MY_REPOSITORIES": "MEINE REPOSITORIES",
|
||||
"INDEX_PUB": "ÖFFENTLICH",
|
||||
"INDEX_TOTAL": "GESAMT",
|
||||
"STORAGE": "SPEICHER",
|
||||
"LIMIT": "Limit"
|
||||
"LIMIT": "Limit",
|
||||
"STORAGE_USED": "Storage used"
|
||||
},
|
||||
"SEARCH": {
|
||||
"IN_PROGRESS": "Suche...",
|
||||
|
@ -991,16 +991,14 @@
|
||||
},
|
||||
"TOP_REPO": "Popular Repositories",
|
||||
"STATISTICS": {
|
||||
"TITLE": "STATISTICS",
|
||||
"PRO_ITEM": "PROJECTS",
|
||||
"REPO_ITEM": "REPOSITORIES",
|
||||
"INDEX_PRIVATE": "PRIVATE",
|
||||
"INDEX_MY_PROJECTS": "MY PROJECTS",
|
||||
"INDEX_MY_REPOSITORIES": "MY REPOSITORIES",
|
||||
"INDEX_PUB": "PUBLIC",
|
||||
"INDEX_TOTAL": "TOTAL",
|
||||
"PRO_ITEM": "Projects",
|
||||
"REPO_ITEM": "Repositories",
|
||||
"INDEX_PRIVATE": "Private",
|
||||
"INDEX_PUB": "Public",
|
||||
"INDEX_TOTAL": "Total",
|
||||
"STORAGE": "STORAGE",
|
||||
"LIMIT": "Limit"
|
||||
"LIMIT": "Limit",
|
||||
"STORAGE_USED": "Storage used"
|
||||
},
|
||||
"SEARCH": {
|
||||
"IN_PROGRESS": "Search...",
|
||||
|
@ -991,16 +991,14 @@
|
||||
},
|
||||
"TOP_REPO": "Repositorios Populares",
|
||||
"STATISTICS": {
|
||||
"TITLE": "ESTADÍSTICAS",
|
||||
"PRO_ITEM": "PROYECTOS",
|
||||
"REPO_ITEM": "REPOSITORIOS",
|
||||
"INDEX_PRIVATE": "PRIVADO",
|
||||
"INDEX_MY_PROJECTS": "MY PROJECTS",
|
||||
"INDEX_MY_REPOSITORIES": "MY REPOSITORIES",
|
||||
"INDEX_PUB": "PÚBLICO",
|
||||
"INDEX_TOTAL": "TOTAL",
|
||||
"STORAGE": "ALMACENAMIENTO",
|
||||
"LIMIT": "Límite"
|
||||
"LIMIT": "Límite",
|
||||
"STORAGE_USED": "Storage used"
|
||||
},
|
||||
"SEARCH": {
|
||||
"IN_PROGRESS": "Buscar...",
|
||||
|
@ -964,16 +964,14 @@
|
||||
},
|
||||
"TOP_REPO": "Dépôts Populaires",
|
||||
"STATISTICS": {
|
||||
"TITLE": "STATISTIQUES",
|
||||
"PRO_ITEM": "PROJETS",
|
||||
"REPO_ITEM": "DÉPÔTS",
|
||||
"INDEX_PRIVATE": "PRIVÉ",
|
||||
"INDEX_MY_PROJECTS": "MES PROJETS",
|
||||
"INDEX_MY_REPOSITORIES": "MES DÉPÔTS",
|
||||
"INDEX_PUB": "PUBLIC",
|
||||
"INDEX_TOTAL": "TOTAL",
|
||||
"STORAGE": "STOCKAGE",
|
||||
"LIMIT": "Limite"
|
||||
"LIMIT": "Limite",
|
||||
"STORAGE_USED": "Storage used"
|
||||
},
|
||||
"SEARCH": {
|
||||
"IN_PROGRESS": "Rechercher...",
|
||||
|
@ -987,16 +987,14 @@
|
||||
},
|
||||
"TOP_REPO": "Repositórios Populares",
|
||||
"STATISTICS": {
|
||||
"TITLE": "ESTATÍSTICAS",
|
||||
"PRO_ITEM": "PROJETOS",
|
||||
"REPO_ITEM": "REPOSITÓRIOS",
|
||||
"INDEX_PRIVATE": "PRIVADO",
|
||||
"INDEX_MY_PROJECTS": "MEUS PROJETOS",
|
||||
"INDEX_MY_REPOSITORIES": "MEUS REPOSITÓRIOS",
|
||||
"INDEX_PUB": "PUBLICO",
|
||||
"INDEX_TOTAL": "TOTAL",
|
||||
"STORAGE": "ARMAZENAMENTO",
|
||||
"LIMIT": "Limite"
|
||||
"LIMIT": "Limite",
|
||||
"STORAGE_USED": "Storage used"
|
||||
},
|
||||
"SEARCH": {
|
||||
"IN_PROGRESS": "Buscando...",
|
||||
|
@ -991,16 +991,14 @@
|
||||
},
|
||||
"TOP_REPO": "Popüler Depolar",
|
||||
"STATISTICS": {
|
||||
"TITLE": "İSTATİSTİK",
|
||||
"PRO_ITEM": "PROJELER",
|
||||
"REPO_ITEM": "DEPOLAR",
|
||||
"INDEX_PRIVATE": "ÖZEL",
|
||||
"INDEX_MY_PROJECTS": "BENİM PROJELERİM",
|
||||
"INDEX_MY_REPOSITORIES": "BENİM DEPOLARIM",
|
||||
"INDEX_PUB": "GENEL",
|
||||
"INDEX_TOTAL": "TOPLAM",
|
||||
"STORAGE": "DEPOLAMA",
|
||||
"LIMIT": "Limit"
|
||||
"LIMIT": "Limit",
|
||||
"STORAGE_USED": "Storage used"
|
||||
},
|
||||
"SEARCH": {
|
||||
"IN_PROGRESS": "Ara...",
|
||||
|
@ -991,16 +991,14 @@
|
||||
},
|
||||
"TOP_REPO": "受欢迎的镜像仓库",
|
||||
"STATISTICS": {
|
||||
"TITLE": "统计",
|
||||
"PRO_ITEM": "项目",
|
||||
"REPO_ITEM": "镜像仓库",
|
||||
"INDEX_PRIVATE": "私有",
|
||||
"INDEX_MY_PROJECTS": "我的项目",
|
||||
"INDEX_MY_REPOSITORIES": "我的镜像仓库",
|
||||
"INDEX_PUB": "公开",
|
||||
"INDEX_TOTAL": "总计",
|
||||
"STORAGE": "存储",
|
||||
"LIMIT": "容量"
|
||||
"LIMIT": "容量",
|
||||
"STORAGE_USED": "已使用的存储空间"
|
||||
},
|
||||
"SEARCH": {
|
||||
"IN_PROGRESS": "搜索中...",
|
||||
|
@ -987,16 +987,14 @@
|
||||
},
|
||||
"TOP_REPO": "受歡迎的鏡像倉庫",
|
||||
"STATISTICS":{
|
||||
"TITLE": "統計",
|
||||
"PRO_ITEM": "項目",
|
||||
"REPO_ITEM": "鏡像倉庫",
|
||||
"INDEX_PRIVATE": "私有",
|
||||
"INDEX_MY_PROJECTS": "我的項目",
|
||||
"INDEX_MY_REPOSITORIES": "我的鏡像倉庫",
|
||||
"INDEX_PUB": "公開",
|
||||
"INDEX_TOTAL": "總計",
|
||||
"STORAGE": "存儲",
|
||||
"LIMIT": "容量"
|
||||
"LIMIT": "容量",
|
||||
"STORAGE_USED": "Storage used"
|
||||
},
|
||||
"SEARCH":{
|
||||
"IN_PROGRESS": "搜索中...",
|
||||
|
Loading…
Reference in New Issue
Block a user