All checks were successful
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 38s
CI / test-go-edu-search (push) Successful in 29s
CI / test-python-klausur (push) Successful in 1m46s
CI / test-python-agent-core (push) Successful in 17s
CI / test-nodejs-website (push) Successful in 22s
Neue Route /ai/ocr-pipeline mit schrittweiser Begradigung (Deskew), Raster-Overlay und Ground Truth. Schritte 2-6 als Platzhalter. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
54 lines
2.1 KiB
TypeScript
54 lines
2.1 KiB
TypeScript
'use client'
|
|
|
|
import { PipelineStep } from '@/app/(admin)/ai/ocr-pipeline/types'
|
|
|
|
interface PipelineStepperProps {
|
|
steps: PipelineStep[]
|
|
currentStep: number
|
|
onStepClick: (index: number) => void
|
|
}
|
|
|
|
export function PipelineStepper({ steps, currentStep, onStepClick }: PipelineStepperProps) {
|
|
return (
|
|
<div className="flex items-center justify-between px-4 py-3 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700">
|
|
{steps.map((step, index) => {
|
|
const isActive = index === currentStep
|
|
const isCompleted = step.status === 'completed'
|
|
const isFailed = step.status === 'failed'
|
|
const isClickable = index <= currentStep || isCompleted
|
|
|
|
return (
|
|
<div key={step.id} className="flex items-center">
|
|
{index > 0 && (
|
|
<div
|
|
className={`h-0.5 w-8 mx-1 ${
|
|
index <= currentStep ? 'bg-teal-400' : 'bg-gray-300 dark:bg-gray-600'
|
|
}`}
|
|
/>
|
|
)}
|
|
<button
|
|
onClick={() => isClickable && onStepClick(index)}
|
|
disabled={!isClickable}
|
|
className={`flex items-center gap-1.5 px-3 py-1.5 rounded-full text-sm font-medium transition-all ${
|
|
isActive
|
|
? 'bg-teal-100 text-teal-700 dark:bg-teal-900/40 dark:text-teal-300 ring-2 ring-teal-400'
|
|
: isCompleted
|
|
? 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300'
|
|
: isFailed
|
|
? 'bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-300'
|
|
: 'text-gray-400 dark:text-gray-500'
|
|
} ${isClickable ? 'cursor-pointer hover:opacity-80' : 'cursor-default'}`}
|
|
>
|
|
<span className="text-base">
|
|
{isCompleted ? '✓' : isFailed ? '✗' : step.icon}
|
|
</span>
|
|
<span className="hidden sm:inline">{step.name}</span>
|
|
<span className="sm:hidden">{index + 1}</span>
|
|
</button>
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
)
|
|
}
|