"use client"; import * as React from "react"; import type { ConvoyStatus } from "@tasks/shared/convoy-lifecycle"; import { Loader2, Sparkles } from "lucide-react"; import { Button } from "@/components/ui/button"; import { api } from "@/lib/trpc"; function gateActionsForStatus(status: ConvoyStatus): Array<{ action: "approve" | "revise" | "request_changes" | "promote"; label: string; variant?: "default" | "outline" | "destructive"; }> { switch (status) { case "convoy_review": return [ { action: "approve", label: "Approve plan" }, { action: "revise", label: "Request changes", variant: "outline" }, ]; case "pr_review": return [ { action: "approve", label: "Approve merge" }, { action: "request_changes", label: "Request changes", variant: "outline" }, ]; case "merged": return [{ action: "promote", label: "Promote to prod" }]; default: return []; } } export function ConvoyDetailPanel({ workspaceSlug, convoyId, }: { workspaceSlug: string; convoyId: string | null; }) { const utils = api.useUtils(); const [copilotText, setCopilotText] = React.useState(null); const detailQuery = api.convoys.get.useQuery( { workspace: workspaceSlug, convoyId: convoyId ?? "" }, { enabled: Boolean(workspaceSlug && convoyId) }, ); const gateMut = api.convoys.gateAction.useMutation({ onSuccess: () => { void utils.convoys.kanban.invalidate(); if (convoyId) void utils.convoys.get.invalidate({ workspace: workspaceSlug, convoyId }); }, }); const copilotMut = api.convoys.gateCopilot.useMutation({ onSuccess: (result) => setCopilotText(result.text), }); if (!convoyId) { return (
Select a convoy to review gates and co-pilot suggestions.
); } if (detailQuery.isLoading) { return (
Loading convoy…
); } const convoy = detailQuery.data?.convoy; if (!convoy) { return

Convoy not found.

; } const status = convoy.status as ConvoyStatus; const actions = gateActionsForStatus(status); return (

{convoy.content?.convoySlug ?? convoy.title}

Status: {status}

{convoy.content?.successMetric && (

{convoy.content.successMetric}

)}

Worker checkpoints

{detailQuery.data?.checkpoints.count ?? 0} checkpoint {(detailQuery.data?.checkpoints.count ?? 0) === 1 ? "" : "s"} {detailQuery.data?.checkpoints.lastOccurredAt ? ` · last ${new Date(detailQuery.data.checkpoints.lastOccurredAt).toLocaleString()}` : ""}

{convoy.description && (

Plan

{convoy.description}
)} {actions.length > 0 && (
{actions.map((item) => ( ))}
)}

Gate co-pilot

{copilotMut.data && (

Model: {copilotMut.data.resolvedAlias} ({copilotMut.data.modelId})

)} {copilotMut.error && (

{copilotMut.error.message}

)} {copilotText && (

{copilotText}

)}
{(detailQuery.data?.briefs.length ?? 0) > 0 && (

Briefs

    {detailQuery.data?.briefs.map((brief) => (
  • {brief.title}{" "} ({brief.status ?? "—"})
  • ))}
)}
); }