@using LucideBlazor @using MoonlightServers.Frontend.Infrastructure.Helpers @using MoonlightServers.Frontend.Shared @using MoonlightServers.Shared @using MoonlightServers.Shared.Admin.Nodes @using ShadcnBlazor.Cards @using ShadcnBlazor.Emptys @using ShadcnBlazor.Spinners @using ShadcnBlazor.Progresses @inject HttpClient HttpClient @implements IAsyncDisposable

Overview

@if (HasLoaded && StatisticsDto != null) { Uptime @Formatter.FormatDuration(StatisticsDto.Uptime) } else { } @if (HasLoaded && HealthDto != null) { Health Status @if (HealthDto.IsHealthy) { Healthy } else { Unhealthy } } else { }

Details

System Details Details over your general system configuration @if (StatisticsDto == null) { No details No details about your system found } else {
CPU Model @StatisticsDto.Cpu.ModelName
Total Memory @Formatter.FormatSize(StatisticsDto.Memory.TotalBytes)
Total Disk Space @{ var totalDiskSpace = StatisticsDto .Disks .DistinctBy(x => x.Device) .Sum(x => x.TotalBytes); } @Formatter.FormatSize(totalDiskSpace)
}
Disk Details Details over all your mounted disks @if (StatisticsDto == null) { No details No details about disk and their usage found } else {
@foreach (var disk in StatisticsDto.Disks) {
@disk.MountPoint @disk.FileSystem @disk.Device
@Formatter.FormatSize(disk.UsedBytes) / @Formatter.FormatSize(disk.TotalBytes)
}
}
@code { [Parameter] public NodeDto Node { get; set; } private NodeHealthDto? HealthDto; private NodeStatisticsDto? StatisticsDto; private bool HasLoaded; private RealtimeChart? CpuChart; private RealtimeChart? NetworkInChart; private RealtimeChart? NetworkOutChart; private RealtimeChart? MemoryChart; private Timer? Timer; protected override async Task OnAfterRenderAsync(bool firstRender) { if (!firstRender) return; HealthDto = await HttpClient.GetFromJsonAsync( $"api/admin/servers/nodes/{Node.Id}/health", SerializationContext.Default.Options ); if (HealthDto is { IsHealthy: true }) { StatisticsDto = await HttpClient.GetFromJsonAsync( $"api/admin/servers/nodes/{Node.Id}/statistics", SerializationContext.Default.Options ); } HasLoaded = true; await InvokeAsync(StateHasChanged); Timer = new Timer(RefreshCallbackAsync, null, TimeSpan.Zero, TimeSpan.FromSeconds(1)); } private async void RefreshCallbackAsync(object? state) { try { StatisticsDto = await HttpClient.GetFromJsonAsync( $"api/admin/servers/nodes/{Node.Id}/statistics", SerializationContext.Default.Options ); if (StatisticsDto == null) return; if (CpuChart != null) await CpuChart.PushAsync(StatisticsDto.Cpu.TotalUsagePercent); if (MemoryChart != null) await MemoryChart.PushAsync(new MemoryDataPoint(StatisticsDto.Memory.UsedBytes, StatisticsDto.Memory.UsedPercent)); if (NetworkInChart != null && NetworkOutChart != null) { var networkInterface = StatisticsDto .Network .FirstOrDefault(x => x.Name.StartsWith("eth")); if (networkInterface == null) { networkInterface = StatisticsDto .Network .FirstOrDefault(x => x.Name.StartsWith("en")); } if (networkInterface == null) return; await NetworkInChart.PushAsync(networkInterface.RxBytesPerSec); await NetworkOutChart.PushAsync(networkInterface.TxBytesPerSec); } await InvokeAsync(StateHasChanged); } catch (Exception e) { Console.WriteLine(e); } } public async ValueTask DisposeAsync() { if (Timer != null) await Timer.DisposeAsync(); if (CpuChart != null) await CpuChart.DisposeAsync(); } private record MemoryDataPoint(long UsedMemory, double Percent); }