Files
Network-MGMT/resources/views/network/dashboard.blade.php
T

243 lines
16 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<x-app-layout>
<x-slot name="header">
<div class="flex items-center justify-between">
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200">Netzwerk-Dashboard</h2>
<div class="flex gap-2">
<a href="{{ route('network.segments.create') }}"
class="px-4 py-2 text-sm font-medium rounded-md border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 transition">
+ Segment anlegen
</a>
<a href="{{ route('network.import') }}" style="background-color: var(--color-primary)"
class="px-4 py-2 text-white text-sm font-medium rounded-md hover:opacity-90 transition">
+ Scan importieren
</a>
</div>
</div>
</x-slot>
<div class="py-8">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
{{-- KPI-Karten --}}
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm p-4">
<p class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider">Segmente</p>
<p class="mt-1 text-2xl font-bold text-gray-900 dark:text-gray-100">{{ $segments->count() }}</p>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm p-4">
<p class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider">Geräte gesamt</p>
<p class="mt-1 text-2xl font-bold text-gray-900 dark:text-gray-100">{{ $totalDevices }}</p>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm p-4">
<p class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider">Aktuell online</p>
<p class="mt-1 text-2xl font-bold text-green-600 dark:text-green-400">{{ $onlineDevices }}</p>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm p-4">
<p class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider">Offene Ereignisse</p>
<p class="mt-1 text-2xl font-bold text-yellow-600 dark:text-yellow-400">
{{ $recentEvents->count() + $ipChangeEvents->count() }}
</p>
</div>
</div>
{{-- ⚠️ IP-Wechsel prominenter Warnblock --}}
@if($ipChangeEvents->count() > 0)
<div class="bg-amber-50 dark:bg-amber-900/20 border border-amber-300 dark:border-amber-700 rounded-lg overflow-hidden">
<div class="px-5 py-3 border-b border-amber-200 dark:border-amber-700 flex items-center justify-between">
<h3 class="font-semibold text-amber-800 dark:text-amber-300 flex items-center gap-2">
⚠️ IP-Adressen-Wechsel erkannt
<span class="bg-amber-200 dark:bg-amber-800 text-amber-900 dark:text-amber-200 text-xs px-2 py-0.5 rounded-full font-bold">
{{ $ipChangeEvents->count() }}
</span>
</h3>
<span class="text-xs text-amber-600 dark:text-amber-400">Bitte prüfen und quittieren</span>
</div>
<div class="divide-y divide-amber-100 dark:divide-amber-800">
@foreach($ipChangeEvents as $event)
<div class="px-5 py-4">
<div class="flex flex-wrap items-center justify-between gap-3">
{{-- Gerät und IP-Wechsel --}}
<div class="flex-1 min-w-0">
<div class="flex items-center flex-wrap gap-2 mb-1">
<a href="{{ route('network.device', $event->device) }}"
class="font-semibold text-gray-900 dark:text-gray-100 hover:text-indigo-600">
{{ $event->device->display_name }}
</a>
@if($event->device->mac_address)
<span class="font-mono text-xs text-gray-400 bg-gray-100 dark:bg-gray-700 px-1 py-0.5 rounded">
{{ $event->device->mac_address }}
</span>
@endif
</div>
<div class="flex items-center gap-3">
<span class="font-mono text-sm font-bold text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900/30 px-2 py-0.5 rounded">
{{ $event->old_value }}
</span>
<span class="text-gray-400"></span>
<span class="font-mono text-sm font-bold text-green-700 dark:text-green-400 bg-green-50 dark:bg-green-900/30 px-2 py-0.5 rounded">
{{ $event->new_value }}
</span>
<span class="text-xs text-gray-400">{{ $event->created_at->format('d.m.Y H:i') }}</span>
</div>
</div>
{{-- Bestätigen mit Notiz --}}
<form method="POST" action="{{ route('network.document', $event) }}"
class="flex gap-2 items-center shrink-0">
@csrf
<input type="text" name="description"
placeholder="Notiz zur Änderung (optional)"
class="text-xs border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded px-2 py-1.5 w-56 focus:ring-indigo-500 focus:border-indigo-500" />
<button type="submit"
class="shrink-0 text-xs px-3 py-1.5 rounded bg-green-600 text-white hover:bg-green-700 transition font-medium">
Quittieren
</button>
</form>
</div>
{{-- IP-Verlauf (sofern vorhanden) --}}
@php
$ipCount = $event->device->hosts()
->selectRaw('DISTINCT ip_address')
->count();
@endphp
@if($ipCount > 1)
<div class="mt-2 text-xs text-amber-600 dark:text-amber-400">
📋 Dieses Gerät hatte {{ $ipCount }} verschiedene IP-Adressen
<a href="{{ route('network.device', $event->device) }}" class="underline hover:no-underline">IP-Verlauf anzeigen </a>
</div>
@endif
</div>
@endforeach
</div>
</div>
@endif
{{-- Globale Suche --}}
<div class="bg-white dark:bg-gray-800 shadow-sm rounded-lg p-5">
<form method="GET" action="{{ route('network.search') }}" class="flex gap-3">
<input type="text" name="q" placeholder="IP-Adresse, MAC, Hostname, Bezeichnung über alle Segmente suchen..."
class="flex-1 border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md shadow-sm text-sm focus:ring-indigo-500 focus:border-indigo-500" />
<button type="submit" style="background-color: var(--color-primary)"
class="px-5 py-2 text-white text-sm font-medium rounded-md hover:opacity-90 transition whitespace-nowrap">
🔍 Suchen
</button>
</form>
</div>
{{-- Segmente --}}
<div class="bg-white dark:bg-gray-800 shadow-sm rounded-lg overflow-hidden">
<div class="px-5 py-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between">
<h3 class="font-semibold text-gray-900 dark:text-gray-100">Netzwerk-Segmente</h3>
<a href="{{ route('network.segments.index') }}" class="text-xs text-indigo-600 hover:underline">Alle verwalten </a>
</div>
@if($segments->isEmpty())
<div class="px-5 py-10 text-center">
<p class="text-gray-500 dark:text-gray-400 mb-3">Noch keine Segmente definiert.</p>
<a href="{{ route('network.segments.create') }}" style="background-color: var(--color-primary)"
class="inline-block px-4 py-2 text-white text-sm font-medium rounded-md hover:opacity-90 transition">
Erstes Segment anlegen
</a>
</div>
@else
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700 text-sm">
<thead class="bg-gray-50 dark:bg-gray-700">
<tr>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Status</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Name</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Subnetz</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">VLAN</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Letzter Scan</th>
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Online / Gesamt</th>
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Scans</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
@foreach($segments as $segment)
@php $lastScan = $latestScans->get($segment->id)?->first(); @endphp
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700 transition">
<td class="px-4 py-3">
<span class="inline-block w-2 h-2 rounded-full {{ $segment->active ? 'bg-green-500' : 'bg-gray-300' }}"></span>
</td>
<td class="px-4 py-3 font-medium text-gray-900 dark:text-gray-100">
<a href="{{ route('network.segments.show', $segment) }}" class="hover:text-indigo-600">
{{ $segment->name }}
</a>
</td>
<td class="px-4 py-3 font-mono text-xs text-gray-600 dark:text-gray-400">{{ $segment->subnet }}</td>
<td class="px-4 py-3 text-xs text-gray-500 dark:text-gray-400">
{{ $segment->vlan_id ? 'VLAN ' . $segment->vlan_id : '—' }}
</td>
<td class="px-4 py-3 text-xs text-gray-500 dark:text-gray-400">
{{ $lastScan?->created_at->format('d.m.Y H:i') ?? '—' }}
</td>
<td class="px-4 py-3 text-right text-xs">
@if($lastScan)
<span class="text-green-600 font-medium">{{ $lastScan->online_hosts }}</span>
<span class="text-gray-400"> / {{ $lastScan->total_hosts }}</span>
@else
<span class="text-gray-400"></span>
@endif
</td>
<td class="px-4 py-3 text-right text-xs text-gray-500 dark:text-gray-400">
{{ $segment->scans_count }}
</td>
</tr>
@endforeach
</tbody>
</table>
@endif
</div>
{{-- Sonstige undokumentierte Ereignisse --}}
@if($recentEvents->count() > 0)
<div class="bg-white dark:bg-gray-800 shadow-sm rounded-lg overflow-hidden">
<div class="px-5 py-4 border-b border-gray-200 dark:border-gray-700">
<h3 class="font-semibold text-gray-900 dark:text-gray-100">
Undokumentierte Ereignisse
<span class="ml-2 bg-yellow-100 text-yellow-800 text-xs px-2 py-0.5 rounded-full">{{ $recentEvents->count() }}</span>
</h3>
</div>
<div class="divide-y divide-gray-100 dark:divide-gray-700">
@foreach($recentEvents as $event)
<div class="flex items-center justify-between px-5 py-3 gap-4">
<div class="flex items-center space-x-3 flex-1 min-w-0">
<span class="w-2 h-2 rounded-full flex-shrink-0
{{ $event->event_color === 'green' ? 'bg-green-500' :
($event->event_color === 'blue' ? 'bg-blue-500' :
($event->event_color === 'red' ? 'bg-red-500' : 'bg-yellow-500')) }}">
</span>
<div class="min-w-0">
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">{{ $event->event_label }}</span>
<span class="text-xs text-gray-400 ml-2">
<a href="{{ route('network.device', $event->device) }}" class="hover:text-indigo-600">
{{ $event->device->display_name }}
</a>
· {{ $event->created_at->format('d.m.Y H:i') }}
</span>
@if($event->old_value && $event->new_value)
<span class="ml-2 text-xs text-gray-400">
<span class="font-mono">{{ $event->old_value }}</span> <span class="font-mono">{{ $event->new_value }}</span>
</span>
@endif
</div>
</div>
<form method="POST" action="{{ route('network.document', $event) }}"
class="flex gap-2 items-center shrink-0">
@csrf
<input type="text" name="description" placeholder="Notiz..."
class="text-xs border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded px-2 py-1 w-40 focus:ring-indigo-500 focus:border-indigo-500" />
<button type="submit"
class="text-xs px-3 py-1 rounded border border-green-300 text-green-700 hover:bg-green-50 dark:hover:bg-green-900/20 transition whitespace-nowrap">
Quittieren
</button>
</form>
</div>
@endforeach
</div>
</div>
@endif
</div>
</div>
</x-app-layout>