import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { Play, Trash2, Plus } from 'lucide-react'; import toast from 'react-hot-toast'; import { adminApi } from '../../api/client'; interface Source { id: number; source_type: string; name: string; query: string | null; lang: string | null; year_from: number | null; year_to: number | null; limit: number; enabled: boolean; last_status: string; last_error: string | null; last_run_at: string | null; docs_added: number; } const STATUS_COLORS: Record = { idle: 'bg-gray-100 text-gray-600', running: 'bg-blue-100 text-blue-700', done: 'bg-emerald-100 text-emerald-700', error: 'bg-red-100 text-red-700', }; export function Sources() { const qc = useQueryClient(); const [form, setForm] = useState({ source_type: 'openalex', name: '', query: '', lang: '', limit: 100 }); const { data: sources } = useQuery({ queryKey: ['admin-sources'], queryFn: () => adminApi.sources().then((r) => r.data as Source[]), refetchInterval: 5000, }); const create = useMutation({ mutationFn: (data: Record) => adminApi.createSource(data), onSuccess: () => { qc.invalidateQueries({ queryKey: ['admin-sources'] }); toast.success('Источник добавлен'); setForm({ source_type: 'openalex', name: '', query: '', lang: '', limit: 100 }); }, onError: (e: any) => toast.error(e.response?.data?.detail || 'Ошибка'), }); const run = useMutation({ mutationFn: (id: number) => adminApi.runSource(id), onSuccess: () => { qc.invalidateQueries({ queryKey: ['admin-sources'] }); toast.success('Парсинг запущен'); }, onError: (e: any) => toast.error(e.response?.data?.detail || 'Ошибка'), }); const del = useMutation({ mutationFn: (id: number) => adminApi.deleteSource(id), onSuccess: () => { qc.invalidateQueries({ queryKey: ['admin-sources'] }); toast.success('Удалён'); }, }); return (

Источники парсинга

{/* Форма добавления */}

Добавить источник

setForm({ ...form, name: e.target.value })} placeholder="Название" className="border border-gray-200 rounded-lg px-3 py-2 text-sm" /> setForm({ ...form, query: e.target.value })} placeholder="Запрос" className="border border-gray-200 rounded-lg px-3 py-2 text-sm" /> setForm({ ...form, lang: e.target.value })} placeholder="Язык (ru/en)" className="border border-gray-200 rounded-lg px-3 py-2 text-sm" /> setForm({ ...form, limit: Number(e.target.value) })} placeholder="Лимит" className="border border-gray-200 rounded-lg px-3 py-2 text-sm" />
{/* Список */}
{sources?.map((s) => ( ))}
НазваниеТип ЗапросЛимит СтатусДобавлено
{s.name} {s.source_type} {s.query || '—'} {s.limit} {s.last_status} {s.docs_added}
{!sources?.length &&
Нет источников
}
); }