"use client"; import { ChevronRight, RotateCcw, ShieldOff, Undo2 } from "lucide-react"; import { useState } from "react"; import { toast } from "sonner"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "@/components/ui/alert-dialog"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Separator } from "@/components/ui/separator"; import { getToolIcon } from "@/contracts/enums/toolIcons"; import { type AgentAction, agentActionsApiService } from "@/lib/apis/agent-actions-api.service"; import { AppError } from "@/lib/error"; import { formatRelativeDate } from "@/lib/format-date"; import { cn } from "@/lib/utils"; function formatToolName(name: string): string { return name.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()); } interface ActionLogItemProps { action: AgentAction; threadId: number; onRevertSuccess: () => void; } export function ActionLogItem({ action, threadId, onRevertSuccess }: ActionLogItemProps) { const [isExpanded, setIsExpanded] = useState(false); const [isReverting, setIsReverting] = useState(false); const [confirmOpen, setConfirmOpen] = useState(false); const isAlreadyReverted = action.reverted_by_action_id !== null; const isRevertAction = action.is_revert_action; const hasError = action.error !== null && action.error !== undefined; const Icon = getToolIcon(action.tool_name); const displayName = formatToolName(action.tool_name); const argsPreview = action.args ? JSON.stringify(action.args, null, 2) : null; const truncatedArgs = argsPreview && argsPreview.length > 600 ? `${argsPreview.slice(0, 600)}…` : argsPreview; const canRevert = action.reversible && !isAlreadyReverted && !isRevertAction && !hasError; const handleRevert = async () => { setIsReverting(true); try { const response = await agentActionsApiService.revert(threadId, action.id); toast.success(response.message || "Action reverted successfully."); onRevertSuccess(); } catch (err) { const message = err instanceof AppError ? err.message : err instanceof Error ? err.message : "Failed to revert action."; toast.error(message); } finally { setIsReverting(false); setConfirmOpen(false); } }; return (
{isExpanded && (
{truncatedArgs && (

Arguments

								{truncatedArgs}
							
)} {action.error && (

Error

								{JSON.stringify(action.error, null, 2)}
							
)} {action.reverse_descriptor && (

Reverse plan

								{JSON.stringify(action.reverse_descriptor, null, 2)}
							
)}

Action ID: {action.id}

{canRevert ? ( Revert this action? This will undo {displayName} and append a new audit entry. The agent's chat history is preserved — only the tool's effects on your knowledge base or connectors will be reversed where possible. Cancel { e.preventDefault(); handleRevert(); }} disabled={isReverting} > {isReverting ? "Reverting…" : "Revert"} ) : (
{isAlreadyReverted ? "Already reverted" : isRevertAction ? "Revert entry" : hasError ? "Cannot revert errored action" : "Not reversible"}
)}
)}
); }