UI: Update-Seite überarbeitet – sauberes mbx-Design, eine Karte

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main v1.1.359
boban 2026-04-26 22:52:34 +02:00
parent ea37abacf8
commit a2ba9a7c03
1 changed files with 100 additions and 127 deletions

View File

@ -3,12 +3,10 @@
<div>
{{-- Polling --}}
@if($state === 'running' || $running)
<div wire:poll.2s="pollStatus"></div>
@endif
{{-- ═══ Page Header ═══ --}}
<div class="mbx-page-header">
<div class="mbx-page-title">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
@ -18,21 +16,14 @@
Updates
</div>
<div class="mbx-page-actions">
<button wire:click="checkForUpdates"
wire:loading.attr="disabled"
wire:target="checkForUpdates"
class="mbx-btn-mute">
<button wire:click="checkForUpdates" wire:loading.attr="disabled" wire:target="checkForUpdates" class="mbx-btn-mute">
<svg width="12" height="12" viewBox="0 0 14 14" fill="none"><path d="M7 1.5A5.5 5.5 0 1 1 1.5 7" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/><path d="M1.5 2v3.5H5" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span wire:loading.remove wire:target="checkForUpdates">Auf Updates prüfen</span>
<span wire:loading wire:target="checkForUpdates">Prüfe </span>
</button>
@if($hasUpdate)
<button wire:click="runUpdate"
wire:loading.attr="disabled"
wire:target="runUpdate"
class="mbx-btn-primary"
@if($state === 'running') disabled @endif>
<svg width="12" height="12" viewBox="0 0 14 14" fill="none"><path d="M7 1L7 9" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/><path d="M4 6l3 3 3-3" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/><path d="M2 12h10" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg>
<button wire:click="runUpdate" wire:loading.attr="disabled" wire:target="runUpdate" class="mbx-btn-primary" @if($state === 'running') disabled @endif>
<svg width="12" height="12" viewBox="0 0 14 14" fill="none"><path d="M7 1v8" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/><path d="M4 6l3 3 3-3" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/><path d="M2 12h10" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg>
<span wire:loading.remove wire:target="runUpdate">{{ $displayLatest ?? 'Update' }} installieren</span>
<span wire:loading wire:target="runUpdate">Starte </span>
</button>
@ -42,119 +33,118 @@
<div class="mbx-sections">
{{-- ═══ Version + Status (2-spaltig) ═══ --}}
<div class="mw-update-grid" style="display:grid;grid-template-columns:1fr 1fr;gap:14px">
{{-- Versionen --}}
<div class="mbx-section" style="margin:0">
<div class="mbx-domain-head">
<div class="mbx-domain-info">
<span class="mbx-badge-mute">Versionsinformation</span>
</div>
@if($state === 'running')
<span style="font-size:10.5px;padding:2px 8px;border-radius:9px;background:rgba(14,165,233,.1);border:1px solid rgba(14,165,233,.3);color:#7dd3fc;font-weight:600">Update läuft </span>
@elseif($rc !== null && $rc !== 0)
<span class="mbx-badge-warn">Fehler (rc={{ $rc }})</span>
@elseif($hasUpdate)
<span class="mbx-badge-warn">Update verfügbar</span>
@else
<span class="mbx-badge-ok">Aktuell</span>
@endif
{{-- ═══ Versions-Karte ═══ --}}
<div class="mbx-section">
<div class="mbx-domain-head">
<div class="mbx-domain-info">
<span class="mbx-badge-mute">Versionsinformation</span>
</div>
<div style="padding:16px 18px;display:flex;flex-direction:column;gap:14px">
<div style="display:flex;align-items:center;gap:12px">
<div style="width:36px;height:36px;border-radius:8px;background:var(--mw-bg4);border:1px solid var(--mw-b2);display:flex;align-items:center;justify-content:center;flex-shrink:0">
<svg width="15" height="15" viewBox="0 0 14 14" fill="none"><rect x="1.5" y="1.5" width="11" height="11" rx="2" stroke="var(--mw-t3)" stroke-width="1.2"/><path d="M4 7h6M4 4.5h6M4 9.5h3.5" stroke="var(--mw-t3)" stroke-width="1.1" stroke-linecap="round"/></svg>
</div>
<div>
<div style="font-size:10.5px;color:var(--mw-t4);margin-bottom:2px">Installierte Version</div>
<div style="font-family:monospace;font-size:14px;font-weight:600;color:var(--mw-t1)">{{ $displayCurrent ?? '—' }}</div>
</div>
@if($state === 'running')
<span style="font-size:10.5px;padding:2px 8px;border-radius:9px;background:rgba(14,165,233,.1);border:1px solid rgba(14,165,233,.3);color:#7dd3fc;font-weight:600">
Update läuft
</span>
@elseif($rc !== null && $rc !== 0)
<span class="mbx-badge-warn">Fehler (rc={{ $rc }})</span>
@elseif($hasUpdate)
<span class="mbx-badge-warn">Update verfügbar</span>
@else
<span class="mbx-badge-ok">Aktuell</span>
@endif
</div>
{{-- Version-Zeile --}}
<div style="padding:14px 18px;display:flex;align-items:center;gap:0;flex-wrap:wrap;border-bottom:1px solid var(--mw-b1)">
{{-- Installiert --}}
<div style="flex:1;min-width:120px;padding:8px 14px 8px 0">
<div style="font-size:10.5px;color:var(--mw-t4);margin-bottom:4px;text-transform:uppercase;letter-spacing:.05em">Installiert</div>
<div style="font-family:monospace;font-size:15px;font-weight:600;color:var(--mw-t1)">{{ $displayCurrent ?? '—' }}</div>
</div>
{{-- Pfeil --}}
@if($hasUpdate)
<div style="padding:0 10px;flex-shrink:0">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8h10M9 4l4 4-4 4" stroke="rgba(234,179,8,.7)" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
@else
<div style="padding:0 10px;flex-shrink:0">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8h10M9 4l4 4-4 4" stroke="var(--mw-b2)" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
@endif
{{-- Verfügbar --}}
<div style="flex:1;min-width:120px;padding:8px 0 8px 14px;border-left:1px solid var(--mw-b1)">
<div style="font-size:10.5px;color:var(--mw-t4);margin-bottom:4px;text-transform:uppercase;letter-spacing:.05em">Verfügbar</div>
<div style="font-family:monospace;font-size:15px;font-weight:600;color:{{ $hasUpdate ? '#fbbf24' : 'var(--mw-t1)' }}">
{{ $displayLatest ?? ($displayCurrent ?? '—') }}
</div>
<div style="height:1px;background:var(--mw-b1)"></div>
<div style="display:flex;align-items:center;gap:12px">
<div style="width:36px;height:36px;border-radius:8px;background:{{ $hasUpdate ? 'rgba(234,179,8,.1)' : 'var(--mw-bg4)' }};border:1px solid {{ $hasUpdate ? 'rgba(234,179,8,.3)' : 'var(--mw-b2)' }};display:flex;align-items:center;justify-content:center;flex-shrink:0">
<svg width="15" height="15" viewBox="0 0 14 14" fill="none"><path d="M7 1.5A5.5 5.5 0 1 1 1.5 7" stroke="{{ $hasUpdate ? '#fbbf24' : 'var(--mw-t3)' }}" stroke-width="1.2" stroke-linecap="round"/><path d="M1.5 2v3.5H5" stroke="{{ $hasUpdate ? '#fbbf24' : 'var(--mw-t3)' }}" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
</div>
{{-- Status-Zeile --}}
<div style="padding:12px 18px">
@if($state === 'running')
<div style="display:flex;flex-direction:column;gap:10px">
<div style="display:flex;align-items:center;gap:10px">
<div style="width:28px;height:28px;border-radius:50%;background:rgba(14,165,233,.1);border:1px solid rgba(14,165,233,.3);display:flex;align-items:center;justify-content:center;flex-shrink:0;animation:spin 1.5s linear infinite">
<svg width="13" height="13" viewBox="0 0 16 16" fill="none"><path d="M8 2a6 6 0 1 1-4.24 1.76" stroke="#7dd3fc" stroke-width="1.5" stroke-linecap="round"/><path d="M2 2v3.5H5.5" stroke="#7dd3fc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
<div>
<div style="font-size:12.5px;font-weight:600;color:var(--mw-t1)">Update wird installiert </div>
<div style="font-size:11px;color:var(--mw-t4);margin-top:1px">Bitte nicht unterbrechen. Die Seite aktualisiert sich automatisch.</div>
</div>
</div>
<div>
<div style="font-size:10.5px;color:var(--mw-t4);margin-bottom:2px">Verfügbare Version</div>
<div style="font-family:monospace;font-size:14px;font-weight:600;color:{{ $hasUpdate ? '#fbbf24' : 'var(--mw-t1)' }}">
{{ $displayLatest ?? ($displayCurrent ?? '—') }}
<div style="display:flex;justify-content:space-between;margin-bottom:4px">
<span style="font-size:10.5px;color:var(--mw-t4)">Fortschritt</span>
<span style="font-size:10.5px;color:var(--mw-t4);font-family:monospace">{{ $progressPct }}%</span>
</div>
<div style="height:5px;background:var(--mw-bg4);border-radius:4px;overflow:hidden;border:1px solid var(--mw-b2)">
<div style="height:100%;width:{{ $progressPct }}%;transition:width .6s ease;background:rgba(14,165,233,.8);border-radius:4px"></div>
</div>
</div>
</div>
@if(!$hasUpdate && $displayCurrent)
<div style="display:flex;align-items:center;gap:7px;font-size:11.5px;color:rgba(34,197,94,.75)">
<svg width="11" height="11" viewBox="0 0 12 12" fill="none"><path d="M2 6.5l2.5 2.5 5.5-5.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
Du bist auf dem neuesten Stand.
</div>
@endif
</div>
</div>
{{-- Status + Fortschritt --}}
<div class="mbx-section" style="margin:0">
<div class="mbx-domain-head">
<div class="mbx-domain-info">
<span class="mbx-badge-mute">Update-Status</span>
</div>
</div>
<div style="padding:16px 18px;display:flex;flex-direction:column;gap:14px">
@if($state === 'running')
<div style="display:flex;align-items:center;gap:12px">
<div style="width:36px;height:36px;border-radius:50%;background:rgba(14,165,233,.1);border:1px solid rgba(14,165,233,.3);display:flex;align-items:center;justify-content:center;flex-shrink:0;animation:spin 1.5s linear infinite">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M8 2a6 6 0 1 1-4.24 1.76" stroke="#7dd3fc" stroke-width="1.4" stroke-linecap="round"/><path d="M2 2v3.5H5.5" stroke="#7dd3fc" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
@elseif($rc !== null && $rc !== 0)
<div style="display:flex;align-items:flex-start;gap:9px;padding:10px 13px;background:rgba(239,68,68,.07);border:1px solid rgba(239,68,68,.22);border-radius:7px">
<svg width="13" height="13" viewBox="0 0 14 14" fill="none" style="flex-shrink:0;margin-top:1px;color:#f87171"><path d="M7 1L13 12H1L7 1Z" stroke="currentColor" stroke-width="1.3" stroke-linejoin="round"/><path d="M7 5.5v3" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/><circle cx="7" cy="10" r=".7" fill="currentColor"/></svg>
<div>
<div style="font-size:13px;font-weight:600;color:var(--mw-t1)">Update wird installiert </div>
<div style="font-size:11.5px;color:var(--mw-t4);margin-top:2px">Bitte nicht unterbrechen.</div>
<div style="font-size:12px;font-weight:600;color:#f87171">Update fehlgeschlagen (rc={{ $rc }})</div>
<div style="font-size:11px;color:var(--mw-t4);margin-top:2px">Bitte das Log unten prüfen. Der Mailserver bleibt weiterhin in Betrieb.</div>
</div>
</div>
@elseif($rc !== null && $rc !== 0)
<div style="display:flex;align-items:flex-start;gap:10px;padding:12px 14px;background:rgba(239,68,68,.07);border:1px solid rgba(239,68,68,.25);border-radius:8px">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" style="flex-shrink:0;margin-top:1px;color:#f87171"><path d="M7 1L13 12H1L7 1Z" stroke="currentColor" stroke-width="1.3" stroke-linejoin="round"/><path d="M7 5.5v3" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/><circle cx="7" cy="10" r=".7" fill="currentColor"/></svg>
<div>
<div style="font-size:12.5px;font-weight:600;color:#f87171">Fehlgeschlagen (rc={{ $rc }})</div>
<div style="font-size:11.5px;color:var(--mw-t4);margin-top:3px">Bitte das Log prüfen.</div>
</div>
</div>
@elseif($rc === 0)
<div style="display:flex;align-items:center;gap:10px;padding:12px 14px;background:rgba(34,197,94,.06);border:1px solid rgba(34,197,94,.2);border-radius:8px">
<svg width="14" height="14" viewBox="0 0 12 12" fill="none" style="color:#22c55e;flex-shrink:0"><path d="M2 6.5l2.5 2.5 5.5-5.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span style="font-size:12.5px;color:rgba(34,197,94,.9)">Update erfolgreich abgeschlossen.</span>
</div>
@else
<div style="font-size:12.5px;color:var(--mw-t4)">Kein Update aktiv. Klicke "Auf Updates prüfen" um die neueste Version zu ermitteln.</div>
@endif
@if($state === 'running' || $progressPct > 0)
<div>
<div style="display:flex;justify-content:space-between;margin-bottom:5px">
<span style="font-size:11px;color:var(--mw-t4)">Fortschritt</span>
<span style="font-size:11px;color:var(--mw-t4);font-family:monospace">{{ $progressPct }}%</span>
</div>
<div style="height:6px;background:var(--mw-bg4);border-radius:4px;overflow:hidden;border:1px solid var(--mw-b2)">
<div style="height:100%;width:{{ $progressPct }}%;transition:width .6s ease;background:{{ $rc !== null && $rc !== 0 ? 'rgba(239,68,68,.7)' : ($progressPct >= 100 ? 'rgba(34,197,94,.8)' : 'rgba(14,165,233,.8)') }};border-radius:4px"></div>
</div>
@elseif($rc === 0)
<div style="display:flex;align-items:center;gap:9px;padding:10px 13px;background:rgba(34,197,94,.06);border:1px solid rgba(34,197,94,.18);border-radius:7px">
<svg width="13" height="13" viewBox="0 0 12 12" fill="none" style="color:#22c55e;flex-shrink:0"><path d="M2 6.5l2.5 2.5 5.5-5.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span style="font-size:12px;color:rgba(34,197,94,.9)">Update erfolgreich abgeschlossen.</span>
</div>
@endif
</div>
@elseif($hasUpdate)
<div style="display:flex;align-items:center;gap:9px;padding:10px 13px;background:rgba(234,179,8,.06);border:1px solid rgba(234,179,8,.2);border-radius:7px">
<svg width="13" height="13" viewBox="0 0 14 14" fill="none" style="color:#fbbf24;flex-shrink:0"><path d="M7 2v7M4 6l3 3 3-3" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span style="font-size:12px;color:rgba(234,179,8,.9)">Eine neue Version ist verfügbar. Klicke auf "{{ $displayLatest }} installieren".</span>
</div>
@else
<div style="display:flex;align-items:center;gap:9px">
<svg width="13" height="13" viewBox="0 0 12 12" fill="none" style="color:rgba(34,197,94,.7);flex-shrink:0"><path d="M2 6.5l2.5 2.5 5.5-5.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span style="font-size:12px;color:var(--mw-t4)">Du bist auf dem neuesten Stand.</span>
</div>
@endif
</div>
</div>
{{-- ═══ Log Viewer ═══ --}}
{{-- ═══ Log-Viewer ═══ --}}
<div class="mbx-section"
x-data="{
autoScroll: true,
init() {
this.$watch('$wire.logLines', () => {
if (this.autoScroll && this.$refs.logBox) {
this.$nextTick(() => {
this.$refs.logBox.scrollTop = this.$refs.logBox.scrollHeight;
});
this.$nextTick(() => { this.$refs.logBox.scrollTop = this.$refs.logBox.scrollHeight; });
}
});
}
@ -164,9 +154,8 @@
<span class="mbx-badge-mute">Update-Log</span>
</div>
<div style="display:flex;align-items:center;gap:8px">
<label style="display:flex;align-items:center;gap:7px;cursor:pointer;user-select:none">
<span x-on:click="autoScroll=!autoScroll"
style="position:relative;display:inline-block;width:28px;height:16px;flex-shrink:0">
<label style="display:flex;align-items:center;gap:6px;cursor:pointer;user-select:none">
<span x-on:click="autoScroll=!autoScroll" style="position:relative;display:inline-block;width:28px;height:16px;flex-shrink:0">
<span :style="autoScroll ? 'background:var(--mw-v);border-color:var(--mw-v)' : 'background:var(--mw-bg4);border-color:var(--mw-b2)'"
style="position:absolute;inset:0;border-radius:8px;border:1px solid var(--mw-b2);transition:background .2s,border-color .2s"></span>
<span :style="autoScroll ? 'left:14px' : 'left:2px'"
@ -174,11 +163,8 @@
</span>
<span style="font-size:11.5px;color:var(--mw-t4)">Auto-Scroll</span>
</label>
<button wire:click="clearLog"
wire:loading.attr="disabled"
wire:target="clearLog"
class="mbx-btn-mute"
style="font-size:11px;padding:3px 10px">
<button wire:click="clearLog" wire:loading.attr="disabled" wire:target="clearLog"
class="mbx-btn-mute" style="font-size:11px;padding:3px 10px">
<svg width="11" height="11" viewBox="0 0 14 14" fill="none"><path d="M2 4h10M5 4V2.5h4V4M11.5 4l-.5 8H3L2.5 4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
Log leeren
</button>
@ -191,17 +177,11 @@
<span style="color:var(--mw-t5);font-style:italic">Keine Log-Einträge vorhanden.</span>
@else
@foreach($logLines as $line)@php
$color = 'inherit';
if (str_contains($line, '[!]') || str_contains($line, 'error') || str_contains($line, 'Error') || str_contains($line, 'fehlgeschlagen')) {
$color = '#f87171';
} elseif (str_contains($line, '[✓]') || str_contains($line, 'beendet') || str_contains($line, 'abgeschlossen')) {
$color = 'rgba(34,197,94,.85)';
} elseif (str_contains($line, '[i]')) {
$color = 'var(--mw-t3)';
} elseif (str_contains($line, '=====')) {
$color = 'rgba(14,165,233,.8)';
}
@endphp<span style="display:block;color:{{ $color }}">{{ $line }}</span>@endforeach
$c = 'inherit';
if (str_contains($line, '[!]') || str_contains($line, 'error') || str_contains($line, 'Error') || str_contains($line, 'fehlgeschlagen')) $c = '#f87171';
elseif (str_contains($line, '[✓]') || str_contains($line, 'beendet') || str_contains($line, 'abgeschlossen')) $c = 'rgba(34,197,94,.85)';
elseif (str_contains($line, '=====')) $c = 'rgba(14,165,233,.7)';
@endphp<span style="display:block;color:{{ $c }}">{{ $line }}</span>@endforeach
@endif
</div>
<div style="margin-top:6px;font-size:11px;color:var(--mw-t5)">
@ -211,11 +191,4 @@
</div>
</div>
<style>
@media (max-width: 640px) {
.mw-update-grid { grid-template-columns: 1fr !important; }
}
</style>
</div>