fix(ui): подтверждать удаление туннеля GRE

This commit is contained in:
Denozordec committed 2026-09-30 00:39:39 +07:00
1 parent f5b64ea154
commit 780d5e9237
5 files changed
+80 -10

No files matched your search

+14 -6
View File
@@ -275,6 +275,8 @@ function GrePageContent({ selectedServerId, selectedTunnelId, allTunnelsHref, on
const [tunnelMode, setTunnelMode] = useState<"create" | "edit">("create")
const [editingTunnel, setEditingTunnel] = useState<GreTunnel | null>(null)
const [pendingDelete, setPendingDelete] = useState<GreTunnel | null>(null)
const deleteLock = useRef(false)
const [deleteError, setDeleteError] = useState<string | null>(null)
const [mutateBusy, setMutateBusy] = useState(false)
const [liveStale, setLiveStale] = useState(false)
const [historyOpen, setHistoryOpen] = useState(false)
@@ -506,19 +508,23 @@ function GrePageContent({ selectedServerId, selectedTunnelId, allTunnelsHref, on
async function confirmDeleteTunnel() {
const t = pendingDelete
if (!t || !isLive) return
if (!t || !isLive || mutationsLocked || deleteLock.current) return
deleteLock.current = true
setDeleteError(null)
setMutateBusy(true)
try {
await apiFetch("/api/gre/tunnels", {
const result = await apiFetch<{ ok: boolean }>("/api/gre/tunnels", {
method: "DELETE",
body: JSON.stringify({ serverId: t.serverId, rosId: t.id, name: t.name }),
})
if (result?.ok !== true) throw new Error("Сервер не подтвердил удаление туннеля")
toast.success(`Удалён ${t.name}`)
setPendingDelete(null)
await loadLive()
} catch (err) {
toast.error("Не удалось удалить туннель", { description: String(err) })
setDeleteError(err instanceof Error ? err.message : "Не удалось удалить туннель")
} finally {
deleteLock.current = false
setMutateBusy(false)
}
}
@@ -1091,7 +1097,7 @@ function GrePageContent({ selectedServerId, selectedTunnelId, allTunnelsHref, on
onRestore={restoreRevision}
/>
<AlertDialog open={!!pendingDelete} onOpenChange={(v) => { if (!v) setPendingDelete(null) }}>
<AlertDialog open={!!pendingDelete} onOpenChange={(v) => { if (!v && !deleteLock.current) { setPendingDelete(null); setDeleteError(null) } }}>
<AlertDialogContent size="default">
<AlertDialogHeader>
<AlertDialogMedia className="bg-destructive/10 text-destructive">
@@ -1103,10 +1109,12 @@ function GrePageContent({ selectedServerId, selectedTunnelId, allTunnelsHref, on
? `${pendingDelete.name} на сервере ${serverById[pendingDelete.serverId]?.name ?? pendingDelete.serverId}. Будут удалены интерфейс и связанный /ip/address.`
: null}
</AlertDialogDescription>
{mutateBusy && <p role="status" className="text-sm text-muted-foreground">Ожидание результата удаления…</p>}
{deleteError && <p role="alert" className="text-sm text-destructive">{deleteError}</p>}
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel onClick={() => setPendingDelete(null)}>Отмена</AlertDialogCancel>
<AlertDialogAction variant="destructive" onClick={() => void confirmDeleteTunnel()}>
<AlertDialogCancel disabled={mutateBusy}>Отмена</AlertDialogCancel>
<AlertDialogAction variant="destructive" disabled={mutationsLocked} onClick={(e) => { e.preventDefault(); void confirmDeleteTunnel() }}>
Удалить
</AlertDialogAction>
</AlertDialogFooter>