Refactor UI modules and harden run/API behavior
This commit is contained in:
88
ui/src/pages/History.tsx
Normal file
88
ui/src/pages/History.tsx
Normal file
@@ -0,0 +1,88 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { History as HistoryIcon, RefreshCw } from 'lucide-react';
|
||||
|
||||
const History: React.FC = () => {
|
||||
const [runs, setRuns] = useState<any[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const fetchHistory = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await fetch('/api/sessions');
|
||||
const data = await res.json();
|
||||
if (data.ok) {
|
||||
// Sort by descending update time (assuming default or simple sort needed)
|
||||
const sortedRuns = (data.runs || []).sort((a: any, b: any) => {
|
||||
return new Date(b.updatedAt || 0).getTime() - new Date(a.updatedAt || 0).getTime();
|
||||
});
|
||||
setRuns(sortedRuns);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to fetch history', e);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchHistory();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="fade-in">
|
||||
<section className="panel">
|
||||
<div className="panel-header">
|
||||
<h2 className="panel-title">
|
||||
<HistoryIcon size={18} className="text-secondary" /> Run History
|
||||
</h2>
|
||||
<button className="primary" onClick={fetchHistory} disabled={loading}>
|
||||
<RefreshCw size={14} className={loading ? 'animate-spin' : ''} /> Refresh
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-left border-collapse">
|
||||
<thead>
|
||||
<tr className="border-b border-color text-subtle">
|
||||
<th className="p-3 font-medium">Session ID</th>
|
||||
<th className="p-3 font-medium">Status</th>
|
||||
<th className="p-3 font-medium">Attempts</th>
|
||||
<th className="p-3 font-medium">Updated</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{runs.length === 0 ? (
|
||||
<tr>
|
||||
<td className="p-3" colSpan={4}>
|
||||
<div className="text-center py-8 text-subtle">
|
||||
{loading ? 'Loading...' : 'No run history available.'}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
runs.map((run: any) => {
|
||||
const dateStr = run.updatedAt ? new Date(run.updatedAt).toLocaleString() : 'N/A';
|
||||
let statusColor = 'text-subtle';
|
||||
if (run.status === 'success') statusColor = 'text-success';
|
||||
if (run.status === 'failure' || run.status === 'cancelled') statusColor = 'text-danger';
|
||||
if (run.status === 'validation_fail') statusColor = 'text-warning';
|
||||
|
||||
return (
|
||||
<tr key={run.id} className="border-b border-color hover:bg-highlight transition-colors">
|
||||
<td className="p-3 font-mono text-sm">{run.sessionId || 'N/A'}</td>
|
||||
<td className={`p-3 font-medium ${statusColor}`}>{run.status || 'unknown'}</td>
|
||||
<td className="p-3">{run.attempts ?? 0}</td>
|
||||
<td className="p-3 text-sm text-subtle">{dateStr}</td>
|
||||
</tr>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default History;
|
||||
Reference in New Issue
Block a user