Change status page to dashboard

This commit is contained in:
Albrecht Lohofener
2025-03-26 14:26:56 +01:00
parent c4193c1fe8
commit e042dea8c4
11 changed files with 198 additions and 94 deletions
+4 -4
View File
@@ -1,8 +1,8 @@
import { Routes } from '@angular/router';
import { SystemInformationComponent } from "./system-information/system-information.component";
import { StatusComponent } from './status/status.component';
import { ConsoleComponent } from './console/console.component';
import { InfoComponent } from './info/info.component';
import { DashboardComponent } from './dashboard/dashboard.component';
export const routes: Routes = [
{ // Redirect to 'status' by default
@@ -11,9 +11,9 @@ export const routes: Routes = [
pathMatch: 'full'
},
{
path: 'status',
component: StatusComponent,
title: 'Status'
path: 'dashboard',
component: DashboardComponent,
title: 'Dashboard'
},
{
path: 'console',
@@ -7,12 +7,19 @@ interface OpenWrtInfo {
kernelVersion: string;
}
interface AttachedHardware {
wan: string;
lan: string;
usb: string[];
pci: string[];
}
@Injectable({
providedIn: 'root'
})
export class BackendCommunicationService {
//urlPrefix: string = 'http://localhost:8006'; // Just for development
urlPrefix: string = '';
urlPrefix: string = 'http://localhost:8006'; // Just for development
//urlPrefix: string = '';
constructor(private http: HttpClient) { }
@@ -72,4 +79,34 @@ export class BackendCommunicationService {
})
);
}
// TODO TODO TODO: Implement an API call for getting attached hardware
getAttachedHardware(): Observable<AttachedHardware> {
return this.http.get<any>(this.urlPrefix + '/api/get_container_info').pipe(
map(response => {
const text = response['combined_output']
const tmpLan = text.match(/declare -x LAN_IF="([^"]+)"/)[1];
const tmpWan = text.match(/declare -x WAN_IF="([^"]+)"/)[1];
const tmpUsb = [];
const tmpUsb1 = text.match(/declare -x USB_1="([^"]+)"/);
const tmpUsb2 = text.match(/declare -x USB_2="([^"]+)"/);
if (tmpUsb1) tmpUsb.push(tmpUsb1[1]);
if (tmpUsb2) tmpUsb.push(tmpUsb2[1]);
const tmpPci = [];
const tmpPci1 = text.match(/declare -x PCI_1="([^"]+)"/);
const tmpPci2 = text.match(/declare -x PCI_2="([^"]+)"/);
if (tmpPci1) tmpPci.push(tmpPci1[1]);
if (tmpPci2) tmpPci.push(tmpPci2[1]);
return {
lan: tmpLan,
wan: tmpWan,
usb: tmpUsb,
pci: tmpPci
};
})
);
}
}
@@ -0,0 +1,59 @@
<div class="grid-container">
<mat-grid-list cols="2" rowHeight="300px">
<mat-grid-tile [colspan]="1" [rowspan]="1">
<mat-card class="dashboard-card">
<mat-card-header>
<mat-card-title>Running</mat-card-title>
</mat-card-header>
<mat-card-content class="dashboard-card-content">
@if (openwrtVersion) {
<mat-list role="list">
<mat-list-item role="listitem">
<mat-icon matListItemIcon>computer</mat-icon>
{{ openwrtVersion }}
</mat-list-item>
<mat-list-item role="listitem">
<mat-icon matListItemIcon>info</mat-icon>
Linux kernel {{ openWrtKernel }}
</mat-list-item>
</mat-list>
} @else {
<mat-spinner [diameter]="50"></mat-spinner>
}
</mat-card-content>
</mat-card>
</mat-grid-tile>
<mat-grid-tile [colspan]="1" [rowspan]="1">
<mat-card class="dashboard-card">
<mat-card-header>
<mat-card-title>Attached hardware</mat-card-title>
</mat-card-header>
<mat-card-content class="dashboard-card-content">
<mat-list role="list">
<mat-list-item role="listitem">
<mat-icon matListItemIcon>lan</mat-icon>
WAN: {{ wan }}
</mat-list-item>
<mat-list-item role="listitem">
<mat-icon matListItemIcon>lan</mat-icon>
LAN: {{ lan }}
</mat-list-item>
@for (usbDevice of usb; track usbDevice) {
<mat-list-item role="listitem">
<mat-icon matListItemIcon>usb</mat-icon>
USB: {{ usbDevice }}
</mat-list-item>
}
@for (pciDevice of pci; track pciDevice) {
<mat-list-item role="listitem">
<mat-icon matListItemIcon>memory</mat-icon>
PCI: {{ pciDevice }}
</mat-list-item>
}
</mat-list>
</mat-card-content>
</mat-card>
</mat-grid-tile>
</mat-grid-list>
</div>
@@ -0,0 +1,21 @@
.grid-container {
margin: 20px;
}
.dashboard-card {
position: absolute;
top: 15px;
left: 15px;
right: 15px;
bottom: 15px;
}
.more-button {
position: absolute;
top: 5px;
right: 10px;
}
.dashboard-card-content {
text-align: left;
}
@@ -0,0 +1,25 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { DashboardComponent } from './dashboard.component';
describe('DashboardComponent', () => {
let component: DashboardComponent;
let fixture: ComponentFixture<DashboardComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [NoopAnimationsModule]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DashboardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should compile', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,49 @@
import { Component, inject } from '@angular/core';
import { MatGridListModule } from '@angular/material/grid-list';
import { MatMenuModule } from '@angular/material/menu';
import { MatIconModule } from '@angular/material/icon';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatListModule } from '@angular/material/list';
import { BackendCommunicationService } from '../backend-communication.service';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrl: './dashboard.component.scss',
standalone: true,
imports: [
MatGridListModule,
MatMenuModule,
MatIconModule,
MatButtonModule,
MatCardModule,
MatProgressSpinnerModule,
MatListModule
]
})
export class DashboardComponent {
openwrtVersion?: string;
openWrtKernel?: string;
wan?: string;
lan?: string;
usb?: string[];
pci?: string[];
constructor(private service: BackendCommunicationService) {
this.service.pollOpenWrtInfo().subscribe(response => {
this.openwrtVersion = response.version;
this.openWrtKernel = response.kernelVersion;
});
this.service.getAttachedHardware().subscribe(response => {
this.wan = response.wan;
this.lan = response.lan;
this.usb = response.usb;
this.pci = response.pci;
});
}
}
@@ -5,7 +5,7 @@
[opened]="(isHandset$ | async) === false">
<mat-toolbar>Menu</mat-toolbar>
<mat-nav-list>
<a mat-list-item [routerLink]="['status']">Status</a>
<a mat-list-item [routerLink]="['dashboard']">Dashboard</a>
<a mat-list-item [routerLink]="['console']">Console</a>
<a mat-list-item [routerLink]="['system_information']">System information</a>
<a mat-list-item [routerLink]="['info']">Info</a>
@@ -1,26 +0,0 @@
<div class="responsive-grid">
<mat-card class="status-card" appearance="outlined">
<mat-card-header>
<mat-card-title>OpenWrt image</mat-card-title>
</mat-card-header>
<mat-card-content>
@if (openwrtVersion) {
<ul>
<li>Version: {{ openwrtVersion }}</li>
<li>Kernel: {{ openWrtKernel }}</li>
</ul>
} @else {
<mat-spinner [diameter]="50"></mat-spinner>
}
</mat-card-content>
</mat-card>
<mat-card class="status-card" appearance="outlined">
<mat-card-header>
<mat-card-title>Attached hardware</mat-card-title>
</mat-card-header>
<mat-card-content>
</mat-card-content>
</mat-card>
</div>
@@ -1,14 +0,0 @@
.status-card {
max-width: 400px;
margin: 5px;
}
.responsive-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
//gap: 24px;
}
mat-spinner {
margin-top: 10px;
}
@@ -1,23 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { StatusComponent } from './status.component';
describe('StatusComponent', () => {
let component: StatusComponent;
let fixture: ComponentFixture<StatusComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [StatusComponent]
})
.compileComponents();
fixture = TestBed.createComponent(StatusComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -1,24 +0,0 @@
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { BackendCommunicationService } from '../backend-communication.service';
@Component({
selector: 'app-status',
imports: [MatCardModule, MatButtonModule, MatProgressSpinnerModule],
templateUrl: './status.component.html',
styleUrl: './status.component.scss',
})
export class StatusComponent {
openwrtVersion?: string;
openWrtKernel?: string;
constructor(private service: BackendCommunicationService) {
this.service.pollOpenWrtInfo().subscribe(response => {
this.openwrtVersion = response.version;
this.openWrtKernel = response.kernelVersion;
})
}
}