import { useEffect, useState } from 'react' import { useQuery } from '@tanstack/react-query' import { getRouteApi } from '@tanstack/react-router' import { type SortingState, type VisibilityState, flexRender, getCoreRowModel, getFacetedRowModel, getFacetedUniqueValues, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from '@tanstack/react-table' import { useMediaQuery } from '@/hooks' import { useTranslation } from 'react-i18next' import { toast } from 'sonner' import { cn } from '@/lib/utils' import { useTableUrlState } from '@/hooks/use-table-url-state' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { DataTablePagination, DataTableToolbar, TableSkeleton, TableEmpty, MobileCardList, } from '@/components/data-table' import { PageFooterPortal } from '@/components/layout' import { getApiKeys, searchApiKeys } from '../api' import { API_KEY_STATUS_OPTIONS, ERROR_MESSAGES } from '../constants' import { type ApiKey } from '../types' import { useApiKeysColumns } from './api-keys-columns' import { useApiKeys } from './api-keys-provider' import { DataTableBulkActions } from './data-table-bulk-actions' const route = getRouteApi('/_authenticated/keys/') export function ApiKeysTable() { const { t } = useTranslation() const { refreshTrigger } = useApiKeys() const columns = useApiKeysColumns() const isMobile = useMediaQuery('(max-width: 640px)') const [rowSelection, setRowSelection] = useState({}) const [sorting, setSorting] = useState([]) const [columnVisibility, setColumnVisibility] = useState({}) const { globalFilter, onGlobalFilterChange, columnFilters, onColumnFiltersChange, pagination, onPaginationChange, ensurePageInRange, } = useTableUrlState({ search: route.useSearch(), navigate: route.useNavigate(), pagination: { defaultPage: 1, defaultPageSize: 20 }, globalFilter: { enabled: true, key: 'filter' }, columnFilters: [{ columnId: 'status', searchKey: 'status', type: 'array' }], }) // Fetch data with React Query // eslint-disable-next-line @tanstack/query/exhaustive-deps const { data, isLoading, isFetching } = useQuery({ queryKey: [ 'keys', pagination.pageIndex + 1, pagination.pageSize, globalFilter, refreshTrigger, ], queryFn: async () => { // If there's a global filter, use search const hasFilter = globalFilter?.trim() if (hasFilter) { const result = await searchApiKeys({ keyword: globalFilter }) if (!result.success) { toast.error(result.message || t(ERROR_MESSAGES.SEARCH_FAILED)) return { items: [], total: 0 } } return { items: result.data || [], total: result.data?.length || 0, } } // Otherwise use pagination const result = await getApiKeys({ p: pagination.pageIndex + 1, size: pagination.pageSize, }) if (!result.success) { toast.error(result.message || t(ERROR_MESSAGES.LOAD_FAILED)) return { items: [], total: 0 } } return { items: result.data?.items || [], total: result.data?.total || 0, } }, placeholderData: (previousData) => previousData, }) const apiKeys = data?.items || [] const table = useReactTable({ data: apiKeys, columns, state: { sorting, columnVisibility, rowSelection, columnFilters, globalFilter, pagination, }, enableRowSelection: true, onRowSelectionChange: setRowSelection, onSortingChange: setSorting, onColumnVisibilityChange: setColumnVisibility, globalFilterFn: (row, _columnId, filterValue) => { const name = String(row.getValue('name')).toLowerCase() const key = String(row.original.key).toLowerCase() const searchValue = String(filterValue).toLowerCase() return name.includes(searchValue) || key.includes(searchValue) }, getCoreRowModel: getCoreRowModel(), getFilteredRowModel: getFilteredRowModel(), getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), getFacetedRowModel: getFacetedRowModel(), getFacetedUniqueValues: getFacetedUniqueValues(), onPaginationChange, onGlobalFilterChange, onColumnFiltersChange, manualPagination: !globalFilter, pageCount: globalFilter ? Math.ceil((data?.total || 0) / pagination.pageSize) : Math.ceil((data?.total || 0) / pagination.pageSize), }) const pageCount = table.getPageCount() useEffect(() => { ensurePageInRange(pageCount) }, [pageCount, ensurePageInRange]) return ( <>
{isMobile ? ( ) : (
{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( {header.isPlaceholder ? null : flexRender( header.column.columnDef.header, header.getContext() )} ))} ))} {isLoading ? ( ) : table.getRowModel().rows.length === 0 ? ( ) : ( table.getRowModel().rows.map((row) => ( {row.getVisibleCells().map((cell) => ( {flexRender( cell.column.columnDef.cell, cell.getContext() )} ))} )) )}
)} {!isMobile && }
) }