"use client"; import { useState, useEffect } from "react"; import { ListTodo } from "lucide-react"; import type { Agent, AgentTask } from "@multica/core/types"; import { Skeleton } from "@multica/ui/components/ui/skeleton"; import { api } from "@multica/core/api"; import { useWorkspaceId } from "@multica/core/hooks"; import { useWorkspacePaths } from "@multica/core/paths"; import { issueListOptions } from "@multica/core/issues/queries"; import { useQuery } from "@tanstack/react-query"; import { AppLink } from "../../../navigation"; import { taskStatusConfig } from "../../config"; export function TasksTab({ agent }: { agent: Agent }) { const [tasks, setTasks] = useState([]); const [loading, setLoading] = useState(true); const wsId = useWorkspaceId(); const paths = useWorkspacePaths(); const { data: issues = [] } = useQuery(issueListOptions(wsId)); useEffect(() => { setLoading(true); api .listAgentTasks(agent.id) .then(setTasks) .catch(() => setTasks([])) .finally(() => setLoading(false)); }, [agent.id]); if (loading) { return (
{Array.from({ length: 3 }).map((_, i) => (
))}
); } // Sort: active tasks (running > dispatched > queued) first, then completed/failed by date const activeStatuses = ["running", "dispatched", "queued"]; const sortedTasks = [...tasks].sort((a, b) => { const aActive = activeStatuses.indexOf(a.status); const bActive = activeStatuses.indexOf(b.status); const aIsActive = aActive !== -1; const bIsActive = bActive !== -1; if (aIsActive && !bIsActive) return -1; if (!aIsActive && bIsActive) return 1; if (aIsActive && bIsActive) return aActive - bActive; return new Date(b.created_at).getTime() - new Date(a.created_at).getTime(); }); const issueMap = new Map(issues.map((i) => [i.id, i])); return (

Task Queue

Issues assigned to this agent and their execution status.

{tasks.length === 0 ? (

No tasks in queue

Assign an issue to this agent to get started.

) : (
{sortedTasks.map((task) => { const config = taskStatusConfig[task.status] ?? taskStatusConfig.queued!; const Icon = config.icon; const issue = issueMap.get(task.issue_id); const isActive = task.status === "running" || task.status === "dispatched"; const isRunning = task.status === "running"; const rowClassName = `flex items-center gap-3 rounded-lg border px-4 py-3 transition-shadow hover:shadow-sm ${ isRunning ? "border-success/40 bg-success/5" : task.status === "dispatched" ? "border-info/40 bg-info/5" : "" }`; const content = ( <>
{issue && ( {issue.identifier} )} {issue?.title ?? `Issue ${task.issue_id.slice(0, 8)}...`}
{isRunning && task.started_at ? `Started ${new Date(task.started_at).toLocaleString()}` : task.status === "dispatched" && task.dispatched_at ? `Dispatched ${new Date(task.dispatched_at).toLocaleString()}` : task.status === "completed" && task.completed_at ? `Completed ${new Date(task.completed_at).toLocaleString()}` : task.status === "failed" && task.completed_at ? `Failed ${new Date(task.completed_at).toLocaleString()}` : `Queued ${new Date(task.created_at).toLocaleString()}`}
{config.label} ); return ( {content} ); })}
)}
); }