import React, { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useAppContext } from '../context/AppContext'; import { formatLocalDateTime } from '../utils/time'; type TaskAuditItem = { task_id?: string; time?: string; channel?: string; session?: string; chat_id?: string; sender_id?: string; status?: string; source?: string; idle_run?: boolean; block_reason?: string; last_pause_reason?: string; last_pause_at?: string; duration_ms?: number; retry_count?: number; attempts?: number; error?: string; provider?: string; model?: string; input_preview?: string; logs?: string[]; media_items?: Array<{ source?: string; type?: string; ref?: string; path?: string; channel?: string }>; [key: string]: any; }; const TaskAudit: React.FC = () => { const { t } = useTranslation(); const { q } = useAppContext(); const [items, setItems] = useState([]); const [selected, setSelected] = useState(null); const [loading, setLoading] = useState(false); const [sourceFilter, setSourceFilter] = useState('all'); const [statusFilter, setStatusFilter] = useState('all'); const fetchData = async () => { setLoading(true); try { const url = `/webui/api/task_queue${q ? `${q}&limit=300` : '?limit=300'}`; const r = await fetch(url); if (!r.ok) throw new Error(await r.text()); const j = await r.json(); const arr = Array.isArray(j.items) ? j.items : []; const sorted = arr.sort((a: any, b: any) => String(b.time || '').localeCompare(String(a.time || ''))); setItems(sorted); if (sorted.length > 0) setSelected(sorted[0]); } catch (e) { console.error(e); setItems([]); setSelected(null); } finally { setLoading(false); } }; useEffect(() => { fetchData(); }, [q]); const filteredItems = useMemo(() => items.filter((it) => { if (sourceFilter !== 'all' && String(it.source || '-') !== sourceFilter) return false; if (statusFilter !== 'all' && String(it.status || '-') !== statusFilter) return false; return true; }), [items, sourceFilter, statusFilter]); const selectedPretty = useMemo(() => selected ? JSON.stringify(selected, null, 2) : '', [selected]); return (

{t('taskAudit')}

{t('taskQueue')}
{filteredItems.length === 0 ? (
{t('noTaskAudit')}
) : filteredItems.map((it, idx) => { const active = selected?.task_id === it.task_id && selected?.time === it.time; return ( ); })}
{t('taskDetail')}
{!selected ? (
{t('selectTask')}
) : ( <>
{t('taskId')}
{selected.task_id}
{t('status')}
{selected.status}
{t('source')}
{selected.source || '-'}
{t('duration')}
{selected.duration_ms || 0}ms
{t('channel')}
{selected.channel}
{t('session')}
{selected.session}
{t('provider')}
{selected.provider || '-'}
{t('model')}
{selected.model || '-'}
{t('time')}
{formatLocalDateTime(selected.time)}
{t('inputPreview')}
{selected.input_preview || '-'}
{t('error')}
{selected.error || '-'}
{t('blockReason')}
{selected.block_reason || '-'}
{t('lastPauseReason')}
{selected.last_pause_reason || '-'}
{t('lastPauseAt')}
{formatLocalDateTime(selected.last_pause_at)}
{t('taskLogs')}
{Array.isArray(selected.logs) && selected.logs.length ? selected.logs.join('\n') : '-'}
{t('mediaSources')}
{Array.isArray(selected.media_items) && selected.media_items.length > 0 ? (
{selected.media_items.map((m, i) => (
[{m.channel || '-'}] {m.source || '-'} / {m.type || '-'} · {m.path || m.ref || '-'}
))}
) : '-'}
{t('rawJson')}
{selectedPretty}
)}
); }; export default TaskAudit;