feat(network): add delete functionality for speakers in network speakers card
CI / changes (push) Successful in 7s
CI / commitlint (push) Skipped
CI / openapi (push) Skipped
CI / go (push) Skipped
CI / bird2 (push) Skipped
CI / web (push) Successful in 1m6s
CI / release (push) Successful in 4m12s

Implemented a delete feature for speakers within the NetworkSpeakersCard component. This includes a confirmation dialog for deletion and integration with the delete speaker mutation. Updated the table columns to include an action button for deleting speakers, enhancing the user experience for managing network speakers.
This commit is contained in:
Denozordec
2026-07-31 03:19:54 +07:00
parent 5fbe9c9b56
commit 1e04e91dd8
@@ -1,8 +1,10 @@
import { useMemo, useState } from 'react'
import { Plus, SearchIcon, TagIcon } from 'lucide-react'
import type { ColumnDef } from '@tanstack/react-table'
import { Plus, SearchIcon, TagIcon, Trash2 } from 'lucide-react'
import { Button } from '@evobgp/ui/components/button'
import { ConfirmDialog } from '@/components/confirm-dialog'
import { SpeakerFormDialog } from '@/components/network/speaker-form-dialog'
import {
getSpeakerFilterFieldValue,
@@ -15,6 +17,7 @@ import {
type FilterFieldConfig,
} from '@/components/reui/filters'
import { ResourcePage, renderSingleSelectedLabel } from '@/components/reui-kit'
import { useDeleteSpeakerMutation } from '@/queries/network'
import type { SpeakerRow } from '@/types/api'
/**
@@ -22,6 +25,10 @@ import type { SpeakerRow } from '@/types/api'
* @see https://reui.io/preview/base/data-grid-filtering-2
*/
function speakerDeleteLabel(s: SpeakerRow): string {
return s.agent_domain ?? s.endpoint ?? s.id
}
const SPEAKER_TABS = [
{ id: 'all', label: 'Все' },
{ id: 'online', label: 'Online' },
@@ -75,7 +82,9 @@ export function NetworkSpeakersCard({
error,
onRetry,
}: NetworkSpeakersCardProps) {
const deleteMutation = useDeleteSpeakerMutation()
const [dialogOpen, setDialogOpen] = useState(false)
const [deleteTarget, setDeleteTarget] = useState<SpeakerRow | null>(null)
const [filters, setFilters] = useState<Filter[]>(createDefaultSpeakerFilters)
const addButton = useMemo(
@@ -88,6 +97,33 @@ export function NetworkSpeakersCard({
[],
)
const columns = useMemo<ColumnDef<SpeakerRow, unknown>[]>(
() => [
...speakerColumns,
{
id: 'actions',
enableSorting: false,
header: () => <span className="sr-only">Действия</span>,
cell: ({ row }) => (
<div className="flex items-center justify-end">
<Button
variant="ghost"
size="icon-sm"
type="button"
className="text-destructive"
aria-label="Удалить спикера"
title="Удалить"
onClick={() => setDeleteTarget(row.original)}
>
<Trash2 className="size-3.5" />
</Button>
</div>
),
},
],
[],
)
return (
<>
<ResourcePage
@@ -100,7 +136,7 @@ export function NetworkSpeakersCard({
onFiltersChange={setFilters}
onClearFilters={() => setFilters(createDefaultSpeakerFilters())}
getFilterFieldValue={getSpeakerFilterFieldValue}
columns={speakerColumns}
columns={columns}
data={items}
getRowId={(row) => row.id}
isLoading={isLoading}
@@ -116,6 +152,27 @@ export function NetworkSpeakersCard({
/>
<SpeakerFormDialog open={dialogOpen} onOpenChange={setDialogOpen} />
<ConfirmDialog
open={deleteTarget !== null}
onOpenChange={(open) => {
if (!open) setDeleteTarget(null)
}}
title="Удалить спикера?"
description={
deleteTarget
? `${speakerDeleteLabel(deleteTarget)} будет удалён. Привязки пиров к этому спикеру сбросятся.`
: undefined
}
confirmLabel="Удалить"
confirmLoadingLabel="Удаление…"
destructive
confirmLoading={deleteMutation.isPending}
onConfirm={() => {
if (!deleteTarget) return
void deleteMutation.mutateAsync(deleteTarget.id).then(() => setDeleteTarget(null))
}}
/>
</>
)
}