64 lines
2.2 KiB
TypeScript
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>
|
|
)
|
|
}
|