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
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:
195
admin-lehrer/app/(admin)/ai/rag/_components/DataTab.tsx
Normal file
195
admin-lehrer/app/(admin)/ai/rag/_components/DataTab.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user