clusev/resources/views/livewire/dashboard.blade.php

143 lines
8.7 KiB
PHP

@php
$svcLabel = ['online' => 'aktiv', 'warning' => 'degradiert', 'offline' => 'gestoppt'];
// dual-series chart paths (CPU + MEM) — static seed; live wiring via Reverb is a follow-up
$chart = function (array $s) {
$w = 300; $h = 100; $pad = 6; $n = count($s); $pts = [];
foreach ($s as $i => $v) {
$x = $n > 1 ? round($i / ($n - 1) * $w, 2) : 0;
$y = round($h - $pad - ($v / 100) * ($h - 2 * $pad), 2);
$pts[] = "$x,$y";
}
$line = implode(' ', $pts);
return ['line' => $line, 'area' => "0,$h ".$line." $w,$h"];
};
$cpuP = $chart($cpuSeries);
$memP = $chart($memSeries);
@endphp
<div class="space-y-4" wire:poll.10s wire:init="load">
{{-- Header --}}
<div class="flex flex-wrap items-end justify-between gap-3">
<div>
<p class="font-mono text-[11px] uppercase tracking-[0.2em] text-accent-text">{{ $active?->name ?? '—' }}</p>
<h2 class="mt-0.5 font-display text-xl font-semibold text-ink sm:text-2xl">Übersicht</h2>
</div>
<x-status-pill :status="$active?->status ?? 'offline'">{{ $active?->ip ?? '—' }}</x-status-pill>
</div>
{{-- KPI tiles with sparklines (active server) --}}
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2 xl:grid-cols-4">
<x-metric label="CPU" :value="$cpu" unit="%" icon="cpu" tone="accent" :series="$cpuSeries" :trend="$cpuTrend" />
<x-metric label="Memory" :value="$mem" unit="%" icon="activity" tone="cyan" :series="$memSeries" :trend="$memTrend" />
<x-metric label="Disk" :value="$disk" unit="%" icon="server" tone="online" :series="$diskSeries" :trend="$diskTrend" />
<x-metric label="Load avg" :value="number_format($load, 2)" icon="activity" tone="warning" :series="$loadSeries" :trend="$loadTrend" sub="1 min" />
</div>
{{-- Big dual-series chart --}}
<x-panel title="Auslastung" subtitle="CPU & Memory · 15 Min">
<x-slot:actions>
<span class="inline-flex items-center gap-1.5 font-mono text-[11px]"><span class="h-2 w-2 rounded-xs bg-accent"></span><span class="text-ink-2">CPU</span></span>
<span class="inline-flex items-center gap-1.5 font-mono text-[11px]"><span class="h-2 w-2 rounded-xs bg-cyan"></span><span class="text-ink-2">MEM</span></span>
<x-badge tone="accent">Live</x-badge>
</x-slot:actions>
<div class="relative pl-7">
{{-- Y axis --}}
<div class="pointer-events-none absolute inset-y-0 left-0 w-6 font-mono text-[9px] text-ink-4">
<span class="absolute right-0 top-0 -translate-y-1/2">100</span>
<span class="absolute right-0 top-1/4 -translate-y-1/2">75</span>
<span class="absolute right-0 top-1/2 -translate-y-1/2">50</span>
<span class="absolute right-0 top-3/4 -translate-y-1/2">25</span>
<span class="absolute right-0 top-full -translate-y-1/2">0</span>
</div>
<div class="h-44 w-full">
<svg viewBox="0 0 300 100" preserveAspectRatio="none" class="h-full w-full" aria-hidden="true">
{{-- grid --}}
<g class="text-line-soft">
@foreach ([0, 25, 50, 75, 100] as $g)
<line x1="0" x2="300" y1="{{ 100 * (1 - $g / 100) }}" y2="{{ 100 * (1 - $g / 100) }}" stroke="currentColor" stroke-width="1" vector-effect="non-scaling-stroke" />
@endforeach
</g>
{{-- MEM (cyan) --}}
<g class="text-cyan">
<polyline points="{{ $memP['area'] }}" fill="currentColor" fill-opacity="0.10" stroke="none" />
<polyline points="{{ $memP['line'] }}" fill="none" stroke="currentColor" stroke-width="1.5" vector-effect="non-scaling-stroke" stroke-linejoin="round" />
</g>
{{-- CPU (accent) --}}
<g class="text-accent">
<polyline points="{{ $cpuP['area'] }}" fill="currentColor" fill-opacity="0.13" stroke="none" />
<polyline points="{{ $cpuP['line'] }}" fill="none" stroke="currentColor" stroke-width="1.75" vector-effect="non-scaling-stroke" stroke-linejoin="round" />
</g>
</svg>
</div>
<div class="mt-1.5 flex justify-between font-mono text-[9px] text-ink-4">
<span>-15 Min</span><span>-10</span><span>-5</span><span>jetzt</span>
</div>
</div>
</x-panel>
{{-- systemd table + audit --}}
<div class="grid grid-cols-1 gap-3 lg:grid-cols-3">
<x-panel title="systemd-Dienste" :subtitle="$active?->name" class="lg:col-span-2" :padded="false">
<div class="overflow-x-auto">
<table class="w-full border-collapse">
<thead>
<tr class="border-b border-line">
<th class="px-4 py-2.5 text-left font-mono text-[10px] uppercase tracking-wider text-ink-3 sm:px-5">Unit</th>
<th class="px-4 py-2.5 text-left font-mono text-[10px] uppercase tracking-wider text-ink-3">Status</th>
<th class="px-4 py-2.5 text-right font-mono text-[10px] uppercase tracking-wider text-ink-3">Zustand</th>
<th class="hidden px-4 py-2.5 text-right font-mono text-[10px] uppercase tracking-wider text-ink-3 sm:table-cell">Boot</th>
</tr>
</thead>
<tbody>
@if (! $ready)
@for ($i = 0; $i < 5; $i++)
<tr class="border-b border-line/60">
<td class="px-4 py-3 sm:px-5"><x-skeleton class="h-3 w-40 max-w-full" /><x-skeleton class="mt-1.5 h-2.5 w-56 max-w-full" /></td>
<td class="px-4 py-3"><x-skeleton class="h-5 w-16 rounded-full" /></td>
<td class="px-4 py-3 text-right"><x-skeleton class="ml-auto h-3 w-12" /></td>
<td class="hidden px-4 py-3 sm:table-cell"><x-skeleton class="ml-auto h-3 w-14" /></td>
</tr>
@endfor
@else
@forelse ($services as $svc)
<tr class="border-b border-line/60 transition-colors last:border-0 hover:bg-raised">
<td class="px-4 py-2.5 sm:px-5">
<p class="font-mono text-sm text-ink">{{ $svc['name'] }}</p>
<p class="truncate text-[11px] text-ink-3">{{ $svc['desc'] }}</p>
</td>
<td class="px-4 py-2.5"><x-status-pill :status="$svc['status']">{{ $svcLabel[$svc['status']] }}</x-status-pill></td>
<td class="px-4 py-2.5 text-right font-mono text-xs text-ink-2">{{ $svc['sub'] }}</td>
<td class="hidden px-4 py-2.5 text-right font-mono text-xs sm:table-cell {{ $svc['enabled'] ? 'text-ink-2' : 'text-ink-4' }}">{{ $svc['enabled'] ? 'enabled' : 'disabled' }}</td>
</tr>
@empty
<tr><td colspan="4" class="px-5 py-8 text-center font-mono text-[11px] text-ink-3">Keine Dienstdaten Server nicht verbunden.</td></tr>
@endforelse
@endif
</tbody>
</table>
</div>
</x-panel>
<x-panel title="Audit-Log" subtitle="letzte Ereignisse" :padded="false">
<div class="divide-y divide-line">
@forelse ($events as $e)
<div class="flex items-start gap-3 px-4 py-2.5 sm:px-5">
<span class="mt-0.5 grid h-7 w-7 shrink-0 place-items-center rounded-sm bg-raised text-ink-3"><x-icon name="audit" class="h-3.5 w-3.5" /></span>
<div class="min-w-0 flex-1">
<p class="text-sm text-ink"><span class="text-ink-2">{{ $e->actor }}</span> · {{ $e->action }}</p>
<p class="truncate font-mono text-[11px] text-ink-3">{{ $e->target }}</p>
</div>
<span class="shrink-0 font-mono text-[11px] text-ink-4">{{ $e->created_at->diffForHumans(null, true) }}</span>
</div>
@empty
<p class="px-5 py-8 text-center font-mono text-[11px] text-ink-3">Keine Ereignisse.</p>
@endforelse
</div>
</x-panel>
</div>
</div>