Skip to content

Commit 21e619c

Browse files
committed
Allow run deletion
1 parent c26c131 commit 21e619c

File tree

8 files changed

+773
-8
lines changed

8 files changed

+773
-8
lines changed

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: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,56 @@
11
"use client"
22

3-
import { useMemo } from "react"
3+
import { useCallback, useMemo, useState } 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

37+
const [deleteRunId, setDeleteRunId] = useState<number>()
38+
1639
const visibleRuns = useMemo(() => runs.filter((run) => run.taskMetrics !== null), [runs])
1740

41+
const onConfirmDelete = useCallback(async () => {
42+
if (!deleteRunId) {
43+
return
44+
}
45+
46+
try {
47+
await deleteRun(deleteRunId)
48+
setDeleteRunId(undefined)
49+
} catch (error) {
50+
console.error(error)
51+
}
52+
}, [deleteRunId])
53+
1854
return (
1955
<>
2056
<Table className="border border-t-0">
@@ -47,11 +83,21 @@ export function Home({ runs }: { runs: (Run & { taskMetrics: TaskMetrics | null
4783
<TableCell>{formatCurrency(taskMetrics!.cost)}</TableCell>
4884
<TableCell>{formatDuration(taskMetrics!.duration)}</TableCell>
4985
<TableCell>
50-
<Button variant="ghost" size="icon" asChild>
51-
<Link href={`/runs/${run.id}`}>
52-
<ChevronRight />
53-
</Link>
54-
</Button>
86+
<DropdownMenu>
87+
<Button variant="ghost" size="icon" asChild>
88+
<DropdownMenuTrigger>
89+
<Ellipsis />
90+
</DropdownMenuTrigger>
91+
</Button>
92+
<DropdownMenuContent>
93+
<DropdownMenuItem asChild>
94+
<Link href={`/runs/${run.id}`}>View Tasks</Link>
95+
</DropdownMenuItem>
96+
<DropdownMenuItem onClick={() => setDeleteRunId(run.id)}>
97+
Delete
98+
</DropdownMenuItem>
99+
</DropdownMenuContent>
100+
</DropdownMenu>
55101
</TableCell>
56102
</TableRow>
57103
))
@@ -74,6 +120,18 @@ export function Home({ runs }: { runs: (Run & { taskMetrics: TaskMetrics | null
74120
onClick={() => router.push("/runs/new")}>
75121
<Rocket className="size-6" />
76122
</Button>
123+
<AlertDialog open={!!deleteRunId} onOpenChange={() => setDeleteRunId(undefined)}>
124+
<AlertDialogContent>
125+
<AlertDialogHeader>
126+
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
127+
<AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
128+
</AlertDialogHeader>
129+
<AlertDialogFooter>
130+
<AlertDialogCancel>Cancel</AlertDialogCancel>
131+
<AlertDialogAction onClick={onConfirmDelete}>Continue</AlertDialogAction>
132+
</AlertDialogFooter>
133+
</AlertDialogContent>
134+
</AlertDialog>
77135
</>
78136
)
79137
}
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)