Files
ladill-servers/resources/views/hosting/server-panel/show.blade.php
T
isaaccladandCursor b6c8ac343f Extract Ladill Servers as standalone app at servers.ladill.com.
VPS and dedicated server ordering, managed panels, SSO, billing, and launcher integration — forked from hosting infrastructure with server-focused routes and dashboard.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-06 19:18:30 +00:00

499 lines
36 KiB
PHP

<x-user-layout>
<x-slot name="title">{{ $order->domain_name }} - Ladill Server Manager</x-slot>
@php
$powerStatus = strtolower((string) ($panelState['power_status'] ?? 'unknown'));
$instanceStatus = strtolower((string) ($panelState['instance_status'] ?? 'unknown'));
$badgeClasses = [
'on' => 'bg-emerald-50 text-emerald-700 border-emerald-200',
'off' => 'bg-gray-100 text-gray-600 border-gray-200',
'running' => 'bg-emerald-50 text-emerald-700 border-emerald-200',
'stopped' => 'bg-gray-100 text-gray-600 border-gray-200',
'provisioning' => 'bg-blue-50 text-blue-700 border-blue-200',
'unknown' => 'bg-amber-50 text-amber-700 border-amber-200',
'online' => 'bg-emerald-50 text-emerald-700 border-emerald-200',
'offline' => 'bg-gray-100 text-gray-600 border-gray-200',
'pending_registration' => 'bg-amber-50 text-amber-700 border-amber-200',
'queued' => 'bg-slate-100 text-slate-700 border-slate-200',
'dispatched' => 'bg-blue-50 text-blue-700 border-blue-200',
'completed' => 'bg-emerald-50 text-emerald-700 border-emerald-200',
'failed' => 'bg-rose-50 text-rose-700 border-rose-200',
];
$panelRuntime = $panelRuntime ?? [];
$agentStatus = strtolower((string) ($serverAgent?->status ?? 'pending_registration'));
$managedTasksEnabled = (bool) ($panelRuntime['managed_stack_candidate'] ?? false);
$taskTypeLabels = [
'domain.add' => 'Add Domain',
'site.delete' => 'Remove Site',
'ssl.request' => 'Request SSL',
'database.create' => 'Create Database',
'php.configure' => 'Configure PHP',
'cron.list' => 'List Cron Jobs',
'cron.upsert' => 'Save Cron Job',
'cron.remove' => 'Remove Cron Job',
'log.read' => 'Read Logs',
'file.list' => 'List Files',
'file.read' => 'Read File',
'file.write' => 'Write File',
];
$cronEntries = (array) data_get($order->meta, 'server_panel.managed_cron_entries', []);
$logSnapshots = collect((array) data_get($order->meta, 'server_panel.log_snapshots', []))
->sortByDesc('read_at')
->values();
@endphp
<div class="space-y-6">
<div class="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
<div>
<a href="{{ route('servers.orders.show', $order) }}" class="mb-2 inline-flex items-center gap-1 text-sm text-gray-500 hover:text-gray-700">
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5"/></svg>
Back to server details
</a>
<h1 class="text-2xl font-semibold tracking-tight text-gray-900">Ladill Server Manager</h1>
<p class="mt-1 text-sm text-gray-500">{{ $order->domain_name }} · {{ $order->product?->name ?? 'Server' }}</p>
</div>
<div class="flex gap-2">
<form method="POST" action="{{ route('hosting.server-panel.sync', $order) }}">
@csrf
<button type="submit" class="rounded-lg border border-gray-200 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50">
Refresh Status
</button>
</form>
</div>
</div>
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
<div class="rounded-xl border border-gray-200 bg-white p-5">
<p class="text-xs font-medium text-gray-500">Power</p>
<span class="mt-2 inline-flex items-center rounded-lg border px-3 py-1.5 text-sm font-medium {{ $badgeClasses[$powerStatus] ?? $badgeClasses['unknown'] }}">
{{ strtoupper($powerStatus) }}
</span>
</div>
<div class="rounded-xl border border-gray-200 bg-white p-5">
<p class="text-xs font-medium text-gray-500">Instance Status</p>
<span class="mt-2 inline-flex items-center rounded-lg border px-3 py-1.5 text-sm font-medium {{ $badgeClasses[$instanceStatus] ?? $badgeClasses['unknown'] }}">
{{ strtoupper($instanceStatus) }}
</span>
</div>
<div class="rounded-xl border border-gray-200 bg-white p-5">
<p class="text-xs font-medium text-gray-500">IPv4 Address</p>
<p class="mt-2 font-mono text-sm font-semibold text-gray-900">{{ $order->server_ip ?: '-' }}</p>
</div>
<div class="rounded-xl border border-gray-200 bg-white p-5">
<p class="text-xs font-medium text-gray-500">Last Sync</p>
<p class="mt-2 text-sm font-semibold text-gray-900">
{{ data_get($panelState, 'last_synced_at') ? \Illuminate\Support\Carbon::parse(data_get($panelState, 'last_synced_at'))->format('M d, Y H:i') : 'Not synced yet' }}
</p>
</div>
</div>
<div class="grid gap-6 lg:grid-cols-3">
<div class="space-y-6 lg:col-span-2">
@if ($panelRuntime !== [])
<div class="rounded-xl border border-gray-200 bg-white">
<div class="border-b border-gray-100 px-5 py-4">
<h2 class="text-sm font-semibold text-gray-900">Panel Mode</h2>
</div>
<div class="space-y-3 px-5 py-4">
<div>
<p class="text-sm font-medium text-gray-900">{{ $panelRuntime['label'] ?? 'Server Manager' }}</p>
<p class="mt-1 text-sm text-gray-600">{{ $panelRuntime['primary_message'] ?? '' }}</p>
@if (!empty($panelRuntime['secondary_message']))
<p class="mt-1 text-xs text-gray-500">{{ $panelRuntime['secondary_message'] }}</p>
@endif
</div>
@if (!empty($panelRuntime['future_capabilities']))
<div class="rounded-lg bg-amber-50 px-3 py-2 text-xs text-amber-900">
Managed features: {{ implode(', ', (array) $panelRuntime['future_capabilities']) }}
</div>
@endif
</div>
</div>
@endif
<div class="rounded-xl border border-gray-200 bg-white">
<div class="border-b border-gray-100 px-5 py-4">
<h2 class="text-sm font-semibold text-gray-900">Server Controls</h2>
</div>
<div class="grid gap-3 p-5 sm:grid-cols-3">
<form method="POST" action="{{ route('hosting.server-panel.power', [$order, 'start']) }}">
@csrf
<button type="submit" class="w-full rounded-lg bg-emerald-600 px-4 py-2.5 text-sm font-medium text-white hover:bg-emerald-700">
Start Server
</button>
</form>
<form method="POST" action="{{ route('hosting.server-panel.power', [$order, 'reboot']) }}">
@csrf
<button type="submit" class="w-full rounded-lg bg-blue-600 px-4 py-2.5 text-sm font-medium text-white hover:bg-blue-700">
Reboot Server
</button>
</form>
<form method="POST" action="{{ route('hosting.server-panel.power', [$order, 'stop']) }}">
@csrf
<button type="submit" class="w-full rounded-lg bg-gray-900 px-4 py-2.5 text-sm font-medium text-white hover:bg-gray-800">
Stop Server
</button>
</form>
</div>
</div>
<div class="rounded-xl border border-gray-200 bg-white">
<div class="border-b border-gray-100 px-5 py-4">
<h2 class="text-sm font-semibold text-gray-900">Selected Configuration</h2>
</div>
<div class="divide-y divide-gray-100">
@foreach ($selectionSummary as $item)
<div class="flex items-start justify-between gap-4 px-5 py-3">
<div>
<p class="text-sm text-gray-500">{{ $item['label'] ?? 'Option' }}</p>
@if (!empty($item['description']))
<p class="mt-1 text-xs text-gray-400">{{ $item['description'] }}</p>
@endif
</div>
<p class="text-right text-sm font-medium text-gray-900">{{ $item['value'] ?? '-' }}</p>
</div>
@endforeach
</div>
</div>
@if ($managedTasksEnabled)
<div class="rounded-xl border border-gray-200 bg-white">
<div class="border-b border-gray-100 px-5 py-4">
<h2 class="text-sm font-semibold text-gray-900">Managed Tasks</h2>
</div>
<div class="space-y-6 p-5">
<div class="grid gap-6 md:grid-cols-2">
<form method="POST" action="{{ route('hosting.server-panel.tasks.domain', $order) }}" class="space-y-3 rounded-lg border border-gray-200 p-4">
@csrf
<div>
<p class="text-sm font-medium text-gray-900">Queue Domain Link</p>
<p class="mt-1 text-xs text-gray-500">Create or update a site/vhost on the managed server stack.</p>
</div>
<input type="text" name="domain" placeholder="example.com" class="w-full rounded-lg border-gray-200 text-sm" required>
<input type="text" name="document_root" placeholder="/var/www/example.com/public" class="w-full rounded-lg border-gray-200 text-sm">
<select name="php_version" class="w-full rounded-lg border-gray-200 text-sm">
<option value="">Default PHP Version</option>
<option value="8.0">PHP 8.0</option>
<option value="8.1">PHP 8.1</option>
<option value="8.2">PHP 8.2</option>
<option value="8.3">PHP 8.3</option>
<option value="8.4">PHP 8.4</option>
</select>
<button type="submit" class="rounded-lg bg-gray-900 px-4 py-2 text-sm font-medium text-white hover:bg-gray-800">Queue Domain Task</button>
</form>
<form method="POST" action="{{ route('hosting.server-panel.tasks.database', $order) }}" class="space-y-3 rounded-lg border border-gray-200 p-4">
@csrf
<div>
<p class="text-sm font-medium text-gray-900">Queue Database Create</p>
<p class="mt-1 text-xs text-gray-500">The server agent will provision the database on the managed stack.</p>
</div>
<input type="text" name="name" placeholder="app_db" class="w-full rounded-lg border-gray-200 text-sm" required>
<button type="submit" class="rounded-lg bg-gray-900 px-4 py-2 text-sm font-medium text-white hover:bg-gray-800">Queue Database Task</button>
</form>
<form method="POST" action="{{ route('hosting.server-panel.tasks.ssl', $order) }}" class="space-y-3 rounded-lg border border-gray-200 p-4">
@csrf
<div>
<p class="text-sm font-medium text-gray-900">Queue SSL Request</p>
<p class="mt-1 text-xs text-gray-500">Issue or renew a certificate for a managed server domain.</p>
</div>
<input type="text" name="domain" placeholder="example.com" class="w-full rounded-lg border-gray-200 text-sm" required>
<button type="submit" class="rounded-lg bg-gray-900 px-4 py-2 text-sm font-medium text-white hover:bg-gray-800">Queue SSL Task</button>
</form>
<form method="POST" action="{{ route('hosting.server-panel.tasks.file', $order) }}" class="space-y-3 rounded-lg border border-gray-200 p-4">
@csrf
<div>
<p class="text-sm font-medium text-gray-900">Queue File Task</p>
<p class="mt-1 text-xs text-gray-500">Use this for file listing, reads, or writes through the server agent.</p>
</div>
<select name="operation" class="w-full rounded-lg border-gray-200 text-sm">
<option value="list">List Path</option>
<option value="read">Read File</option>
<option value="write">Write File</option>
</select>
<input type="text" name="path" placeholder="/var/www/example.com/public/index.php" class="w-full rounded-lg border-gray-200 text-sm" required>
<textarea name="content" rows="4" placeholder="Optional file contents for write operations" class="w-full rounded-lg border-gray-200 text-sm"></textarea>
<button type="submit" class="rounded-lg bg-gray-900 px-4 py-2 text-sm font-medium text-white hover:bg-gray-800">Queue File Task</button>
</form>
<form method="POST" action="{{ route('hosting.server-panel.tasks.php', $order) }}" class="space-y-3 rounded-lg border border-gray-200 p-4">
@csrf
<div>
<p class="text-sm font-medium text-gray-900">Queue PHP Version Change</p>
<p class="mt-1 text-xs text-gray-500">Switch the nginx vhost for a known site to a different PHP-FPM version.</p>
</div>
<input type="text" name="domain" placeholder="example.com" class="w-full rounded-lg border-gray-200 text-sm" required>
<select name="php_version" class="w-full rounded-lg border-gray-200 text-sm">
<option value="8.0">PHP 8.0</option>
<option value="8.1">PHP 8.1</option>
<option value="8.2">PHP 8.2</option>
<option value="8.3">PHP 8.3</option>
<option value="8.4">PHP 8.4</option>
</select>
<button type="submit" class="rounded-lg bg-gray-900 px-4 py-2 text-sm font-medium text-white hover:bg-gray-800">Queue PHP Task</button>
</form>
<form method="POST" action="{{ route('hosting.server-panel.tasks.site-delete', $order) }}" class="space-y-3 rounded-lg border border-rose-200 p-4">
@csrf
<div>
<p class="text-sm font-medium text-gray-900">Queue Site Removal</p>
<p class="mt-1 text-xs text-gray-500">Remove the nginx site configuration for a managed domain. Website files are left on disk.</p>
</div>
<input type="text" name="domain" placeholder="example.com" class="w-full rounded-lg border-gray-200 text-sm" required>
<button type="submit" class="rounded-lg bg-rose-600 px-4 py-2 text-sm font-medium text-white hover:bg-rose-700">Queue Removal Task</button>
</form>
<form method="POST" action="{{ route('hosting.server-panel.tasks.cron', $order) }}" class="space-y-3 rounded-lg border border-gray-200 p-4">
@csrf
<div>
<p class="text-sm font-medium text-gray-900">Queue Cron Task</p>
<p class="mt-1 text-xs text-gray-500">Manage the Ladill-owned cron file on this server. Use a standard 5-field cron expression.</p>
</div>
<select name="operation" class="w-full rounded-lg border-gray-200 text-sm">
<option value="list">List Cron Jobs</option>
<option value="upsert">Create or Update Job</option>
<option value="remove">Remove Job</option>
</select>
<input type="text" name="name" placeholder="nightly-backup" class="w-full rounded-lg border-gray-200 text-sm">
<input type="text" name="expression" placeholder="0 2 * * *" class="w-full rounded-lg border-gray-200 text-sm">
<input type="text" name="command" placeholder="cd /var/www/example.com && php artisan schedule:run" class="w-full rounded-lg border-gray-200 text-sm">
<select name="user" class="w-full rounded-lg border-gray-200 text-sm">
<option value="web">Run as web user</option>
<option value="root">Run as root</option>
</select>
<button type="submit" class="rounded-lg bg-gray-900 px-4 py-2 text-sm font-medium text-white hover:bg-gray-800">Queue Cron Task</button>
</form>
<form method="POST" action="{{ route('hosting.server-panel.tasks.log', $order) }}" class="space-y-3 rounded-lg border border-gray-200 p-4">
@csrf
<div>
<p class="text-sm font-medium text-gray-900">Queue Log Read</p>
<p class="mt-1 text-xs text-gray-500">Tail domain-specific nginx logs or service journals directly from the managed server.</p>
</div>
<select name="target" class="w-full rounded-lg border-gray-200 text-sm">
<option value="nginx_access">Nginx Access Log</option>
<option value="nginx_error">Nginx Error Log</option>
<option value="php_fpm">PHP-FPM Journal</option>
<option value="mariadb">MariaDB Journal</option>
<option value="agent_service">Ladill Agent Journal</option>
</select>
<input type="text" name="domain" placeholder="example.com for nginx logs" class="w-full rounded-lg border-gray-200 text-sm">
<input type="number" name="lines" min="20" max="500" value="120" class="w-full rounded-lg border-gray-200 text-sm">
<button type="submit" class="rounded-lg bg-gray-900 px-4 py-2 text-sm font-medium text-white hover:bg-gray-800">Queue Log Task</button>
</form>
</div>
<div class="rounded-lg border border-gray-200">
<div class="border-b border-gray-100 px-4 py-3">
<h3 class="text-sm font-medium text-gray-900">Recent Tasks</h3>
</div>
<div class="divide-y divide-gray-100">
@forelse ($serverTasks as $task)
<div class="flex flex-col gap-3 px-4 py-3 sm:flex-row sm:items-start sm:justify-between">
<div>
<p class="text-sm font-medium text-gray-900">{{ $taskTypeLabels[$task->type] ?? $task->type }}</p>
<p class="mt-1 text-xs text-gray-500">{{ json_encode($task->payload ?? [], JSON_UNESCAPED_SLASHES) }}</p>
@if ($task->error_message)
<p class="mt-2 text-xs text-rose-600">{{ $task->error_message }}</p>
@elseif (($task->result['message'] ?? null))
<p class="mt-2 text-xs text-gray-500">{{ $task->result['message'] }}</p>
@endif
</div>
<div class="text-left sm:text-right">
<span class="inline-flex items-center rounded-lg border px-3 py-1 text-xs font-medium {{ $badgeClasses[strtolower((string) $task->status)] ?? $badgeClasses['unknown'] }}">
{{ strtoupper((string) $task->status) }}
</span>
<p class="mt-2 text-xs text-gray-500">{{ $task->updated_at?->format('M d, Y H:i') }}</p>
</div>
</div>
@empty
<div class="px-4 py-6 text-sm text-gray-500">No managed tasks queued yet.</div>
@endforelse
</div>
</div>
<div class="grid gap-4 xl:grid-cols-3">
<div class="rounded-lg border border-gray-200">
<div class="border-b border-gray-100 px-4 py-3">
<h3 class="text-sm font-medium text-gray-900">Known Sites</h3>
</div>
<div class="divide-y divide-gray-100">
@forelse ($serverSites as $site)
<div class="px-4 py-3">
<p class="text-sm font-medium text-gray-900">{{ $site->domain }}</p>
<p class="mt-1 text-xs text-gray-500">{{ $site->document_root ?: 'Document root pending' }}</p>
<p class="mt-1 text-xs text-gray-400">
PHP {{ $site->php_version ?: 'default' }} · SSL {{ strtoupper((string) ($site->ssl_status ?: 'pending')) }}
</p>
<p class="mt-1 text-xs {{ $site->status === 'removed' ? 'text-rose-500' : 'text-gray-400' }}">
{{ strtoupper((string) $site->status) }}
</p>
</div>
@empty
<div class="px-4 py-5 text-sm text-gray-500">No managed sites recorded yet.</div>
@endforelse
</div>
</div>
<div class="rounded-lg border border-gray-200">
<div class="border-b border-gray-100 px-4 py-3">
<h3 class="text-sm font-medium text-gray-900">Known Databases</h3>
</div>
<div class="divide-y divide-gray-100">
@forelse ($serverDatabases as $database)
<div class="px-4 py-3">
<p class="text-sm font-medium text-gray-900">{{ $database->name }}</p>
<p class="mt-1 text-xs text-gray-500">{{ $database->username ?: 'Username pending' }} · {{ strtoupper((string) $database->status) }}</p>
<p class="mt-1 text-xs text-gray-400">{{ strtoupper((string) $database->engine) }}</p>
</div>
@empty
<div class="px-4 py-5 text-sm text-gray-500">No managed databases recorded yet.</div>
@endforelse
</div>
</div>
<div class="rounded-lg border border-gray-200">
<div class="border-b border-gray-100 px-4 py-3">
<h3 class="text-sm font-medium text-gray-900">File Sync Records</h3>
</div>
<div class="divide-y divide-gray-100">
@forelse ($serverFiles as $file)
<div class="px-4 py-3">
<p class="truncate text-sm font-medium text-gray-900">{{ $file->path }}</p>
<p class="mt-1 text-xs text-gray-500">{{ ucfirst($file->kind) }} · {{ $file->size_bytes !== null ? number_format($file->size_bytes) . ' bytes' : 'Size pending' }}</p>
<p class="mt-1 text-xs text-gray-400">{{ $file->last_synced_at?->format('M d, Y H:i') ?: 'Not synced yet' }}</p>
</div>
@empty
<div class="px-4 py-5 text-sm text-gray-500">No managed file records yet.</div>
@endforelse
</div>
</div>
</div>
<div class="grid gap-4 xl:grid-cols-2">
<div class="rounded-lg border border-gray-200">
<div class="border-b border-gray-100 px-4 py-3">
<h3 class="text-sm font-medium text-gray-900">Managed Cron Entries</h3>
</div>
<div class="divide-y divide-gray-100">
@forelse ($cronEntries as $entry)
<div class="px-4 py-3">
<p class="text-sm font-medium text-gray-900">{{ $entry['name'] ?? 'cron-job' }}</p>
<p class="mt-1 text-xs text-gray-500">{{ $entry['schedule'] ?? '-' }} · {{ $entry['user'] ?? 'web' }}</p>
<p class="mt-1 truncate text-xs text-gray-400">{{ $entry['command'] ?? '-' }}</p>
</div>
@empty
<div class="px-4 py-5 text-sm text-gray-500">No managed cron entries synced yet.</div>
@endforelse
</div>
</div>
<div class="rounded-lg border border-gray-200">
<div class="border-b border-gray-100 px-4 py-3">
<h3 class="text-sm font-medium text-gray-900">Recent Log Snapshots</h3>
</div>
<div class="divide-y divide-gray-100">
@forelse ($logSnapshots as $snapshot)
<div class="px-4 py-3">
<p class="text-sm font-medium text-gray-900">
{{ strtoupper(str_replace('_', ' ', (string) ($snapshot['target'] ?? 'log'))) }}
@if (!empty($snapshot['domain']))
<span class="text-gray-400">· {{ $snapshot['domain'] }}</span>
@endif
</p>
<p class="mt-1 text-xs text-gray-500">{{ $snapshot['read_at'] ? \Illuminate\Support\Carbon::parse($snapshot['read_at'])->format('M d, Y H:i') : 'Pending' }}</p>
<pre class="mt-2 max-h-40 overflow-auto whitespace-pre-wrap rounded bg-gray-950 p-3 text-[11px] leading-5 text-green-300">{{ $snapshot['content_preview'] ?? 'No preview available yet.' }}</pre>
</div>
@empty
<div class="px-4 py-5 text-sm text-gray-500">No log snapshots captured yet.</div>
@endforelse
</div>
</div>
</div>
</div>
</div>
@endif
</div>
<div class="space-y-6">
@if ($managedTasksEnabled)
<div class="rounded-xl border border-gray-200 bg-white">
<div class="border-b border-gray-100 px-5 py-4">
<h2 class="text-sm font-semibold text-gray-900">Agent Status</h2>
</div>
<div class="space-y-3 px-5 py-4">
<div class="flex items-center justify-between gap-3">
<span class="text-sm text-gray-500">Status</span>
<span class="inline-flex items-center rounded-lg border px-3 py-1.5 text-xs font-medium {{ $badgeClasses[$agentStatus] ?? $badgeClasses['unknown'] }}">
{{ strtoupper($agentStatus) }}
</span>
</div>
<div class="flex items-center justify-between gap-3">
<span class="text-sm text-gray-500">Hostname</span>
<span class="text-right text-sm font-medium text-gray-900">{{ $serverAgent?->hostname ?: 'Not registered yet' }}</span>
</div>
<div class="flex items-center justify-between gap-3">
<span class="text-sm text-gray-500">Version</span>
<span class="text-right text-sm font-medium text-gray-900">{{ $serverAgent?->agent_version ?: '-' }}</span>
</div>
<div class="flex items-center justify-between gap-3">
<span class="text-sm text-gray-500">Last Heartbeat</span>
<span class="text-right text-sm font-medium text-gray-900">
{{ $serverAgent?->last_heartbeat_at ? $serverAgent->last_heartbeat_at->format('M d, Y H:i') : 'Waiting for registration' }}
</span>
</div>
@if (! empty($serverAgent?->capabilities))
<div>
<p class="text-sm text-gray-500">Reported Capabilities</p>
<p class="mt-1 text-xs text-gray-700">{{ implode(', ', (array) $serverAgent->capabilities) }}</p>
</div>
@endif
<div class="rounded-lg bg-amber-50 px-3 py-2 text-xs text-amber-900">
The agent registration and heartbeat pipeline is now active. Task execution still depends on the server-side agent binary being installed on the machine.
</div>
</div>
</div>
@endif
<div class="rounded-xl border border-gray-200 bg-white">
<div class="border-b border-gray-100 px-5 py-4">
<h2 class="text-sm font-semibold text-gray-900">Instance Details</h2>
</div>
<div class="divide-y divide-gray-100">
<div class="flex items-center justify-between px-5 py-3">
<span class="text-sm text-gray-500">Region</span>
<span class="text-sm font-medium text-gray-900">{{ data_get($panelState, 'region', $order->meta['region'] ?? '-') }}</span>
</div>
<div class="flex items-center justify-between px-5 py-3">
<span class="text-sm text-gray-500">Datacenter</span>
<span class="text-sm font-medium text-gray-900">{{ data_get($panelState, 'datacenter', '-') }}</span>
</div>
<div class="flex items-center justify-between px-5 py-3">
<span class="text-sm text-gray-500">Image</span>
<span class="text-right text-sm font-medium text-gray-900">{{ data_get($panelState, 'image', '-') }}</span>
</div>
<div class="flex items-center justify-between px-5 py-3">
<span class="text-sm text-gray-500">Username</span>
<span class="font-mono text-sm font-medium text-gray-900">{{ $order->server_username ?: 'root' }}</span>
</div>
</div>
</div>
<div class="rounded-xl border border-gray-200 bg-white px-5 py-4">
<h2 class="text-sm font-semibold text-gray-900">Access</h2>
<div class="mt-3 space-y-2 text-sm text-gray-600">
<p>Use the server password you set at checkout to access the machine.</p>
@if ($order->server_ip)
<div class="rounded-lg bg-gray-900 p-3">
<code class="text-xs text-green-400">ssh {{ $order->server_username ?: 'root' }}@{{ $order->server_ip }}</code>
</div>
@endif
</div>
</div>
</div>
</div>
</div>
</x-user-layout>