|
@@ -4,52 +4,153 @@
|
|
|
@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"/>
|
|
|
|
|
|
-<AutoCrud TItem="ServerNode"
|
|
|
- TCreateForm="CreateNodeForm"
|
|
|
- TUpdateForm="UpdateNodeForm"
|
|
|
- Title=""
|
|
|
- Load="Load"
|
|
|
- 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">
|
|
|
- <Template>
|
|
|
- <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 Load="Load">
|
|
|
+ <AutoCrud TItem="ServerNode"
|
|
|
+ TCreateForm="CreateNodeForm"
|
|
|
+ TUpdateForm="UpdateNodeForm"
|
|
|
+ Title=""
|
|
|
+ Load="LoadData"
|
|
|
+ ValidateAdd="ValidateAdd"
|
|
|
+ ValidateUpdate="ValidateUpdate"
|
|
|
+ ValidateDelete="ValidateDelete">
|
|
|
+ <View>
|
|
|
+ <CrudColumn TItem="ServerNode" Field="@(x => x.Id)" Title="Id"/>
|
|
|
+ <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>
|
|
|
+ <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
|
|
|
{
|
|
|
- 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();
|
|
|
+ }
|
|
|
}
|