import { useMemo } from 'react' import { Link } from '@tanstack/react-router' import { GlobeIcon, MoreHorizontalIcon } from 'lucide-react' import { Badge } from '@cfdm/ui/components/badge' import { Button } from '@cfdm/ui/components/button' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@cfdm/ui/components/dropdown-menu' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@cfdm/ui/components/select' import { ConfirmDialog } from '@/components/confirm-dialog' import { DataGridCard, columnDefFromDataGrid, } from '@/components/data-grid-card' import type { DataGridColumn } from '@/components/data-grid-types' import { DomainsFiltersToolbar } from '@/components/domains-filters-toolbar' import { StatusBadge } from '@/components/status-badge' import type { DomainListItem } from '@/lib/schemas' import { useState } from 'react' export type DomainTableRow = DomainListItem interface GroupFilterItem { label: string value: string } export interface DomainsDataGridProps { data: DomainTableRow[] totalCount: number groupFilterItems: GroupFilterItem[] groupFilterValue: string onGroupFilterChange: (value: string | null) => void search: string onSearchChange: (value: string) => void onDelete: (domain: DomainTableRow) => void isDeleting?: boolean emptyAction?: React.ReactNode } export function DomainsDataGrid({ data, totalCount, groupFilterItems, groupFilterValue, onGroupFilterChange, search, onSearchChange, onDelete, isDeleting = false, emptyAction, }: DomainsDataGridProps) { const [deleteTarget, setDeleteTarget] = useState(null) const filteredData = useMemo(() => { const query = search.trim().toLowerCase() if (!query) return data return data.filter( (d) => d.zone_name.toLowerCase().includes(query) || (d.group_name ?? '').toLowerCase().includes(query), ) }, [data, search]) const columns = useMemo[]>( () => [ { key: 'zone_name', header: 'Зона', icon: GlobeIcon, sortable: true, sortValue: (row) => row.zone_name, cell: (row) => ( ), }, { key: 'group', header: 'Группа', sortable: true, sortValue: (row) => row.group_name ?? 'Без группы', cell: (row) => { if (row.group_id && row.group_name) { return ( ) } return Без группы }, }, { key: 'service_count', header: 'Сервисы', sortable: true, sortValue: (row) => row.service_count, className: 'tabular-nums', cell: (row) => ( ), }, { key: 'status', header: 'Статус', cell: (row) => , }, { key: 'last_synced_at', header: 'Синхронизация', sortable: true, sortValue: (row) => row.last_synced_at ?? '', className: 'text-muted-foreground tabular-nums', cell: (row) => row.last_synced_at ?? '—', }, { key: 'actions', header: '', enableHiding: false, className: 'text-right', cell: (row) => (
} > Действия } > Обзор } > DNS setDeleteTarget(row)} > Удалить
), }, ], [isDeleting], ) const groupSelect = ( ) const hasActiveFilters = Boolean(groupFilterValue) || Boolean(search.trim()) return ( <> String(row.id)} emptyTitle="Домены не найдены" emptyDescription="Импортируйте зону из Cloudflare или измените фильтры" emptyAction={emptyAction} pinLastColumn actions={ { onSearchChange('') onGroupFilterChange(null) }} /> } /> { if (!open) setDeleteTarget(null) }} title="Удалить зону?" description={ deleteTarget ? `Зона «${deleteTarget.zone_name}» будет удалена из менеджера вместе с DNS-записями и привязками. Зона в Cloudflare не затрагивается.` : '' } onConfirm={() => { if (!deleteTarget) return onDelete(deleteTarget) setDeleteTarget(null) }} disabled={isDeleting} /> ) }