import { useState } from 'react' import { CircleCheck, CircleDashed, CircleX, Clock, Loader } from 'lucide-react' import { ErrorPanel, PanelNote } from '@/shared/ui' import { fmtRelative, useAsync } from '@/shared/lib' import { getPullChecks, type PullRef } from '@/entities/pull-request' import { Copyable } from './parts' const RUN_STATE: Record = { pending: { label: '排队中', icon: CircleDashed, tone: 'text-shell-ink-muted' }, running: { label: '运行中', icon: Loader, tone: 'text-[#8a6100]' }, success: { label: '通过', icon: CircleCheck, tone: 'text-[#1a7f37]' }, failed: { label: '失败', icon: CircleX, tone: 'text-[#b42318]' }, cancelled: { label: '已取消', icon: Clock, tone: 'text-shell-ink-muted' }, } const STATUS_STATE: Record = { pending: { label: '等待', tone: 'text-shell-ink-muted' }, success: { label: '通过', tone: 'text-[#1a7f37]' }, failure: { label: '失败', tone: 'text-[#b42318]' }, error: { label: '错误', tone: 'text-[#b42318]' }, } /** 检查页签:最新 head 的流水线运行 + 提交状态。 */ export function ChecksTab({ refObj, headSha }: { refObj: PullRef; headSha: string }) { const [tick, setTick] = useState(0) const checks = useAsync(() => getPullChecks(refObj), [refObj.space, refObj.repo, refObj.pull, tick]) const failure = checks.error as { code?: number; message?: string } | undefined if (checks.loading && !checks.data) return if (failure) return setTick(t => t + 1)} /> const data = checks.data if (!data) return const runs = data.runs ?? [] const statuses = data.statuses ?? [] if (!runs.length && !statuses.length) { return } return (

版本

{runs.map(run => { const hit = RUN_STATE[run.state] ?? { label: run.state, icon: Clock, tone: 'text-shell-ink-muted' } const Icon = hit.icon return (
流水线 #{run.id.slice(0, 8)} {hit.label} {run.branch || '—'} · {fmtRelative(run.created_at)}
) })} {statuses.map((status, index) => { const hit = STATUS_STATE[status.state] ?? { label: status.state, tone: 'text-shell-ink-muted' } return (
{status.context} {hit.label} {status.description ? {status.description} : null} {status.target_url ? ( ) : null}
) })}
) }