import { useMemo, useState } from 'react' import { useNavigate } from '@tanstack/react-router' import { Boxes, SearchIcon } from 'lucide-react' import { CategoryBadge } from '@/components/category-badge' import { DataGridMonoCell, DataGridMutedCell, DataGridNameCell } from '@/components/data-grid-cell' import { Badge } from '@/components/reui/badge' import { DataGridColumnHeader } from '@/components/reui/data-grid/data-grid-column-header' import type { FilterField, FilterQuery } from '@/components/reui/filters/filters-types' import { ResourcePage, createTextFilterQuery, type DataGridColumnDef, } from '@/components/reui-kit' import type { LookupMatch } from '@/types/api' /** * Lookup matches grid — ResourcePage hideHeader inside wizard-2 Frame. * @see https://reui.io/preview/base/wizard-2 * @see https://reui.io/preview/base/data-grid-filtering-2 * @see https://reui.io/docs/components/base/badge */ const filterFields: FilterField[] = [ { id: 'search', label: 'Поиск', icon: , type: 'text', placeholder: 'Фильтр совпадений…', }, ] export function LookupMatchesGrid({ items, isLoading = false, }: { items: LookupMatch[] isLoading?: boolean }) { const navigate = useNavigate() const [filterQuery, setFilterQuery] = useState(() => createTextFilterQuery('search'), ) const columns = useMemo[]>( () => [ { accessorKey: 'layer', header: ({ column }) => , cell: ({ row }) => ( {row.original.layer} ), meta: { headerTitle: 'Слой' }, }, { accessorKey: 'module_name', header: ({ column }) => , cell: ({ row }) => ( ), meta: { headerTitle: 'Модуль' }, }, { accessorKey: 'matched_value', header: ({ column }) => , cell: ({ row }) => (
{row.original.matched_value} {row.original.resolved_ip ? `${row.original.match_kind} · via ${row.original.resolved_ip}` : row.original.match_kind}
), meta: { headerTitle: 'Совпадение' }, }, { id: 'community', accessorFn: (row) => row.community_title || row.community || '', header: ({ column }) => , cell: ({ row }) => { const title = row.original.community_title?.trim() const value = row.original.community?.trim() if (!title && !value) { return — } return (
{title || value || '—'} {title && value && title !== value ? ( {value} ) : null}
) }, meta: { headerTitle: 'Community' }, }, { id: 'source', enableSorting: false, header: 'Источник', cell: ({ row }) => row.original.source ? ( {row.original.source} ) : ( — ), meta: { headerTitle: 'Источник' }, }, ], [], ) return ( setFilterQuery(createTextFilterQuery('search'))} getFilterFieldValue={(item, field) => { if (field !== 'search') return undefined return `${item.layer} ${item.module_name} ${item.module_type} ${item.matched_value} ${item.community ?? ''} ${item.community_title ?? ''} ${item.source ?? ''}` }} columns={columns} data={items} getRowId={(row) => `${row.layer}|${row.module_id}|${row.match_kind}|${row.matched_value}|${row.entry_id ?? ''}|${row.source ?? ''}|${row.community_id ?? ''}` } isLoading={isLoading} onRowClick={(row) => void navigate({ to: '/modules/$moduleId', params: { moduleId: row.module_id } }) } emptyState={{ title: 'Нет совпадений' }} /> ) }