'use client' import React, { useMemo, useState, useRef, useEffect } from 'react' import { SearchInput, FilterDropdown, Pagination, ExternalLinkIcon } from './LibraryTable' export interface CEDocument { regulation_id: string name_de: string name_en: string category: string source_url: string source_org: string chunk_count: number } const PER_PAGE = 50 const CATEGORY_LABELS: Record = { trbs: 'TRBS — Betriebssicherheit', trgs: 'TRGS — Gefahrstoffe', asr: 'ASR — Arbeitsstaetten', osha: 'OSHA — US Occupational Safety', ce_machinery: 'EU — Maschinenrecht', ce_machinery_guidance: 'EU — Leitfaeden', ce_electrical: 'EU — Niederspannung', ce_emc: 'EU — EMV', ce_radio: 'EU — Funkanlagen', ce_ai: 'EU — KI-Verordnung', ce_ai_safety: 'KI-Sicherheit', ce_software_safety: 'Software-Sicherheit', ce_software_security: 'Software-Security', ce_software_weaknesses: 'Software-Schwachstellen', ce_ot_cybersecurity: 'OT-Cybersecurity', eu_recht: 'EU-Recht', eu_datenschutz: 'EU-Datenschutz', guidance: 'Guidance', } function categoryLabel(cat: string): string { return CATEGORY_LABELS[cat] || cat.replace(/_/g, ' ') } function categoryColor(cat: string): string { if (cat.startsWith('trbs')) return 'bg-orange-100 text-orange-800 dark:bg-orange-900/40 dark:text-orange-300' if (cat.startsWith('trgs')) return 'bg-red-100 text-red-800 dark:bg-red-900/40 dark:text-red-300' if (cat.startsWith('asr')) return 'bg-teal-100 text-teal-800 dark:bg-teal-900/40 dark:text-teal-300' if (cat === 'osha') return 'bg-blue-100 text-blue-800 dark:bg-blue-900/40 dark:text-blue-300' if (cat.startsWith('ce_')) return 'bg-purple-100 text-purple-800 dark:bg-purple-900/40 dark:text-purple-300' if (cat.startsWith('eu_')) return 'bg-indigo-100 text-indigo-800 dark:bg-indigo-900/40 dark:text-indigo-300' return 'bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-300' } interface Props { documents: CEDocument[] loading?: boolean } export default function DokumenteTab({ documents, loading }: Props) { const [search, setSearch] = useState('') const [debounced, setDebounced] = useState('') const [categoryFilter, setCategoryFilter] = useState('') const [page, setPage] = useState(1) const timer = useRef | null>(null) useEffect(() => { timer.current = setTimeout(() => setDebounced(search), 300) return () => { if (timer.current) clearTimeout(timer.current) } }, [search]) useEffect(() => { setPage(1) }, [debounced, categoryFilter]) const categories = useMemo(() => { const cats = new Set(documents.map((d) => d.category)) const opts = [{ value: '', label: 'Alle Kategorien' }] Array.from(cats).sort().forEach((c) => opts.push({ value: c, label: categoryLabel(c) })) return opts }, [documents]) const filtered = useMemo(() => { const q = debounced.toLowerCase() return documents.filter((d) => { if (categoryFilter && d.category !== categoryFilter) return false if (q) { const hay = `${d.regulation_id} ${d.name_de} ${d.name_en} ${d.source_org}`.toLowerCase() if (!hay.includes(q)) return false } return true }) }, [documents, debounced, categoryFilter]) const totalPages = Math.ceil(filtered.length / PER_PAGE) const pageItems = filtered.slice((page - 1) * PER_PAGE, page * PER_PAGE) const totalChunks = filtered.reduce((sum, d) => sum + d.chunk_count, 0) if (loading) { return (
Lade Dokumentenindex aus Qdrant...
) } return (
{/* Stats bar */}
{documents.length} Dokumente | {documents.reduce((s, d) => s + d.chunk_count, 0).toLocaleString()} Chunks im Vektorspeicher | Quellen: BAuA, OSHA, EUR-Lex, NIST, ENISA
{/* Filters */}
{filtered.length !== documents.length && `${filtered.length} gefiltert | `}{totalChunks.toLocaleString()} Chunks
{/* Table */}
{['Kennung', 'Bezeichnung', 'Kategorie', 'Quelle', 'Chunks'].map((h) => ( ))} {pageItems.map((d) => ( ))} {pageItems.length === 0 && ( )}
{h}
{d.regulation_id}
{d.name_de || d.name_en || d.regulation_id}
{d.source_url && ( e.stopPropagation()} > Quelle )}
{categoryLabel(d.category)} {d.source_org || '-'} {d.chunk_count.toLocaleString()}
{documents.length === 0 ? 'Keine Dokumente im CE-Corpus gefunden. Qdrant-Verbindung pruefen.' : 'Keine Dokumente fuer diesen Filter gefunden'}
) }