diff --git a/app/Livewire/Dashboard.php b/app/Livewire/Dashboard.php index f65cee6..1e71405 100644 --- a/app/Livewire/Dashboard.php +++ b/app/Livewire/Dashboard.php @@ -18,6 +18,18 @@ class Dashboard extends Component { use WithFleetContext; + public bool $ready = false; + + /** @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; + } + /** Deterministic wavy series — fallback sparkline for metrics without history. */ private function series(float $base, int $n = 40, float $amp = 9): array { @@ -111,7 +123,7 @@ class Dashboard extends Component 'memTrend' => $this->trend($memSeries), 'diskTrend' => $this->trend($diskSeries), 'loadTrend' => $this->trend($loadSeries, ''), - 'services' => $this->liveServices($fleet, $active), + 'services' => $this->svcRows, 'events' => AuditEvent::with('server')->latest()->limit(6)->get(), ]); } diff --git a/app/Livewire/Files/Index.php b/app/Livewire/Files/Index.php index b6fa73a..e7ac2f0 100644 --- a/app/Livewire/Files/Index.php +++ b/app/Livewire/Files/Index.php @@ -21,31 +21,33 @@ class Index extends Component public bool $connected = false; + public bool $ready = false; + /** @var array */ public array $entries = []; public function mount(): void { - $this->load(); + // listing loads lazily via wire:init -> load() } /** Read the active server's directory over SSH; empty + offline on failure. */ - private function load(): void + public function load(): void { $this->entries = []; $this->connected = false; $active = $this->activeServer(); - if (! $active || ! $active->credential_exists) { - return; + if ($active && $active->credential_exists) { + try { + $this->entries = app(FleetService::class)->files($active, $this->path); + $this->connected = true; + } catch (Throwable) { + $this->connected = false; + } } - try { - $this->entries = app(FleetService::class)->files($active, $this->path); - $this->connected = true; - } catch (Throwable) { - $this->connected = false; - } + $this->ready = true; } public function open(string $name): void diff --git a/app/Livewire/Servers/Show.php b/app/Livewire/Servers/Show.php index de68062..51cedb0 100644 --- a/app/Livewire/Servers/Show.php +++ b/app/Livewire/Servers/Show.php @@ -19,6 +19,8 @@ class Show extends Component public bool $connected = false; + public bool $ready = false; + public array $volumes = []; public array $interfaces = []; @@ -32,7 +34,14 @@ class Show extends Component * On any failure (no credential, unreachable) the page renders an offline * state from the last persisted values instead of crashing. */ - public function mount(FleetService $fleet): void + public function mount(): void + { + // identity + gauges render from the persisted row immediately; + // the live snapshot loads lazily via wire:init -> load(). + } + + /** Lazy: pull the full SSH snapshot after the shell renders, behind skeletons. */ + public function load(FleetService $fleet): void { try { $snap = $fleet->snapshot($this->server); @@ -69,14 +78,14 @@ class Show extends Component $this->server->forceFill(['status' => 'offline'])->save(); } } + + $this->ready = true; } /** Refresh the live gauges from the poller-updated row (wire:poll). */ public function pollMetrics(): void { - if ($this->connected) { - $this->server->refresh(); - } + $this->server->refresh(); } /** diff --git a/app/Livewire/Services/Index.php b/app/Livewire/Services/Index.php index 842a81d..96240b1 100644 --- a/app/Livewire/Services/Index.php +++ b/app/Livewire/Services/Index.php @@ -21,6 +21,8 @@ class Index extends Component public bool $connected = false; + public bool $ready = false; + /** wire:model search over service name + description */ public string $search = ''; @@ -30,23 +32,28 @@ class Index extends Component /** @var array */ public array $journal = []; - public function mount(FleetService $fleet): void + public function mount(): void + { + $this->server = $this->activeServer()?->name ?? '—'; + } + + /** Lazy: the SSH read runs after the shell renders (wire:init), behind a skeleton. */ + public function load(FleetService $fleet): void { $active = $this->activeServer(); - $this->server = $active?->name ?? '—'; - if (! $active || ! $active->credential_exists) { - return; + if ($active && $active->credential_exists) { + try { + $data = $fleet->systemd($active); + $this->services = $data['services']; + $this->journal = $data['journal']; + $this->connected = true; + } catch (Throwable) { + $this->connected = false; + } } - try { - $data = $fleet->systemd($active); - $this->services = $data['services']; - $this->journal = $data['journal']; - $this->connected = true; - } catch (Throwable) { - $this->connected = false; - } + $this->ready = true; } /** diff --git a/resources/css/safelist-tailwindcss.txt b/resources/css/safelist-tailwindcss.txt new file mode 100644 index 0000000..c99c89b --- /dev/null +++ b/resources/css/safelist-tailwindcss.txt @@ -0,0 +1,5 @@ +sm:max-w-md +md:max-w-xl +lg:max-w-3xl +xl:max-w-5xl +2xl:max-w-7xl diff --git a/resources/views/components/skeleton.blade.php b/resources/views/components/skeleton.blade.php new file mode 100644 index 0000000..101c7d3 --- /dev/null +++ b/resources/views/components/skeleton.blade.php @@ -0,0 +1,2 @@ +{{-- Shimmer placeholder for lazy-loaded content (R4: animation via utility, no inline style). --}} +
merge(['class' => 'animate-pulse rounded bg-raised']) }}>
diff --git a/resources/views/livewire/dashboard.blade.php b/resources/views/livewire/dashboard.blade.php index ccbcfeb..e5b92e3 100644 --- a/resources/views/livewire/dashboard.blade.php +++ b/resources/views/livewire/dashboard.blade.php @@ -16,7 +16,7 @@ $memP = $chart($memSeries); @endphp -
+
{{-- Header --}}
@@ -93,6 +93,16 @@ + @if (! $ready) + @for ($i = 0; $i < 5; $i++) + + + + + + + @endfor + @else @forelse ($services as $svc) @@ -106,6 +116,7 @@ @empty Keine Dienstdaten — Server nicht verbunden. @endforelse + @endif
diff --git a/resources/views/livewire/files/index.blade.php b/resources/views/livewire/files/index.blade.php index 3306628..457d690 100644 --- a/resources/views/livewire/files/index.blade.php +++ b/resources/views/livewire/files/index.blade.php @@ -19,7 +19,7 @@ }; @endphp -
+
{{-- Header --}}
@@ -63,7 +63,16 @@ Aktionen
-
+
+ @if (! $ready) + @for ($i = 0; $i < 8; $i++) +
+ + +
+ @endfor + @else @foreach ($entries as $e) @php $isDir = $e['type'] === 'dir'; @endphp
@@ -123,6 +132,7 @@
@endforeach + @endif
diff --git a/resources/views/livewire/modals/add-ssh-key.blade.php b/resources/views/livewire/modals/add-ssh-key.blade.php index bd76898..9c05dd9 100644 --- a/resources/views/livewire/modals/add-ssh-key.blade.php +++ b/resources/views/livewire/modals/add-ssh-key.blade.php @@ -27,15 +27,17 @@
diff --git a/resources/views/livewire/modals/confirm-action.blade.php b/resources/views/livewire/modals/confirm-action.blade.php index 4c90045..4320489 100644 --- a/resources/views/livewire/modals/confirm-action.blade.php +++ b/resources/views/livewire/modals/confirm-action.blade.php @@ -20,19 +20,21 @@
diff --git a/resources/views/livewire/servers/show.blade.php b/resources/views/livewire/servers/show.blade.php index 9aea6bd..e5c4b08 100644 --- a/resources/views/livewire/servers/show.blade.php +++ b/resources/views/livewire/servers/show.blade.php @@ -17,7 +17,7 @@ ]; @endphp - diff --git a/resources/views/livewire/services/index.blade.php b/resources/views/livewire/services/index.blade.php index e2537d3..15733ee 100644 --- a/resources/views/livewire/services/index.blade.php +++ b/resources/views/livewire/services/index.blade.php @@ -10,7 +10,7 @@ $logTone = ['info' => 'text-ink-3', 'warn' => 'text-warning', 'error' => 'text-offline']; @endphp -
+
{{-- Header --}}
@@ -37,6 +37,15 @@
+ @if (! $ready) + @for ($i = 0; $i < 7; $i++) +
+ +
+
+ @endfor + @else @forelse ($list as $svc)
{{-- identity --}} @@ -88,6 +97,7 @@

Suche „{{ $search }}“ ergab keine Treffer.

@endforelse + @endif
diff --git a/resources/views/vendor/wire-elements-modal/modal.blade.php b/resources/views/vendor/wire-elements-modal/modal.blade.php index a7a20a2..85e8386 100644 --- a/resources/views/vendor/wire-elements-modal/modal.blade.php +++ b/resources/views/vendor/wire-elements-modal/modal.blade.php @@ -11,7 +11,7 @@ x-on:close.stop="setShowPropertyTo(false)" x-on:keydown.escape.window="show && closeModalOnEscape()" x-show="show" - class="fixed inset-0 z-10 overflow-y-auto" + class="fixed inset-0 z-50 overflow-y-auto" style="display: none;" >
@@ -39,8 +39,7 @@ x-transition:leave="ease-in duration-200" x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100" x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" - x-bind:class="modalWidth" - class="inline-block w-full align-bottom bg-surface border border-line rounded-lg text-left overflow-hidden shadow-pop transform transition-all sm:my-8 sm:align-middle sm:w-full" + class="inline-block w-full max-w-lg align-bottom bg-surface border border-line rounded-lg text-left overflow-hidden shadow-pop transform transition-all sm:my-8 sm:align-middle" id="modal-container" x-trap.noscroll.inert="show && showActiveComponent" aria-modal="true"