diff --git a/ogWebconsole/src/app/app.module.ts b/ogWebconsole/src/app/app.module.ts index 7a944c5..e2eb538 100644 --- a/ogWebconsole/src/app/app.module.ts +++ b/ogWebconsole/src/app/app.module.ts @@ -135,6 +135,7 @@ import { registerLocaleData } from '@angular/common'; import localeEs from '@angular/common/locales/es'; import { GlobalStatusComponent } from './components/global-status/global-status.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) { return new TranslateHttpLoader(http, './locale/', '.json'); @@ -229,7 +230,8 @@ registerLocaleData(localeEs, 'es-ES'); OperationResultDialogComponent, ConvertImageComponent, GlobalStatusComponent, - ShowImagesComponent + ShowImagesComponent, + StatusTabComponent ], bootstrap: [AppComponent], imports: [BrowserModule, diff --git a/ogWebconsole/src/app/components/global-status/status-tab/status-tab.component.css b/ogWebconsole/src/app/components/global-status/status-tab/status-tab.component.css new file mode 100644 index 0000000..0fccf20 --- /dev/null +++ b/ogWebconsole/src/app/components/global-status/status-tab/status-tab.component.css @@ -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; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/global-status/status-tab/status-tab.component.html b/ogWebconsole/src/app/components/global-status/status-tab/status-tab.component.html new file mode 100644 index 0000000..c94d266 --- /dev/null +++ b/ogWebconsole/src/app/components/global-status/status-tab/status-tab.component.html @@ -0,0 +1,56 @@ + +
+ +
+

{{ 'diskUsageTitle' | translate }}

+
+ + +
+

{{ 'totalLabel' | translate }}: {{ formatBytes(diskUsage.total) }} +

+

{{ 'usedLabel' | translate }}: {{ formatBytes(diskUsage.used) }} +

+

{{ 'availableLabel' | translate }}: {{ formatBytes(diskUsage.available) + }}

+

{{ 'freeLabel' | translate }}: {{ diskUsage.percentage }}

+
+
+
+ + +
+

{{ 'servicesTitle' | translate }}

+ +
+ + +
+

{{ 'installedOglivesTitle' | translate }}

+ + + + + + + + + + + + + + + + + +
{{ 'idLabel' | translate }}{{ 'kernelLabel' | translate }}{{ 'architectureLabel' | translate }}{{ 'revisionLabel' | translate }}
{{ oglive.id }}{{ oglive.kernel }}{{ oglive.architecture }}{{ oglive.revision }}
+
+
\ No newline at end of file diff --git a/ogWebconsole/src/app/components/global-status/status-tab/status-tab.component.spec.ts b/ogWebconsole/src/app/components/global-status/status-tab/status-tab.component.spec.ts new file mode 100644 index 0000000..c29ac03 --- /dev/null +++ b/ogWebconsole/src/app/components/global-status/status-tab/status-tab.component.spec.ts @@ -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; + + 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(); + }); +}); diff --git a/ogWebconsole/src/app/components/global-status/status-tab/status-tab.component.ts b/ogWebconsole/src/app/components/global-status/status-tab/status-tab.component.ts new file mode 100644 index 0000000..970cfa1 --- /dev/null +++ b/ogWebconsole/src/app/components/global-status/status-tab/status-tab.component.ts @@ -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'; + } + } +}