diff --git a/apps/web/src/components/network/network-peers-card.tsx b/apps/web/src/components/network/network-peers-card.tsx index 99b8234..e2f7d96 100644 --- a/apps/web/src/components/network/network-peers-card.tsx +++ b/apps/web/src/components/network/network-peers-card.tsx @@ -1,8 +1,10 @@ import { useMemo, useState } from 'react' -import { Plus, SearchIcon, ActivityIcon } from 'lucide-react' +import type { ColumnDef } from '@tanstack/react-table' +import { Plus, SearchIcon, ActivityIcon, Trash2 } from 'lucide-react' import { Button } from '@evobgp/ui/components/button' +import { ConfirmDialog } from '@/components/confirm-dialog' import { PeerFormDialog } from '@/components/network/peer-form-dialog' import { getPeerFilterFieldValue, @@ -15,13 +17,19 @@ import { type FilterFieldConfig, } from '@/components/reui/filters' import { ResourcePage, renderSingleSelectedLabel } from '@/components/reui-kit' +import { useDeletePeerMutation } from '@/queries/network' import type { PeerRow, SpeakerRow } from '@/types/api' /** * BGP peers list — ResourcePage (Frame + tabs + Filters + DataGrid). * @see https://reui.io/preview/base/data-grid-filtering-2 + * @see https://reui.io/docs/components/base/data-grid */ +function peerDeleteLabel(p: PeerRow): string { + return p.name?.trim() || p.neighbor || p.id +} + const PEER_TABS = [ { id: 'all', label: 'Все' }, { id: 'established', label: 'Established' }, @@ -89,7 +97,9 @@ export function NetworkPeersCard({ error, onRetry, }: NetworkPeersCardProps) { + const deleteMutation = useDeletePeerMutation() const [dialogOpen, setDialogOpen] = useState(false) + const [deleteTarget, setDeleteTarget] = useState(null) const [filters, setFilters] = useState(createDefaultPeerFilters) const addButton = useMemo( @@ -102,6 +112,33 @@ export function NetworkPeersCard({ [], ) + const columns = useMemo[]>( + () => [ + ...peerColumns, + { + id: 'actions', + enableSorting: false, + header: () => Действия, + cell: ({ row }) => ( +
+ +
+ ), + }, + ], + [], + ) + return ( <> setFilters(createDefaultPeerFilters())} getFilterFieldValue={getPeerFilterFieldValue} - columns={peerColumns} + columns={columns} data={items} getRowId={(row) => row.id} isLoading={isLoading} @@ -129,7 +166,34 @@ export function NetworkPeersCard({ }} /> - + + + { + if (!open) setDeleteTarget(null) + }} + title="Удалить пира?" + description={ + deleteTarget + ? `${peerDeleteLabel(deleteTarget)} будет удалён. Запустится reconcile пиров и apply на спикеры.` + : undefined + } + confirmLabel="Удалить" + confirmLoadingLabel="Удаление…" + destructive + confirmLoading={deleteMutation.isPending} + onConfirm={() => { + if (!deleteTarget) return + void deleteMutation + .mutateAsync(deleteTarget.id) + .then(() => setDeleteTarget(null)) + }} + /> ) }