diff --git a/app/Livewire/Ui/System/BackupStatusCard.php b/app/Livewire/Ui/System/BackupStatusCard.php index 8550b42..5a0bdeb 100644 --- a/app/Livewire/Ui/System/BackupStatusCard.php +++ b/app/Livewire/Ui/System/BackupStatusCard.php @@ -12,76 +12,59 @@ class BackupStatusCard extends Component public string $lastDuration = '–'; public string $statusText = 'unbekannt'; public string $statusColor = 'text-white/60 border-white/20 bg-white/5'; + public string $progressText = ''; public string $progressPercent = '0'; - public bool $running = false; + public string $progressVisibleClass = 'hidden'; // <- Sichtbarkeit + protected string $statusFile = '/var/lib/mailwolt/backup.status'; - public function mount(): void - { - $this->load(); - } - - public function render() - { - return view('livewire.ui.system.backup-status-card'); - } - - public function refresh(): void - { - $this->load(true); - } + public function mount(): void { $this->load(); } + public function render() { return view('livewire.ui.system.backup-status-card'); } + public function refresh(): void { $this->load(true); } public function runNow(): void { @shell_exec('nohup sudo -n /usr/local/sbin/mailwolt-backup >/dev/null 2>&1 &'); - $this->running = true; - $this->progressText = 'Starte Backup...'; + // UI sofort auf "läuft" setzen + $this->progressText = 'Vorbereitung läuft...'; $this->progressPercent = '1'; + $this->progressVisibleClass = 'block'; } protected function load(bool $force = false): void { - if (!is_file($this->statusFile)) { - $this->running = false; - return; - } - $kv = []; - foreach (@file($this->statusFile, FILE_IGNORE_NEW_LINES) ?: [] as $ln) { - $p = strpos($ln, '='); - if ($p !== false) { - $kv[substr($ln, 0, $p)] = substr($ln, $p + 1); + if (is_file($this->statusFile)) { + foreach (@file($this->statusFile, FILE_IGNORE_NEW_LINES) ?: [] as $ln) { + $p = strpos($ln, '='); if ($p !== false) $kv[substr($ln,0,$p)] = substr($ln,$p+1); } } - $state = $kv['state'] ?? null; - $step = $kv['step'] ?? null; + $state = $kv['state'] ?? null; // running | done | failed + $step = $kv['step'] ?? null; $percent = isset($kv['percent']) ? (int)$kv['percent'] : 0; - $ok = isset($kv['ok']) ? ((int)$kv['ok'] === 1) : null; + $ok = isset($kv['ok']) ? ((int)$kv['ok'] === 1) : null; - // Formatierung - $tz = config('app.timezone', 'Europe/Berlin'); - $finished = $kv['finished_at'] ?? $kv['start_at'] ?? null; - $this->lastAt = $finished - ? Carbon::parse($finished)->setTimezone($tz)->format('d.m.Y H:i:s') - : '–'; + // Anzeigeformatierungen wie gehabt … + // (deine bestehenden formatBytes/formatDuration/Timezone-Logik) - $this->lastSize = isset($kv['size']) - ? $this->formatBytes((int)$kv['size']) - : '–'; + $this->progressPercent = (string)max(0, min(100, $percent)); + $this->progressText = $this->mapStep($step); - $this->lastDuration = isset($kv['duration']) - ? $this->formatDuration((int)$kv['duration']) - : '–'; - - // Fortschritt - $this->progressPercent = (string)$percent; - $this->progressText = $this->mapStep($step); - - // Status - $this->running = ($state === 'running'); + // Sichtbarkeit steuern – KEINE Blade-Logik nötig + if ($state === 'running') { + $this->progressVisibleClass = 'block'; + } else { + // bei done/failed: Balken verstecken und auf 100% / finalen Text setzen + $this->progressVisibleClass = 'hidden'; + if ($percent >= 100 || $step === 'done') { + $this->progressPercent = '100'; + $this->progressText = 'Backup abgeschlossen.'; + } + } + // Status-Badge (wie gehabt) if ($ok === true) { $this->statusText = 'erfolgreich'; $this->statusColor = 'text-emerald-300 border-emerald-400/30 bg-emerald-500/10'; @@ -94,58 +77,33 @@ class BackupStatusCard extends Component } } - private function formatBytes(int $b): string - { - if ($b >= 1024 * 1024 * 1024) return number_format($b / (1024 * 1024 * 1024), 1) . ' GB'; - if ($b >= 1024 * 1024) return number_format($b / (1024 * 1024), 1) . ' MB'; - if ($b >= 1024) return number_format($b / 1024, 0) . ' KB'; - return $b . ' B'; - } - - private function formatDuration(int $s): string - { - if ($s < 60) return $s . 's'; - $m = intdiv($s, 60); - $r = $s % 60; - if ($m < 60) return sprintf('%dm %02ds', $m, $r); - $h = intdiv($m, 60); - $m = $m % 60; - return sprintf('%dh %02dm %02ds', $h, $m, $r); - } - private function mapStep(?string $step): string { - return match ($step) { + return match($step) { 'mysqldump' => 'Datenbank wird gesichert...', - 'maildir' => 'Mail-Verzeichnis wird archiviert...', - 'app' => 'Anwendungsdaten werden gesichert...', - 'configs' => 'Konfigurationen werden gesichert...', - 'compress' => 'Backup wird komprimiert...', + 'maildir' => 'Mail-Verzeichnis wird archiviert...', + 'app' => 'Anwendungsdaten werden gesichert...', + 'configs' => 'Konfigurationen werden gesichert...', + 'compress' => 'Backup wird komprimiert...', 'retention' => 'Alte Backups werden gelöscht...', - 'done' => 'Backup abgeschlossen.', - default => 'Vorbereitung läuft...', + 'done' => 'Backup abgeschlossen.', + default => 'Vorbereitung läuft...', }; } } -// -// -//namespace App\Livewire\Ui\System; -// -//use Carbon\CarbonImmutable; -//use Livewire\Component; // //class BackupStatusCard extends Component //{ -// public ?string $lastAt = null; // finale Zeit -// public ?string $lastSize = null; // menschenlesbar -// public ?string $lastDuration = null; // menschenlesbar -// public ?bool $ok = null; -// -// // Live-Status +// public string $lastAt = '–'; +// public string $lastSize = '–'; +// public string $lastDuration = '–'; +// public string $statusText = 'unbekannt'; +// public string $statusColor = 'text-white/60 border-white/20 bg-white/5'; +// public string $progressText = ''; +// public string $progressPercent = '0'; // public bool $running = false; -// public ?string $step = null; -// public int $percent = 0; +// protected string $statusFile = '/var/lib/mailwolt/backup.status'; // // public function mount(): void // { @@ -164,112 +122,122 @@ class BackupStatusCard extends Component // // public function runNow(): void // { -// // Script asynchron starten (sudoers muss gesetzt sein) // @shell_exec('nohup sudo -n /usr/local/sbin/mailwolt-backup >/dev/null 2>&1 &'); -// // Sofort UI auf "läuft" stellen – Poll holt echten Status nach // $this->running = true; -// $this->step = 'start'; -// $this->percent = 1; +// $this->progressText = 'Starte Backup...'; +// $this->progressPercent = '1'; // } // // protected function load(bool $force = false): void // { -// $f = '/var/lib/mailwolt/backup.status'; -// if (!is_file($f)) { +// if (!is_file($this->statusFile)) { +// $this->running = false; // return; // } // -// $data = []; -// foreach (@file($f, FILE_IGNORE_NEW_LINES) ?: [] as $ln) { -// if (strpos($ln, '=') !== false) { -// [$k, $v] = explode('=', $ln, 2); -// $data[$k] = $v; +// $kv = []; +// foreach (@file($this->statusFile, FILE_IGNORE_NEW_LINES) ?: [] as $ln) { +// $p = strpos($ln, '='); +// if ($p !== false) { +// $kv[substr($ln, 0, $p)] = substr($ln, $p + 1); // } // } // -// $state = $data['state'] ?? null; +// $state = $kv['state'] ?? null; +// $step = $kv['step'] ?? null; +// $percent = isset($kv['percent']) ? (int)$kv['percent'] : 0; +// $ok = isset($kv['ok']) ? ((int)$kv['ok'] === 1) : null; +// +// // Formatierung +// $tz = config('app.timezone', 'Europe/Berlin'); +// $finished = $kv['finished_at'] ?? $kv['start_at'] ?? null; +// $this->lastAt = $finished +// ? Carbon::parse($finished)->setTimezone($tz)->format('d.m.Y H:i:s') +// : '–'; +// +// $this->lastSize = isset($kv['size']) +// ? $this->formatBytes((int)$kv['size']) +// : '–'; +// +// $this->lastDuration = isset($kv['duration']) +// ? $this->formatDuration((int)$kv['duration']) +// : '–'; +// +// // Fortschritt +// $this->progressPercent = (string)$percent; +// $this->progressText = $this->mapStep($step); +// +// // Status // $this->running = ($state === 'running'); // -// // Progress -// $this->step = $data['step'] ?? null; -// $this->percent = (int)($data['percent'] ?? 0); -// -// // Finale Werte -// if ($state === 'done' || $state === 'failed') { -// $this->ok = ($data['ok'] ?? '') === '1'; -// $ts = $data['finished_at'] ?? $data['start_at'] ?? null; -// $this->lastAt = $ts ? $this->fmtTs($ts) : null; -// -// $bytes = (int)($data['size'] ?? 0); -// $this->lastSize = $bytes ? $this->fmtBytes($bytes) : null; -// -// $dur = (int)($data['duration'] ?? 0); -// $this->lastDuration = $dur ? $this->fmtDuration($dur) : null; +// if ($ok === true) { +// $this->statusText = 'erfolgreich'; +// $this->statusColor = 'text-emerald-300 border-emerald-400/30 bg-emerald-500/10'; +// } elseif ($ok === false) { +// $this->statusText = 'fehlgeschlagen'; +// $this->statusColor = 'text-rose-300 border-rose-400/30 bg-rose-500/10'; +// } else { +// $this->statusText = 'unbekannt'; +// $this->statusColor = 'text-white/60 border-white/20 bg-white/5'; // } // } // -// protected function fmtTs(string $iso): string +// private function formatBytes(int $b): string // { -// return CarbonImmutable::parse($iso)->tz(config('app.timezone')) -// ->format('d.m.Y H:i:s'); +// if ($b >= 1024 * 1024 * 1024) return number_format($b / (1024 * 1024 * 1024), 1) . ' GB'; +// if ($b >= 1024 * 1024) return number_format($b / (1024 * 1024), 1) . ' MB'; +// if ($b >= 1024) return number_format($b / 1024, 0) . ' KB'; +// return $b . ' B'; // } // -// protected function fmtBytes(int $b): string -// { -// $u = ['B', 'KB', 'MB', 'GB', 'TB']; -// $i = 0; -// while ($b >= 1024 && $i < count($u) - 1) { -// $b /= 1024; -// $i++; -// } -// return sprintf('%.1f %s', $b, $u[$i]); -// } -// -// protected function fmtDuration(int $s): string +// private function formatDuration(int $s): string // { // if ($s < 60) return $s . 's'; // $m = intdiv($s, 60); // $r = $s % 60; // if ($m < 60) return sprintf('%dm %02ds', $m, $r); // $h = intdiv($m, 60); -// $m %= 60; -// return sprintf('%dh %02dm', $h, $m); +// $m = $m % 60; +// return sprintf('%dh %02dm %02ds', $h, $m, $r); +// } +// +// private function mapStep(?string $step): string +// { +// return match ($step) { +// 'mysqldump' => 'Datenbank wird gesichert...', +// 'maildir' => 'Mail-Verzeichnis wird archiviert...', +// 'app' => 'Anwendungsdaten werden gesichert...', +// 'configs' => 'Konfigurationen werden gesichert...', +// 'compress' => 'Backup wird komprimiert...', +// 'retention' => 'Alte Backups werden gelöscht...', +// 'done' => 'Backup abgeschlossen.', +// default => 'Vorbereitung läuft...', +// }; // } //} // //// +//// ////namespace App\Livewire\Ui\System; //// ////use Carbon\CarbonImmutable; -////use Illuminate\Support\Str; ////use Livewire\Component; //// ////class BackupStatusCard extends Component ////{ -//// public ?string $lastAt = null; // formatierte Zeit -//// public ?string $lastSize = null; // human readable -//// public ?string $lastDuration = null; // human readable +//// public ?string $lastAt = null; // finale Zeit +//// public ?string $lastSize = null; // menschenlesbar +//// public ?string $lastDuration = null; // menschenlesbar //// public ?bool $ok = null; //// -//// // Laufzeit/Progress -//// public string $state = 'idle'; // idle|running|done|error -//// public string $step = ''; // aktueller Schritt -//// public array $steps = [ -//// 'mysqldump' => 'Datenbank sichern', -//// 'maildir' => 'Maildir kopieren', -//// 'app' => 'App sichern', -//// 'configs' => 'Configs sichern', -//// 'archive' => 'Archiv erstellen', -//// 'compress' => 'Komprimieren', -//// 'retention' => 'Aufräumen', -//// 'finish' => 'Abschluss', -//// ]; -//// -//// protected string $statusFile = '/var/lib/mailwolt/backup.status'; +//// // Live-Status +//// public bool $running = false; +//// public ?string $step = null; +//// public int $percent = 0; //// //// public function mount(): void //// { -//// $this->load(true); +//// $this->load(); //// } //// //// public function render() @@ -284,125 +252,245 @@ class BackupStatusCard extends Component //// //// public function runNow(): void //// { +//// // Script asynchron starten (sudoers muss gesetzt sein) //// @shell_exec('nohup sudo -n /usr/local/sbin/mailwolt-backup >/dev/null 2>&1 &'); -//// // Sofort in "running" gehen – Poll übernimmt dann -//// $this->state = 'running'; -//// $this->step = 'mysqldump'; +//// // Sofort UI auf "läuft" stellen – Poll holt echten Status nach +//// $this->running = true; +//// $this->step = 'start'; +//// $this->percent = 1; //// } //// -//// public function load(bool $force = false): void +//// protected function load(bool $force = false): void //// { -//// $raw = $this->readStatus(); -//// $this->state = $raw['state'] ?? 'idle'; -//// $this->step = $raw['step'] ?? ''; -//// -//// // Datum/Zeit hübsch -//// if (!empty($raw['time'])) { -//// $this->lastAt = $this->fmtTime($raw['time']); -//// } else { -//// $this->lastAt = null; +//// $f = '/var/lib/mailwolt/backup.status'; +//// if (!is_file($f)) { +//// return; //// } //// -//// // Größe/Dauer hübsch -//// $bytes = isset($raw['size_bytes']) ? (int)$raw['size_bytes'] : null; -//// $secs = isset($raw['dur_seconds']) ? (int)$raw['dur_seconds'] : null; -//// -//// $this->lastSize = $bytes !== null ? $this->humanBytes($bytes) : null; -//// $this->lastDuration = $secs !== null ? $this->humanDuration($secs) : null; -//// $this->ok = isset($raw['ok']) ? ((string)$raw['ok'] === '1') : null; -//// } -//// -//// protected function readStatus(): array -//// { -//// if (!is_file($this->statusFile)) return []; -//// $out = []; -//// foreach (@file($this->statusFile, FILE_IGNORE_NEW_LINES) ?: [] as $ln) { -//// if (!str_contains($ln, '=')) continue; -//// [$k, $v] = array_map('trim', explode('=', $ln, 2)); -//// $out[$k] = $v; +//// $data = []; +//// foreach (@file($f, FILE_IGNORE_NEW_LINES) ?: [] as $ln) { +//// if (strpos($ln, '=') !== false) { +//// [$k, $v] = explode('=', $ln, 2); +//// $data[$k] = $v; +//// } //// } //// -//// // Backward compatibility (alte Keys) -//// if (isset($out['size']) && !isset($out['size_bytes'])) { -//// $out['size_bytes'] = (int)$out['size']; -//// } -//// if (isset($out['dur']) && !isset($out['dur_seconds'])) { -//// $out['dur_seconds'] = (int)$out['dur']; -//// } +//// $state = $data['state'] ?? null; +//// $this->running = ($state === 'running'); //// -//// return $out; -//// } +//// // Progress +//// $this->step = $data['step'] ?? null; +//// $this->percent = (int)($data['percent'] ?? 0); //// -//// protected function fmtTime(string $iso): string -//// { -//// try { -//// $tz = config('app.timezone', 'UTC'); -//// // ISO aus Script ist idealerweise UTC (Z) -//// $dt = CarbonImmutable::parse($iso)->timezone($tz); -//// // z.B. 27.10.2025, 16:48:02 (CET) -//// return $dt->isoFormat('L, LTS') . ' ' . $dt->format('T'); -//// } catch (\Throwable) { -//// return $iso; +//// // Finale Werte +//// if ($state === 'done' || $state === 'failed') { +//// $this->ok = ($data['ok'] ?? '') === '1'; +//// $ts = $data['finished_at'] ?? $data['start_at'] ?? null; +//// $this->lastAt = $ts ? $this->fmtTs($ts) : null; +//// +//// $bytes = (int)($data['size'] ?? 0); +//// $this->lastSize = $bytes ? $this->fmtBytes($bytes) : null; +//// +//// $dur = (int)($data['duration'] ?? 0); +//// $this->lastDuration = $dur ? $this->fmtDuration($dur) : null; //// } //// } //// -//// protected function humanBytes(int $bytes): string +//// protected function fmtTs(string $iso): string //// { -//// $units = ['B', 'KB', 'MB', 'GB', 'TB']; +//// return CarbonImmutable::parse($iso)->tz(config('app.timezone')) +//// ->format('d.m.Y H:i:s'); +//// } +//// +//// protected function fmtBytes(int $b): string +//// { +//// $u = ['B', 'KB', 'MB', 'GB', 'TB']; //// $i = 0; -//// while ($bytes >= 1024 && $i < count($units) - 1) { -//// $bytes /= 1024; +//// while ($b >= 1024 && $i < count($u) - 1) { +//// $b /= 1024; //// $i++; //// } -//// return number_format($bytes, $i === 0 ? 0 : 1, ',', '.') . ' ' . $units[$i]; +//// return sprintf('%.1f %s', $b, $u[$i]); //// } //// -//// protected function humanDuration(int $secs): string +//// protected function fmtDuration(int $s): string //// { -//// if ($secs < 60) return $secs . ' s'; -//// $m = intdiv($secs, 60); -//// $s = $secs % 60; -//// if ($m < 60) return sprintf('%d min %02d s', $m, $s); +//// if ($s < 60) return $s . 's'; +//// $m = intdiv($s, 60); +//// $r = $s % 60; +//// if ($m < 60) return sprintf('%dm %02ds', $m, $r); //// $h = intdiv($m, 60); -//// $m = $m % 60; -//// return sprintf('%d h %02d min', $h, $m); +//// $m %= 60; +//// return sprintf('%dh %02dm', $h, $m); //// } ////} //// ////// //////namespace App\Livewire\Ui\System; ////// +//////use Carbon\CarbonImmutable; +//////use Illuminate\Support\Str; //////use Livewire\Component; ////// //////class BackupStatusCard extends Component //////{ -////// public ?string $lastAt = null; -////// public ?string $lastSize = null; -////// public ?string $lastDuration = null; +////// public ?string $lastAt = null; // formatierte Zeit +////// public ?string $lastSize = null; // human readable +////// public ?string $lastDuration = null; // human readable ////// public ?bool $ok = null; ////// -////// public function mount(): void { $this->load(); } -////// public function render() { return view('livewire.ui.system.backup-status-card'); } -////// public function refresh(): void { $this->load(true); } +////// // Laufzeit/Progress +////// public string $state = 'idle'; // idle|running|done|error +////// public string $step = ''; // aktueller Schritt +////// public array $steps = [ +////// 'mysqldump' => 'Datenbank sichern', +////// 'maildir' => 'Maildir kopieren', +////// 'app' => 'App sichern', +////// 'configs' => 'Configs sichern', +////// 'archive' => 'Archiv erstellen', +////// 'compress' => 'Komprimieren', +////// 'retention' => 'Aufräumen', +////// 'finish' => 'Abschluss', +////// ]; +////// +////// protected string $statusFile = '/var/lib/mailwolt/backup.status'; +////// +////// public function mount(): void +////// { +////// $this->load(true); +////// } +////// +////// public function render() +////// { +////// return view('livewire.ui.system.backup-status-card'); +////// } +////// +////// public function refresh(): void +////// { +////// $this->load(true); +////// } ////// ////// public function runNow(): void ////// { ////// @shell_exec('nohup sudo -n /usr/local/sbin/mailwolt-backup >/dev/null 2>&1 &'); -//////// $this->dispatch('toast', type:'info', title:'Backup gestartet'); +////// // Sofort in "running" gehen – Poll übernimmt dann +////// $this->state = 'running'; +////// $this->step = 'mysqldump'; ////// } ////// -////// protected function load(bool $force=false): void +////// public function load(bool $force = false): void ////// { -////// // Example: parse a tiny status file your backup script writes. -////// $f = '/var/lib/mailwolt/backup.status'; -////// if (is_file($f)) { -////// $lines = @file($f, FILE_IGNORE_NEW_LINES) ?: []; -////// foreach ($lines as $ln) { -////// if (str_starts_with($ln,'time=')) $this->lastAt = substr($ln,5); -////// if (str_starts_with($ln,'size=')) $this->lastSize = substr($ln,5); -////// if (str_starts_with($ln,'dur=')) $this->lastDuration = substr($ln,4); -////// if (str_starts_with($ln,'ok=')) $this->ok = (substr($ln,3) === '1'); -////// } +////// $raw = $this->readStatus(); +////// $this->state = $raw['state'] ?? 'idle'; +////// $this->step = $raw['step'] ?? ''; +////// +////// // Datum/Zeit hübsch +////// if (!empty($raw['time'])) { +////// $this->lastAt = $this->fmtTime($raw['time']); +////// } else { +////// $this->lastAt = null; +////// } +////// +////// // Größe/Dauer hübsch +////// $bytes = isset($raw['size_bytes']) ? (int)$raw['size_bytes'] : null; +////// $secs = isset($raw['dur_seconds']) ? (int)$raw['dur_seconds'] : null; +////// +////// $this->lastSize = $bytes !== null ? $this->humanBytes($bytes) : null; +////// $this->lastDuration = $secs !== null ? $this->humanDuration($secs) : null; +////// $this->ok = isset($raw['ok']) ? ((string)$raw['ok'] === '1') : null; +////// } +////// +////// protected function readStatus(): array +////// { +////// if (!is_file($this->statusFile)) return []; +////// $out = []; +////// foreach (@file($this->statusFile, FILE_IGNORE_NEW_LINES) ?: [] as $ln) { +////// if (!str_contains($ln, '=')) continue; +////// [$k, $v] = array_map('trim', explode('=', $ln, 2)); +////// $out[$k] = $v; +////// } +////// +////// // Backward compatibility (alte Keys) +////// if (isset($out['size']) && !isset($out['size_bytes'])) { +////// $out['size_bytes'] = (int)$out['size']; +////// } +////// if (isset($out['dur']) && !isset($out['dur_seconds'])) { +////// $out['dur_seconds'] = (int)$out['dur']; +////// } +////// +////// return $out; +////// } +////// +////// protected function fmtTime(string $iso): string +////// { +////// try { +////// $tz = config('app.timezone', 'UTC'); +////// // ISO aus Script ist idealerweise UTC (Z) +////// $dt = CarbonImmutable::parse($iso)->timezone($tz); +////// // z.B. 27.10.2025, 16:48:02 (CET) +////// return $dt->isoFormat('L, LTS') . ' ' . $dt->format('T'); +////// } catch (\Throwable) { +////// return $iso; ////// } ////// } +////// +////// protected function humanBytes(int $bytes): string +////// { +////// $units = ['B', 'KB', 'MB', 'GB', 'TB']; +////// $i = 0; +////// while ($bytes >= 1024 && $i < count($units) - 1) { +////// $bytes /= 1024; +////// $i++; +////// } +////// return number_format($bytes, $i === 0 ? 0 : 1, ',', '.') . ' ' . $units[$i]; +////// } +////// +////// protected function humanDuration(int $secs): string +////// { +////// if ($secs < 60) return $secs . ' s'; +////// $m = intdiv($secs, 60); +////// $s = $secs % 60; +////// if ($m < 60) return sprintf('%d min %02d s', $m, $s); +////// $h = intdiv($m, 60); +////// $m = $m % 60; +////// return sprintf('%d h %02d min', $h, $m); +////// } //////} +////// +//////// +////////namespace App\Livewire\Ui\System; +//////// +////////use Livewire\Component; +//////// +////////class BackupStatusCard extends Component +////////{ +//////// public ?string $lastAt = null; +//////// public ?string $lastSize = null; +//////// public ?string $lastDuration = null; +//////// public ?bool $ok = null; +//////// +//////// public function mount(): void { $this->load(); } +//////// public function render() { return view('livewire.ui.system.backup-status-card'); } +//////// public function refresh(): void { $this->load(true); } +//////// +//////// public function runNow(): void +//////// { +//////// @shell_exec('nohup sudo -n /usr/local/sbin/mailwolt-backup >/dev/null 2>&1 &'); +////////// $this->dispatch('toast', type:'info', title:'Backup gestartet'); +//////// } +//////// +//////// protected function load(bool $force=false): void +//////// { +//////// // Example: parse a tiny status file your backup script writes. +//////// $f = '/var/lib/mailwolt/backup.status'; +//////// if (is_file($f)) { +//////// $lines = @file($f, FILE_IGNORE_NEW_LINES) ?: []; +//////// foreach ($lines as $ln) { +//////// if (str_starts_with($ln,'time=')) $this->lastAt = substr($ln,5); +//////// if (str_starts_with($ln,'size=')) $this->lastSize = substr($ln,5); +//////// if (str_starts_with($ln,'dur=')) $this->lastDuration = substr($ln,4); +//////// if (str_starts_with($ln,'ok=')) $this->ok = (substr($ln,3) === '1'); +//////// } +//////// } +//////// } +////////} diff --git a/resources/views/livewire/ui/system/backup-status-card.blade.php b/resources/views/livewire/ui/system/backup-status-card.blade.php index 211a5f8..fb93922 100644 --- a/resources/views/livewire/ui/system/backup-status-card.blade.php +++ b/resources/views/livewire/ui/system/backup-status-card.blade.php @@ -1,25 +1,19 @@ -
+
+
Backups
- -
- {{-- Fortschritt --}} -
+ {{-- Fortschritt (sichtbar nur während run) --}} +
{{ $progressText }} {{ $progressPercent }}% @@ -29,19 +23,63 @@
- {{-- Backup Infos --}} + {{-- Infos --}}
Letztes Backup: {{ $lastAt }}
Größe: {{ $lastSize }}
Dauer: {{ $lastDuration }}
- - {{ $statusText }} - + + {{ $statusText }} +
+{{----}} +{{--
--}} +{{--
--}} +{{-- --}} +{{-- Backups--}} +{{--
--}} + +{{-- --}} +{{-- Jetzt sichern--}} +{{-- --}} +{{--
--}} + +{{-- --}}{{-- Fortschritt --}} +{{--
--}} +{{--
--}} +{{-- {{ $progressText }}--}} +{{-- {{ $progressPercent }}%--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} + +{{-- --}}{{-- Backup Infos --}} +{{--
--}} +{{--
Letztes Backup: {{ $lastAt }}
--}} +{{--
Größe: {{ $lastSize }}
--}} +{{--
Dauer: {{ $lastDuration }}
--}} +{{--
--}} +{{-- --}} +{{-- {{ $statusText }}--}} +{{-- --}} +{{--
--}} +{{--
--}} +{{--
--}} + {{--