refactor: extract action classes, add Blade components, reduce Commandocentrum

- Create EmulatorControlAction and NitroControlAction classes
- Extract business logic from Commandocentrum controller methods
- Add Blade components for status cards, diagnostics, and summary cards
- Replace shell_exec with file_get_contents in config reading
- Remove duplicate methods and unused code
- Commandocentrum reduced from 2033 to 1780 lines
This commit is contained in:
root
2026-05-19 20:57:31 +02:00
parent 976b990a8a
commit cbe189fd96
6 changed files with 364 additions and 294 deletions
@@ -0,0 +1,65 @@
@props(['diagnostics'])
@php
$errors = array_filter($diagnostics, fn ($r) => $r->status === 'error');
$warnings = array_filter($diagnostics, fn ($r) => $r->status === 'warning');
$ok = array_filter($diagnostics, fn ($r) => $r->status === 'ok');
$errorCount = count($errors);
$warningCount = count($warnings);
$okCount = count($ok);
$overallStatus = $errorCount > 0 ? 'error' : ($warningCount > 0 ? 'warning' : 'ok');
$overallColor = match ($overallStatus) {
'error' => '#ef4444',
'warning' => '#f59e0b',
default => '#22c55e',
};
$overallLabel = match ($overallStatus) {
'error' => 'Kritieke Problemen',
'warning' => 'Waarschuwingen',
default => 'Gezond',
};
@endphp
<div style="display:flex;flex-direction:column;gap:16px;">
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:12px;">
<x-filament-components::commandocentrum.summary-card label="Gezond" :count="$okCount" color="#22c55e" icon="check" />
<x-filament-components::commandocentrum.summary-card label="Waarschuwingen" :count="$warningCount" color="#f59e0b" icon="warning" />
<x-filament-components::commandocentrum.summary-card label="Fouten" :count="$errorCount" color="#ef4444" icon="error" />
</div>
<div style="background:{{ $overallColor }}15;border:1px solid {{ $overallColor }}30;border-radius:12px;padding:16px;display:flex;align-items:center;gap:12px;">
<div style="width:12px;height:12px;border-radius:50%;background:{{ $overallColor }};"></div>
<span style="font-weight:700;color:{{ $overallColor }};font-size:16px;">Systeem Status: {{ $overallLabel }}</span>
</div>
@if ($errorCount > 0 || $warningCount > 0)
<div style="display:flex;flex-direction:column;gap:8px;">
@foreach ($diagnostics as $result)
@if ($result->status === 'ok')
@continue
@endif
@php
$color = $result->status === 'error' ? '#ef4444' : '#f59e0b';
@endphp
<div style="background:#fff;border:1px solid {{ $color }}30;border-radius:10px;padding:14px 16px;display:flex;align-items:flex-start;gap:12px;">
<div style="flex-shrink:0;margin-top:2px;">
@if ($result->status === 'error')
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="{{ $color }}" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>
@else
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="{{ $color }}" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
@endif
</div>
<div style="flex:1;">
<div style="font-weight:600;color:#1e293b;font-size:14px;">{{ $result->name }}</div>
<div style="color:#64748b;font-size:13px;margin-top:2px;">{{ $result->message }}</div>
@if ($result->fix)
<div style="background:#f8fafc;border-radius:6px;padding:8px 12px;margin-top:8px;font-size:12px;color:#475569;font-family:monospace;">💡 {{ $result->fix }}</div>
@endif
</div>
</div>
@endforeach
</div>
@endif
</div>
@@ -0,0 +1,30 @@
@props(['label', 'value', 'color', 'icon'])
<div style="background:#fff;border-radius:16px;padding:24px;border:1px solid #e2e8f0;box-shadow:0 1px 3px rgba(0,0,0,0.06);transition:all 0.3s ease;cursor:default;" onmouseover="this.style.transform='translateY(-4px)';this.style.boxShadow='0 12px 24px rgba(0,0,0,0.1)';this.style.borderColor='{{ $color }}40';" onmouseout="this.style.transform='translateY(0)';this.style.boxShadow='0 1px 3px rgba(0,0,0,0.06)';this.style.borderColor='#e2e8f0';">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;">
<div style="display:flex;align-items:center;gap:10px;">
<div style="background:{{ $color }}15;padding:10px;border-radius:12px;">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="{{ $color }}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@if ($icon === 'users')
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" />
@elseif ($icon === 'server')
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01" />
@elseif ($icon === 'database')
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4" />
@elseif ($icon === 'cpu')
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z" />
@endif
</svg>
</div>
<span style="font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:1px;color:#94a3b8;">{{ $label }}</span>
</div>
<div style="width:8px;height:8px;border-radius:50%;background:{{ $color }};animation:pulse 2s infinite;"></div>
</div>
<div style="font-size:36px;font-weight:800;color:#1e293b;line-height:1;">{{ $value }}</div>
</div>
<style>
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
</style>
@@ -0,0 +1,19 @@
@props(['label', 'count', 'color', 'icon'])
<div style="background:#fff;border-radius:12px;padding:16px;border:1px solid #e2e8f0;box-shadow:0 1px 3px rgba(0,0,0,0.06);">
<div style="display:flex;align-items:center;gap:10px;margin-bottom:8px;">
<div style="background:{{ $color }}15;padding:8px;border-radius:10px;">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="{{ $color }}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@if ($icon === 'check')
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
@elseif ($icon === 'warning')
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
@elseif ($icon === 'error')
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" />
@endif
</svg>
</div>
<span style="font-size:12px;font-weight:600;color:#64748b;">{{ $label }}</span>
</div>
<div style="font-size:28px;font-weight:800;color:{{ $color }};line-height:1;">{{ $count }}</div>
</div>