thread-master/frontend/src/components/CopyMissionAnalyzeJobPanel.tsx

69 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { ANALYZE_COPY_MISSION_PIPELINE_STEPS } from '../lib/copyFlow'
import { jobStatusBadgeClass, jobStatusLabel } from '../lib/jobStatus'
import type { JobData } from '../types/api'
import { ProgressBar, StatusBadge } from './ui'
const STEP_STATUS_LABEL: Record<string, string> = {
pending: '等待',
running: '進行中',
succeeded: '完成',
failed: '失敗',
skipped: '略過',
cancelled: '取消',
}
function analyzeJobHint(job: JobData): string {
if (job.status === 'cancel_requested') {
return '研究地圖任務取消中,通常幾秒內完成。'
}
if (job.status === 'queued' || job.status === 'pending') {
return '任務已排隊,背景 worker 即將接手…'
}
return job.progress?.summary?.trim() || '研究地圖產生中,請稍候…'
}
export function CopyMissionAnalyzeJobPanel({ job }: { job: JobData }) {
const steps = job.progress?.steps ?? []
const stepMap = new Map(steps.map((s) => [s.id, s]))
const pct = job.progress?.percentage ?? 0
return (
<div className="space-y-4">
<p className="text-sm leading-relaxed text-ink">{analyzeJobHint(job)}</p>
<div className="flex flex-wrap items-center gap-2">
<StatusBadge className={jobStatusBadgeClass(job.status)}>
{jobStatusLabel(job.status)}
</StatusBadge>
<span className="text-xs font-bold text-muted">{pct}%</span>
</div>
<ProgressBar value={pct} />
<ol className="flex flex-wrap gap-2 text-[11px]">
{ANALYZE_COPY_MISSION_PIPELINE_STEPS.map((step) => {
const live = stepMap.get(step.id)
const status = live?.status ?? 'pending'
const isDone = status === 'succeeded' || status === 'done'
const isRunning = status === 'running'
return (
<li
key={step.id}
className={`inline-flex items-center gap-1 rounded-[var(--radius-pill)] border-2 px-2.5 py-1 font-bold ${
isDone
? 'border-success/40 bg-success-soft text-success'
: isRunning
? 'border-brand/40 bg-brand-soft text-brand'
: 'border-line text-muted'
}`}
title={step.hint}
>
<span>{step.title}</span>
<span className="opacity-70">· {STEP_STATUS_LABEL[status] ?? status}</span>
</li>
)
})}
</ol>
{job.error ? (
<p className="text-xs font-semibold leading-relaxed text-danger">{job.error}</p>
) : null}
</div>
)
}