File size: 2,574 Bytes
900a32d
722753e
 
900a32d
 
 
 
722753e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
900a32d
 
 
722753e
 
 
900a32d
722753e
900a32d
575f8ed
900a32d
 
722753e
575f8ed
722753e
900a32d
 
 
722753e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
900a32d
722753e
900a32d
575f8ed
900a32d
 
722753e
 
900a32d
722753e
 
 
900a32d
722753e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import type { JobStatus } from "../types";

interface ProgressIndicatorProps {
  progress: number;
  message: string;
  status: JobStatus;
  elapsedSeconds?: number;
}

/**
 * Visual progress indicator for long-running ML inference jobs.
 *
 * Shows:
 * - Progress bar with percentage
 * - Current operation message
 * - Elapsed time
 * - Status-appropriate coloring (blue for running, red for failed)
 */
export function ProgressIndicator({
  progress,
  message,
  status,
  elapsedSeconds,
}: ProgressIndicatorProps) {
  const isError = status === "failed";
  const isComplete = status === "completed";
  const isWakingUp = status === "waking_up";

  // Determine bar color based on status
  const barColorClass = isError
    ? "bg-red-500"
    : isComplete
      ? "bg-green-500"
      : isWakingUp
        ? "bg-yellow-500"
        : "bg-blue-500";

  // Animate the bar while running or waking up
  const animationClass =
    status === "running" || status === "pending" || status === "waking_up"
      ? "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"
                : isWakingUp
                  ? "text-yellow-400"
                  : "text-blue-400"
          }`}
        >
          {status === "waking_up" ? "waking up" : status}
        </span>
      </div>
    </div>
  );
}