11import { Card , CardContent , CardDescription , CardHeader , CardTitle } from './ui/card' ;
22import { Badge } from './ui/badge' ;
33import { Button } from './ui/button' ;
4- import { Play , Pause , Settings , Trash2 , Activity } from 'lucide-react' ;
4+ import { Play , Pause , Settings , Trash2 , Activity , MessageSquare , Target , Clock , ChevronDown , ChevronUp } from 'lucide-react' ;
5+ import { useState } from 'react' ;
6+
7+ interface DailyTask {
8+ id : string ;
9+ date : string ;
10+ task : string ;
11+ status : 'completed' | 'failed' | 'in_progress' ;
12+ }
513
614interface AgentCardProps {
715 id : string ;
@@ -11,10 +19,15 @@ interface AgentCardProps {
1119 language : string ;
1220 lastRun : string ;
1321 executionCount : number ;
22+ currentTask ?: string ;
23+ stopScore ?: number ;
24+ slackChannel ?: string ;
25+ dailyTasks ?: DailyTask [ ] ;
1426 onStart : ( id : string ) => void ;
1527 onPause : ( id : string ) => void ;
1628 onConfigure : ( id : string ) => void ;
1729 onDelete : ( id : string ) => void ;
30+ onSlackOpen ?: ( channel : string ) => void ;
1831}
1932
2033export function AgentCard ( {
@@ -25,69 +38,146 @@ export function AgentCard({
2538 language,
2639 lastRun,
2740 executionCount,
41+ currentTask,
42+ stopScore,
43+ slackChannel,
44+ dailyTasks = [ ] ,
2845 onStart,
2946 onPause,
3047 onConfigure,
3148 onDelete,
49+ onSlackOpen,
3250} : AgentCardProps ) {
51+ const [ expanded , setExpanded ] = useState ( false ) ;
52+
3353 const statusColors = {
3454 active : 'bg-green-500' ,
3555 paused : 'bg-yellow-500' ,
3656 stopped : 'bg-gray-500' ,
3757 } ;
3858
59+ const scoreColor = ( score : number ) => {
60+ if ( score >= 70 ) return 'text-red-500' ;
61+ if ( score >= 40 ) return 'text-yellow-500' ;
62+ return 'text-green-500' ;
63+ } ;
64+
65+ const taskStatusIcon = ( status : DailyTask [ 'status' ] ) => {
66+ switch ( status ) {
67+ case 'completed' : return '✅' ;
68+ case 'failed' : return '❌' ;
69+ case 'in_progress' : return '🔄' ;
70+ }
71+ } ;
72+
3973 return (
4074 < Card className = "hover:shadow-lg transition-shadow" >
41- < CardHeader >
75+ < CardHeader className = "pb-2" >
4276 < div className = "flex items-start justify-between" >
4377 < div className = "flex-1" >
4478 < div className = "flex items-center gap-2" >
45- < CardTitle > { name } </ CardTitle >
46- < div className = { `w-2 h-2 rounded-full ${ statusColors [ status ] } ` } />
79+ < CardTitle className = "text-base" > { name } </ CardTitle >
80+ < div className = { `w-2 h-2 rounded-full ${ statusColors [ status ] } ${ status === 'active' ? 'animate-pulse' : '' } ` } />
81+ { stopScore !== undefined && (
82+ < Badge variant = "outline" className = { scoreColor ( stopScore ) } >
83+ Score: { stopScore }
84+ </ Badge >
85+ ) }
4786 </ div >
48- < CardDescription className = "mt-2 " > { description } </ CardDescription >
87+ < CardDescription className = "mt-1 text-xs " > { description } </ CardDescription >
4988 </ div >
89+ { slackChannel && (
90+ < Button
91+ size = "sm"
92+ variant = "ghost"
93+ className = "h-8 w-8 p-0"
94+ onClick = { ( ) => onSlackOpen ?.( slackChannel ) }
95+ title = { `Slack: ${ slackChannel } ` }
96+ >
97+ < MessageSquare className = "w-4 h-4" />
98+ </ Button >
99+ ) }
50100 </ div >
51101 </ CardHeader >
52- < CardContent >
53- < div className = "space-y-4" >
54- < div className = "flex items-center justify-between text-sm" >
55- < span className = "text-muted-foreground" > Language:</ span >
56- < Badge variant = "outline" > { language } </ Badge >
57- </ div >
58- < div className = "flex items-center justify-between text-sm" >
59- < span className = "text-muted-foreground" > Executions:</ span >
60- < span className = "flex items-center gap-1" >
61- < Activity className = "w-4 h-4" />
62- { executionCount }
63- </ span >
64- </ div >
65- < div className = "flex items-center justify-between text-sm" >
66- < span className = "text-muted-foreground" > Last Run:</ span >
67- < span > { lastRun } </ span >
102+ < CardContent className = "pt-2" >
103+ < div className = "space-y-3" >
104+ { /* Live Status */ }
105+ { currentTask && status === 'active' && (
106+ < div className = "bg-blue-50 dark:bg-blue-950 rounded-md p-2" >
107+ < div className = "flex items-center gap-2 text-xs" >
108+ < div className = "w-2 h-2 bg-blue-500 rounded-full animate-pulse" />
109+ < span className = "font-medium text-blue-700 dark:text-blue-300" > Live:</ span >
110+ < span className = "text-blue-600 dark:text-blue-400 truncate" > { currentTask } </ span >
111+ </ div >
112+ </ div >
113+ ) }
114+
115+ { /* Stats Row */ }
116+ < div className = "grid grid-cols-3 gap-2 text-xs" >
117+ < div className = "flex items-center gap-1" >
118+ < Activity className = "w-3 h-3 text-muted-foreground" />
119+ < span > { executionCount } </ span >
120+ </ div >
121+ < div className = "flex items-center gap-1" >
122+ < Clock className = "w-3 h-3 text-muted-foreground" />
123+ < span > { lastRun } </ span >
124+ </ div >
125+ < div className = "flex items-center gap-1" >
126+ < Target className = "w-3 h-3 text-muted-foreground" />
127+ < Badge variant = "outline" className = "text-xs py-0" > { language } </ Badge >
128+ </ div >
68129 </ div >
69- < div className = "flex gap-2 mt-4" >
130+
131+ { /* Daily Tasks Toggle */ }
132+ { dailyTasks . length > 0 && (
133+ < div >
134+ < Button
135+ variant = "ghost"
136+ size = "sm"
137+ className = "w-full justify-between h-7 text-xs"
138+ onClick = { ( ) => setExpanded ( ! expanded ) }
139+ >
140+ < span > Tagesaufgaben ({ dailyTasks . length } )</ span >
141+ { expanded ? < ChevronUp className = "w-3 h-3" /> : < ChevronDown className = "w-3 h-3" /> }
142+ </ Button >
143+
144+ { expanded && (
145+ < div className = "mt-2 space-y-1 max-h-32 overflow-y-auto" >
146+ { dailyTasks . map ( ( task ) => (
147+ < div key = { task . id } className = "flex items-center gap-2 text-xs p-1 bg-muted/50 rounded" >
148+ < span > { taskStatusIcon ( task . status ) } </ span >
149+ < span className = "text-muted-foreground" > { task . date } </ span >
150+ < span className = "truncate flex-1" > { task . task } </ span >
151+ </ div >
152+ ) ) }
153+ </ div >
154+ ) }
155+ </ div >
156+ ) }
157+
158+ { /* Action Buttons */ }
159+ < div className = "flex gap-2 pt-2 border-t" >
70160 { status === 'active' ? (
71- < Button size = "sm" variant = "outline" onClick = { ( ) => onPause ( id ) } >
72- < Pause className = "w-4 h-4 mr-1" />
161+ < Button size = "sm" variant = "outline" className = "h-7 text-xs" onClick = { ( ) => onPause ( id ) } >
162+ < Pause className = "w-3 h-3 mr-1" />
73163 Pause
74164 </ Button >
75165 ) : (
76- < Button size = "sm" onClick = { ( ) => onStart ( id ) } >
77- < Play className = "w-4 h-4 mr-1" />
166+ < Button size = "sm" className = "h-7 text-xs" onClick = { ( ) => onStart ( id ) } >
167+ < Play className = "w-3 h-3 mr-1" />
78168 Start
79169 </ Button >
80170 ) }
81- < Button size = "sm" variant = "outline" onClick = { ( ) => onConfigure ( id ) } >
82- < Settings className = "w-4 h-4 " />
171+ < Button size = "sm" variant = "outline" className = "h-7 w-7 p-0" onClick = { ( ) => onConfigure ( id ) } >
172+ < Settings className = "w-3 h-3 " />
83173 </ Button >
84174 < Button
85175 size = "sm"
86176 variant = "outline"
87- className = "ml-auto text-destructive"
177+ className = "h-7 w-7 p-0 ml-auto text-destructive"
88178 onClick = { ( ) => onDelete ( id ) }
89179 >
90- < Trash2 className = "w-4 h-4 " />
180+ < Trash2 className = "w-3 h-3 " />
91181 </ Button >
92182 </ div >
93183 </ div >
0 commit comments