Fix: Remove broken getKlausurApiUrl and clean up empty lines
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>
This commit is contained in:
Benjamin Admin
2026-04-24 16:02:04 +02:00
parent b07f802c24
commit 9ba420fa91
150 changed files with 30231 additions and 32053 deletions

View File

@@ -0,0 +1,195 @@
'use client'
import React from 'react'
import type { UseRAGPageReturn } from '../_hooks/useRAGPage'
interface DataTabProps {
hook: UseRAGPageReturn
}
export function DataTab({ hook }: DataTabProps) {
const {
customDocuments,
uploadFile,
setUploadFile,
uploadTitle,
setUploadTitle,
uploadCode,
setUploadCode,
uploading,
handleUpload,
linkUrl,
setLinkUrl,
linkTitle,
setLinkTitle,
linkCode,
setLinkCode,
addingLink,
handleAddLink,
handleDeleteDocument,
fetchCustomDocuments,
} = hook
return (
<div className="space-y-6">
{/* Upload Document */}
<div className="bg-white rounded-xl border border-slate-200 p-6">
<h3 className="font-semibold text-slate-900 mb-4">Dokument hochladen (PDF)</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">PDF-Datei</label>
<input
type="file"
accept=".pdf"
onChange={(e) => setUploadFile(e.target.files?.[0] || null)}
className="w-full px-3 py-2 border rounded-lg text-sm"
/>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Titel</label>
<input
type="text"
value={uploadTitle}
onChange={(e) => setUploadTitle(e.target.value)}
placeholder="z.B. Firmen-Datenschutzrichtlinie"
className="w-full px-3 py-2 border rounded-lg"
/>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Code (eindeutig)</label>
<input
type="text"
value={uploadCode}
onChange={(e) => setUploadCode(e.target.value.toUpperCase())}
placeholder="z.B. CUSTOM-DSR-01"
className="w-full px-3 py-2 border rounded-lg font-mono"
/>
</div>
</div>
<button
onClick={handleUpload}
disabled={uploading || !uploadFile || !uploadTitle || !uploadCode}
className="mt-4 px-6 py-2 bg-teal-600 text-white rounded-lg hover:bg-teal-700 disabled:opacity-50"
>
{uploading ? 'Wird hochgeladen...' : 'Hochladen & Indexieren'}
</button>
</div>
{/* Add Link */}
<div className="bg-white rounded-xl border border-slate-200 p-6">
<h3 className="font-semibold text-slate-900 mb-4">Link hinzufuegen (Webseite/PDF)</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">URL</label>
<input
type="url"
value={linkUrl}
onChange={(e) => setLinkUrl(e.target.value)}
placeholder="https://example.com/document.pdf"
className="w-full px-3 py-2 border rounded-lg"
/>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Titel</label>
<input
type="text"
value={linkTitle}
onChange={(e) => setLinkTitle(e.target.value)}
placeholder="z.B. BSI IT-Grundschutz"
className="w-full px-3 py-2 border rounded-lg"
/>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Code (eindeutig)</label>
<input
type="text"
value={linkCode}
onChange={(e) => setLinkCode(e.target.value.toUpperCase())}
placeholder="z.B. BSI-GRUNDSCHUTZ"
className="w-full px-3 py-2 border rounded-lg font-mono"
/>
</div>
</div>
<button
onClick={handleAddLink}
disabled={addingLink || !linkUrl || !linkTitle || !linkCode}
className="mt-4 px-6 py-2 bg-teal-600 text-white rounded-lg hover:bg-teal-700 disabled:opacity-50"
>
{addingLink ? 'Wird hinzugefuegt...' : 'Link hinzufuegen & Indexieren'}
</button>
</div>
{/* Custom Documents List */}
<div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
<div className="px-4 py-3 border-b bg-slate-50 flex items-center justify-between">
<h3 className="font-semibold text-slate-900">Eigene Dokumente ({customDocuments.length})</h3>
<button
onClick={fetchCustomDocuments}
className="text-sm text-teal-600 hover:text-teal-700"
>
Aktualisieren
</button>
</div>
{customDocuments.length === 0 ? (
<div className="p-8 text-center text-slate-500">
Noch keine eigenen Dokumente hinzugefuegt.
</div>
) : (
<div className="divide-y">
{customDocuments.map((doc) => (
<div key={doc.id} className="px-4 py-3 flex items-center justify-between">
<div className="flex items-center gap-3">
<span className="w-8 h-8 rounded-lg bg-slate-100 flex items-center justify-center text-lg">
{doc.url ? '🔗' : '📄'}
</span>
<div>
<p className="font-medium text-slate-900">{doc.title}</p>
<p className="text-sm text-slate-500">
<span className="font-mono text-teal-600">{doc.code}</span>
{' • '}
{doc.filename || doc.url}
</p>
</div>
</div>
<div className="flex items-center gap-4">
<span className={`px-2 py-1 rounded text-xs font-medium ${
doc.status === 'indexed' ? 'bg-green-100 text-green-700' :
doc.status === 'error' ? 'bg-red-100 text-red-700' :
doc.status === 'processing' || doc.status === 'fetching' ? 'bg-blue-100 text-blue-700' :
'bg-slate-100 text-slate-700'
}`}>
{doc.status === 'indexed' ? `${doc.chunk_count} Chunks` :
doc.status === 'error' ? 'Fehler' :
doc.status === 'processing' ? 'Verarbeitung...' :
doc.status === 'fetching' ? 'Abruf...' :
doc.status}
</span>
<button
onClick={() => handleDeleteDocument(doc.id)}
className="text-red-500 hover:text-red-700 text-sm"
>
Loeschen
</button>
</div>
</div>
))}
</div>
)}
</div>
{/* Info Box */}
<div className="bg-teal-50 border border-teal-200 rounded-xl p-6">
<h4 className="font-semibold text-teal-800 flex items-center gap-2">
<span></span>
Hinweis zur Verwendung
</h4>
<p className="text-sm text-teal-700 mt-2">
Laden Sie eigene Dokumente (z.B. interne Datenschutzrichtlinien, Vertraege) oder
externe Links hoch. Diese werden automatisch in Chunks aufgeteilt und indexiert.
Nach dem Hinzufuegen koennen Sie im <strong>Pipeline</strong>-Tab die vollstaendige
Compliance-Analyse starten.
</p>
</div>
</div>
)
}