[split-required] Split final batch of monoliths >1000 LOC

Python (6 files in klausur-service):
- rbac.py (1,132 → 4), admin_api.py (1,012 → 4)
- routes/eh.py (1,111 → 4), ocr_pipeline_geometry.py (1,105 → 5)

Python (2 files in backend-lehrer):
- unit_api.py (1,226 → 6), game_api.py (1,129 → 5)

Website (6 page files):
- 4x klausur-korrektur pages (1,249-1,328 LOC each) → shared components
  in website/components/klausur-korrektur/ (17 shared files)
- companion (1,057 → 10), magic-help (1,017 → 8)

All re-export barrels preserve backward compatibility.
Zero import errors verified.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-24 23:17:30 +02:00
parent b2a0126f14
commit 6811264756
67 changed files with 12270 additions and 13651 deletions

View File

@@ -0,0 +1,108 @@
'use client'
/**
* Top navigation bar for the Korrektur-Workspace.
* Shows back link, student navigation, workflow status, and grade.
*/
import Link from 'next/link'
import type { ExaminerWorkflow } from './workspace-types'
import { WORKFLOW_STATUS_LABELS, ROLE_LABELS, GRADE_LABELS } from './workspace-types'
interface WorkspaceTopBarProps {
klausurId: string
backPath: string
currentIndex: number
studentCount: number
workflow: ExaminerWorkflow | null
saving: boolean
totals: { gradePoints: number; weighted: number }
onGoToStudent: (direction: 'prev' | 'next') => void
}
export default function WorkspaceTopBar({
klausurId, backPath, currentIndex, studentCount,
workflow, saving, totals, onGoToStudent,
}: WorkspaceTopBarProps) {
return (
<div className="bg-white border-b border-slate-200 -mx-6 -mt-6 px-6 py-3 mb-4 flex items-center justify-between sticky top-0 z-10">
{/* Back link */}
<Link
href={backPath}
className="text-primary-600 hover:text-primary-800 flex items-center gap-1 text-sm"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
</svg>
Zurueck
</Link>
{/* Student navigation */}
<div className="flex items-center gap-4">
<button
onClick={() => onGoToStudent('prev')}
disabled={currentIndex <= 0}
className="p-2 rounded-lg hover:bg-slate-100 disabled:opacity-50 disabled:cursor-not-allowed"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
</svg>
</button>
<span className="text-sm font-medium">
{currentIndex + 1} / {studentCount}
</span>
<button
onClick={() => onGoToStudent('next')}
disabled={currentIndex >= studentCount - 1}
className="p-2 rounded-lg hover:bg-slate-100 disabled:opacity-50 disabled:cursor-not-allowed"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</button>
</div>
{/* Workflow status and role */}
<div className="flex items-center gap-3">
{workflow && (
<div className="flex items-center gap-2">
<span
className={`px-2 py-1 text-xs font-medium rounded-full text-white ${
ROLE_LABELS[workflow.user_role]?.color || 'bg-slate-500'
}`}
>
{ROLE_LABELS[workflow.user_role]?.label || workflow.user_role}
</span>
<span
className={`px-2 py-1 text-xs font-medium rounded-full ${
WORKFLOW_STATUS_LABELS[workflow.workflow_status]?.color || 'bg-slate-100'
}`}
>
{WORKFLOW_STATUS_LABELS[workflow.workflow_status]?.label || workflow.workflow_status}
</span>
{workflow.user_role === 'zk' && workflow.visibility_mode !== 'full' && (
<span className="px-2 py-1 text-xs bg-purple-100 text-purple-700 rounded-full">
{workflow.visibility_mode === 'blind' ? 'Blind-Modus' : 'Semi-Blind'}
</span>
)}
</div>
)}
{saving && (
<span className="text-sm text-slate-500 flex items-center gap-1">
<div className="animate-spin rounded-full h-3 w-3 border-b-2 border-primary-600"></div>
Speichern...
</span>
)}
<div className="text-right">
<div className="text-lg font-bold text-slate-800">
{totals.gradePoints} Punkte
</div>
<div className="text-sm text-slate-500">
Note: {GRADE_LABELS[totals.gradePoints] || '-'}
</div>
</div>
</div>
</div>
)
}