Fix: ClamAV Feedback – Loading-Overlay + Erfolg/Fehler-Banner inline

- Loading-Overlay über Status-Karte beim Aktivieren/Deaktivieren/Installieren
- $lastSuccess Property für grünen Erfolg-Banner (kein Toast nötig)
- runCmd() helper mit Log für Debugging
- Fehler-Text white-space:pre-wrap für mehrzeilige Ausgaben

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main v1.1.329
boban 2026-04-26 20:42:45 +02:00
parent a9ad26757b
commit dc5d8582e1
2 changed files with 44 additions and 35 deletions

View File

@ -17,6 +17,7 @@ class ClamavManager extends Component
public string $dbVersion = '—';
public ?int $ramMb = null;
public string $lastError = '';
public string $lastSuccess = '';
public bool $installing = false;
public function mount(): void
@ -26,11 +27,12 @@ class ClamavManager extends Component
public function refresh(): void
{
$this->lastError = '';
$this->running = $this->serviceActive();
$this->enabled = $this->serviceEnabled();
$this->installed = true; // Mailwolt setzt ClamAV voraus; Fehler kommen vom Wrapper
$this->ramMb = $this->running ? $this->readRamMb() : null;
$this->lastError = '';
$this->lastSuccess = '';
$this->running = $this->serviceActive();
$this->enabled = $this->serviceEnabled();
$this->installed = true;
$this->ramMb = $this->running ? $this->readRamMb() : null;
[$this->dbDate, $this->dbVersion] = $this->readDbInfo();
}
@ -51,41 +53,37 @@ class ClamavManager extends Component
public function enable(): void
{
$out = [];
@exec('sudo -n /usr/local/sbin/mailwolt-clamav enable 2>&1', $out, $rc);
if ($rc !== 0) {
$this->lastError = implode(' ', $out) ?: 'Fehler beim Aktivieren.';
} else {
$this->dispatch('toast', type: 'success', badge: 'ClamAV',
title: 'Aktiviert', text: 'ClamAV läuft jetzt und startet automatisch beim Booten.');
}
$this->refresh();
[$ok, $msg] = $this->runCmd('enable');
if ($ok) $this->lastSuccess = 'ClamAV wurde aktiviert und gestartet.';
else $this->lastError = $msg;
$this->running = $this->serviceActive();
$this->enabled = $this->serviceEnabled();
}
public function disable(): void
{
$out = [];
@exec('sudo -n /usr/local/sbin/mailwolt-clamav disable 2>&1', $out, $rc);
if ($rc !== 0) {
$this->lastError = implode(' ', $out) ?: 'Fehler beim Deaktivieren.';
} else {
$this->dispatch('toast', type: 'success', badge: 'ClamAV',
title: 'Deaktiviert', text: 'ClamAV wurde gestoppt und aus dem Autostart entfernt.');
}
$this->refresh();
[$ok, $msg] = $this->runCmd('disable');
if ($ok) $this->lastSuccess = 'ClamAV wurde gestoppt und deaktiviert.';
else $this->lastError = $msg;
$this->running = $this->serviceActive();
$this->enabled = $this->serviceEnabled();
}
public function updateDb(): void
{
$out = [];
@exec('sudo -n /usr/local/sbin/mailwolt-clamav freshclam 2>&1', $out, $rc);
if ($rc !== 0) {
$this->lastError = implode(' ', $out) ?: 'Fehler beim Aktualisieren.';
} else {
$this->dispatch('toast', type: 'success', badge: 'ClamAV',
title: 'Datenbank aktualisiert', text: 'Virensignaturen wurden aktualisiert.');
}
$this->refresh();
[$ok, $msg] = $this->runCmd('freshclam');
if ($ok) $this->lastSuccess = 'Virensignaturen wurden aktualisiert.';
else $this->lastError = $msg;
[$this->dbDate, $this->dbVersion] = $this->readDbInfo();
}
private function runCmd(string $action): array
{
$out = []; $rc = null;
exec('sudo -n /usr/local/sbin/mailwolt-clamav ' . escapeshellarg($action) . ' 2>&1', $out, $rc);
\Log::info('ClamAV ' . $action, ['rc' => $rc, 'out' => $out]);
$msg = implode(' ', $out) ?: 'Unbekannter Fehler (rc=' . $rc . ')';
return [$rc === 0, $msg];
}
private function serviceActive(): bool

View File

@ -19,11 +19,16 @@
</div>
</div>
{{-- Fehler-Banner --}}
@if($lastSuccess)
<div style="margin-bottom:16px;padding:10px 14px;background:rgba(52,211,153,.08);border:1px solid rgba(52,211,153,.25);border-radius:8px;display:flex;align-items:center;gap:8px">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" style="color:#34d399;flex-shrink:0"><circle cx="7" cy="7" r="6" stroke="currentColor" stroke-width="1.3"/><path d="M4.5 7l2 2 3-3" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span style="font-size:12.5px;color:#6ee7b7;font-weight:500">{{ $lastSuccess }}</span>
</div>
@endif
@if($lastError)
<div style="margin-bottom:16px;padding:10px 14px;background:rgba(239,68,68,.08);border:1px solid rgba(239,68,68,.25);border-radius:8px;display:flex;align-items:center;gap:8px">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" style="color:#ef4444;flex-shrink:0"><circle cx="7" cy="7" r="6" stroke="currentColor" stroke-width="1.3"/><path d="M7 4v3.5" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/><circle cx="7" cy="10" r=".6" fill="currentColor"/></svg>
<span style="font-size:12.5px;color:#fca5a5">{{ $lastError }}</span>
<span style="font-size:12.5px;color:#fca5a5;white-space:pre-wrap">{{ $lastError }}</span>
</div>
@endif
@ -33,7 +38,13 @@
<div style="min-width:0;display:flex;flex-direction:column;gap:16px">
{{-- Status-Karte --}}
<div class="mbx-section">
<div class="mbx-section" style="position:relative">
<div wire:loading wire:target="enable,disable,install" style="position:absolute;inset:0;background:rgba(0,0,0,.45);border-radius:11px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;z-index:10">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" style="color:#a78bfa;animation:spin 1s linear infinite"><path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
<span style="font-size:12.5px;color:#e2d9fa;font-weight:500" wire:loading wire:target="enable">ClamAV wird gestartet…</span>
<span style="font-size:12.5px;color:#e2d9fa;font-weight:500" wire:loading wire:target="disable">ClamAV wird gestoppt…</span>
<span style="font-size:12.5px;color:#e2d9fa;font-weight:500" wire:loading wire:target="install">ClamAV wird installiert…</span>
</div>
<div class="mbx-domain-head">
<div class="mbx-domain-info">
<span class="mbx-badge-mute">Status</span>