Add endpoint deletion
The endpoints screen could only create and edit servers, so a mistyped or retired endpoint stayed in the list forever. Tasks reference endpoints without ON DELETE CASCADE, so a referenced endpoint is refused with 409 and a count of the tasks using it rather than cascading away migration history. The foreign-key violation is mapped to the same status to cover a task created between check and delete. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -82,6 +82,8 @@ export const updateEndpoint = (
|
||||
body: { role_label: string; host: string; port: number; tls_mode: TLSMode },
|
||||
) => api(`/api/endpoints/${id}`, { ...jsonBody(body), method: 'PUT' })
|
||||
|
||||
export const deleteEndpoint = (id: number) => api(`/api/endpoints/${id}`, { method: 'DELETE' })
|
||||
|
||||
export const deleteTask = (id: number) => api(`/api/tasks/${id}`, { method: 'DELETE' })
|
||||
|
||||
export const deleteAccount = (taskId: number, accountId: number) =>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useState, type FormEvent } from 'react'
|
||||
import { createEndpoint, listEndpoints, updateEndpoint, type Endpoint, type TLSMode } from '../api'
|
||||
import { createEndpoint, deleteEndpoint, listEndpoints, updateEndpoint, type Endpoint, type TLSMode } from '../api'
|
||||
import { useConfirm } from '../components/ConfirmProvider'
|
||||
|
||||
const emptyForm = { role_label: '', host: '', port: '993', tls_mode: 'ssl' as TLSMode }
|
||||
|
||||
@@ -9,6 +10,7 @@ export function Endpoints() {
|
||||
const [editingId, setEditingId] = useState<number | null>(null)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [busy, setBusy] = useState(false)
|
||||
const confirm = useConfirm()
|
||||
|
||||
function startEdit(ep: Endpoint) {
|
||||
setEditingId(ep.id)
|
||||
@@ -29,6 +31,25 @@ export function Endpoints() {
|
||||
|
||||
useEffect(reload, [])
|
||||
|
||||
async function onDelete(ep: Endpoint) {
|
||||
const ok = await confirm({
|
||||
title: 'Delete endpoint',
|
||||
message: `Delete endpoint "${ep.role_label}" (${ep.host}:${ep.port})?`,
|
||||
confirmLabel: 'Delete',
|
||||
danger: true,
|
||||
})
|
||||
if (!ok) return
|
||||
setError(null)
|
||||
try {
|
||||
await deleteEndpoint(ep.id)
|
||||
// The form still edits a row that no longer exists — drop back to create mode.
|
||||
if (editingId === ep.id) cancelEdit()
|
||||
reload()
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : 'Failed to delete endpoint')
|
||||
}
|
||||
}
|
||||
|
||||
async function submit(e: FormEvent) {
|
||||
e.preventDefault()
|
||||
setBusy(true)
|
||||
@@ -159,6 +180,9 @@ export function Endpoints() {
|
||||
<td className="num-cell">
|
||||
<button type="button" className="link-btn" onClick={() => startEdit(ep)} disabled={busy}>
|
||||
edit
|
||||
</button>{' '}
|
||||
<button type="button" className="link-btn danger" onClick={() => onDelete(ep)} disabled={busy}>
|
||||
delete
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
Reference in New Issue
Block a user