Some checks failed
Build + Deploy / build-admin-compliance (push) Failing after 34s
Build + Deploy / build-developer-portal (push) Successful in 56s
Build + Deploy / build-tts (push) Successful in 1m8s
CI/CD / go-lint (push) Has been skipped
Build + Deploy / trigger-orca (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Successful in 38s
CI/CD / test-python-backend-compliance (push) Successful in 32s
Build + Deploy / build-backend-compliance (push) Successful in 7s
Build + Deploy / build-ai-sdk (push) Successful in 7s
Build + Deploy / build-document-crawler (push) Successful in 33s
Build + Deploy / build-dsms-gateway (push) Successful in 20s
CI/CD / test-python-dsms-gateway (push) Has been cancelled
CI/CD / validate-canonical-controls (push) Has been cancelled
CI/CD / test-python-document-crawler (push) Has been cancelled
All 8 components imported by app/sdk/training/page.tsx were missing. Docker build was failing with Module not found errors. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
74 lines
3.0 KiB
TypeScript
74 lines
3.0 KiB
TypeScript
'use client'
|
|
|
|
import type { AuditLogEntry } from '@/lib/sdk/training/types'
|
|
|
|
const ACTION_LABELS: Record<string, string> = {
|
|
assigned: 'Zugewiesen',
|
|
started: 'Gestartet',
|
|
completed: 'Abgeschlossen',
|
|
quiz_submitted: 'Quiz eingereicht',
|
|
escalated: 'Eskaliert',
|
|
certificate_issued: 'Zertifikat ausgestellt',
|
|
content_generated: 'Content generiert',
|
|
}
|
|
|
|
const ACTION_COLORS: Record<string, string> = {
|
|
assigned: 'bg-blue-100 text-blue-700',
|
|
started: 'bg-yellow-100 text-yellow-700',
|
|
completed: 'bg-green-100 text-green-700',
|
|
quiz_submitted: 'bg-purple-100 text-purple-700',
|
|
escalated: 'bg-red-100 text-red-700',
|
|
certificate_issued: 'bg-emerald-100 text-emerald-700',
|
|
content_generated: 'bg-gray-100 text-gray-700',
|
|
}
|
|
|
|
export default function AuditTab({ auditLog }: { auditLog: AuditLogEntry[] }) {
|
|
return (
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<p className="text-sm text-gray-500">{auditLog.length} Eintraege</p>
|
|
</div>
|
|
|
|
{auditLog.length === 0 ? (
|
|
<div className="text-center py-12 text-gray-500 text-sm">Keine Audit-Eintraege gefunden.</div>
|
|
) : (
|
|
<div className="bg-white border rounded-lg overflow-hidden">
|
|
<table className="w-full text-sm">
|
|
<thead className="bg-gray-50">
|
|
<tr>
|
|
<th className="px-4 py-3 text-left font-medium text-gray-600">Zeitpunkt</th>
|
|
<th className="px-4 py-3 text-left font-medium text-gray-600">Aktion</th>
|
|
<th className="px-4 py-3 text-left font-medium text-gray-600">Entitaet</th>
|
|
<th className="px-4 py-3 text-left font-medium text-gray-600">Details</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody className="divide-y">
|
|
{auditLog.map(entry => (
|
|
<tr key={entry.id} className="hover:bg-gray-50">
|
|
<td className="px-4 py-3 text-xs text-gray-500 whitespace-nowrap">
|
|
{new Date(entry.created_at).toLocaleString('de-DE')}
|
|
</td>
|
|
<td className="px-4 py-3">
|
|
<span className={`text-xs px-2 py-0.5 rounded-full ${ACTION_COLORS[entry.action] ?? 'bg-gray-100 text-gray-700'}`}>
|
|
{ACTION_LABELS[entry.action] ?? entry.action}
|
|
</span>
|
|
</td>
|
|
<td className="px-4 py-3 text-xs text-gray-600">
|
|
<span className="font-medium">{entry.entity_type}</span>
|
|
{entry.entity_id && <span className="ml-1 text-gray-400">{entry.entity_id.slice(0, 8)}</span>}
|
|
</td>
|
|
<td className="px-4 py-3 text-xs text-gray-500 max-w-xs truncate">
|
|
{Object.keys(entry.details).length > 0
|
|
? Object.entries(entry.details).map(([k, v]) => `${k}: ${v}`).join(', ')
|
|
: '—'}
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|