'use client'; import React from 'react'; import { AlertCircle, CheckCircle2, Circle, FileJson, FileOutput, FileText, Image as ImageIcon, Link2, ListChecks, Loader2, PanelRightOpen, X, } from 'lucide-react'; import { ScrollArea } from '@/components/ui/scroll-area'; import { appStatusLabel } from '@/lib/i18n/common'; import { pickAppText } from '@/lib/i18n/core'; import { useAppI18n } from '@/lib/i18n/provider'; import type { SessionProgressArtifactView, SessionProgressStepView, SessionProgressView, } from '@/lib/session-progress'; import type { ProcessArtifact, ProcessRunStatus } from '@/types'; function formatShortTime(value: string, locale: 'zh-CN' | 'en-US') { const date = new Date(value); if (Number.isNaN(date.getTime())) return value; return new Intl.DateTimeFormat(locale, { hour: '2-digit', minute: '2-digit', }).format(date); } function statusTone(status: ProcessRunStatus) { if (status === 'done') return 'text-[#2F8D50] bg-[#E3F1E7] border-[#B8D9C2]'; if (status === 'running') return 'text-[#2F6FCA] bg-[#E7EEF9] border-[#B8CBE8]'; if (status === 'error') return 'text-[#8A3A2D] bg-[#F0E5E1] border-[#D9BDB4]'; if (status === 'cancelled') return 'text-[#6A5E58] bg-[#ECE8E5] border-[#D8D2CE]'; return 'text-[#6A5E58] bg-[#F0ECE9] border-[#D8D2CE]'; } function StepMarker({ step, index }: { step: SessionProgressStepView; index: number }) { if (step.status === 'done') { return ( ); } if (step.status === 'running') { return ( {index + 1} ); } if (step.status === 'error') { return ( ); } return ( ); } function artifactIcon(type: ProcessArtifact['artifact_type']) { if (type === 'json') return ; if (type === 'image') return ; if (type === 'link') return ; if (type === 'markdown' || type === 'text') return ; return ; } function ProgressHeader({ view }: { view: SessionProgressView }) { const { locale } = useAppI18n(); const percent = view.progress.percent; return (
{view.title}
{appStatusLabel(view.status, locale)} {pickAppText(locale, '更新于', 'Updated')} {formatShortTime(view.updatedAt, locale)}
{view.progress.label} {percent !== null && {percent}%}
{view.summary && (

{view.summary}

)}
); } function StepList({ steps }: { steps: SessionProgressStepView[] }) { const { locale } = useAppI18n(); return (

{pickAppText(locale, '运行步骤', 'Run Steps')}

{pickAppText(locale, `${steps.length} 步`, `${steps.length} steps`)}
{steps.map((step, index) => (
{index < steps.length - 1 && }
{index + 1}. {step.title}
{step.actorName} · {formatShortTime(step.updatedAt, locale)}
{appStatusLabel(step.status, locale)}
{step.description && (

{step.description}

)} {step.status === 'running' && (
{pickAppText(locale, '正在处理', 'In progress')}
)}
))}
); } function ArtifactRow({ artifact }: { artifact: SessionProgressArtifactView }) { return (
{artifactIcon(artifact.type)}
{artifact.title}
{artifact.actorName} · {artifact.typeLabel}

{artifact.preview}

); } function ArtifactSection({ view }: { view: SessionProgressView }) { const { locale } = useAppI18n(); return (

{pickAppText(locale, '生成内容', 'Generated Content')}

{pickAppText(locale, `${view.artifacts.length} 个`, `${view.artifacts.length} items`)}
{view.artifactTypeSummaries.length > 0 ? (
{view.artifactTypeSummaries.map((item) => ( {artifactIcon(item.type)} {item.label} {item.count} ))}
) : (

{pickAppText(locale, '暂时还没有生成内容。', 'No generated content yet.')}

)}
{view.artifacts.map((artifact) => ( ))}
); } function ProgressPanel({ view, onClose, }: { view: SessionProgressView; onClose?: () => void; }) { const { locale } = useAppI18n(); return (

{pickAppText(locale, '当前会话的运行进度', 'Current Session Progress')}

{pickAppText(locale, '任务列表会自动刷新', 'Task updates refresh automatically')}

{onClose && ( )}
); } export function CurrentSessionProgressSidebar({ view }: { view: SessionProgressView }) { const { locale } = useAppI18n(); const [mobileOpen, setMobileOpen] = React.useState(false); return ( <> {mobileOpen && (
)} ); }