Deploy Ladill Hosting / deploy (push) Successful in 28s
Add shared btn-primary components and plus icons on create/new actions for a consistent Ladill UI. Co-authored-by: Cursor <cursoragent@cursor.com>
156 lines
11 KiB
PHP
156 lines
11 KiB
PHP
<x-hosting-panel-layout :account="$account">
|
|
<x-slot name="title">Databases - {{ $account->username }}</x-slot>
|
|
<x-slot name="header">Databases</x-slot>
|
|
|
|
<div class="space-y-6">
|
|
@if(session('success'))
|
|
<div class="rounded-lg bg-emerald-50 border border-emerald-200 p-4">
|
|
<p class="text-sm text-emerald-800">{{ session('success') }}</p>
|
|
</div>
|
|
@endif
|
|
|
|
@if(session('error'))
|
|
<div class="rounded-lg bg-red-50 border border-red-200 p-4">
|
|
<p class="text-sm text-red-800">{{ session('error') }}</p>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="rounded-xl border border-slate-200 bg-white p-6">
|
|
<h3 class="text-base font-semibold text-slate-900 mb-4">Create New Database</h3>
|
|
<form action="{{ route('hosting.panel.databases.create', $account) }}" method="POST" class="flex flex-wrap items-end gap-4">
|
|
@csrf
|
|
<div class="flex-1 min-w-[200px]">
|
|
<label class="block text-sm font-medium text-slate-700 mb-1">Database Name</label>
|
|
<div class="flex items-center">
|
|
<span class="inline-flex items-center rounded-l-lg border border-r-0 border-slate-200 bg-slate-50 px-3 py-2.5 text-sm text-slate-500">{{ substr($account->username, 0, 8) }}_</span>
|
|
<input type="text" name="name" required pattern="[a-zA-Z0-9_]+" maxlength="24" placeholder="mydb" class="flex-1 rounded-r-lg border border-slate-200 px-4 py-2.5 text-sm focus:border-indigo-500 focus:ring-indigo-500">
|
|
</div>
|
|
</div>
|
|
<button type="submit" class="btn-primary">
|
|
<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="M12 4.5v15m7.5-7.5h-15"/></svg>
|
|
Create Database
|
|
</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="rounded-xl border border-slate-200 bg-white overflow-hidden">
|
|
<div class="px-6 py-4 border-b border-slate-200">
|
|
<h3 class="text-base font-semibold text-slate-900">Your Databases</h3>
|
|
</div>
|
|
@if($account->databases->count())
|
|
<table class="min-w-full divide-y divide-slate-200">
|
|
<thead class="bg-slate-50">
|
|
<tr>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 uppercase">Database Name</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 uppercase">Username</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-slate-500 uppercase">Host</th>
|
|
<th class="px-6 py-3 text-right text-xs font-medium text-slate-500 uppercase">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-slate-200">
|
|
@foreach($account->databases as $database)
|
|
<tr class="hover:bg-slate-50">
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
<span class="text-sm font-mono text-slate-900">{{ $database->name }}</span>
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
<span class="text-sm font-mono text-slate-600">{{ $database->username }}</span>
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
<span class="text-sm font-mono text-slate-600">{{ $database->host }}</span>
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-right">
|
|
<div class="flex items-center justify-end gap-2">
|
|
@if($phpMyAdminUrl)
|
|
<a href="{{ $phpMyAdminUrl }}" target="_blank" class="inline-flex items-center gap-1.5 rounded-lg border border-indigo-200 bg-indigo-50 px-3 py-1.5 text-xs font-medium text-indigo-700 hover:bg-indigo-100 transition">
|
|
<svg class="h-3.5 w-3.5" 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>
|
|
phpMyAdmin
|
|
</a>
|
|
@endif
|
|
<button onclick="resetPassword({{ $database->id }})" class="inline-flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-700 hover:bg-slate-50 transition">
|
|
<svg class="h-3.5 w-3.5" 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>
|
|
Reset Password
|
|
</button>
|
|
<x-confirm-dialog
|
|
:name="'delete-db-'.$database->id"
|
|
title="Delete database?"
|
|
message="This will permanently delete the database and all its data."
|
|
:action="route('hosting.panel.databases.delete', [$account, $database])"
|
|
method="DELETE"
|
|
confirm-label="Delete"
|
|
>
|
|
<x-slot:trigger>
|
|
<button type="button" class="inline-flex items-center gap-1.5 rounded-lg border border-red-200 bg-white px-3 py-1.5 text-xs font-medium text-red-600 hover:bg-red-50 transition">
|
|
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"/></svg>
|
|
Delete
|
|
</button>
|
|
</x-slot:trigger>
|
|
</x-confirm-dialog>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
@else
|
|
<div class="px-6 py-12 text-center">
|
|
<svg class="mx-auto h-12 w-12 text-slate-300" fill="none" stroke="currentColor" stroke-width="1.5" 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>
|
|
<p class="mt-4 text-sm text-slate-500">No databases yet. Create one above.</p>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="rounded-xl border border-slate-200 bg-white p-6">
|
|
<h3 class="text-base font-semibold text-slate-900 mb-4">Connection 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">Host</p>
|
|
<p class="mt-1 text-sm font-mono text-slate-900">localhost</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">3306</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs font-medium text-slate-500">External Access</p>
|
|
<p class="mt-1 text-sm text-slate-500">Not available (localhost only)</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs font-medium text-slate-500">phpMyAdmin</p>
|
|
@if($phpMyAdminUrl)
|
|
<a href="{{ $phpMyAdminUrl }}" target="_blank" rel="noopener noreferrer" class="mt-1 inline-flex items-center gap-1.5 text-sm font-medium text-indigo-600 hover:text-indigo-800">
|
|
Open phpMyAdmin
|
|
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M13.5 6H18m0 0v4.5M18 6l-7.5 7.5"/><path stroke-linecap="round" stroke-linejoin="round" d="M6 18h12a2 2 0 002-2V9.75m-16 0V16a2 2 0 002 2"/></svg>
|
|
</a>
|
|
<p class="mt-1 text-xs text-slate-500">Use your database username and password to log in.</p>
|
|
@else
|
|
<p class="mt-1 text-sm text-slate-500">phpMyAdmin is not configured for this server.</p>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@push('scripts')
|
|
<script>
|
|
async async function resetPassword(databaseId) {
|
|
if (!await window.ladillConfirm({ title: 'Reset password?', message: 'Reset the database password? You will need to update your application configuration.', confirmLabel: 'Reset', variant: 'primary' })) return;
|
|
try {
|
|
const res = await fetch(`{{ url('hosting/panel/' . $account->id . '/databases') }}/${databaseId}/reset-password`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': '{{ csrf_token() }}' }
|
|
});
|
|
const data = await res.json();
|
|
if (data.success) {
|
|
alert('New password: ' + data.password + '\n\nPlease save this password - it will not be shown again.');
|
|
} else {
|
|
alert(data.error || 'Failed to reset password');
|
|
}
|
|
} catch (e) {
|
|
alert('Error: ' + e.message);
|
|
}
|
|
}
|
|
</script>
|
|
@endpush
|
|
</x-hosting-panel-layout>
|