Files
breakpilot-lehrer/website/app/admin/edu-search/page.tsx
Benjamin Admin b6983ab1dc [split-required] Split 500-1000 LOC files across all services
backend-lehrer (5 files):
- alerts_agent/db/repository.py (992 → 5), abitur_docs_api.py (956 → 3)
- teacher_dashboard_api.py (951 → 3), services/pdf_service.py (916 → 3)
- mail/mail_db.py (987 → 6)

klausur-service (5 files):
- legal_templates_ingestion.py (942 → 3), ocr_pipeline_postprocess.py (929 → 4)
- ocr_pipeline_words.py (876 → 3), ocr_pipeline_ocr_merge.py (616 → 2)
- KorrekturPage.tsx (956 → 6)

website (5 pages):
- mail (985 → 9), edu-search (958 → 8), mac-mini (950 → 7)
- ocr-labeling (946 → 7), audit-workspace (871 → 4)

studio-v2 (5 files + 1 deleted):
- page.tsx (946 → 5), MessagesContext.tsx (925 → 4)
- korrektur (914 → 6), worksheet-cleanup (899 → 6)
- useVocabWorksheet.ts (888 → 3)
- Deleted dead page-original.tsx (934 LOC)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 23:35:37 +02:00

111 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
/**
* Education Search Admin Page
*
* Manages seed URLs, crawl settings, and index statistics for the
* edu-search-service (Tavily alternative for German education content)
*/
import { useState } from 'react'
import AdminLayout from '@/components/admin/AdminLayout'
import { useEduSearchData } from './useEduSearchData'
import SeedsTab from './_components/SeedsTab'
import CrawlTab from './_components/CrawlTab'
import StatsTab from './_components/StatsTab'
import RulesTab from './_components/RulesTab'
const tabDefs = [
{ id: 'seeds' as const, name: 'Seed-URLs', icon: '🌱' },
{ id: 'crawl' as const, name: 'Crawl-Steuerung', icon: '🕷️' },
{ id: 'stats' as const, name: 'Statistiken', icon: '📊' },
{ id: 'rules' as const, name: 'Tagging-Regeln', icon: '🏷️' },
]
export default function EduSearchAdminPage() {
const [activeTab, setActiveTab] = useState<'seeds' | 'crawl' | 'stats' | 'rules'>('seeds')
const [searchQuery, setSearchQuery] = useState('')
const {
seeds, allSeeds, categories, stats, selectedCategory, setSelectedCategory,
loading, initialLoading, error,
handleStartCrawl, handleDelete, handleToggleEnabled, handleSaved,
fetchSeeds, fetchStats,
} = useEduSearchData()
return (
<AdminLayout title="Education Search" description="Bildungsquellen & Crawler verwalten">
{initialLoading && (
<div className="flex items-center justify-center py-12">
<svg className="w-8 h-8 animate-spin text-primary-600" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
</svg>
<span className="ml-3 text-slate-600">Seeds werden geladen...</span>
</div>
)}
{error && !initialLoading && (
<div className="mb-6 bg-red-50 border border-red-200 rounded-lg p-4">
<div className="flex items-center gap-3">
<span className="text-red-500 text-xl"></span>
<div>
<h4 className="font-medium text-red-800">{error}</h4>
<p className="text-sm text-red-600 mt-1">
Stelle sicher, dass der Backend-Service (http://localhost:8000) erreichbar ist.
</p>
<button
onClick={() => { fetchSeeds(); fetchStats(); }}
className="mt-2 text-sm text-red-700 underline hover:no-underline"
>
Erneut versuchen
</button>
</div>
</div>
</div>
)}
{!initialLoading && (
<div className="bg-white rounded-xl shadow-sm border border-slate-200 mb-6">
<div className="border-b border-slate-200">
<nav className="flex -mb-px">
{tabDefs.map(tab => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
className={`px-6 py-4 text-sm font-medium border-b-2 transition-colors ${
activeTab === tab.id
? 'border-primary-600 text-primary-600'
: 'border-transparent text-slate-500 hover:text-slate-700 hover:border-slate-300'
}`}
>
<span className="mr-2">{tab.icon}</span>
{tab.name}
</button>
))}
</nav>
</div>
<div className="p-6">
{activeTab === 'seeds' && (
<SeedsTab
seeds={seeds} allSeeds={allSeeds} categories={categories}
searchQuery={searchQuery} setSearchQuery={setSearchQuery}
selectedCategory={selectedCategory} setSelectedCategory={setSelectedCategory}
onToggleEnabled={handleToggleEnabled} onDelete={handleDelete} onSaved={handleSaved}
/>
)}
{activeTab === 'crawl' && (
<CrawlTab stats={stats} loading={loading} onStartCrawl={handleStartCrawl} />
)}
{activeTab === 'stats' && (
<StatsTab stats={stats} categories={categories} />
)}
{activeTab === 'rules' && <RulesTab />}
</div>
</div>
)}
</AdminLayout>
)
}