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:
commit
e1fbf601f3
2 changed files with 163 additions and 31 deletions
26
Moonlight/Core/UI/Components/ColoredBar.razor
Normal file
26
Moonlight/Core/UI/Components/ColoredBar.razor
Normal 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;
|
||||||
|
}
|
|
@ -4,52 +4,153 @@
|
||||||
@using Moonlight.Features.Servers.UI.Components
|
@using Moonlight.Features.Servers.UI.Components
|
||||||
@using Moonlight.Features.Servers.Entities
|
@using Moonlight.Features.Servers.Entities
|
||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
@using BlazorTable
|
|
||||||
@using Microsoft.EntityFrameworkCore
|
@using Microsoft.EntityFrameworkCore
|
||||||
@using MoonCore.Exceptions
|
@using MoonCore.Exceptions
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using System.Text.RegularExpressions;
|
@using System.Text.RegularExpressions;
|
||||||
|
@using Moonlight.Features.Servers.Api.Resources
|
||||||
|
@using Moonlight.Features.Servers.Services
|
||||||
|
|
||||||
@inject Repository<Server> ServerRepository
|
@inject Repository<Server> ServerRepository
|
||||||
@inject Repository<ServerNode> NodeRepository
|
@inject Repository<ServerNode> NodeRepository
|
||||||
|
@inject NodeService NodeService
|
||||||
|
@inject IServiceProvider ServiceProvider
|
||||||
|
|
||||||
|
@implements IDisposable
|
||||||
|
|
||||||
@attribute [RequirePermission(5001)]
|
@attribute [RequirePermission(5001)]
|
||||||
|
|
||||||
<AdminServersNavigation Index="1"/>
|
<AdminServersNavigation Index="1"/>
|
||||||
|
|
||||||
<AutoCrud TItem="ServerNode"
|
<LazyLoader Load="Load">
|
||||||
TCreateForm="CreateNodeForm"
|
<AutoCrud TItem="ServerNode"
|
||||||
TUpdateForm="UpdateNodeForm"
|
TCreateForm="CreateNodeForm"
|
||||||
Title=""
|
TUpdateForm="UpdateNodeForm"
|
||||||
Load="Load"
|
Title=""
|
||||||
ValidateAdd="ValidateAdd"
|
Load="LoadData"
|
||||||
ValidateUpdate="ValidateUpdate"
|
ValidateAdd="ValidateAdd"
|
||||||
ValidateDelete="ValidateDelete">
|
ValidateUpdate="ValidateUpdate"
|
||||||
<Actions>
|
ValidateDelete="ValidateDelete">
|
||||||
<a href="/admin/servers/nodes/view/@(context.Id)" class="btn btn-icon btn-info">
|
<View>
|
||||||
<i class="bx bx-sm bx-wrench"></i>
|
<CrudColumn TItem="ServerNode" Field="@(x => x.Id)" Title="Id"/>
|
||||||
</a>
|
<CrudColumn TItem="ServerNode" Field="@(x => x.Name)" Title="Name">
|
||||||
</Actions>
|
<Template>
|
||||||
<View>
|
<a href="/admin/servers/nodes/view/@(context!.Id)">@context!.Name</a>
|
||||||
<CrudColumn TItem="ServerNode" Field="@(x => x.Id)" Title="Id"/>
|
</Template>
|
||||||
<CrudColumn TItem="ServerNode" Field="@(x => x.Name)" Title="Name"/>
|
</CrudColumn>
|
||||||
<CrudColumn TItem="ServerNode" Field="@(x => x.Fqdn)" Title="Fqdn"/>
|
<CrudColumn TItem="ServerNode" Field="@(x => x.Fqdn)" Title="Fqdn"/>
|
||||||
<CrudColumn TItem="ServerNode" Field="@(x => x.Id)" Title="Status">
|
<CrudColumn TItem="ServerNode" Title="Status">
|
||||||
<Template>
|
<Template>
|
||||||
<span class="text-muted">N/A</span>
|
@if (NodeStats.ContainsKey(context!.Id))
|
||||||
</Template>
|
{
|
||||||
</CrudColumn>
|
if (NodeStats[context.Id] == null)
|
||||||
</View>
|
{
|
||||||
<NoItemsView>
|
<span class="text-danger">Offline</span>
|
||||||
<IconAlert Title="No nodes found" Color="primary" Icon="bx-search-alt">
|
}
|
||||||
Add a new node in order to get started. Need help? Check out our <a href="https://docs.moonlightpanel.xyz">documentation</a>
|
else
|
||||||
</IconAlert>
|
{
|
||||||
</NoItemsView>
|
<span class="text-success">Online</span>
|
||||||
</AutoCrud>
|
}
|
||||||
|
}
|
||||||
|
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>
|
||||||
|
<NoItemsView>
|
||||||
|
<IconAlert Title="No nodes found" Color="primary" Icon="bx-search-alt">
|
||||||
|
Add a new node in order to get started. Need help? Check out our <a href="https://docs.moonlightpanel.xyz">documentation</a>
|
||||||
|
</IconAlert>
|
||||||
|
</NoItemsView>
|
||||||
|
</AutoCrud>
|
||||||
|
</LazyLoader>
|
||||||
|
|
||||||
@code
|
@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
|
return repository
|
||||||
.Get()
|
.Get()
|
||||||
|
@ -106,4 +207,9 @@
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
UpdateTimer?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue