Tim Jones 2 месяцев назад
Родитель
Сommit
2d6d5a0d95

+ 87 - 0
RackPeek.Web/Components/Components/ServerCardComponent.razor

@@ -0,0 +1,87 @@
+@using RackPeek.Domain.Resources.Hardware.Models
+@using RackPeek.Domain.Resources.Hardware.Servers
+@typeparam TServer where TServer : Server
+
+<div class="border border-zinc-800 rounded p-4 bg-zinc-900">
+    <div class="flex justify-between items-center mb-3">
+        <div class="text-zinc-100">
+            @Server.Name
+        </div>
+
+        @if (Server.Ipmi == true)
+        {
+            <span class="text-xs text-emerald-400">IPMI</span>
+        }
+    </div>
+
+    <div class="grid grid-cols-1 md:grid-cols-2 gap-3 text-sm">
+
+        @if (Server.Cpus?.Any() == true)
+        {
+            <div>
+                <div class="text-zinc-400 mb-1">CPU</div>
+                @foreach (var cpu in Server.Cpus)
+                {
+                    <div class="text-zinc-300">
+                        @cpu.Model — @cpu.Cores cores / @cpu.Threads threads
+                    </div>
+                }
+            </div>
+        }
+
+        @if (Server.Ram is not null)
+        {
+            <div>
+                <div class="text-zinc-400 mb-1">RAM</div>
+                <div class="text-zinc-300">
+                    @Server.Ram.Size GB @Server.Ram.Mts MT/s
+                </div>
+            </div>
+        }
+
+        @if (Server.Drives?.Any() == true)
+        {
+            <div>
+                <div class="text-zinc-400 mb-1">Drives</div>
+                @foreach (var drive in Server.Drives)
+                {
+                    <div class="text-zinc-300">
+                        @drive.Type — @drive.Size GB
+                    </div>
+                }
+            </div>
+        }
+
+        @if (Server.Nics?.Any() == true)
+        {
+            <div>
+                <div class="text-zinc-400 mb-1">NICs</div>
+                @foreach (var nic in Server.Nics)
+                {
+                    <div class="text-zinc-300">
+                        @nic.Type — @nic.Speed Gbps (@nic.Ports ports)
+                    </div>
+                }
+            </div>
+        }
+
+        @if (Server.Gpus?.Any() == true)
+        {
+            <div>
+                <div class="text-zinc-400 mb-1">GPU</div>
+                @foreach (var gpu in Server.Gpus)
+                {
+                    <div class="text-zinc-300">
+                        @gpu.Model — @gpu.Vram GB VRAM
+                    </div>
+                }
+            </div>
+        }
+
+    </div>
+</div>
+
+@code {
+    [Parameter, EditorRequired]
+    public TServer Server { get; set; } = default!;
+}

+ 69 - 71
RackPeek.Web/Components/Components/ServersListComponent.razor

@@ -2,13 +2,9 @@
 @using RackPeek.Domain.Resources.Hardware.Servers
 @inject GetServersUseCase GetServers
 
-<PageTitle>CLI Monitor</PageTitle>
+<PageTitle>Servers</PageTitle>
 
 <div class="min-h-screen bg-zinc-950 text-zinc-200 font-mono p-6">
-    <h1 class="text-lg text-zinc-100 mb-6">
-        CLI Hardware Monitor
-    </h1>
-
     @if (_servers is null)
     {
         <div class="text-zinc-500">loading servers…</div>
@@ -22,84 +18,86 @@
         <div class="space-y-4">
             @foreach (var server in _servers)
             {
-                <div class="border border-zinc-800 rounded p-4 bg-zinc-900">
-                    <div class="flex justify-between items-center mb-3">
-                        <div class="text-zinc-100">
-                            @server.Name
+                <NavLink href="@($"/resources/hardware/{server.Name}")" class="block">
+                    <div class="border border-zinc-800 rounded p-4 bg-zinc-900">
+                        <div class="flex justify-between items-center mb-3">
+                            <div class="text-zinc-100">
+                                @server.Name
+                            </div>
+
+                            @if (server.Ipmi == true)
+                            {
+                                <span class="text-xs text-emerald-400">IPMI</span>
+                            }
                         </div>
 
-                        @if (server.Ipmi == true)
-                        {
-                            <span class="text-xs text-emerald-400">IPMI</span>
-                        }
-                    </div>
+                        <div class="grid grid-cols-1 md:grid-cols-2 gap-3 text-sm">
 
-                    <div class="grid grid-cols-1 md:grid-cols-2 gap-3 text-sm">
+                            @if (server.Cpus?.Any() == true)
+                            {
+                                <div>
+                                    <div class="text-zinc-400 mb-1">CPU</div>
+                                    @foreach (var cpu in server.Cpus)
+                                    {
+                                        <div class="text-zinc-300">
+                                            @cpu.Model — @cpu.Cores cores / @cpu.Threads threads
+                                        </div>
+                                    }
+                                </div>
+                            }
 
-                        @if (server.Cpus?.Any() == true)
-                        {
-                            <div>
-                                <div class="text-zinc-400 mb-1">CPU</div>
-                                @foreach (var cpu in server.Cpus)
-                                {
+                            @if (server.Ram is not null)
+                            {
+                                <div>
+                                    <div class="text-zinc-400 mb-1">RAM</div>
                                     <div class="text-zinc-300">
-                                        @cpu.Model — @cpu.Cores cores / @cpu.Threads threads
+                                        @server.Ram.Size GB @server.Ram.Mts MT/s
                                     </div>
-                                }
-                            </div>
-                        }
-
-                        @if (server.Ram is not null)
-                        {
-                            <div>
-                                <div class="text-zinc-400 mb-1">RAM</div>
-                                <div class="text-zinc-300">
-                                    @server.Ram.Size GB @server.Ram.Mts MT/s
                                 </div>
-                            </div>
-                        }
+                            }
 
-                        @if (server.Drives?.Any() == true)
-                        {
-                            <div>
-                                <div class="text-zinc-400 mb-1">Drives</div>
-                                @foreach (var drive in server.Drives)
-                                {
-                                    <div class="text-zinc-300">
-                                        @drive.Type — @drive.Size GB
-                                    </div>
-                                }
-                            </div>
-                        }
+                            @if (server.Drives?.Any() == true)
+                            {
+                                <div>
+                                    <div class="text-zinc-400 mb-1">Drives</div>
+                                    @foreach (var drive in server.Drives)
+                                    {
+                                        <div class="text-zinc-300">
+                                            @drive.Type — @drive.Size GB
+                                        </div>
+                                    }
+                                </div>
+                            }
 
-                        @if (server.Nics?.Any() == true)
-                        {
-                            <div>
-                                <div class="text-zinc-400 mb-1">NICs</div>
-                                @foreach (var nic in server.Nics)
-                                {
-                                    <div class="text-zinc-300">
-                                        @nic.Type — @nic.Speed Gbps (@nic.Ports ports)
-                                    </div>
-                                }
-                            </div>
-                        }
+                            @if (server.Nics?.Any() == true)
+                            {
+                                <div>
+                                    <div class="text-zinc-400 mb-1">NICs</div>
+                                    @foreach (var nic in server.Nics)
+                                    {
+                                        <div class="text-zinc-300">
+                                            @nic.Type — @nic.Speed Gbps (@nic.Ports ports)
+                                        </div>
+                                    }
+                                </div>
+                            }
 
-                        @if (server.Gpus?.Any() == true)
-                        {
-                            <div>
-                                <div class="text-zinc-400 mb-1">GPU</div>
-                                @foreach (var gpu in server.Gpus)
-                                {
-                                    <div class="text-zinc-300">
-                                        @gpu.Model — @gpu.Vram GB VRAM
-                                    </div>
-                                }
-                            </div>
-                        }
+                            @if (server.Gpus?.Any() == true)
+                            {
+                                <div>
+                                    <div class="text-zinc-400 mb-1">GPU</div>
+                                    @foreach (var gpu in server.Gpus)
+                                    {
+                                        <div class="text-zinc-300">
+                                            @gpu.Model — @gpu.Vram GB VRAM
+                                        </div>
+                                    }
+                                </div>
+                            }
 
+                        </div>
                     </div>
-                </div>
+                </NavLink>
             }
         </div>
     }

+ 25 - 1
RackPeek.Web/Components/Layout/MainLayout.razor

@@ -1,3 +1,27 @@
 @inherits LayoutComponentBase
 
-@Body
+<div class="min-h-screen bg-zinc-950 text-zinc-200 font-mono">
+
+    <!-- Header / Branding -->
+    <header class="flex items-center justify-between p-4 border-b border-zinc-800 bg-zinc-900">
+        <div class="text-xl font-bold text-emerald-400 tracking-wider">
+            rackpeek
+        </div>
+
+        <!-- Navigation -->
+        <nav class="space-x-6 text-sm">
+            <NavLink href="/hardware/tree" class="hover:text-emerald-400" activeClass="text-emerald-400 font-semibold">
+                Hardware
+            </NavLink>
+            <NavLink href="/servers/list" class="hover:text-emerald-400" activeClass="text-emerald-400 font-semibold">
+                Servers
+            </NavLink>
+        </nav>
+    </header>
+
+    <!-- Page content -->
+    <main class="p-6">
+        @Body
+    </main>
+
+</div>

+ 28 - 19
RackPeek.Web/Components/Layout/ReconnectModal.razor

@@ -1,31 +1,40 @@
-<script type="module" src="@Assets["Components/Layout/ReconnectModal.razor.js"]"></script>
+<dialog id="components-reconnect-modal" class="w-full max-w-md p-6 bg-zinc-900 text-zinc-200 font-mono rounded-lg border border-zinc-800 shadow-lg" data-nosnippet>
+    <div class="flex flex-col items-center space-y-4">
 
-<dialog id="components-reconnect-modal" data-nosnippet>
-    <div class="components-reconnect-container">
-        <div class="components-rejoining-animation" aria-hidden="true">
-            <div></div>
-            <div></div>
+        <!-- Animated rejoin indicator -->
+        <div class="flex space-x-2 h-6 items-end">
+            <div class="w-1 h-3 bg-emerald-400 animate-bounce"></div>
+            <div class="w-1 h-3 bg-emerald-400 animate-bounce delay-200"></div>
         </div>
-        <p class="components-reconnect-first-attempt-visible">
+
+        <!-- Status messages -->
+        <p class="components-reconnect-first-attempt-visible text-sm text-zinc-300">
             Rejoining the server...
         </p>
-        <p class="components-reconnect-repeated-attempt-visible">
-            Rejoin failed... trying again in <span id="components-seconds-to-next-attempt"></span> seconds.
+        <p class="components-reconnect-repeated-attempt-visible text-sm text-amber-400">
+            Rejoin failed... trying again in <span id="components-seconds-to-next-attempt" class="font-bold"></span> seconds.
         </p>
-        <p class="components-reconnect-failed-visible">
+        <p class="components-reconnect-failed-visible text-sm text-red-500 text-center">
             Failed to rejoin.<br/>Please retry or reload the page.
         </p>
-        <button id="components-reconnect-button" class="components-reconnect-failed-visible">
-            Retry
-        </button>
-        <p class="components-pause-visible">
+
+        <!-- Buttons -->
+        <div class="flex space-x-3">
+            <button id="components-reconnect-button" class="components-reconnect-failed-visible px-4 py-1 bg-emerald-400 text-zinc-900 rounded hover:bg-emerald-500 transition">
+                Retry
+            </button>
+            <button id="components-resume-button" class="components-pause-visible px-4 py-1 bg-emerald-400 text-zinc-900 rounded hover:bg-emerald-500 transition">
+                Resume
+            </button>
+        </div>
+
+        <p class="components-pause-visible text-sm text-zinc-400 text-center">
             The session has been paused by the server.
         </p>
-        <button id="components-resume-button" class="components-pause-visible">
-            Resume
-        </button>
-        <p class="components-resume-failed-visible">
+        <p class="components-resume-failed-visible text-sm text-red-500 text-center">
             Failed to resume the session.<br/>Please reload the page.
         </p>
     </div>
-</dialog>
+</dialog>
+
+<script type="module" src="@Assets["Components/Layout/ReconnectModal.razor.js"]"></script>

+ 49 - 0
RackPeek.Web/Components/Pages/HardwareDetailsPage.razor

@@ -0,0 +1,49 @@
+@page "/resources/hardware/{HardwareName}"
+@using RackPeek.Domain.Resources.Hardware
+@using RackPeek.Domain.Resources.Hardware.Models
+@using RackPeek.Web.Components.Components
+@inject IHardwareRepository HardwareRepository
+
+<PageTitle>Hardware Details</PageTitle>
+
+<div class="min-h-screen bg-zinc-950 text-zinc-200 font-mono p-6">
+    @if (_hardware is null && !_loading)
+    {
+        <div class="text-zinc-500">Hardware not found</div>
+    }
+    else if (_loading)
+    {
+        <div class="text-zinc-500">loading hardware…</div>
+    }
+    else
+    {
+        <h1 class="text-lg text-zinc-100 mb-6">
+            @_hardware.Name (@_hardware.Kind)
+        </h1>
+
+        @if (_hardware is Server server)
+        {
+            <ServerCardComponent Server="server" />
+        }
+        else
+        {
+            <div class="text-zinc-400">
+                No detailed view for hardware type: @_hardware.Kind
+            </div>
+        }
+    }
+</div>
+
+@code {
+    [Parameter]
+    public string HardwareName { get; set; } = string.Empty;
+
+    private Hardware? _hardware;
+    private bool _loading = true;
+
+    protected override async Task OnInitializedAsync()
+    {
+        _hardware = await HardwareRepository.GetByNameAsync(HardwareName);
+        _loading = false;
+    }
+}

+ 7 - 8
RackPeek.Web/Components/Components/HardwareTreeComponent.razor → RackPeek.Web/Components/Pages/HardwareTreePage.razor

@@ -1,13 +1,10 @@
-@page "/tree"
+@page "/hardware/tree"
 @using RackPeek.Domain.Resources.Hardware
 @inject IHardwareRepository HardwareRepository
 
-<PageTitle>Tree View</PageTitle>
+<PageTitle>Hardware Tree</PageTitle>
 
 <div class="min-h-screen bg-zinc-950 text-zinc-200 font-mono p-6">
-    <h1 class="text-lg text-zinc-100 mb-6">
-        Tree View
-    </h1>
 
     @if (_tree is null)
     {
@@ -35,9 +32,11 @@
                     {
                         <li>
                             <!-- Hardware -->
-                            <div class="text-zinc-100">
-                                @hardware.HardwareName
-                            </div>
+                            <NavLink href="@($"/resources/hardware/{hardware.HardwareName}")" class="block">
+                                <div class="text-zinc-100">
+                                    @hardware.HardwareName
+                                </div>
+                            </NavLink>
 
                             @if (hardware.Systems.Any())
                             {

+ 1 - 2
RackPeek.Web/Components/Pages/Home.razor

@@ -1,6 +1,5 @@
 @page "/"
 @using RackPeek.Web.Components.Components
 
-<PageTitle>CLI Monitor</PageTitle>
+<PageTitle>rackpeek</PageTitle>
 
-<ServersListComponent/>

+ 0 - 1
RackPeek.Web/Components/Pages/NotFound.razor

@@ -1,5 +1,4 @@
 @page "/not-found"
 @layout MainLayout
 
-<h3>Not Found</h3>
 <p>Sorry, the content you are looking for does not exist.</p>

+ 6 - 0
RackPeek.Web/Components/Pages/ServersListPage.razor

@@ -0,0 +1,6 @@
+@page "/servers/list"
+@using RackPeek.Web.Components.Components
+
+<PageTitle>Servers</PageTitle>
+
+<ServersListComponent/>

+ 0 - 1
RackPeek.Web/Components/Routes.razor

@@ -1,6 +1,5 @@
 <Router AppAssembly="typeof(Program).Assembly" NotFoundPage="typeof(Pages.NotFound)">
     <Found Context="routeData">
         <RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)"/>
-        <FocusOnNavigate RouteData="routeData" Selector="h1"/>
     </Found>
 </Router>