import React, { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useAppContext } from '../context/AppContext'; 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; error?: 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 [draft, setDraft] = useState({ id: '', content: '', priority: 'normal', status: 'todo', source: 'manual', due_at: '' }); const [dailyReport, setDailyReport] = useState(''); const [reportDate, setReportDate] = useState(new Date().toISOString().slice(0,10)); 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]); const rq = q ? `${q}&date=${encodeURIComponent(reportDate)}` : `?date=${encodeURIComponent(reportDate)}`; const dr = await fetch(`/webui/api/task_daily_summary${rq}`); if (dr.ok) { const dj = await dr.json(); setDailyReport(String(dj.report || '')); } else { setDailyReport(''); } } catch (e) { console.error(e); setItems([]); setSelected(null); } finally { setLoading(false); } }; useEffect(() => { fetchData(); }, [q, reportDate]); const exportDailyReport = () => { const content = dailyReport || ''; const blob = new Blob([content], { type: 'text/markdown;charset=utf-8' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `autonomy-daily-${reportDate}.md`; a.click(); URL.revokeObjectURL(url); }; 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 taskAction = async (action: 'pause'|'retry'|'complete'|'ignore') => { if (!selected?.task_id) return; try { const url = `/webui/api/task_queue${q}`; const r = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action, task_id: selected.task_id }) }); if (!r.ok) throw new Error(await r.text()); await fetchData(); } catch (e) { console.error(e); } }; const resetDraftForNew = () => { setSelected(null); setDraft({ id: '', content: '', priority: 'normal', status: 'todo', source: 'manual', due_at: '' }); }; const saveTask = async (action: 'create'|'update'|'delete') => { try { const url = `/webui/api/tasks${q}`; const payload: any = { action }; if (action === 'create') payload.item = draft; if (action === 'update') { payload.id = draft.id; payload.item = draft; } if (action === 'delete') payload.id = draft.id; const r = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!r.ok) throw new Error(await r.text()); await fetchData(); } catch (e) { console.error(e); } }; const selectedPretty = useMemo(() => selected ? JSON.stringify(selected, null, 2) : '', [selected]); return (

{t('taskAudit')}

{t('dailySummary')}
setReportDate(e.target.value)} className="px-2 py-1 rounded bg-zinc-900 border border-zinc-700 text-xs" />
{dailyReport || t('noDailySummary')}
{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('taskCrud')} {selected ? `(${selected.task_id || selected.id || ''})` : '(new)'}
setDraft({ ...draft, id: e.target.value })} placeholder="id" className="w-full px-2 py-1 text-xs bg-zinc-900 border border-zinc-700 rounded" />