feat: composant SyncHistory
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,78 @@
|
|||||||
|
'use client'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import React from 'react'
|
||||||
|
import type { SyncHistoryEntry } from '@/types/sync'
|
||||||
|
|
||||||
|
interface SyncHistoryProps {
|
||||||
|
entries: SyncHistoryEntry[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const STATUS_STYLE = {
|
||||||
|
success: 'text-green-400',
|
||||||
|
partial: 'text-yellow-400',
|
||||||
|
error: 'text-red-400',
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SyncHistory({ entries }: SyncHistoryProps) {
|
||||||
|
const [expandedId, setExpandedId] = useState<string | null>(null)
|
||||||
|
|
||||||
|
if (entries.length === 0) {
|
||||||
|
return <p className="text-slate-600 text-sm text-center py-6">Aucune synchronisation effectuée.</p>
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="border border-slate-700 rounded-xl overflow-hidden">
|
||||||
|
<table className="w-full text-xs">
|
||||||
|
<thead className="bg-slate-800 text-slate-400">
|
||||||
|
<tr>
|
||||||
|
<th className="px-3 py-2 text-left">Date</th>
|
||||||
|
<th className="px-3 py-2 text-left">Utilisateur</th>
|
||||||
|
<th className="px-3 py-2 text-right">Créés</th>
|
||||||
|
<th className="px-3 py-2 text-right">MàJ</th>
|
||||||
|
<th className="px-3 py-2 text-right">Désactivés</th>
|
||||||
|
<th className="px-3 py-2 text-right">Erreurs</th>
|
||||||
|
<th className="px-3 py-2 text-left">Statut</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{entries.map((entry) => (
|
||||||
|
<React.Fragment key={entry.id}>
|
||||||
|
<tr
|
||||||
|
onClick={() => setExpandedId(expandedId === entry.id ? null : entry.id)}
|
||||||
|
className="border-t border-slate-800 hover:bg-slate-800/50 cursor-pointer"
|
||||||
|
>
|
||||||
|
<td className="px-3 py-2 text-slate-400">
|
||||||
|
{new Date(entry.createdAt).toLocaleString('fr-FR', {
|
||||||
|
day: '2-digit', month: '2-digit', year: '2-digit',
|
||||||
|
hour: '2-digit', minute: '2-digit',
|
||||||
|
})}
|
||||||
|
</td>
|
||||||
|
<td className="px-3 py-2 text-slate-300">{entry.userName}</td>
|
||||||
|
<td className="px-3 py-2 text-right text-green-400">{entry.created}</td>
|
||||||
|
<td className="px-3 py-2 text-right text-blue-400">{entry.updated}</td>
|
||||||
|
<td className="px-3 py-2 text-right text-red-400">{entry.deactivated}</td>
|
||||||
|
<td className="px-3 py-2 text-right text-yellow-400">{entry.errors || '—'}</td>
|
||||||
|
<td className={`px-3 py-2 font-semibold ${STATUS_STYLE[entry.status]}`}>
|
||||||
|
{entry.status}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{expandedId === entry.id && (
|
||||||
|
<tr className="border-t border-slate-800 bg-slate-950">
|
||||||
|
<td colSpan={7} className="px-3 py-3">
|
||||||
|
<div className="font-mono text-xs max-h-32 overflow-y-auto space-y-0.5">
|
||||||
|
{entry.log.map((l, i) => (
|
||||||
|
<p key={i} className={l.status === 'error' ? 'text-red-400' : 'text-slate-400'}>
|
||||||
|
{l.message}
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user