357 lines
12 KiB
Plaintext
357 lines
12 KiB
Plaintext
@page "/admin/nodes/view/{id:int}"
|
|
|
|
@using Moonlight.App.Repositories
|
|
@using Moonlight.App.Database.Entities
|
|
@using Moonlight.App.Helpers
|
|
@using Moonlight.App.Models.Daemon.Resources
|
|
@using Moonlight.App.Models.Wings.Resources
|
|
@using Moonlight.App.Services
|
|
|
|
@inject NodeRepository NodeRepository
|
|
@inject NodeService NodeService
|
|
|
|
<OnlyAdmin>
|
|
<LazyLoader Load="Load">
|
|
@if (Node == null)
|
|
{
|
|
<div class="alert alert-warning">
|
|
<TL>No node with this id found</TL>
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
<div class="d-flex flex-center">
|
|
<div class="row">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h3 class="card-title">
|
|
<span class="fw-bold fs-3">
|
|
@(Node.Name) <TL>details</TL>
|
|
</span>
|
|
</h3>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row g-3 g-lg-6">
|
|
<div class="col">
|
|
<div class="bg-gray-100 bg-opacity-70 rounded-2 px-6 py-5">
|
|
<div class="symbol symbol-30px me-5 mb-8">
|
|
<span class="symbol-label">
|
|
<i class="text-primary bx bx-lg bx-chip"></i>
|
|
</span>
|
|
</div>
|
|
<div class="m-0">
|
|
<span class="fw-bolder d-block fs-2qx lh-1 ls-n1 mb-1">
|
|
@if (CpuStats == null)
|
|
{
|
|
<span class="text-muted">
|
|
<TL>Loading</TL>
|
|
</span>
|
|
}
|
|
else
|
|
{
|
|
<span>
|
|
@(CpuStats.Usage)% <TL>of</TL> @(CpuStats.Cores) <TL>Cores used</TL>
|
|
</span>
|
|
}
|
|
</span>
|
|
<span class="fw-semibold fs-6">
|
|
@if (CpuStats == null)
|
|
{
|
|
<span class="text-muted">
|
|
<TL>Loading</TL>
|
|
</span>
|
|
}
|
|
else
|
|
{
|
|
<span>@(CpuStats.Model)</span>
|
|
}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col">
|
|
<div class="bg-gray-100 bg-opacity-70 rounded-2 px-6 py-5">
|
|
<div class="symbol symbol-30px me-5 mb-8">
|
|
<span class="symbol-label">
|
|
<i class="text-primary bx bx-lg bx-microchip"></i>
|
|
</span>
|
|
</div>
|
|
<div class="m-0">
|
|
<span class="fw-bolder d-block fs-2qx lh-1 ls-n1 mb-1">
|
|
@if (MemoryStats == null)
|
|
{
|
|
<span class="text-muted">
|
|
<TL>Loading</TL>
|
|
</span>
|
|
}
|
|
else
|
|
{
|
|
<span>
|
|
@(Formatter.FormatSize(MemoryStats.Used * 1024D * 1024D)) <TL>of</TL> @(Formatter.FormatSize(MemoryStats.Total * 1024D * 1024D)) <TL>used</TL>
|
|
</span>
|
|
}
|
|
</span>
|
|
<span class="fw-semibold fs-6">
|
|
@if (MemoryStats == null)
|
|
{
|
|
<span class="text-muted">
|
|
<TL>Loading</TL>
|
|
</span>
|
|
}
|
|
else
|
|
{
|
|
if (MemoryStats.Sticks.Any())
|
|
{
|
|
foreach (var stick in SortMemorySticks(MemoryStats.Sticks))
|
|
{
|
|
<span>@(stick)</span>
|
|
<br/>
|
|
}
|
|
}
|
|
else
|
|
{
|
|
<span>No memory sticks detected</span>
|
|
}
|
|
}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col">
|
|
<div class="bg-gray-100 bg-opacity-70 rounded-2 px-6 py-5">
|
|
<div class="symbol symbol-30px me-5 mb-8">
|
|
<span class="symbol-label">
|
|
<i class="text-primary bx bx-lg bx-microchip"></i>
|
|
</span>
|
|
</div>
|
|
<div class="m-0">
|
|
<span class="fw-bolder d-block fs-2qx lh-1 ls-n1 mb-1">
|
|
@if (DiskStats == null)
|
|
{
|
|
<span class="text-muted">
|
|
<TL>Loading</TL>
|
|
</span>
|
|
}
|
|
else
|
|
{
|
|
<span>
|
|
@(Formatter.FormatSize(DiskStats.TotalSize - DiskStats.FreeBytes)) <TL>of</TL> @(Formatter.FormatSize(DiskStats.TotalSize)) <TL>used</TL>
|
|
</span>
|
|
}
|
|
</span>
|
|
<span class="fw-semibold fs-6">
|
|
@if (DiskStats == null)
|
|
{
|
|
<span class="text-muted">
|
|
<TL>Loading</TL>
|
|
</span>
|
|
}
|
|
else
|
|
{
|
|
<span>@(DiskStats.Name) - @(DiskStats.DriveFormat)</span>
|
|
}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="mt-3 row g-3 g-lg-6">
|
|
<div class="col">
|
|
<div class="bg-gray-100 bg-opacity-70 rounded-2 px-6 py-5">
|
|
<div class="symbol symbol-30px me-5 mb-8">
|
|
<span class="symbol-label">
|
|
<i class="text-primary bx bx-lg bx-purchase-tag"></i>
|
|
</span>
|
|
</div>
|
|
<div class="m-0">
|
|
<span class="fw-bolder d-block fs-2qx lh-1 ls-n1 mb-1">
|
|
@if (SystemStatus == null)
|
|
{
|
|
<span class="text-muted">
|
|
<TL>Loading</TL>
|
|
</span>
|
|
}
|
|
else
|
|
{
|
|
<span class="text-success">
|
|
<TL>Online</TL>
|
|
</span>
|
|
}
|
|
</span>
|
|
<span class="fw-semibold fs-6">
|
|
@if (SystemStatus == null)
|
|
{
|
|
<span class="text-muted">
|
|
<TL>Loading</TL>
|
|
</span>
|
|
}
|
|
else
|
|
{
|
|
<span>@(SystemStatus.Version)</span>
|
|
}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col">
|
|
<div class="bg-gray-100 bg-opacity-70 rounded-2 px-6 py-5">
|
|
<div class="symbol symbol-30px me-5 mb-8">
|
|
<span class="symbol-label">
|
|
<i class="text-primary bx bx-lg bx-fingerprint"></i>
|
|
</span>
|
|
</div>
|
|
<div class="m-0">
|
|
<span class="fw-bolder d-block fs-2qx lh-1 ls-n1 mb-1">
|
|
@if (SystemStatus == null)
|
|
{
|
|
<span class="text-muted">
|
|
<TL>Loading</TL>
|
|
</span>
|
|
}
|
|
else
|
|
{
|
|
<span>
|
|
@(SystemStatus.KernelVersion) - @(SystemStatus.Architecture)
|
|
</span>
|
|
}
|
|
</span>
|
|
<span class="fw-semibold fs-6">
|
|
@if (SystemStatus == null)
|
|
{
|
|
<span class="text-muted">
|
|
<TL>Loading</TL>
|
|
</span>
|
|
}
|
|
else
|
|
{
|
|
<TL>Host system information</TL>
|
|
}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col">
|
|
<div class="bg-gray-100 bg-opacity-70 rounded-2 px-6 py-5">
|
|
<div class="symbol symbol-30px me-5 mb-8">
|
|
<span class="symbol-label">
|
|
<i class="text-primary bx bx-lg bxl-docker"></i>
|
|
</span>
|
|
</div>
|
|
<div class="m-0">
|
|
<span class="fw-bolder d-block fs-2qx lh-1 ls-n1 mb-1">
|
|
@if (ContainerStats == null)
|
|
{
|
|
<span class="text-muted">
|
|
<TL>Loading</TL>
|
|
</span>
|
|
}
|
|
else
|
|
{
|
|
<span>
|
|
<TL>@(ContainerStats.Containers.Count)</TL>
|
|
</span>
|
|
}
|
|
</span>
|
|
<span class="fw-semibold fs-6">
|
|
@if (ContainerStats == null)
|
|
{
|
|
<span class="text-muted">
|
|
<TL>Loading</TL>
|
|
</span>
|
|
}
|
|
else
|
|
{
|
|
<TL>Docker containers running</TL>
|
|
}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="mt-5 card card-body">
|
|
<div class="d-flex justify-content-end">
|
|
<a href="/admin/nodes" class="btn btn-primary">
|
|
<TL>Cancel</TL>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
</LazyLoader>
|
|
</OnlyAdmin>
|
|
|
|
@code
|
|
{
|
|
[Parameter]
|
|
public int Id { get; set; }
|
|
|
|
private Node? Node;
|
|
|
|
private CpuStats CpuStats;
|
|
private MemoryStats MemoryStats;
|
|
private DiskStats DiskStats;
|
|
private SystemStatus SystemStatus;
|
|
private ContainerStats ContainerStats;
|
|
|
|
private async Task Load(LazyLoader arg)
|
|
{
|
|
Node = NodeRepository
|
|
.Get()
|
|
.FirstOrDefault(x => x.Id == Id);
|
|
|
|
if (Node != null)
|
|
{
|
|
Task.Run(async () =>
|
|
{
|
|
try
|
|
{
|
|
SystemStatus = await NodeService.GetStatus(Node);
|
|
await InvokeAsync(StateHasChanged);
|
|
|
|
CpuStats = await NodeService.GetCpuStats(Node);
|
|
await InvokeAsync(StateHasChanged);
|
|
|
|
MemoryStats = await NodeService.GetMemoryStats(Node);
|
|
await InvokeAsync(StateHasChanged);
|
|
|
|
DiskStats = await NodeService.GetDiskStats(Node);
|
|
await InvokeAsync(StateHasChanged);
|
|
|
|
ContainerStats = await NodeService.GetContainerStats(Node);
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
// ignored
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
private List<string> SortMemorySticks(List<MemoryStats.MemoryStick> sticks)
|
|
{
|
|
// Thank you ChatGPT <3
|
|
|
|
var groupedMemory = sticks.GroupBy(memory => new { memory.Type, memory.Size })
|
|
.Select(group => new
|
|
{
|
|
Type = group.Key.Type,
|
|
Size = group.Key.Size,
|
|
Count = group.Count()
|
|
});
|
|
|
|
var sortedMemory = groupedMemory.OrderBy(memory => memory.Type)
|
|
.ThenBy(memory => memory.Size);
|
|
|
|
List<string> sortedList = sortedMemory.Select(memory =>
|
|
{
|
|
string sizeString = $"{memory.Size}GB";
|
|
return $"{memory.Count}x {memory.Type} {sizeString}";
|
|
}).ToList();
|
|
|
|
return sortedList;
|
|
}
|
|
} |