legco_ai_assistant/frontend/src/components/PipelineProgress.tsx

64 lines
2.2 KiB
TypeScript

import React from 'react'
import { CheckCircle, Loader2, Circle } from 'lucide-react'
export interface PipelineProgressProps {
currentStep: number
}
const STAGES = [
{ label: 'Extracting keywords...', index: 1 },
{ label: 'Retrieving documents...', index: 2 },
{ label: 'Filtering relevance...', index: 3 },
{ label: 'Generating answer...', index: 4 },
]
export const PipelineProgress: React.FC<PipelineProgressProps> = ({ currentStep }) => {
if (currentStep === 0) {
return null
}
return (
<div className="w-full py-4" data-testid="pipeline-progress">
<div className="flex items-center justify-between">
{STAGES.map((stage, index) => {
const stageNumber = index + 1
const isCompleted = currentStep >= stageNumber && (currentStep === STAGES.length || currentStep > stageNumber)
const isActive = currentStep === stageNumber && currentStep !== STAGES.length
const isPending = currentStep < stageNumber && currentStep !== STAGES.length
return (
<div key={stage.index} className="flex flex-col items-center flex-1 relative">
{index < STAGES.length - 1 && (
<div className="absolute top-4 left-1/2 w-full h-0.5 bg-gray-200 -z-10" />
)}
<div className="relative z-10">
{isCompleted && (
<CheckCircle className="w-8 h-8 text-green-500" data-testid={`stage-${stageNumber}-completed`} />
)}
{isActive && (
<Loader2
className="w-8 h-8 text-blue-500 animate-spin"
data-testid={`stage-${stageNumber}-active`}
/>
)}
{isPending && (
<Circle className="w-8 h-8 text-gray-300" data-testid={`stage-${stageNumber}-pending`} />
)}
</div>
<span
className={`mt-2 text-xs font-medium text-center max-w-[120px] ${
isCompleted ? 'text-gray-600' : isActive ? 'text-blue-600' : 'text-gray-400'
}`}
>
{stage.label}
</span>
</div>
)
})}
</div>
</div>
)
}