Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 42s
CI / test-go-edu-search (push) Successful in 34s
CI / test-python-klausur (push) Failing after 2m51s
CI / test-python-agent-core (push) Successful in 21s
CI / test-nodejs-website (push) Successful in 29s
sed replacement left orphaned hostname references in story page and empty lines in getApiBase functions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
172 lines
6.5 KiB
TypeScript
172 lines
6.5 KiB
TypeScript
'use client'
|
|
|
|
import type { DataSource } from '../types'
|
|
|
|
export function DataSourcesTab({ sources }: { sources: DataSource[] }) {
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Introduction */}
|
|
<div className="bg-blue-50 dark:bg-blue-900/20 rounded-xl p-6 border border-blue-200 dark:border-blue-800">
|
|
<h2 className="text-lg font-semibold text-blue-900 dark:text-blue-100 mb-2">
|
|
Wie werden Daten hinzugefuegt?
|
|
</h2>
|
|
<p className="text-blue-800 dark:text-blue-200 mb-4">
|
|
Das RAG-System nutzt verschiedene Datenquellen. Jede Quelle hat einen eigenen Ingestion-Prozess:
|
|
</p>
|
|
<div className="grid grid-cols-2 gap-4 text-sm">
|
|
<div className="bg-white dark:bg-gray-800 rounded-lg p-4">
|
|
<div className="font-medium text-gray-900 dark:text-white mb-1">Automatisch</div>
|
|
<p className="text-gray-600 dark:text-gray-400">
|
|
NiBiS-PDFs werden automatisch aus dem za-download Verzeichnis eingelesen
|
|
</p>
|
|
</div>
|
|
<div className="bg-white dark:bg-gray-800 rounded-lg p-4">
|
|
<div className="font-medium text-gray-900 dark:text-white mb-1">Manuell</div>
|
|
<p className="text-gray-600 dark:text-gray-400">
|
|
Eigene EH koennen ueber die Klausur-Korrektur hochgeladen werden
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Data Sources List */}
|
|
<div className="grid gap-4">
|
|
{sources.map((source) => (
|
|
<DataSourceCard key={source.id} source={source} />
|
|
))}
|
|
</div>
|
|
|
|
{/* How to add data */}
|
|
<div className="bg-white dark:bg-gray-800 rounded-2xl shadow-lg border border-gray-200 dark:border-gray-700 p-6">
|
|
<h2 className="text-lg font-semibold text-gray-900 dark:text-white mb-4">
|
|
Daten hinzufuegen
|
|
</h2>
|
|
<div className="grid grid-cols-3 gap-6">
|
|
<AddDataCard
|
|
icon="📤"
|
|
title="Erwartungshorizont hochladen"
|
|
description="Laden Sie eigene EH-Dokumente in der Klausur-Korrektur hoch"
|
|
linkHref="/admin/klausur-korrektur"
|
|
linkText="Zur Klausur-Korrektur →"
|
|
/>
|
|
<AddDataCard
|
|
icon="🔄"
|
|
title="NiBiS neu einlesen"
|
|
description="Starten Sie die automatische Ingestion der NiBiS-PDFs"
|
|
linkText="Ingestion starten →"
|
|
/>
|
|
<AddDataCard
|
|
icon="⚖️"
|
|
title="Rechtskorpus erweitern"
|
|
description="Neue Regelwerke (DSGVO, BSI, etc.) zum Korpus hinzufuegen"
|
|
linkText="Regelwerk hinzufuegen →"
|
|
/>
|
|
<AddDataCard
|
|
icon="📋"
|
|
title="DSFA-Quellen verwalten"
|
|
description="WP248, DSK, Muss-Listen mit Lizenzattribution"
|
|
linkHref="/ai/rag-pipeline/dsfa"
|
|
linkText="DSFA-Manager oeffnen →"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
// --- Internal helper components ---
|
|
|
|
function DataSourceCard({ source }: { source: DataSource }) {
|
|
return (
|
|
<div className="bg-white dark:bg-gray-800 rounded-2xl shadow-lg border border-gray-200 dark:border-gray-700 p-6">
|
|
<div className="flex items-start justify-between">
|
|
<div className="flex-1">
|
|
<div className="flex items-center gap-3 mb-2">
|
|
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
|
|
{source.name}
|
|
</h3>
|
|
<DataSourceStatusBadge status={source.status} />
|
|
</div>
|
|
<p className="text-gray-600 dark:text-gray-400 mb-4">
|
|
{source.description}
|
|
</p>
|
|
<div className="flex items-center gap-6 text-sm">
|
|
<div>
|
|
<span className="text-gray-500 dark:text-gray-400">Collection: </span>
|
|
<span className="font-mono text-gray-900 dark:text-white">{source.collection}</span>
|
|
</div>
|
|
<div>
|
|
<span className="text-gray-500 dark:text-gray-400">Dokumente: </span>
|
|
<span className="font-semibold text-gray-900 dark:text-white">{source.document_count}</span>
|
|
</div>
|
|
<div>
|
|
<span className="text-gray-500 dark:text-gray-400">Chunks: </span>
|
|
<span className="font-semibold text-gray-900 dark:text-white">{source.chunk_count}</span>
|
|
</div>
|
|
{source.last_updated && (
|
|
<div>
|
|
<span className="text-gray-500 dark:text-gray-400">Aktualisiert: </span>
|
|
<span className="text-gray-900 dark:text-white">
|
|
{new Date(source.last_updated).toLocaleDateString('de-DE')}
|
|
</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<div className="flex gap-2">
|
|
<button className="px-4 py-2 text-sm font-medium text-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/20 rounded-lg">
|
|
Aktualisieren
|
|
</button>
|
|
<button className="px-4 py-2 text-sm font-medium text-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg">
|
|
Details
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function DataSourceStatusBadge({ status }: { status: DataSource['status'] }) {
|
|
const className = status === 'active'
|
|
? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200'
|
|
: status === 'pending'
|
|
? 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200'
|
|
: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200'
|
|
|
|
const label = status === 'active' ? 'Aktiv' : status === 'pending' ? 'Ausstehend' : 'Fehler'
|
|
|
|
return (
|
|
<span className={`px-2 py-0.5 rounded-full text-xs font-medium ${className}`}>
|
|
{label}
|
|
</span>
|
|
)
|
|
}
|
|
|
|
function AddDataCard({ icon, title, description, linkHref, linkText }: {
|
|
icon: string
|
|
title: string
|
|
description: string
|
|
linkHref?: string
|
|
linkText: string
|
|
}) {
|
|
return (
|
|
<div className="p-4 bg-gray-50 dark:bg-gray-900 rounded-xl">
|
|
<div className="text-2xl mb-2">{icon}</div>
|
|
<h3 className="font-medium text-gray-900 dark:text-white mb-2">{title}</h3>
|
|
<p className="text-sm text-gray-600 dark:text-gray-400 mb-3">{description}</p>
|
|
{linkHref ? (
|
|
<a
|
|
href={linkHref}
|
|
className="text-sm text-blue-600 hover:text-blue-800 dark:text-blue-400"
|
|
>
|
|
{linkText}
|
|
</a>
|
|
) : (
|
|
<button className="text-sm text-blue-600 hover:text-blue-800 dark:text-blue-400">
|
|
{linkText}
|
|
</button>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|