import { useMemo, useState } from 'react'
import { ListTodo, SearchIcon } from 'lucide-react'
import { DataGridMutedCell, DataGridNameCell } from '@/components/data-grid-cell'
import { StatusBadge } from '@/components/status-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 { Badge } from '@/components/reui/badge'
import { isRefreshJobKind, jobKindRu, jobSubtitleRu, jobTriggerRu } from '@/lib/ui-labels'
import type { JobRow } from '@/types/api'
const FAILED_STATUSES = ['failed', 'error', 'cancelled']
const filterFields: FilterField[] = [
{
id: 'search',
label: 'Поиск',
icon: ,
type: 'text',
placeholder: 'Поиск задач…',
},
]
function tabFilter(item: JobRow, tabId: string): boolean {
if (tabId === 'refresh') return isRefreshJobKind(item.kind)
if (tabId === 'failed') return FAILED_STATUSES.includes(item.status.toLowerCase())
return true
}
export function ScheduleJobsGrid({
items,
nameById = new Map(),
isLoading = false,
}: {
items: JobRow[]
nameById?: Map
isLoading?: boolean
}) {
const [filterQuery, setFilterQuery] = useState(() =>
createTextFilterQuery('search'),
)
const tabs = useMemo(
() => [
{ id: 'all', label: 'Все', count: items.length },
{
id: 'refresh',
label: 'Обновление',
count: items.filter((job) => isRefreshJobKind(job.kind)).length,
},
{
id: 'failed',
label: 'С ошибкой',
count: items.filter((job) => FAILED_STATUSES.includes(job.status.toLowerCase())).length,
},
],
[items],
)
const columns = useMemo[]>(
() => [
{
accessorKey: 'kind',
header: ({ column }) => ,
cell: ({ row }) => {
const trigger = jobTriggerRu(row.original.meta?.trigger)
return (
{jobKindRu(row.original.kind)}
{trigger ? (
{trigger}
) : null}
}
subtitle={jobSubtitleRu(row.original.kind, row.original.meta, nameById)}
/>
)
},
meta: { headerTitle: 'Вид' },
},
{
accessorKey: 'status',
header: ({ column }) => ,
cell: ({ row }) => {
const finished = row.original.finished_at
const hint = finished
? new Date(finished).toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' })
: undefined
return
},
meta: { headerTitle: 'Статус' },
},
{
id: 'created_at',
accessorFn: (row) => row.created_at ?? '',
header: ({ column }) => ,
cell: ({ row }) => (
{row.original.created_at
? new Date(row.original.created_at).toLocaleString('ru-RU')
: '—'}
),
meta: { headerTitle: 'Создана' },
},
{
id: 'finished_at',
accessorFn: (row) => row.finished_at ?? '',
header: ({ column }) => ,
cell: ({ row }) => (
{row.original.finished_at
? new Date(row.original.finished_at).toLocaleString('ru-RU')
: '—'}
),
meta: { headerTitle: 'Завершена' },
},
{
accessorKey: 'error',
enableSorting: false,
header: 'Ошибка',
cell: ({ row }) => (
{row.original.error ?? ''}
),
meta: { headerTitle: 'Ошибка' },
},
],
[nameById],
)
return (
setFilterQuery(createTextFilterQuery('search'))}
getFilterFieldValue={(item, field) => {
if (field !== 'search') return undefined
const subtitle = jobSubtitleRu(item.kind, item.meta, nameById)
const trigger = jobTriggerRu(item.meta?.trigger)
return `${jobKindRu(item.kind)} ${item.status} ${item.error ?? ''} ${item.job_id} ${subtitle ?? ''} ${trigger ?? ''}`
}}
columns={columns}
data={items}
getRowId={(row) => row.job_id}
isLoading={isLoading}
virtualization={items.length > 80}
emptyState={{ title: 'Нет задач в выборке' }}
/>
)
}