feat(tenants): add delete button to tenant list page

Each tenant row now has a Delete button with confirmation dialog.
Previously delete was only accessible from the detail page which
had no navigation link from the list.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-03-07 04:54:51 -08:00
parent 6459e5b500
commit 0bc81bbe40
1 changed files with 39 additions and 0 deletions

View File

@ -73,6 +73,7 @@ export default function TenantsPage() {
const [showCreate, setShowCreate] = useState(false);
const [expandedId, setExpandedId] = useState<string | null>(null);
const [editingId, setEditingId] = useState<string | null>(null);
const [deletingId, setDeletingId] = useState<string | null>(null);
const [editPlan, setEditPlan] = useState<Tenant['plan']>('free');
const [editQuota, setEditQuota] = useState<TenantQuota>({
maxServers: 0,
@ -115,6 +116,12 @@ export default function TenantsPage() {
onSuccess: invalidate,
});
const deleteMutation = useMutation({
mutationFn: (id: string) =>
apiClient(`/api/v1/admin/tenants/${id}`, { method: 'DELETE' }),
onSuccess: () => { invalidate(); setDeletingId(null); },
});
/* ---- helpers ---- */
function resetCreateForm() {
setShowCreate(false);
@ -335,6 +342,12 @@ export default function TenantsPage() {
>
{expandedId === tenant.id ? t('actions.hideQuotas') : t('actions.quotas')}
</button>
<button
onClick={() => setDeletingId(tenant.id)}
className="px-2 py-1 text-xs rounded bg-red-100 text-red-700 hover:bg-red-200 dark:bg-red-900 dark:text-red-300"
>
{tc('delete')}
</button>
</>
)}
</div>
@ -367,6 +380,32 @@ export default function TenantsPage() {
</table>
</div>
)}
{/* Delete confirmation dialog */}
{deletingId && (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
<div className="bg-card border rounded-lg p-6 max-w-sm w-full mx-4 space-y-4">
<h2 className="text-lg font-semibold">{t('deleteDialog.title')}</h2>
<p className="text-sm text-muted-foreground">{t('deleteDialog.message')}</p>
<div className="flex gap-3 justify-end">
<button
onClick={() => setDeletingId(null)}
disabled={deleteMutation.isPending}
className="px-4 py-2 text-sm border rounded-md hover:bg-muted"
>
{tc('cancel')}
</button>
<button
onClick={() => deleteMutation.mutate(deletingId)}
disabled={deleteMutation.isPending}
className="px-4 py-2 text-sm bg-destructive text-destructive-foreground rounded-md hover:opacity-90 disabled:opacity-50"
>
{deleteMutation.isPending ? tc('deleting') : tc('delete')}
</button>
</div>
</div>
</div>
)}
</div>
);
}