Ver código fonte

Merge pull request #397 from Moonlight-Panel/v2_AddDetailsInNodeList

Added more details into the node list (like cpu, memory and disk)
Masu Baumgartner 1 ano atrás
pai
commit
e1fbf601f3

+ 26 - 0
Moonlight/Core/UI/Components/ColoredBar.razor

@@ -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;
+}

+ 137 - 31
Moonlight/Features/Servers/UI/Views/Admin/Nodes/Index.razor

@@ -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();
+    }
 }