refs #1727 Add StatusTab component to Global Status for enhanced service and disk usage display
testing/ogGui-multibranch/pipeline/head There was a failure building this commit
Details
testing/ogGui-multibranch/pipeline/head There was a failure building this commit
Details
parent
9f9d73644b
commit
50755bd1d5
|
@ -135,6 +135,7 @@ import { registerLocaleData } from '@angular/common';
|
||||||
import localeEs from '@angular/common/locales/es';
|
import localeEs from '@angular/common/locales/es';
|
||||||
import { GlobalStatusComponent } from './components/global-status/global-status.component';
|
import { GlobalStatusComponent } from './components/global-status/global-status.component';
|
||||||
import { ShowImagesComponent } from './components/repositories/show-images/show-images.component';
|
import { ShowImagesComponent } from './components/repositories/show-images/show-images.component';
|
||||||
|
import { StatusTabComponent } from './components/global-status/status-tab/status-tab.component';
|
||||||
|
|
||||||
export function HttpLoaderFactory(http: HttpClient) {
|
export function HttpLoaderFactory(http: HttpClient) {
|
||||||
return new TranslateHttpLoader(http, './locale/', '.json');
|
return new TranslateHttpLoader(http, './locale/', '.json');
|
||||||
|
@ -229,7 +230,8 @@ registerLocaleData(localeEs, 'es-ES');
|
||||||
OperationResultDialogComponent,
|
OperationResultDialogComponent,
|
||||||
ConvertImageComponent,
|
ConvertImageComponent,
|
||||||
GlobalStatusComponent,
|
GlobalStatusComponent,
|
||||||
ShowImagesComponent
|
ShowImagesComponent,
|
||||||
|
StatusTabComponent
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
imports: [BrowserModule,
|
imports: [BrowserModule,
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
.dashboard {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disk-usage-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disk-usage {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-list {
|
||||||
|
margin-top: 0em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.services-status {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.services-status li {
|
||||||
|
margin: 5px 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-led {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-led.active {
|
||||||
|
background-color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-led.inactive {
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disk-title {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-title {
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
<app-loading [isLoading]="loading"></app-loading>
|
||||||
|
<div *ngIf="!loading" class="dashboard">
|
||||||
|
<!-- Disk Usage Section -->
|
||||||
|
<div class="disk-usage-container">
|
||||||
|
<h3 class="disk-title">{{ 'diskUsageTitle' | translate }}</h3>
|
||||||
|
<div class="disk-usage" joyrideStep="diskUsageStep" text="{{ 'diskUsageDescription' | translate }}">
|
||||||
|
<ngx-charts-pie-chart [view]="view" [scheme]="colorScheme" [results]="diskUsageChartData" [doughnut]="isDoughnut"
|
||||||
|
[labels]="showLabels">
|
||||||
|
</ngx-charts-pie-chart>
|
||||||
|
<div class="disk-usage-info">
|
||||||
|
<p>{{ 'totalLabel' | translate }}: <strong>{{ formatBytes(diskUsage.total) }}</strong>
|
||||||
|
</p>
|
||||||
|
<p>{{ 'usedLabel' | translate }}: <strong>{{ formatBytes(diskUsage.used) }}</strong>
|
||||||
|
</p>
|
||||||
|
<p>{{ 'availableLabel' | translate }}: <strong>{{ formatBytes(diskUsage.available)
|
||||||
|
}}</strong></p>
|
||||||
|
<p>{{ 'freeLabel' | translate }}: <strong>{{ diskUsage.percentage }}</strong></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Services Status Section -->
|
||||||
|
<div class="services-status" joyrideStep="servicesStatusStep" text="{{ 'servicesStatusDescription' | translate }}">
|
||||||
|
<h3 class="service-title">{{ 'servicesTitle' | translate }}</h3>
|
||||||
|
<ul class="service-list">
|
||||||
|
<li *ngFor="let service of getServices()">
|
||||||
|
<span class="status-led"
|
||||||
|
[ngClass]="{ 'active': service.status === 'active', 'inactive': service.status !== 'active' }"></span>
|
||||||
|
{{ service.name }}: {{ service.status | translate }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Installed OgLives Section -->
|
||||||
|
<div class="installed-oglives" joyrideStep="oglivesStep" text="{{ 'oglivesDescription' | translate }}">
|
||||||
|
<h3>{{ 'installedOglivesTitle' | translate }}</h3>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ 'idLabel' | translate }}</th>
|
||||||
|
<th>{{ 'kernelLabel' | translate }}</th>
|
||||||
|
<th>{{ 'architectureLabel' | translate }}</th>
|
||||||
|
<th>{{ 'revisionLabel' | translate }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let oglive of installedOgLives">
|
||||||
|
<td>{{ oglive.id }}</td>
|
||||||
|
<td>{{ oglive.kernel }}</td>
|
||||||
|
<td>{{ oglive.architecture }}</td>
|
||||||
|
<td>{{ oglive.revision }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||||
|
import { ToastrModule } from 'ngx-toastr';
|
||||||
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
|
import { ConfigService } from '@services/config.service';
|
||||||
|
import { LoadingComponent } from 'src/app/shared/loading/loading.component';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { NgxChartsModule } from '@swimlane/ngx-charts';
|
||||||
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { StatusTabComponent } from './status-tab.component';
|
||||||
|
|
||||||
|
describe('StatusTabComponent', () => {
|
||||||
|
let component: StatusTabComponent;
|
||||||
|
let fixture: ComponentFixture<StatusTabComponent>;
|
||||||
|
|
||||||
|
const mockConfigService = {
|
||||||
|
apiUrl: 'http://mock-api-url'
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [StatusTabComponent, LoadingComponent],
|
||||||
|
imports: [
|
||||||
|
HttpClientTestingModule,
|
||||||
|
ToastrModule.forRoot(),
|
||||||
|
MatDialogModule,
|
||||||
|
MatTabsModule,
|
||||||
|
TranslateModule.forRoot(),
|
||||||
|
NgxChartsModule,
|
||||||
|
BrowserAnimationsModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{ provide: ConfigService, useValue: mockConfigService }
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(StatusTabComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-status-tab',
|
||||||
|
templateUrl: './status-tab.component.html',
|
||||||
|
styleUrl: './status-tab.component.css'
|
||||||
|
})
|
||||||
|
export class StatusTabComponent {
|
||||||
|
@Input() loading: boolean = false;
|
||||||
|
@Input() diskUsage: any = {};
|
||||||
|
@Input() servicesStatus: any = {};
|
||||||
|
@Input() installedOgLives: any[] = [];
|
||||||
|
@Input() diskUsageChartData: any[] = [];
|
||||||
|
@Input() showLabels: boolean = true;
|
||||||
|
@Input() isDoughnut: boolean = true;
|
||||||
|
@Input() colorScheme: any = {
|
||||||
|
domain: ['#df200d', '#26a700']
|
||||||
|
};
|
||||||
|
@Input() view: [number, number] = [400, 220];
|
||||||
|
|
||||||
|
getServices(): { name: string, status: string }[] {
|
||||||
|
if (!this.servicesStatus) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const services = Object.keys(this.servicesStatus).map(key => ({
|
||||||
|
name: key,
|
||||||
|
status: this.servicesStatus[key]
|
||||||
|
}))
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
formatBytes(bytes: number): string {
|
||||||
|
if (bytes >= 1e9) {
|
||||||
|
return (bytes / 1e9).toFixed(2) + ' GB';
|
||||||
|
} else if (bytes >= 1e6) {
|
||||||
|
return (bytes / 1e6).toFixed(2) + ' MB';
|
||||||
|
} else if (bytes >= 1e3) {
|
||||||
|
return (bytes / 1e3).toFixed(2) + ' KB';
|
||||||
|
} else {
|
||||||
|
return bytes + ' B';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue