Merge pull request #397 from Moonlight-Panel/v2_AddDetailsInNodeList

Added more details into the node list (like cpu, memory and disk)
This commit is contained in:
Masu Baumgartner 2024-04-27 13:48:03 +02:00 committed by GitHub
commit e1fbf601f3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 163 additions and 31 deletions

View file

@ -0,0 +1,26 @@
@{
var color = "primary";
if (Value >= PrimaryEnd && Value < DangerStart)
color = "warning";
if (Value >= DangerStart)
color = "danger";
var percent = Math.Round(Value);
var percentText = Math.Round(Value, 2) + "%";
}
<div class="progress">
<div class="progress-bar bg-@(color) fs-4" role="progressbar" aria-valuenow="@(percent)" aria-valuemin="0" aria-valuemax="100" style="width: @(percent)%">
</div>
</div>
@code
{
[Parameter]
public double Value { get; set; }
[Parameter] public double PrimaryEnd { get; set; } = 60;
[Parameter] public double DangerStart { get; set; } = 80;
}

View file

@ -4,39 +4,103 @@
@using Moonlight.Features.Servers.UI.Components
@using Moonlight.Features.Servers.Entities
@using MoonCore.Abstractions
@using BlazorTable
@using Microsoft.EntityFrameworkCore
@using MoonCore.Exceptions
@using MoonCore.Helpers
@using System.Text.RegularExpressions;
@using Moonlight.Features.Servers.Api.Resources
@using Moonlight.Features.Servers.Services
@inject Repository<Server> ServerRepository
@inject Repository<ServerNode> NodeRepository
@inject NodeService NodeService
@inject IServiceProvider ServiceProvider
@implements IDisposable
@attribute [RequirePermission(5001)]
<AdminServersNavigation Index="1"/>
<LazyLoader Load="Load">
<AutoCrud TItem="ServerNode"
TCreateForm="CreateNodeForm"
TUpdateForm="UpdateNodeForm"
Title=""
Load="Load"
Load="LoadData"
ValidateAdd="ValidateAdd"
ValidateUpdate="ValidateUpdate"
ValidateDelete="ValidateDelete">
<Actions>
<a href="/admin/servers/nodes/view/@(context.Id)" class="btn btn-icon btn-info">
<i class="bx bx-sm bx-wrench"></i>
</a>
</Actions>
<View>
<CrudColumn TItem="ServerNode" Field="@(x => x.Id)" Title="Id"/>
<CrudColumn TItem="ServerNode" Field="@(x => x.Name)" Title="Name"/>
<CrudColumn TItem="ServerNode" Field="@(x => x.Fqdn)" Title="Fqdn"/>
<CrudColumn TItem="ServerNode" Field="@(x => x.Id)" Title="Status">
<CrudColumn TItem="ServerNode" Field="@(x => x.Name)" Title="Name">
<Template>
<a href="/admin/servers/nodes/view/@(context!.Id)">@context!.Name</a>
</Template>
</CrudColumn>
<CrudColumn TItem="ServerNode" Field="@(x => x.Fqdn)" Title="Fqdn"/>
<CrudColumn TItem="ServerNode" Title="Status">
<Template>
@if (NodeStats.ContainsKey(context!.Id))
{
if (NodeStats[context.Id] == null)
{
<span class="text-danger">Offline</span>
}
else
{
<span class="text-success">Online</span>
}
}
else
{
<span class="text-muted">N/A</span>
}
</Template>
</CrudColumn>
<CrudColumn TItem="ServerNode" Title="CPU">
<Template>
@if (NodeStats.ContainsKey(context!.Id) && NodeStats[context.Id] != null)
{
var cores = NodeStats[context!.Id]!.Hardware.Cores;
var percent = Math.Round(cores.Average(x => x.Usage), 2);
<ColoredBar Value="percent"/>
}
else
{
<span class="text-muted">N/A</span>
}
</Template>
</CrudColumn>
<CrudColumn TItem="ServerNode" Title="Memory">
<Template>
@if (NodeStats.ContainsKey(context!.Id) && NodeStats[context.Id] != null)
{
var memory = NodeStats[context!.Id]!.Hardware.Memory;
var percent = Math.Round(((float)memory.Total - memory.Available - memory.Free) / memory.Total * 100, 2);
<ColoredBar Value="percent"/>
}
else
{
<span class="text-muted">N/A</span>
}
</Template>
</CrudColumn>
<CrudColumn TItem="ServerNode" Title="Disk">
<Template>
@if (NodeStats.ContainsKey(context!.Id) && NodeStats[context.Id] != null)
{
var disk = NodeStats[context!.Id]!.Hardware.Disk;
var percent = Math.Round((float)disk.Free / disk.Total * 100, 2);
<ColoredBar Value="percent"/>
}
else
{
<span class="text-muted">N/A</span>
}
</Template>
</CrudColumn>
</View>
@ -46,10 +110,47 @@
</IconAlert>
</NoItemsView>
</AutoCrud>
</LazyLoader>
@code
{
private ServerNode[] Load(Repository<ServerNode> repository)
private Timer UpdateTimer;
private Dictionary<int, SystemStatus?> NodeStats = new();
private Task Load(LazyLoader lazyLoader)
{
UpdateTimer = new(async _ =>
{
NodeStats.Clear();
using var scope = ServiceProvider.CreateScope();
var nodeRepo = scope.ServiceProvider.GetRequiredService<Repository<ServerNode>>();
var nodes = nodeRepo.Get().ToArray();
foreach (var node in nodes)
{
try
{
var status = await NodeService.GetStatus(node);
NodeStats[node.Id] = status;
}
catch (Exception e)
{
Logger.Warn($"Unable to fetch system status for node '{node.Name}'");
Logger.Warn(e);
NodeStats[node.Id] = null;
}
await InvokeAsync(StateHasChanged);
}
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(1));
return Task.CompletedTask;
}
private ServerNode[] LoadData(Repository<ServerNode> repository)
{
return repository
.Get()
@ -106,4 +207,9 @@
return false;
}
public void Dispose()
{
UpdateTimer?.Dispose();
}
}