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>
161 lines
10 KiB
PHP
161 lines
10 KiB
PHP
<x-hosting-panel-layout :account="$account">
|
|
<x-slot name="title">Settings - {{ $account->username }}</x-slot>
|
|
<x-slot name="header">Settings</x-slot>
|
|
|
|
@php
|
|
$serverIp = $account->node?->ip_address ?? '161.97.138.149';
|
|
$sftpCommand = "sftp {$account->username}@{$serverIp}";
|
|
@endphp
|
|
|
|
<div class="space-y-6">
|
|
@if(session('success'))
|
|
<div class="rounded-lg border border-emerald-200 bg-emerald-50 p-4">
|
|
<p class="text-sm text-emerald-800">{{ session('success') }}</p>
|
|
</div>
|
|
@endif
|
|
|
|
@if(session('error'))
|
|
<div class="rounded-lg border border-red-200 bg-red-50 p-4">
|
|
<p class="text-sm text-red-800">{{ session('error') }}</p>
|
|
</div>
|
|
@endif
|
|
|
|
@if($canChangePassword)
|
|
<div class="rounded-xl border border-slate-200 bg-white p-6">
|
|
<h3 class="mb-4 text-base font-semibold text-slate-900">SFTP Password</h3>
|
|
<p class="mb-4 text-sm text-slate-600">Change the shared SFTP password for this hosting account. Team developers do not see or manage this password.</p>
|
|
<form action="{{ route('hosting.panel.settings.password', $account) }}" method="POST" class="max-w-md space-y-4">
|
|
@csrf
|
|
<div>
|
|
<label class="mb-1 block text-sm font-medium text-slate-700">New Password</label>
|
|
<input type="password" name="password" required minlength="8" class="w-full rounded-lg border border-slate-200 px-4 py-2.5 text-sm focus:border-indigo-500 focus:ring-indigo-500">
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-sm font-medium text-slate-700">Confirm Password</label>
|
|
<input type="password" name="password_confirmation" required minlength="8" class="w-full rounded-lg border border-slate-200 px-4 py-2.5 text-sm focus:border-indigo-500 focus:ring-indigo-500">
|
|
</div>
|
|
<button type="submit" class="inline-flex items-center gap-2 rounded-lg bg-indigo-600 px-5 py-2.5 text-sm font-medium text-white transition hover:bg-indigo-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 5.25a3 3 0 013 3m3 0a6 6 0 01-7.029 5.912c-.563-.097-1.159.026-1.563.43L10.5 17.25H8.25v2.25H6v2.25H2.25v-2.818c0-.597.237-1.17.659-1.591l6.499-6.499c.404-.404.527-1 .43-1.563A6 6 0 1121.75 8.25z"/></svg>
|
|
Change Password
|
|
</button>
|
|
</form>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="rounded-xl border border-slate-200 bg-white p-6">
|
|
<div class="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
|
|
<div>
|
|
<h3 class="text-base font-semibold text-slate-900">SFTP Key Access</h3>
|
|
@if ($teamMembership)
|
|
<p class="mt-2 text-sm text-slate-600">Add your SSH public key to connect over SFTP as <span class="font-mono text-slate-900">{{ $account->username }}</span>. Removing you from the team automatically removes this key.</p>
|
|
@else
|
|
<p class="mt-2 text-sm text-slate-600">Owners connect with the shared account password. Team developers add their own SSH public key here after they sign in.</p>
|
|
@endif
|
|
</div>
|
|
|
|
@if ($teamMembership?->ssh_key_installed_at)
|
|
<span class="inline-flex items-center rounded-full bg-emerald-50 px-3 py-1 text-xs font-medium text-emerald-700">
|
|
Key active
|
|
</span>
|
|
@endif
|
|
</div>
|
|
|
|
@if ($teamMembership)
|
|
<form action="{{ route('hosting.panel.settings.ssh-key', $account) }}" method="POST" class="mt-5 space-y-4">
|
|
@csrf
|
|
<div>
|
|
<label for="ssh_public_key" class="mb-1 block text-sm font-medium text-slate-700">SSH Public Key</label>
|
|
<textarea id="ssh_public_key" name="ssh_public_key" rows="5" required class="w-full rounded-lg border border-slate-200 px-4 py-3 font-mono text-sm focus:border-indigo-500 focus:ring-indigo-500" placeholder="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... your@email.com">{{ old('ssh_public_key', $teamMembership->ssh_public_key) }}</textarea>
|
|
<p class="mt-2 text-xs text-slate-500">Use an OpenSSH public key for SFTP access to this hosting account.</p>
|
|
<x-input-error :messages="$errors->get('ssh_public_key')" class="mt-2" />
|
|
</div>
|
|
|
|
<button type="submit" class="inline-flex items-center rounded-lg bg-indigo-600 px-5 py-2.5 text-sm font-medium text-white transition hover:bg-indigo-700">
|
|
Save SFTP Key
|
|
</button>
|
|
|
|
@if ($teamMembership->ssh_key_installed_at)
|
|
<p class="text-xs text-slate-500">Last installed {{ $teamMembership->ssh_key_installed_at->diffForHumans() }}.</p>
|
|
@endif
|
|
</form>
|
|
|
|
@if ($teamMembership->hasSshAccessKey())
|
|
<form method="POST" action="{{ route('hosting.panel.settings.ssh-key.destroy', $account) }}" class="mt-3" onsubmit="return confirm('Remove your SFTP key access for this hosting account?');">
|
|
@csrf
|
|
@method('DELETE')
|
|
<button type="submit" class="inline-flex items-center rounded-lg border border-slate-300 px-5 py-2.5 text-sm font-medium text-slate-700 transition hover:border-slate-400 hover:text-slate-900">
|
|
Remove SFTP Key
|
|
</button>
|
|
</form>
|
|
@endif
|
|
@else
|
|
<div class="mt-5 rounded-xl bg-slate-50 px-4 py-4 text-sm text-slate-600">
|
|
Developers on your team use their own SSH keys instead of the shared password, so removing them from the team immediately cuts off SFTP access.
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="rounded-xl border border-slate-200 bg-white p-6">
|
|
<div class="flex items-center gap-3 mb-5">
|
|
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-indigo-50">
|
|
<svg class="h-5 w-5 text-indigo-600" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M7.5 7.5h-.75A2.25 2.25 0 004.5 9.75v7.5a2.25 2.25 0 002.25 2.25h7.5a2.25 2.25 0 002.25-2.25v-7.5a2.25 2.25 0 00-2.25-2.25h-.75m-6 3.75l3 3m0 0l3-3m-3 3V1.5m6 9h.75a2.25 2.25 0 012.25 2.25v7.5a2.25 2.25 0 01-2.25 2.25h-7.5a2.25 2.25 0 01-2.25-2.25v-.75"/></svg>
|
|
</div>
|
|
<div>
|
|
<h3 class="text-base font-semibold text-slate-900">SFTP Connection</h3>
|
|
<p class="text-sm text-slate-500">Connect with any SFTP client</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-5 rounded-lg border border-slate-200 bg-slate-50 p-4">
|
|
<div class="flex items-center justify-between gap-4">
|
|
<code class="flex-1 overflow-x-auto font-mono text-sm text-slate-800">{{ $sftpCommand }}</code>
|
|
<button type="button" onclick="navigator.clipboard.writeText('{{ $sftpCommand }}'); this.textContent = 'Copied!'; setTimeout(() => this.textContent = 'Copy', 1500);" class="flex-shrink-0 rounded-md bg-indigo-600 px-3 py-1.5 text-xs font-medium text-white transition hover:bg-indigo-700">Copy</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
<div class="rounded-lg border border-slate-100 bg-slate-50/50 px-4 py-3">
|
|
<p class="text-xs font-medium text-slate-500">Host</p>
|
|
<p class="mt-1 font-mono text-sm text-slate-900">{{ $serverIp }}</p>
|
|
</div>
|
|
<div class="rounded-lg border border-slate-100 bg-slate-50/50 px-4 py-3">
|
|
<p class="text-xs font-medium text-slate-500">Port</p>
|
|
<p class="mt-1 font-mono text-sm text-slate-900">22</p>
|
|
</div>
|
|
<div class="rounded-lg border border-slate-100 bg-slate-50/50 px-4 py-3">
|
|
<p class="text-xs font-medium text-slate-500">Username</p>
|
|
<p class="mt-1 font-mono text-sm text-slate-900">{{ $account->username }}</p>
|
|
</div>
|
|
<div class="rounded-lg border border-slate-100 bg-slate-50/50 px-4 py-3">
|
|
<p class="text-xs font-medium text-slate-500">Authentication</p>
|
|
<p class="mt-1 text-sm text-slate-900">{{ $teamMembership ? 'SSH key' : 'Password' }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-xl border border-slate-200 bg-white p-6">
|
|
<h3 class="mb-4 text-base font-semibold text-slate-900">Account Information</h3>
|
|
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
<div>
|
|
<p class="text-xs font-medium text-slate-500">Account Type</p>
|
|
<p class="mt-1 text-sm text-slate-900">{{ ucfirst($account->type) }} Hosting</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs font-medium text-slate-500">Product</p>
|
|
<p class="mt-1 text-sm text-slate-900">{{ $account->product->name ?? 'N/A' }}</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs font-medium text-slate-500">PHP Version</p>
|
|
<p class="mt-1 text-sm text-slate-900">{{ $account->php_version ?? '8.2' }}</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs font-medium text-slate-500">Status</p>
|
|
<span class="inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium {{ $account->status === 'active' ? 'bg-emerald-100 text-emerald-800' : 'bg-slate-100 text-slate-800' }}">
|
|
{{ ucfirst($account->status) }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</x-hosting-panel-layout>
|