From 5479896bf31800164ab1684d5e65ff116b8c43f6 Mon Sep 17 00:00:00 2001
From: boban
Date: Fri, 12 Jun 2026 23:32:28 +0200
Subject: [PATCH] fix(modal)+ux: panel above backdrop, one style, SSH
credential form
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The modal panel rendered *behind* its own backdrop (it "appeared then vanished"):
Tailwind v4 no longer turns `transform` into a stacking context, so the static
panel sat under the fixed/blurred backdrop. Fixed with `relative z-10` on the
panel (interactively verified by force-opening the modal).
- New component: one compact, consistent style (h-8 text-xs) with
variants (primary/accent/secondary/danger/ghost/ghost-danger). Replaced every
ad-hoc action button — modals, service start/stop/restart, file row actions +
upload, server-details (Zugang/Dateien/key add+remove). No more oversized,
inconsistent buttons.
- New EditCredential form modal + "Zugang" button on Server-Details: deposit or
update a server's SSH login (e.g. root) — this is where the privileged
credential for systemctl/journal gets stored (encrypted vault). Changing it
re-pulls the snapshot with the new login.
Co-Authored-By: Claude Opus 4.8 (1M context)
---
app/Livewire/Modals/EditCredential.php | 85 +++++++++++++++++++
app/Livewire/Servers/Show.php | 9 ++
resources/views/components/btn.blade.php | 17 ++++
.../views/livewire/files/index.blade.php | 19 ++---
.../livewire/modals/add-ssh-key.blade.php | 20 ++---
.../livewire/modals/confirm-action.blade.php | 24 ++----
.../livewire/modals/edit-credential.blade.php | 59 +++++++++++++
.../views/livewire/servers/show.blade.php | 24 +++---
.../views/livewire/services/index.blade.php | 21 +----
.../wire-elements-modal/modal.blade.php | 2 +-
10 files changed, 199 insertions(+), 81 deletions(-)
create mode 100644 app/Livewire/Modals/EditCredential.php
create mode 100644 resources/views/components/btn.blade.php
create mode 100644 resources/views/livewire/modals/edit-credential.blade.php
diff --git a/app/Livewire/Modals/EditCredential.php b/app/Livewire/Modals/EditCredential.php
new file mode 100644
index 0000000..55644ef
--- /dev/null
+++ b/app/Livewire/Modals/EditCredential.php
@@ -0,0 +1,85 @@
+serverId = $serverId;
+
+ if ($cred = Server::find($serverId)?->credential) {
+ $this->username = $cred->username;
+ $this->authType = $cred->auth_type;
+ // secret/passphrase are never pre-filled (encrypted at rest)
+ }
+ }
+
+ public static function modalMaxWidth(): string
+ {
+ return 'lg';
+ }
+
+ public function save(): void
+ {
+ $this->error = null;
+
+ $server = Server::find($this->serverId);
+ if (! $server) {
+ $this->error = 'Server nicht gefunden.';
+
+ return;
+ }
+ if (trim($this->username) === '' || trim($this->secret) === '') {
+ $this->error = 'Benutzer und Passwort/Schlüssel sind erforderlich.';
+
+ return;
+ }
+
+ $server->credential()->updateOrCreate([], [
+ 'username' => trim($this->username),
+ 'auth_type' => $this->authType === 'key' ? 'key' : 'password',
+ 'secret' => $this->secret,
+ 'passphrase' => $this->passphrase !== '' ? $this->passphrase : null,
+ ]);
+
+ AuditEvent::create([
+ 'user_id' => Auth::id(),
+ 'server_id' => $server->id,
+ 'actor' => Auth::user()?->name ?? 'system',
+ 'action' => 'server.credential_updated',
+ 'target' => $server->name.' · '.trim($this->username),
+ 'ip' => request()->ip(),
+ ]);
+
+ $this->dispatch('credentialChanged');
+ $this->dispatch('notify', message: 'Zugangsdaten gespeichert.');
+ $this->closeModal();
+ }
+
+ public function render()
+ {
+ return view('livewire.modals.edit-credential');
+ }
+}
diff --git a/app/Livewire/Servers/Show.php b/app/Livewire/Servers/Show.php
index 51cedb0..ad3849a 100644
--- a/app/Livewire/Servers/Show.php
+++ b/app/Livewire/Servers/Show.php
@@ -138,6 +138,15 @@ class Show extends Component
}
}
+ /** Credential changed -> reconnect with the new login and re-pull the snapshot. */
+ #[On('credentialChanged')]
+ public function reloadAfterCredential(FleetService $fleet): void
+ {
+ $this->server->refresh();
+ $this->ready = false;
+ $this->load($fleet);
+ }
+
/** Open the file manager scoped to this server. */
public function openFiles()
{
diff --git a/resources/views/components/btn.blade.php b/resources/views/components/btn.blade.php
new file mode 100644
index 0000000..d146236
--- /dev/null
+++ b/resources/views/components/btn.blade.php
@@ -0,0 +1,17 @@
+@props(['variant' => 'secondary', 'icon' => false])
+@php
+ // One button style for the whole app — compact, consistent (R10).
+ $variants = [
+ 'primary' => 'bg-accent text-void hover:bg-accent-bright',
+ 'accent' => 'border border-accent/25 bg-accent/10 text-accent-text hover:bg-accent/15',
+ 'secondary' => 'border border-line bg-inset text-ink-2 hover:bg-raised hover:text-ink',
+ 'danger' => 'bg-offline text-void hover:bg-offline/90',
+ 'ghost' => 'text-ink-2 hover:bg-raised hover:text-ink',
+ 'ghost-danger' => 'text-ink-3 hover:bg-offline/10 hover:text-offline',
+ ];
+ $shape = $icon ? 'h-8 w-8 justify-center' : 'h-8 px-3';
+ $classes = 'inline-flex items-center gap-1.5 rounded-md text-xs font-medium transition-colors '
+ .'disabled:opacity-50 disabled:pointer-events-none '
+ .$shape.' '.($variants[$variant] ?? $variants['secondary']);
+@endphp
+
diff --git a/resources/views/livewire/files/index.blade.php b/resources/views/livewire/files/index.blade.php
index 457d690..4f96d41 100644
--- a/resources/views/livewire/files/index.blade.php
+++ b/resources/views/livewire/files/index.blade.php
@@ -49,9 +49,9 @@
{{-- Listing --}}
-
+
{{-- Column header (desktop only) --}}
@@ -116,19 +116,10 @@
{{-- Row actions --}}
@unless ($isDir)
- {{-- R5: wire to wire-elements/modal --}}
-
+ Download
@endunless
- {{-- R5: wire to wire-elements/modal --}}
-
- {{-- R5: destructive → wire-elements/modal confirm + audit --}}
-
+ Bearbeiten
+ Löschen
@endforeach
diff --git a/resources/views/livewire/modals/add-ssh-key.blade.php b/resources/views/livewire/modals/add-ssh-key.blade.php
index 9c05dd9..44fd256 100644
--- a/resources/views/livewire/modals/add-ssh-key.blade.php
+++ b/resources/views/livewire/modals/add-ssh-key.blade.php
@@ -24,21 +24,11 @@
-
-
+
diff --git a/resources/views/livewire/modals/confirm-action.blade.php b/resources/views/livewire/modals/confirm-action.blade.php
index 4320489..1b93702 100644
--- a/resources/views/livewire/modals/confirm-action.blade.php
+++ b/resources/views/livewire/modals/confirm-action.blade.php
@@ -17,25 +17,11 @@
-
-
+
diff --git a/resources/views/livewire/modals/edit-credential.blade.php b/resources/views/livewire/modals/edit-credential.blade.php
new file mode 100644
index 0000000..a437d39
--- /dev/null
+++ b/resources/views/livewire/modals/edit-credential.blade.php
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
SSH-Zugang
+
Hier den Zugang hinterlegen — z. B. root für volle Steuerung (systemctl, Journal).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @if ($authType === 'key')
+
+ @else
+
+ @endif
+
+ @if ($authType === 'key')
+
+
+
+
+ @endif
+
+ @if ($error)
+
+ {{ $error }}
+
+ @endif
+
+
+
+
Abbrechen
+
+
+
+ Speichern
+
+
+
diff --git a/resources/views/livewire/servers/show.blade.php b/resources/views/livewire/servers/show.blade.php
index e5c4b08..4415b9d 100644
--- a/resources/views/livewire/servers/show.blade.php
+++ b/resources/views/livewire/servers/show.blade.php
@@ -43,11 +43,12 @@
-
+
+ Zugang
+
+
+ Dateien
+
{{ $statusLabel }}
@@ -157,12 +158,10 @@
{{-- R5: wire to wire-elements/modal --}}
-
+
@foreach ($sshKeys as $key)
@@ -178,12 +177,9 @@
{{ $key['fingerprint'] }}
{{-- R5: destructive → wire-elements/modal confirm + audit --}}
-
+
@endforeach
diff --git a/resources/views/livewire/services/index.blade.php b/resources/views/livewire/services/index.blade.php
index 15733ee..7cf3a62 100644
--- a/resources/views/livewire/services/index.blade.php
+++ b/resources/views/livewire/services/index.blade.php
@@ -70,24 +70,9 @@
{{-- R5: wire to wire-elements/modal --}}
-
-
-
+ Starten
+ Stopp
+ Neustart
diff --git a/resources/views/vendor/wire-elements-modal/modal.blade.php b/resources/views/vendor/wire-elements-modal/modal.blade.php
index 85e8386..7a41b78 100644
--- a/resources/views/vendor/wire-elements-modal/modal.blade.php
+++ b/resources/views/vendor/wire-elements-modal/modal.blade.php
@@ -39,7 +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"
- 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"
+ class="relative z-10 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"