11import type { LoopSchemas } from "@posthog/api-client/loops" ;
22import { Badge } from "@posthog/ui/primitives/Badge" ;
3+ import { Button } from "@posthog/ui/primitives/Button" ;
34import { navigateToTaskDetail } from "@posthog/ui/router/navigationBridge" ;
45import { Flex , Text } from "@radix-ui/themes" ;
56
@@ -20,43 +21,88 @@ function statusColor(
2021 }
2122}
2223
23- function formatRelativeDate ( iso : string | null ) : string {
24- if ( ! iso ) return "" ;
25- const date = new Date ( iso ) ;
26- if ( Number . isNaN ( date . getTime ( ) ) ) return "" ;
27- return date . toLocaleString ( ) ;
24+ function formatRelative ( iso : string ) : string {
25+ const then = new Date ( iso ) . getTime ( ) ;
26+ if ( Number . isNaN ( then ) ) return "" ;
27+ const sec = Math . round ( ( Date . now ( ) - then ) / 1000 ) ;
28+ if ( sec < 45 ) return "just now" ;
29+ const min = Math . round ( sec / 60 ) ;
30+ if ( min < 60 ) return `${ min } m ago` ;
31+ const hr = Math . round ( min / 60 ) ;
32+ if ( hr < 24 ) return `${ hr } h ago` ;
33+ const day = Math . round ( hr / 24 ) ;
34+ if ( day < 7 ) return `${ day } d ago` ;
35+ return new Date ( iso ) . toLocaleDateString ( ) ;
36+ }
37+
38+ function formatDuration ( ms : number ) : string {
39+ const sec = Math . max ( 0 , Math . round ( ms / 1000 ) ) ;
40+ if ( sec < 60 ) return `${ sec } s` ;
41+ const min = Math . floor ( sec / 60 ) ;
42+ const rem = sec % 60 ;
43+ if ( min < 60 ) return rem ? `${ min } m ${ rem } s` : `${ min } m` ;
44+ const hr = Math . floor ( min / 60 ) ;
45+ const remMin = min % 60 ;
46+ return remMin ? `${ hr } h ${ remMin } m` : `${ hr } h` ;
47+ }
48+
49+ function durationLabel ( run : LoopSchemas . LoopRun ) : string {
50+ const start = new Date ( run . created_at ) . getTime ( ) ;
51+ if ( Number . isNaN ( start ) ) return "" ;
52+ if ( run . completed_at ) {
53+ const end = new Date ( run . completed_at ) . getTime ( ) ;
54+ if ( ! Number . isNaN ( end ) ) return `ran ${ formatDuration ( end - start ) } ` ;
55+ }
56+ if ( run . status === "in_progress" )
57+ return `running ${ formatDuration ( Date . now ( ) - start ) } ` ;
58+ if ( run . status === "queued" ) return "queued" ;
59+ return "" ;
2860}
2961
3062export function LoopRunRow ( { run } : { run : LoopSchemas . LoopRun } ) {
63+ const meta = [
64+ formatRelative ( run . created_at ) ,
65+ durationLabel ( run ) ,
66+ run . environment ,
67+ run . loop_trigger_id ? "Triggered" : "Manual" ,
68+ ] . filter ( Boolean ) ;
69+
3170 return (
32- < button
33- type = "button "
34- onClick = { ( ) => navigateToTaskDetail ( run . task_id ) }
35- title = "Open this run to see the agent's activity "
36- className = "w-full rounded-(--radius-2) border border-border bg-(--color-panel-solid) px-3 py-2.5 text-left transition-colors hover:bg-(--gray-3) "
71+ < Flex
72+ align = "center "
73+ justify = "between"
74+ gap = "3 "
75+ className = "rounded-(--radius-2) border border-border bg-(--color-panel-solid) px-3 py-2.5"
3776 >
38- < Flex align = "center" justify = "between" gap = "3" >
39- < Flex direction = "column" className = "min-w-0 gap-0.5" >
40- < Flex align = "center" gap = "2" >
41- < Badge color = { statusColor ( run . status ) } > { run . status } </ Badge >
42- < Text className = "text-[12px] text-gray-11" >
43- { formatRelativeDate ( run . created_at ) }
44- </ Text >
45- </ Flex >
46- { run . error_message ? (
47- < Text className = "truncate text-(--red-11) text-[11.5px]" >
48- { run . error_message }
49- </ Text >
50- ) : run . branch ? (
51- < Text className = "truncate text-[11.5px] text-gray-10 [font-family:var(--font-mono)]" >
52- { run . branch }
53- </ Text >
54- ) : null }
77+ < Flex direction = "column" className = "min-w-0 gap-1" >
78+ < Flex align = "center" gap = "2" wrap = "wrap" >
79+ < Badge color = { statusColor ( run . status ) } > { run . status } </ Badge >
80+ < Text
81+ className = "text-[12px] text-gray-11"
82+ title = { new Date ( run . created_at ) . toLocaleString ( ) }
83+ >
84+ { meta . join ( " · " ) }
85+ </ Text >
5586 </ Flex >
56- < Text className = "shrink-0 text-[11px] text-gray-10 uppercase" >
57- { run . environment }
58- </ Text >
87+ { run . error_message ? (
88+ < Text className = "truncate text-(--red-11) text-[11.5px]" >
89+ { run . error_message }
90+ </ Text >
91+ ) : run . branch ? (
92+ < Text className = "truncate text-[11.5px] text-gray-10 [font-family:var(--font-mono)]" >
93+ { run . branch }
94+ </ Text >
95+ ) : null }
5996 </ Flex >
60- </ button >
97+ < Button
98+ variant = "soft"
99+ color = "gray"
100+ size = "1"
101+ className = "shrink-0"
102+ onClick = { ( ) => navigateToTaskDetail ( run . task_id ) }
103+ >
104+ View run
105+ </ Button >
106+ </ Flex >
61107 ) ;
62108}
0 commit comments