feat(cc-050): AI Execution History page

This commit is contained in:
admin-valentin 2026-08-01 09:57:55 +00:00
parent c92d3a81b5
commit 58b8a5f9ba

View file

@ -0,0 +1,96 @@
'use client';
import { useQuery } from '@tanstack/react-query';
import { apiFetch } from '../../../../lib/api';
import type { AiRequest } from '../../../../lib/api';
import { useSession } from '../../../../components/session-provider';
export default function AiHistoryPage() {
const { activeTenant } = useSession();
const tenantId = activeTenant?.tenantId ?? '';
const { data: requests = [], isLoading } = useQuery({
queryKey: ['ai-requests', tenantId],
queryFn: () => apiFetch<AiRequest[]>('/v1/ai-requests?limit=200', { tenantId }),
enabled: Boolean(tenantId),
staleTime: 30_000,
});
function statusClass(status: string) {
switch (status) {
case 'completed': return 'bg-signal-ok text-white';
case 'failed': return 'bg-signal-danger text-white';
case 'pending': return 'bg-bronze-wash text-bronze-deep';
default: return 'bg-paper-sunken text-ink-faint';
}
}
return (
<div className="max-w-5xl space-y-6">
<div>
<h1 className="font-display text-2xl font-semibold text-ink">Istoric Execuții AI</h1>
<p className="mt-1 text-sm text-ink-faint">
Toate cererile AI înregistrate pentru workspace {' '}
{isLoading ? '…' : `${requests.length} cereri`}
</p>
</div>
{isLoading ? (
<p className="text-sm text-ink-faint">Se încarcă</p>
) : requests.length === 0 ? (
<div className="card p-10 text-center">
<p className="text-sm font-medium text-ink">Nicio cerere AI înregistrată</p>
<p className="mt-1 text-xs text-ink-faint">
Cererile AI sunt înregistrate automat la utilizare.
</p>
</div>
) : (
<div className="card overflow-hidden">
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-paper-sunken text-left">
<th className="px-4 py-3 text-xs font-medium text-ink-faint">Data</th>
<th className="px-4 py-3 text-xs font-medium text-ink-faint">Scop</th>
<th className="px-4 py-3 text-xs font-medium text-ink-faint">Model</th>
<th className="px-4 py-3 text-xs font-medium text-ink-faint">Clasă acțiune</th>
<th className="px-4 py-3 text-right text-xs font-medium text-ink-faint">Cost USD</th>
<th className="px-4 py-3 text-xs font-medium text-ink-faint">Status</th>
</tr>
</thead>
<tbody>
{requests.map((req) => (
<tr key={req.id} className="border-b border-paper-sunken last:border-0 hover:bg-paper-sunken/50 transition-colors">
<td className="px-4 py-2.5 font-mono text-[11px] text-ink-faint whitespace-nowrap">
{new Date(req.createdAt).toLocaleString('ro-RO', {
month: 'short', day: 'numeric',
hour: '2-digit', minute: '2-digit',
})}
</td>
<td className="max-w-[200px] px-4 py-2.5">
<p className="truncate text-sm text-ink capitalize">{req.purpose.replace(/_/g, ' ')}</p>
</td>
<td className="px-4 py-2.5 font-mono text-[11px] text-ink-faint">{req.model}</td>
<td className="px-4 py-2.5">
<span className="rounded bg-paper-sunken px-1.5 py-0.5 font-mono text-[10px] text-ink-faint">
{req.actionClass}
</span>
</td>
<td className="px-4 py-2.5 text-right font-mono text-xs text-ink">
{req.costUsd ? `$${Number(req.costUsd).toFixed(4)}` : '—'}
</td>
<td className="px-4 py-2.5">
<span className={`rounded-full px-2 py-0.5 text-[10px] font-medium ${statusClass(req.resultStatus)}`}>
{req.resultStatus}
</span>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
</div>
);
}