; localized at runtime (attributes can't call __()). */ public function title(): string { return __('dashboard.page_title'); } /** @var array notable systemd units (lazy-loaded over SSH) */ public array $svcRows = []; /** Lazy: the SSH services read runs after the shell renders (wire:init). */ public function load(FleetService $fleet): void { $this->svcRows = $this->liveServices($fleet, $this->activeServer()); $this->ready = true; } /** Pad a real history series to a minimum length for a stable sparkline. */ private function pad(array $values, float|int $current, int $min = 16): array { if ($values === []) { $values = [$current]; } while (count($values) < $min) { array_unshift($values, $values[0]); } return $values; } /** @param array $series */ private function trend(array $series, string $suffix = '%'): array { $cur = (int) (end($series) ?: 0); $prev = (int) ($series[max(0, count($series) - 8)] ?? $cur); $d = $cur - $prev; return [ 'dir' => $d > 1 ? 'up' : ($d < -1 ? 'down' : 'flat'), 'text' => ($d >= 0 ? '+' : '').$d.$suffix, ]; } /** A handful of notable systemd units (failed + running first), cached. */ private function liveServices(FleetService $fleet, ?Server $active): array { if (! $active || ! $active->credential_exists) { return []; } try { $svc = Cache::remember("svc:{$active->id}", 30, fn () => $fleet->systemd($active, 1)['services']); } catch (Throwable) { return []; } $rank = fn (array $s): int => match ($s['sub']) { 'failed' => 0, 'running' => 1, default => 2, }; usort($svc, fn ($a, $b) => [$rank($a), $a['name']] <=> [$rank($b), $b['name']]); return array_slice($svc, 0, 8); } public function render(FleetService $fleet) { $active = $this->activeServer(); // Metrics come from the poller (DB + cache) — no SSH on web render. $latest = $active ? $fleet->latest($active) : null; $cpu = (int) ($latest['cpu'] ?? $active?->cpu ?? 0); $mem = (int) ($latest['mem'] ?? $active?->mem ?? 0); $disk = (int) ($latest['disk'] ?? $active?->disk ?? 0); $load = (float) ($latest['load'] ?? 0); $cores = (int) ($latest['cores'] ?? ($active?->specs['cores'] ?? 1)) ?: 1; $hist = $active ? $fleet->history($active) : ['cpu' => [], 'mem' => [], 'disk' => [], 'load' => []]; $cpuSeries = $this->pad($hist['cpu'], $cpu); $memSeries = $this->pad($hist['mem'], $mem); $diskSeries = $this->pad($hist['disk'], $disk); $loadSeries = $this->pad($hist['load'], $load); $pctTone = fn (int $v): string => $v >= 90 ? 'offline' : ($v >= 75 ? 'warning' : 'online'); $loadRatio = $cores > 0 ? $load / $cores : $load; return view('livewire.dashboard', [ 'active' => $active, 'cpu' => $cpu, 'mem' => $mem, 'disk' => $disk, 'load' => $load, 'cpuSeries' => $cpuSeries, 'memSeries' => $memSeries, 'diskSeries' => $diskSeries, 'loadSeries' => $loadSeries, 'cpuTrend' => $this->trend($cpuSeries), 'memTrend' => $this->trend($memSeries), 'diskTrend' => $this->trend($diskSeries), 'loadTrend' => $this->trend($loadSeries, ''), 'cpuTone' => $pctTone($cpu), 'memTone' => $pctTone($mem), 'diskTone' => $pctTone($disk), 'loadTone' => $loadRatio >= 1.0 ? 'offline' : ($loadRatio >= 0.7 ? 'warning' : 'online'), 'memSub' => isset($latest['mem_total']) && $latest['mem_total'] > 0 ? number_format((float) $latest['mem_used'], 1, ',', '.').' / '.number_format((float) $latest['mem_total'], 1, ',', '.').' GB' : null, 'diskSub' => isset($latest['disk_total']) && $latest['disk_total'] > 0 ? $latest['disk_used'].' / '.$latest['disk_total'].' GB' : null, 'loadSub' => $cores.' '.($cores === 1 ? __('dashboard.core') : __('dashboard.cores')), 'services' => $this->svcRows, 'events' => AuditEvent::with('server')->latest()->limit(6)->get(), ])->title($this->title()); } }