Task attempt 661f4103-d3a8-4f67-a2b8-fd9c8633ac00 - Final changes

This commit is contained in:
Louis Knight-Webb
2025-06-24 17:09:15 +01:00
parent b16726cc2b
commit fb8c03fb1f

View File

@@ -4,7 +4,6 @@ import {
X, X,
History, History,
Clock, Clock,
FileText,
Code, Code,
ChevronDown, ChevronDown,
ChevronUp, ChevronUp,
@@ -15,6 +14,7 @@ import {
Send, Send,
AlertCircle, AlertCircle,
Play, Play,
GitCompare,
} from "lucide-react"; } from "lucide-react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Alert, AlertDescription } from "@/components/ui/alert"; import { Alert, AlertDescription } from "@/components/ui/alert";
@@ -700,26 +700,53 @@ export function TaskDetailsPanel({
</div> </div>
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
{onEditTask && ( {onEditTask && (
<Button <TooltipProvider>
variant="ghost" <Tooltip>
size="icon" <TooltipTrigger asChild>
onClick={() => onEditTask(task)} <Button
> variant="ghost"
<Edit className="h-4 w-4" /> size="icon"
</Button> onClick={() => onEditTask(task)}
>
<Edit className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Edit task</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)} )}
{onDeleteTask && ( {onDeleteTask && (
<Button <TooltipProvider>
variant="ghost" <Tooltip>
size="icon" <TooltipTrigger asChild>
onClick={() => onDeleteTask(task.id)} <Button
> variant="ghost"
<Trash2 className="h-4 w-4 text-red-500" /> size="icon"
</Button> onClick={() => onDeleteTask(task.id)}
>
<Trash2 className="h-4 w-4 text-red-500" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Delete task</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)} )}
<Button variant="ghost" size="icon" onClick={onClose}> <TooltipProvider>
<X className="h-4 w-4" /> <Tooltip>
</Button> <TooltipTrigger asChild>
<Button variant="ghost" size="icon" onClick={onClose}>
<X className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Close panel</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div> </div>
</div> </div>
@@ -803,78 +830,105 @@ export function TaskDetailsPanel({
{/* Attempt Management Group */} {/* Attempt Management Group */}
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
{taskAttempts.length > 1 && ( {taskAttempts.length > 1 && (
<DropdownMenu> <TooltipProvider>
<DropdownMenuTrigger asChild> <Tooltip>
<Button variant="outline" size="sm"> <TooltipTrigger asChild>
<History className="h-4 w-4" /> <DropdownMenu>
</Button> <DropdownMenuTrigger asChild>
</DropdownMenuTrigger> <Button variant="outline" size="sm">
<DropdownMenuContent align="start" className="w-64"> <History className="h-4 w-4" />
{taskAttempts.map((attempt) => ( </Button>
<DropdownMenuItem </DropdownMenuTrigger>
key={attempt.id} <DropdownMenuContent align="start" className="w-64">
onClick={() => handleAttemptChange(attempt.id)} {taskAttempts.map((attempt) => (
className={ <DropdownMenuItem
selectedAttempt?.id === attempt.id key={attempt.id}
? "bg-accent" onClick={() => handleAttemptChange(attempt.id)}
: "" className={
} selectedAttempt?.id === attempt.id
> ? "bg-accent"
<div className="flex flex-col w-full"> : ""
<span className="font-medium text-sm"> }
{new Date( >
attempt.created_at <div className="flex flex-col w-full">
).toLocaleDateString()}{" "} <span className="font-medium text-sm">
{new Date( {new Date(
attempt.created_at attempt.created_at
).toLocaleTimeString()} ).toLocaleDateString()}{" "}
</span> {new Date(
<span className="text-xs text-muted-foreground"> attempt.created_at
{attempt.executor || "executor"} ).toLocaleTimeString()}
</span> </span>
</div> <span className="text-xs text-muted-foreground">
</DropdownMenuItem> {attempt.executor || "executor"}
))} </span>
</DropdownMenuContent> </div>
</DropdownMenu> </DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
</TooltipTrigger>
<TooltipContent>
<p>View attempt history</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)} )}
<div className="flex"> <div className="flex">
<Button <TooltipProvider>
variant="outline" <Tooltip>
size="sm" <TooltipTrigger asChild>
onClick={() => createNewAttempt()} <Button
className="rounded-r-none border-r-0" variant="outline"
> size="sm"
{selectedAttempt ? "Retry" : "Start"} onClick={() => createNewAttempt()}
</Button> className="rounded-r-none border-r-0"
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
size="sm"
className="rounded-l-none px-2"
>
<Settings2 className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{availableExecutors.map((executor) => (
<DropdownMenuItem
key={executor.id}
onClick={() => setSelectedExecutor(executor.id)}
className={
selectedExecutor === executor.id
? "bg-accent"
: ""
}
> >
{executor.name} {selectedAttempt ? "Retry" : "Start"}
{selectedExecutor === executor.id && </Button>
" (Default)"} </TooltipTrigger>
</DropdownMenuItem> <TooltipContent>
))} <p>{selectedAttempt ? "Retry task with current executor" : "Start task with current executor"}</p>
</DropdownMenuContent> </TooltipContent>
</DropdownMenu> </Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
size="sm"
className="rounded-l-none px-2"
>
<Settings2 className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{availableExecutors.map((executor) => (
<DropdownMenuItem
key={executor.id}
onClick={() => setSelectedExecutor(executor.id)}
className={
selectedExecutor === executor.id
? "bg-accent"
: ""
}
>
{executor.name}
{selectedExecutor === executor.id &&
" (Default)"}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
</TooltipTrigger>
<TooltipContent>
<p>Choose executor</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div> </div>
</div> </div>
@@ -885,15 +939,24 @@ export function TaskDetailsPanel({
{/* Execution Control Group */} {/* Execution Control Group */}
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
{(isAttemptRunning || isStopping) && ( {(isAttemptRunning || isStopping) && (
<Button <TooltipProvider>
variant="outline" <Tooltip>
size="sm" <TooltipTrigger asChild>
onClick={stopAllExecutions} <Button
disabled={isStopping} variant="outline"
className="text-red-600 hover:text-red-700 hover:bg-red-50 disabled:opacity-50" size="sm"
> onClick={stopAllExecutions}
<StopCircle className="h-4 w-4" /> disabled={isStopping}
</Button> className="text-red-600 hover:text-red-700 hover:bg-red-50 disabled:opacity-50"
>
<StopCircle className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>{isStopping ? "Stopping execution..." : "Stop execution"}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)} )}
<TooltipProvider> <TooltipProvider>
<Tooltip> <Tooltip>
@@ -975,20 +1038,38 @@ export function TaskDetailsPanel({
{/* Code Actions Group */} {/* Code Actions Group */}
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<Button <TooltipProvider>
variant="outline" <Tooltip>
size="sm" <TooltipTrigger asChild>
onClick={() => openInEditor()} <Button
> variant="outline"
<Code className="h-4 w-4" /> size="sm"
</Button> onClick={() => openInEditor()}
<Button variant="outline" size="sm" asChild> >
<Link <Code className="h-4 w-4" />
to={`/projects/${projectId}/tasks/${task.id}/attempts/${selectedAttempt.id}/compare`} </Button>
> </TooltipTrigger>
<FileText className="h-4 w-4" /> <TooltipContent>
</Link> <p>Open in editor</p>
</Button> </TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline" size="sm" asChild>
<Link
to={`/projects/${projectId}/tasks/${task.id}/attempts/${selectedAttempt.id}/compare`}
>
<GitCompare className="h-4 w-4" />
</Link>
</Button>
</TooltipTrigger>
<TooltipContent>
<p>View code changes</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div> </div>
</> </>
)} )}