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:
parent
6459e5b500
commit
0bc81bbe40
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue