|
|
import type { JobStatus } from '../types' |
|
|
|
|
|
interface ProgressIndicatorProps { |
|
|
progress: number |
|
|
message: string |
|
|
status: JobStatus |
|
|
elapsedSeconds?: number |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function ProgressIndicator({ |
|
|
progress, |
|
|
message, |
|
|
status, |
|
|
elapsedSeconds, |
|
|
}: ProgressIndicatorProps) { |
|
|
const isError = status === 'failed' |
|
|
const isComplete = status === 'completed' |
|
|
|
|
|
|
|
|
const barColorClass = isError |
|
|
? 'bg-red-500' |
|
|
: isComplete |
|
|
? 'bg-green-500' |
|
|
: 'bg-blue-500' |
|
|
|
|
|
|
|
|
const animationClass = |
|
|
status === 'running' || status === 'pending' ? 'animate-pulse' : '' |
|
|
|
|
|
return ( |
|
|
<div className="bg-gray-800 rounded-lg p-4 space-y-3"> |
|
|
{/* Header with message and percentage */} |
|
|
<div className="flex justify-between items-center text-sm"> |
|
|
<span className="text-gray-300 font-medium">{message}</span> |
|
|
<span className="text-gray-400 tabular-nums">{progress}%</span> |
|
|
</div> |
|
|
|
|
|
{/* Progress bar */} |
|
|
<div className="w-full bg-gray-700 rounded-full h-2.5 overflow-hidden"> |
|
|
<div |
|
|
className={`h-full rounded-full transition-all duration-500 ease-out ${barColorClass} ${animationClass}`} |
|
|
style={{ width: `${progress}%` }} |
|
|
role="progressbar" |
|
|
aria-valuenow={progress} |
|
|
aria-valuemin={0} |
|
|
aria-valuemax={100} |
|
|
aria-label={message} |
|
|
/> |
|
|
</div> |
|
|
|
|
|
{/* Footer with elapsed time and status */} |
|
|
<div className="flex justify-between items-center text-xs text-gray-500"> |
|
|
{elapsedSeconds !== undefined ? ( |
|
|
<span className="tabular-nums"> |
|
|
Elapsed: {elapsedSeconds.toFixed(1)}s |
|
|
</span> |
|
|
) : ( |
|
|
<span>Starting...</span> |
|
|
)} |
|
|
|
|
|
<span |
|
|
className={`capitalize ${ |
|
|
isError |
|
|
? 'text-red-400' |
|
|
: isComplete |
|
|
? 'text-green-400' |
|
|
: 'text-blue-400' |
|
|
}`} |
|
|
> |
|
|
{status} |
|
|
</span> |
|
|
</div> |
|
|
</div> |
|
|
) |
|
|
} |
|
|
|