50 lines
1.8 KiB
TypeScript
50 lines
1.8 KiB
TypeScript
import type { InsightJobStage } from '../../types/api.ts';
|
|
|
|
/** Phase 4 pipeline step indicator for async AI Insight generation. */
|
|
const STEPS: { stage: InsightJobStage; label: string; icon: string }[] = [
|
|
{ stage: 'grading', label: 'Evaluating CP 707 rules...', icon: 'fa-solid fa-scale-balanced' },
|
|
{ stage: 'retrieving', label: 'Fetching SOP guidelines...', icon: 'fa-solid fa-book-open' },
|
|
{
|
|
stage: 'synthesizing',
|
|
label: 'Synthesizing recommendations...',
|
|
icon: 'fa-solid fa-wand-magic-sparkles',
|
|
},
|
|
{ stage: 'saving', label: 'Saving insight...', icon: 'fa-solid fa-floppy-disk' },
|
|
];
|
|
|
|
const ORDER: InsightJobStage[] = ['queued', 'starting', ...STEPS.map((s) => s.stage), 'done'];
|
|
|
|
function stageIndex(stage: InsightJobStage | null): number {
|
|
if (!stage) return 0;
|
|
const i = ORDER.indexOf(stage);
|
|
return i < 0 ? 0 : i;
|
|
}
|
|
|
|
export default function InsightProgressSteps({ stage }: { stage: InsightJobStage | null }) {
|
|
const current = stageIndex(stage);
|
|
return (
|
|
<ol className="space-y-1.5 text-xs text-gray-600" aria-live="polite">
|
|
{STEPS.map((step, i) => {
|
|
const state = current > i ? 'done' : current === i ? 'active' : 'pending';
|
|
return (
|
|
<li
|
|
key={step.stage}
|
|
className={`flex items-center gap-2 ${state === 'pending' ? 'opacity-40' : ''}`}
|
|
>
|
|
<i
|
|
className={`${step.icon} ${
|
|
state === 'done' ? 'text-green-600' : 'text-blue-600'
|
|
} ${state === 'active' ? 'fa-spin' : ''}`}
|
|
aria-hidden="true"
|
|
/>
|
|
<span>{step.label}</span>
|
|
{state === 'done' && (
|
|
<i className="fa-solid fa-check text-green-600" aria-hidden="true" />
|
|
)}
|
|
</li>
|
|
);
|
|
})}
|
|
</ol>
|
|
);
|
|
}
|