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>
157 lines
12 KiB
PHP
157 lines
12 KiB
PHP
<x-hosting-panel-layout :account="$account">
|
|
<x-slot name="title">Hosting Panel - {{ $account->username }}</x-slot>
|
|
<x-slot name="header">Overview - {{ $account->username }}</x-slot>
|
|
|
|
<div class="space-y-6">
|
|
|
|
@php
|
|
$sslProvisioningSites = $account->sites->filter(fn($site) => $site->ssl_status === 'provisioning');
|
|
@endphp
|
|
|
|
@if($sslProvisioningSites->isNotEmpty())
|
|
<div class="rounded-xl border border-amber-200 bg-amber-50 p-4">
|
|
<div class="flex items-start gap-3">
|
|
<div class="flex-shrink-0">
|
|
<svg class="h-5 w-5 text-amber-500 animate-spin" fill="none" viewBox="0 0 24 24">
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
</svg>
|
|
</div>
|
|
<div>
|
|
<h3 class="text-sm font-medium text-amber-800">SSL Certificate Provisioning</h3>
|
|
<p class="mt-1 text-sm text-amber-700">
|
|
SSL certificates are being provisioned for
|
|
<strong>{{ $sslProvisioningSites->pluck('domain')->join(', ') }}</strong>.
|
|
Please wait until this completes before installing applications. This usually takes 1-2 minutes.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
<div class="rounded-xl border border-slate-200 bg-white p-5">
|
|
<div class="flex items-center gap-3">
|
|
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-blue-100">
|
|
<svg class="h-5 w-5 text-blue-600" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" 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 4"/></svg>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs font-medium text-slate-500">Disk Usage</p>
|
|
<p class="text-lg font-semibold text-slate-900">{{ number_format(($stats['disk_used_bytes'] ?? 0) / 1048576, 2) }} MB</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="rounded-xl border border-slate-200 bg-white p-5">
|
|
<div class="flex items-center gap-3">
|
|
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-emerald-100">
|
|
<svg class="h-5 w-5 text-emerald-600" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 9.776c.112-.017.227-.026.344-.026h15.812c.117 0 .232.009.344.026m-16.5 0a2.25 2.25 0 00-1.883 2.542l.857 6a2.25 2.25 0 002.227 1.932H19.05a2.25 2.25 0 002.227-1.932l.857-6a2.25 2.25 0 00-1.883-2.542m-16.5 0V6A2.25 2.25 0 016 3.75h3.879a1.5 1.5 0 011.06.44l2.122 2.12a1.5 1.5 0 001.06.44H18A2.25 2.25 0 0120.25 9v.776"/></svg>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs font-medium text-slate-500">Files</p>
|
|
<p class="text-lg font-semibold text-slate-900">{{ number_format(($stats['file_size_bytes'] ?? 0) / 1048576, 2) }} MB</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@can('manageDatabases', $account)
|
|
<div class="rounded-xl border border-slate-200 bg-white p-5">
|
|
<div class="flex items-center gap-3">
|
|
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-purple-100">
|
|
<svg class="h-5 w-5 text-purple-600" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M20.25 6.375c0 2.278-3.694 4.125-8.25 4.125S3.75 8.653 3.75 6.375m16.5 0c0-2.278-3.694-4.125-8.25-4.125S3.75 4.097 3.75 6.375m16.5 0v11.25c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125V6.375"/></svg>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs font-medium text-slate-500">Databases</p>
|
|
<p class="text-lg font-semibold text-slate-900">{{ $account->databases->count() }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endcan
|
|
<div class="rounded-xl border border-slate-200 bg-white p-5">
|
|
<div class="flex items-center gap-3">
|
|
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-amber-100 text-amber-600">
|
|
@include('components.icons.domain-globe', ['class' => 'h-5 w-5'])
|
|
</div>
|
|
<div>
|
|
<p class="text-xs font-medium text-slate-500">Domains</p>
|
|
<p class="text-lg font-semibold text-slate-900">{{ $account->sites->count() }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-5">
|
|
<a href="{{ route('hosting.panel.files', $account) }}" class="group rounded-xl border border-slate-200 bg-white p-6 hover:border-indigo-300 hover:shadow-md transition">
|
|
<div class="flex h-12 w-12 items-center justify-center rounded-xl bg-indigo-100 group-hover:bg-indigo-200 transition">
|
|
<svg class="h-6 w-6 text-indigo-600" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 9.776c.112-.017.227-.026.344-.026h15.812c.117 0 .232.009.344.026m-16.5 0a2.25 2.25 0 00-1.883 2.542l.857 6a2.25 2.25 0 002.227 1.932H19.05a2.25 2.25 0 002.227-1.932l.857-6a2.25 2.25 0 00-1.883-2.542m-16.5 0V6A2.25 2.25 0 016 3.75h3.879a1.5 1.5 0 011.06.44l2.122 2.12a1.5 1.5 0 001.06.44H18A2.25 2.25 0 0120.25 9v.776"/></svg>
|
|
</div>
|
|
<h3 class="mt-4 text-base font-semibold text-slate-900">File Manager</h3>
|
|
<p class="mt-1 text-sm text-slate-500">Upload, edit, and manage your files</p>
|
|
</a>
|
|
|
|
@can('manageDatabases', $account)
|
|
<a href="{{ route('hosting.panel.databases', $account) }}" class="group rounded-xl border border-slate-200 bg-white p-6 hover:border-purple-300 hover:shadow-md transition">
|
|
<div class="flex h-12 w-12 items-center justify-center rounded-xl bg-purple-100 group-hover:bg-purple-200 transition">
|
|
<svg class="h-6 w-6 text-purple-600" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M20.25 6.375c0 2.278-3.694 4.125-8.25 4.125S3.75 8.653 3.75 6.375m16.5 0c0-2.278-3.694-4.125-8.25-4.125S3.75 4.097 3.75 6.375m16.5 0v11.25c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125V6.375"/></svg>
|
|
</div>
|
|
<h3 class="mt-4 text-base font-semibold text-slate-900">Databases</h3>
|
|
<p class="mt-1 text-sm text-slate-500">Create and manage MySQL databases</p>
|
|
</a>
|
|
@endcan
|
|
|
|
<a href="{{ route('hosting.panel.domains', $account) }}" class="group rounded-xl border border-slate-200 bg-white p-6 hover:border-amber-300 hover:shadow-md transition">
|
|
<div class="flex h-12 w-12 items-center justify-center rounded-xl bg-amber-100 group-hover:bg-amber-200 transition">
|
|
@include('components.icons.domain-globe', ['class' => 'h-6 w-6 text-amber-600'])
|
|
</div>
|
|
<h3 class="mt-4 text-base font-semibold text-slate-900">Domains</h3>
|
|
<p class="mt-1 text-sm text-slate-500">{{ auth()->user()->can('manageDomains', $account) ? 'Add and manage addon domains' : 'Review linked domains' }}</p>
|
|
</a>
|
|
|
|
@can('useTerminal', $account)
|
|
<a href="{{ route('hosting.panel.terminal', $account) }}" class="group rounded-xl border border-slate-200 bg-white p-6 hover:border-emerald-300 hover:shadow-md transition">
|
|
<div class="flex h-12 w-12 items-center justify-center rounded-xl bg-emerald-100 group-hover:bg-emerald-200 transition">
|
|
<svg class="h-6 w-6 text-emerald-600" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M6.75 7.5 10.5 12l-3.75 4.5m6-9h4.5" /></svg>
|
|
</div>
|
|
<h3 class="mt-4 text-base font-semibold text-slate-900">Terminal</h3>
|
|
<p class="mt-1 text-sm text-slate-500">Run app commands inside your account sandbox</p>
|
|
</a>
|
|
@endcan
|
|
|
|
@can('viewSettings', $account)
|
|
<a href="{{ route('hosting.panel.settings', $account) }}" class="group rounded-xl border border-slate-200 bg-white p-6 hover:border-slate-400 hover:shadow-md transition">
|
|
<div class="flex h-12 w-12 items-center justify-center rounded-xl bg-slate-100 group-hover:bg-slate-200 transition">
|
|
<svg class="h-6 w-6 text-slate-600" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z"/><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/></svg>
|
|
</div>
|
|
<h3 class="mt-4 text-base font-semibold text-slate-900">Settings</h3>
|
|
<p class="mt-1 text-sm text-slate-500">{{ auth()->user()->can('changePassword', $account) ? 'SFTP password and team access settings' : 'SFTP connection details and your SSH key' }}</p>
|
|
</a>
|
|
@endcan
|
|
</div>
|
|
|
|
<!-- SFTP Info -->
|
|
<div class="rounded-xl border border-slate-200 bg-white p-6">
|
|
<h3 class="text-base font-semibold text-slate-900 mb-4">SFTP Access</h3>
|
|
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
<div>
|
|
<p class="text-xs font-medium text-slate-500">Host</p>
|
|
<p class="mt-1 text-sm font-mono text-slate-900">{{ $account->node?->ip_address ?? '161.97.138.149' }}</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs font-medium text-slate-500">Port</p>
|
|
<p class="mt-1 text-sm font-mono text-slate-900">22</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs font-medium text-slate-500">Username</p>
|
|
<p class="mt-1 text-sm font-mono text-slate-900">{{ $account->username }}</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs font-medium text-slate-500">Password</p>
|
|
@can('changePassword', $account)
|
|
<p class="mt-1 text-sm text-slate-500">Set in <a href="{{ route('hosting.panel.settings', $account) }}" class="text-indigo-600 hover:underline">Settings</a></p>
|
|
@else
|
|
<p class="mt-1 text-sm text-slate-500">Use your SSH key in <a href="{{ route('hosting.panel.settings', $account) }}" class="text-indigo-600 hover:underline">Settings</a></p>
|
|
@endcan
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</x-hosting-panel-layout>
|