/** * Tasks page - Task Queue monitoring */ import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { getTasks, getWorkerStatus, retryTask, deleteTask } from '../api/organizations'; import { TaskStatus } from '../types/organization'; import { Modal, ConfirmModal } from '../components/Modal'; import { formatDistanceToNow } from 'date-fns'; import { ru } from 'date-fns/locale'; export default function Tasks() { const queryClient = useQueryClient(); const [statusFilter, setStatusFilter] = useState(); // Modal states const [modalMessage, setModalMessage] = useState(''); const [showModal, setShowModal] = useState(false); const [confirmAction, setConfirmAction] = useState<(() => void) | null>(null); const [confirmMessage, setConfirmMessage] = useState(''); const [showConfirm, setShowConfirm] = useState(false); const { data: tasksData, isLoading } = useQuery({ queryKey: ['tasks', statusFilter], queryFn: () => getTasks(statusFilter), refetchInterval: 5000, // Обновление каждые 5 секунд }); const { data: workerStatus } = useQuery({ queryKey: ['workerStatus'], queryFn: getWorkerStatus, refetchInterval: 5000, }); const retryMutation = useMutation({ mutationFn: retryTask, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['tasks'] }); setModalMessage('✅ Задача поставлена в очередь повторно'); setShowModal(true); }, onError: (error: Error) => { setModalMessage(`❌ Ошибка: ${error.message}`); setShowModal(true); }, }); const deleteMutation = useMutation({ mutationFn: deleteTask, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['tasks'] }); setModalMessage('✅ Задача удалена'); setShowModal(true); }, onError: (error: Error) => { setModalMessage(`❌ Ошибка: ${error.message}`); setShowModal(true); }, }); const handleRetry = (taskId: number) => { setConfirmMessage('Повторить выполнение задачи?'); setConfirmAction(() => () => retryMutation.mutate(taskId)); setShowConfirm(true); }; const handleDelete = (taskId: number) => { setConfirmMessage('Удалить задачу из очереди?'); setConfirmAction(() => () => deleteMutation.mutate(taskId)); setShowConfirm(true); }; const getStatusColor = (status: TaskStatus) => { switch (status) { case 'pending': return 'bg-yellow-100 text-yellow-800'; case 'in_progress': return 'bg-blue-100 text-blue-800'; case 'completed': return 'bg-green-100 text-green-800'; case 'failed': return 'bg-red-100 text-red-800'; default: return 'bg-gray-100 text-gray-800'; } }; const getStatusLabel = (status: TaskStatus) => { switch (status) { case 'pending': return '⏳ Ожидает'; case 'in_progress': return '⚙️ Выполняется'; case 'completed': return '✅ Завершено'; case 'failed': return '❌ Ошибка'; default: return status; } }; const getPriorityColor = (priority: string) => { switch (priority) { case 'high': return 'bg-red-100 text-red-800'; case 'normal': return 'bg-gray-100 text-gray-800'; case 'low': return 'bg-green-100 text-green-800'; default: return 'bg-gray-100 text-gray-800'; } }; if (isLoading) { return (
Загрузка...
); } return (
{/* Header */}

Очередь задач

Мониторинг и управление задачами на review

{/* Worker Status */} {workerStatus && (
{workerStatus.running ? '🚀 Worker активен' : '⏹️ Worker остановлен'}
{workerStatus.current_task_id && ( Обрабатывается задача #{workerStatus.current_task_id} )} {!workerStatus.current_task_id && workerStatus.running && ( Ожидание задач... )}
)} {/* Stats */} {tasksData && (
setStatusFilter(undefined)} >
{tasksData.total}
Всего
setStatusFilter('pending')} >
{tasksData.pending}
Ожидает
setStatusFilter('in_progress')} >
{tasksData.in_progress}
Выполняется
setStatusFilter('completed')} >
{tasksData.completed}
Завершено
setStatusFilter('failed')} >
{tasksData.failed}
Ошибок
)} {/* Tasks List */}
{tasksData?.items.map((task) => (
#{task.id} {getStatusLabel(task.status)} {task.priority === 'high' && '🔴 Высокий'} {task.priority === 'normal' && '⚪ Обычный'} {task.priority === 'low' && '🟢 Низкий'}
PR:{' '} #{task.pr_number}{' '} {task.pr_title}
Создано: {formatDistanceToNow(new Date(task.created_at), { addSuffix: true, locale: ru })} {task.started_at && ( Начато: {formatDistanceToNow(new Date(task.started_at), { addSuffix: true, locale: ru })} )} {task.completed_at && ( Завершено: {formatDistanceToNow(new Date(task.completed_at), { addSuffix: true, locale: ru })} )}
{task.error_message && (
Ошибка: {task.error_message}
)} {task.retry_count > 0 && (
Попыток: {task.retry_count} / {task.max_retries}
)}
{(task.status === 'failed' || task.status === 'completed') && ( )} {task.status !== 'in_progress' && ( )}
))}
{tasksData?.items.length === 0 && (

{statusFilter ? `Нет задач со статусом "${statusFilter}"` : 'Нет задач в очереди'}

)} {/* Modals */} setShowModal(false)} title={modalMessage.includes('❌') ? 'Ошибка' : modalMessage.includes('✅') ? 'Успешно' : 'Уведомление'} type={modalMessage.includes('❌') ? 'error' : modalMessage.includes('✅') ? 'success' : 'info'} >

{modalMessage}

setShowConfirm(false)} onConfirm={() => { if (confirmAction) confirmAction(); setShowConfirm(false); }} title="Подтверждение" message={confirmMessage} />
); }