{{-- Die Liste holt sich ihren Stand selbst. Sie tat es nicht, und das fiel an zwei Stellen auf: Zustand, VPN und Belegung standen so lange still, bis jemand neu lud — und ein entfernter Host blieb sichtbar, obwohl er schon weg war. Beides sah aus, als sei nichts passiert. Schneller, solange etwas in Arbeit ist: `ConfirmRemoveHost` setzt den Host auf `disabled` und wirft `PurgeHost` in die Warteschlange, die erst auf die Runner-Sperre wartet. In dieser Zeit steht die Zeile noch da, und ohne kurzes Nachfassen bliebe sie es gefühlt für immer. Läuft nichts, reicht die Minute — die Seite soll nicht dauernd Abfragen erzeugen, nur weil sie offen ist. --}}

{{ __('hosts.title') }}

{{ __('hosts.subtitle') }}

{{ __('hosts.add') }}
{{-- Die Anleitung gehört hierher, nicht nur auf die Anlegen-Seite: ihre ersten zwei Schritte passieren beim Anbieter, und wer erst auf „Host hinzufügen" klickt, hat den Server womöglich noch gar nicht bestellt. Zusammengeklappt, damit sie die Liste nicht verdrängt — aber auffindbar, ohne dass man vorher etwas anlegen muss. --}}
{{ __('hosts.takeover.how_title') }}
{{-- Filter bar — scales to many hosts (search + datacenter + status). --}}
@if ($search !== '' || $datacenter !== '' || $status !== '') @endif {{ __('hosts.count', ['shown' => $hosts->count(), 'total' => $total]) }}
@if ($hosts->isEmpty())

{{ $total === 0 ? __('hosts.empty') : __('hosts.no_matches') }}

@else
{{-- Leer mit Absicht: die Spalte trägt nur den Terminal-Knopf, und der ist nicht auf jeder Zeile da (Berechtigung, Betriebsbereitschaft). Eine Beschriftung, die unabhängig davon immer dastünde, wäre eine falsche Zusage. --}} @foreach ($hosts as $host) @php $badge = ['pending' => 'pending', 'onboarding' => 'provisioning', 'active' => 'active', 'error' => 'failed', 'disabled' => 'suspended'][$host->status] ?? 'info'; $health = $host->healthState(); $hdot = ['online' => 'bg-success-bright', 'stale' => 'bg-warning', 'offline' => 'bg-danger'][$health]; $usedPct = $host->usedPct(); $vpnPeer = $host->vpnPeer; $vpnState = $host->vpnState($vpnPeer); $vpnIcon = ['not_configured' => 'unlock', 'connected' => 'lock', 'silent' => 'alert-triangle', 'unknown' => 'life-buoy'][$vpnState]; $vpnTone = ['not_configured' => 'text-muted', 'connected' => 'text-success', 'silent' => 'text-warning', 'unknown' => 'text-muted'][$vpnState]; @endphp @endforeach
{{ __('hosts.col.host') }} {{ __('hosts.col.datacenter') }} {{ __('hosts.col.health') }} {{ __('hosts.col.vpn') }} {{ __('hosts.col.instances') }} {{ __('hosts.col.capacity') }} {{ __('hosts.col.status') }}
{{ $host->name }} {{ $host->public_ip }} {{ $host->datacenter }} {{ __('hosts.health.'.$health) }} @if ($vpnState === 'silent' && $vpnPeer?->last_handshake_at) {{ __('hosts.vpn.silent_since', ['time' => $vpnPeer->last_handshake_at->diffForHumans()]) }} @else {{ __('hosts.vpn.'.$vpnState) }} @endif {{ $host->instances_count }} @if ($host->total_gb)
{{ $host->availableGb() }} / {{ $host->freeGb() }} GB
@else {{ __('hosts.unknown') }} @endif {{-- Steht getrennt da, statt in der Zahl darüber zu verschwinden: diese Maschine zählt nicht zum allgemeinen Bestand (Host::placeableIn()). --}} @if ($host->reserved_for_customer_id) {{ __('hosts.reserved_badge', ['name' => $host->reservedFor?->name ?? __('hosts.unknown')]) }} @endif
{{ __('hosts.status.'.$host->status) }} {{-- Ohne Tunneladresse oder Fingerabdruck kann keine Sitzung entstehen — TerminalTicket::issue() weist das mit einer RuntimeException zurück (Aufgabe 1). Ein Knopf, der das verlässlich auslöst, ist schlechter als gar keiner. --}} @can('hosts.manage') @if ($host->wg_ip && $host->ssh_host_key) {{-- href direkt am Knopf, nicht als drumherum: interaktiver Inhalt in einem Link ist ungültiges HTML, und Mittelklick/ Statuszeile hingen sonst an einem Element, auf dem der Zeiger nie landet (components/ui/button.blade.php Zeile 6-9). --}} {{ __('hosts.terminal.open') }} @endif @endcan
@endif