Skip to content

Commit 9117862

Browse files
authored
Evals enhancements: delete runs, show all run instead of just completed runs (RooCodeInc#2520)
1 parent c25163a commit 9117862

File tree

9 files changed

+791
-20
lines changed

9 files changed

+791
-20
lines changed

evals/.tool-versions

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
nodejs v20.18.1
21
python 3.13.2
32
golang 1.24.2
43
rust 1.85.1
4+
nodejs 20.18.1

evals/apps/web/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
"@evals/ipc": "workspace:^",
1515
"@evals/types": "workspace:^",
1616
"@hookform/resolvers": "^4.1.3",
17+
"@radix-ui/react-alert-dialog": "^1.1.7",
1718
"@radix-ui/react-dialog": "^1.1.6",
19+
"@radix-ui/react-dropdown-menu": "^2.1.7",
1820
"@radix-ui/react-label": "^2.1.2",
1921
"@radix-ui/react-popover": "^1.1.6",
2022
"@radix-ui/react-scroll-area": "^1.2.3",

evals/apps/web/src/app/home.tsx

Lines changed: 87 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,54 @@
11
"use client"
22

3-
import { useMemo } from "react"
3+
import { useCallback, useState, useRef } from "react"
44
import { useRouter } from "next/navigation"
55
import Link from "next/link"
6-
import { ChevronRight, Rocket } from "lucide-react"
6+
import { Ellipsis, Rocket } from "lucide-react"
77

88
import type { Run, TaskMetrics } from "@evals/db"
99

10+
import { deleteRun } from "@/lib/server/runs"
1011
import { formatCurrency, formatDuration, formatTokens } from "@/lib"
11-
import { Button, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui"
12+
import {
13+
Button,
14+
Table,
15+
TableBody,
16+
TableCell,
17+
TableHead,
18+
TableHeader,
19+
TableRow,
20+
DropdownMenu,
21+
DropdownMenuContent,
22+
DropdownMenuItem,
23+
DropdownMenuTrigger,
24+
AlertDialog,
25+
AlertDialogAction,
26+
AlertDialogCancel,
27+
AlertDialogContent,
28+
AlertDialogDescription,
29+
AlertDialogFooter,
30+
AlertDialogHeader,
31+
AlertDialogTitle,
32+
} from "@/components/ui"
1233

1334
export function Home({ runs }: { runs: (Run & { taskMetrics: TaskMetrics | null })[] }) {
1435
const router = useRouter()
1536

16-
const visibleRuns = useMemo(() => runs.filter((run) => run.taskMetrics !== null), [runs])
37+
const [deleteRunId, setDeleteRunId] = useState<number>()
38+
const continueRef = useRef<HTMLButtonElement>(null)
39+
40+
const onConfirmDelete = useCallback(async () => {
41+
if (!deleteRunId) {
42+
return
43+
}
44+
45+
try {
46+
await deleteRun(deleteRunId)
47+
setDeleteRunId(undefined)
48+
} catch (error) {
49+
console.error(error)
50+
}
51+
}, [deleteRunId])
1752

1853
return (
1954
<>
@@ -31,27 +66,47 @@ export function Home({ runs }: { runs: (Run & { taskMetrics: TaskMetrics | null
3166
</TableRow>
3267
</TableHeader>
3368
<TableBody>
34-
{visibleRuns.length ? (
35-
visibleRuns.map(({ taskMetrics, ...run }) => (
69+
{runs.length ? (
70+
runs.map(({ taskMetrics, ...run }) => (
3671
<TableRow key={run.id}>
3772
<TableCell>{run.model}</TableCell>
3873
<TableCell>{run.passed}</TableCell>
3974
<TableCell>{run.failed}</TableCell>
40-
<TableCell>{((run.passed / (run.passed + run.failed)) * 100).toFixed(1)}%</TableCell>
4175
<TableCell>
42-
<div className="flex items-center justify-evenly">
43-
<div>{formatTokens(taskMetrics!.tokensIn)}</div>/
44-
<div>{formatTokens(taskMetrics!.tokensOut)}</div>
45-
</div>
76+
{run.passed + run.failed > 0 && (
77+
<span>{((run.passed / (run.passed + run.failed)) * 100).toFixed(1)}%</span>
78+
)}
79+
</TableCell>
80+
<TableCell>
81+
{taskMetrics && (
82+
<div className="flex items-center justify-evenly">
83+
<div>{formatTokens(taskMetrics.tokensIn)}</div>/
84+
<div>{formatTokens(taskMetrics.tokensOut)}</div>
85+
</div>
86+
)}
4687
</TableCell>
47-
<TableCell>{formatCurrency(taskMetrics!.cost)}</TableCell>
48-
<TableCell>{formatDuration(taskMetrics!.duration)}</TableCell>
88+
<TableCell>{taskMetrics && formatCurrency(taskMetrics.cost)}</TableCell>
89+
<TableCell>{taskMetrics && formatDuration(taskMetrics.duration)}</TableCell>
4990
<TableCell>
50-
<Button variant="ghost" size="icon" asChild>
51-
<Link href={`/runs/${run.id}`}>
52-
<ChevronRight />
53-
</Link>
54-
</Button>
91+
<DropdownMenu>
92+
<Button variant="ghost" size="icon" asChild>
93+
<DropdownMenuTrigger>
94+
<Ellipsis />
95+
</DropdownMenuTrigger>
96+
</Button>
97+
<DropdownMenuContent align="end">
98+
<DropdownMenuItem asChild>
99+
<Link href={`/runs/${run.id}`}>View Tasks</Link>
100+
</DropdownMenuItem>
101+
<DropdownMenuItem
102+
onClick={() => {
103+
setDeleteRunId(run.id)
104+
setTimeout(() => continueRef.current?.focus(), 0)
105+
}}>
106+
Delete
107+
</DropdownMenuItem>
108+
</DropdownMenuContent>
109+
</DropdownMenu>
55110
</TableCell>
56111
</TableRow>
57112
))
@@ -74,6 +129,20 @@ export function Home({ runs }: { runs: (Run & { taskMetrics: TaskMetrics | null
74129
onClick={() => router.push("/runs/new")}>
75130
<Rocket className="size-6" />
76131
</Button>
132+
<AlertDialog open={!!deleteRunId} onOpenChange={() => setDeleteRunId(undefined)}>
133+
<AlertDialogContent>
134+
<AlertDialogHeader>
135+
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
136+
<AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
137+
</AlertDialogHeader>
138+
<AlertDialogFooter>
139+
<AlertDialogCancel>Cancel</AlertDialogCancel>
140+
<AlertDialogAction ref={continueRef} onClick={onConfirmDelete}>
141+
Continue
142+
</AlertDialogAction>
143+
</AlertDialogFooter>
144+
</AlertDialogContent>
145+
</AlertDialog>
77146
</>
78147
)
79148
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
"use client"
2+
3+
import * as React from "react"
4+
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
5+
6+
import { cn } from "@/lib/utils"
7+
import { buttonVariants } from "@/components/ui/button"
8+
9+
function AlertDialog({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
10+
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
11+
}
12+
13+
function AlertDialogTrigger({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
14+
return <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
15+
}
16+
17+
function AlertDialogPortal({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
18+
return <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
19+
}
20+
21+
function AlertDialogOverlay({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
22+
return (
23+
<AlertDialogPrimitive.Overlay
24+
data-slot="alert-dialog-overlay"
25+
className={cn(
26+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
27+
className,
28+
)}
29+
{...props}
30+
/>
31+
)
32+
}
33+
34+
function AlertDialogContent({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Content>) {
35+
return (
36+
<AlertDialogPortal>
37+
<AlertDialogOverlay />
38+
<AlertDialogPrimitive.Content
39+
data-slot="alert-dialog-content"
40+
className={cn(
41+
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
42+
className,
43+
)}
44+
{...props}
45+
/>
46+
</AlertDialogPortal>
47+
)
48+
}
49+
50+
function AlertDialogHeader({ className, ...props }: React.ComponentProps<"div">) {
51+
return (
52+
<div
53+
data-slot="alert-dialog-header"
54+
className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
55+
{...props}
56+
/>
57+
)
58+
}
59+
60+
function AlertDialogFooter({ className, ...props }: React.ComponentProps<"div">) {
61+
return (
62+
<div
63+
data-slot="alert-dialog-footer"
64+
className={cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className)}
65+
{...props}
66+
/>
67+
)
68+
}
69+
70+
function AlertDialogTitle({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
71+
return (
72+
<AlertDialogPrimitive.Title
73+
data-slot="alert-dialog-title"
74+
className={cn("text-lg font-semibold", className)}
75+
{...props}
76+
/>
77+
)
78+
}
79+
80+
function AlertDialogDescription({
81+
className,
82+
...props
83+
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
84+
return (
85+
<AlertDialogPrimitive.Description
86+
data-slot="alert-dialog-description"
87+
className={cn("text-muted-foreground text-sm", className)}
88+
{...props}
89+
/>
90+
)
91+
}
92+
93+
function AlertDialogAction({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Action>) {
94+
return <AlertDialogPrimitive.Action className={cn(buttonVariants(), className)} {...props} />
95+
}
96+
97+
function AlertDialogCancel({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) {
98+
return <AlertDialogPrimitive.Cancel className={cn(buttonVariants({ variant: "outline" }), className)} {...props} />
99+
}
100+
101+
export {
102+
AlertDialog,
103+
AlertDialogPortal,
104+
AlertDialogOverlay,
105+
AlertDialogTrigger,
106+
AlertDialogContent,
107+
AlertDialogHeader,
108+
AlertDialogFooter,
109+
AlertDialogTitle,
110+
AlertDialogDescription,
111+
AlertDialogAction,
112+
AlertDialogCancel,
113+
}

0 commit comments

Comments
 (0)