'use client'; import { format } from 'date-fns'; import { ChevronDown, LoaderCircle, X } from 'lucide-react'; import { useEffect, useMemo, useState } from 'react'; import { useTaskTimelineQuery } from '@/hooks/use-api-queries'; import { buildStageTimeline, stageLabel, taskTypeLabel } from '@/components/notifications/task-stage-helpers'; import { StatusPill } from '@/components/ui/status-pill'; import { Button } from '@/components/ui/button'; function formatTimestamp(value: string | null) { if (!value) { return 'n/a'; } const parsed = new Date(value); if (Number.isNaN(parsed.getTime())) { return 'n/a'; } return format(parsed, 'MMM dd, yyyy HH:mm:ss'); } type TaskDetailModalProps = { isOpen: boolean; taskId: string | null; onClose: () => void; }; export function TaskDetailModal({ isOpen, taskId, onClose }: TaskDetailModalProps) { const { data, isLoading, error } = useTaskTimelineQuery(taskId ?? '', isOpen && Boolean(taskId)); const task = data?.task ?? null; const events = data?.events ?? []; const timeline = task ? buildStageTimeline(task, events) : []; const [expandedStage, setExpandedStage] = useState(null); const defaultExpandedStage = useMemo(() => { if (task?.status === 'completed' || task?.status === 'failed') { return null; } for (const item of timeline) { if (item.state === 'active') { return item.stage; } } for (let index = timeline.length - 1; index >= 0; index -= 1) { if (timeline[index]?.state === 'completed') { return timeline[index].stage; } } return timeline[0]?.stage ?? null; }, [timeline]); useEffect(() => { if (!isOpen) { setExpandedStage(null); return; } setExpandedStage((current) => { if (current && timeline.some((item) => item.stage === current)) { return current; } return defaultExpandedStage; }); }, [defaultExpandedStage, isOpen, timeline]); if (!isOpen || !taskId) { return null; } return (
{isLoading ? (
Loading task timeline...
{Array.from({ length: 4 }).map((_, index) => (
))}
) : null} {error ? (

Unable to load task timeline.

) : null} {task ? ( <>

Stage: {stageLabel(task.stage)}

Workflow run: {task.workflow_run_id ?? 'n/a'}

Created: {formatTimestamp(task.created_at)}

Finished: {formatTimestamp(task.finished_at)}

Updated: {formatTimestamp(task.updated_at)}

Attempts: {task.attempts}/{task.max_attempts}

Stage timeline

    {timeline.map((item) => (
  1. {expandedStage === item.stage ? (

    {item.detail ?? 'No additional detail for this step.'}

    {item.stage === 'completed' && task.result ? (

    Result detail

    {JSON.stringify(task.result, null, 2)}
    ) : null}
    ) : null}
  2. ))}
{task.error ? (

Error

{task.error}

) : null} ) : null}
); }