11"use client"
22
3- import { useMemo } from "react"
3+ import { useCallback , useState , useRef } from "react"
44import { useRouter } from "next/navigation"
55import Link from "next/link"
6- import { ChevronRight , Rocket } from "lucide-react"
6+ import { Ellipsis , Rocket } from "lucide-react"
77
88import type { Run , TaskMetrics } from "@evals/db"
99
10+ import { deleteRun } from "@/lib/server/runs"
1011import { 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
1334export 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}
0 commit comments