refactor(admin): split dsfa, audit-llm, quality pages

Extract components and hooks from oversized page files (563/561/520 LOC)
into colocated _components/ and _hooks/ subdirectories. All three
page.tsx files are now thin orchestrators under 300 LOC each
(dsfa: 216, audit-llm: 121, quality: 163). Zero behavior changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-04-16 13:20:17 +02:00
parent 653fa07f57
commit 519ffdc8dc
16 changed files with 1246 additions and 1206 deletions

View File

@@ -0,0 +1,94 @@
'use client'
import { useState, useCallback } from 'react'
import { API_BASE, getDateRange, type LLMLogEntry, type UsageStats, type ComplianceReport } from '../_components/types'
export function useAuditData(period: string, logFilter: { model: string; pii: string }) {
const [logEntries, setLogEntries] = useState<LLMLogEntry[]>([])
const [usageStats, setUsageStats] = useState<UsageStats | null>(null)
const [complianceReport, setComplianceReport] = useState<ComplianceReport | null>(null)
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const loadLLMLog = useCallback(async () => {
setLoading(true)
setError(null)
try {
const { from, to } = getDateRange(period)
const params = new URLSearchParams({ from, to, limit: '100' })
if (logFilter.model) params.set('model', logFilter.model)
if (logFilter.pii === 'true') params.set('pii_detected', 'true')
if (logFilter.pii === 'false') params.set('pii_detected', 'false')
const res = await fetch(`${API_BASE}/llm?${params}`)
if (!res.ok) throw new Error(`HTTP ${res.status}`)
const data = await res.json()
setLogEntries(Array.isArray(data) ? data : data.entries || data.logs || [])
} catch (e) {
setError(e instanceof Error ? e.message : 'Fehler beim Laden')
} finally {
setLoading(false)
}
}, [period, logFilter])
const loadUsage = useCallback(async () => {
setLoading(true)
setError(null)
try {
const { from, to } = getDateRange(period)
const res = await fetch(`${API_BASE}/usage?from=${from}&to=${to}`)
if (!res.ok) throw new Error(`HTTP ${res.status}`)
const data = await res.json()
setUsageStats(data)
} catch (e) {
setError(e instanceof Error ? e.message : 'Fehler beim Laden')
} finally {
setLoading(false)
}
}, [period])
const loadCompliance = useCallback(async () => {
setLoading(true)
setError(null)
try {
const { from, to } = getDateRange(period)
const res = await fetch(`${API_BASE}/compliance-report?from=${from}&to=${to}`)
if (!res.ok) throw new Error(`HTTP ${res.status}`)
const data = await res.json()
setComplianceReport(data)
} catch (e) {
setError(e instanceof Error ? e.message : 'Fehler beim Laden')
} finally {
setLoading(false)
}
}, [period])
const handleExport = useCallback(async (type: 'llm' | 'general' | 'compliance', format: 'json' | 'csv') => {
try {
const { from, to } = getDateRange(period)
const res = await fetch(`${API_BASE}/export/${type}?from=${from}&to=${to}&format=${format}`)
if (!res.ok) throw new Error(`Export fehlgeschlagen: ${res.status}`)
const blob = await res.blob()
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `audit-${type}-${from}-${to}.${format}`
a.click()
URL.revokeObjectURL(url)
} catch (e) {
setError(e instanceof Error ? e.message : 'Export fehlgeschlagen')
}
}, [period])
return {
logEntries,
usageStats,
complianceReport,
loading,
error,
loadLLMLog,
loadUsage,
loadCompliance,
handleExport,
}
}