Skip to content

Commit e6ac3fd

Browse files
committed
Add enhanced agent dashboard features
New features: - Live status: Shows current task per agent - STOP scoring: Color-coded score display - Daily tasks: Expandable task history per agent - Slack integration: Click to open agent channel - Task input: Create tasks with priority and agent assignment Components: - Enhanced AgentCard with all new features - New TaskInput component for task creation
1 parent 6059cf2 commit e6ac3fd

3 files changed

Lines changed: 335 additions & 30 deletions

File tree

src/App.tsx

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ import {
4646
SelectTrigger,
4747
SelectValue,
4848
} from './components/ui/select';
49+
import { TaskInput } from './components/TaskInput';
50+
51+
interface DailyTask {
52+
id: string;
53+
date: string;
54+
task: string;
55+
status: 'completed' | 'failed' | 'in_progress';
56+
}
4957

5058
interface Agent {
5159
id: string;
@@ -55,6 +63,10 @@ interface Agent {
5563
language: string;
5664
lastRun: string;
5765
executionCount: number;
66+
currentTask?: string;
67+
stopScore?: number;
68+
slackChannel?: string;
69+
dailyTasks?: DailyTask[];
5870
}
5971

6072
interface LogEntry {
@@ -75,6 +87,14 @@ export default function App() {
7587
language: 'TypeScript',
7688
lastRun: '1 min ago',
7789
executionCount: 2847,
90+
currentTask: 'Routing: Research Task → Cloud Assistant',
91+
stopScore: 12,
92+
slackChannel: '#supervisor',
93+
dailyTasks: [
94+
{ id: '1', date: '25.12.', task: 'Task geroutet: Memory Server', status: 'completed' },
95+
{ id: '2', date: '25.12.', task: 'Health-Check alle Agents', status: 'completed' },
96+
{ id: '3', date: '25.12.', task: 'Neuen Task zuweisen', status: 'in_progress' },
97+
],
7898
},
7999
{
80100
id: 'engineering-lead',
@@ -84,6 +104,14 @@ export default function App() {
84104
language: 'TypeScript',
85105
lastRun: '2 min ago',
86106
executionCount: 1923,
107+
currentTask: 'Verifying: MCP Server Artefakte',
108+
stopScore: 28,
109+
slackChannel: '#engineering',
110+
dailyTasks: [
111+
{ id: '1', date: '25.12.', task: 'Code Review: AgentCard.tsx', status: 'completed' },
112+
{ id: '2', date: '25.12.', task: 'STOP Score berechnet: 28', status: 'completed' },
113+
{ id: '3', date: '25.12.', task: 'Artefakte prüfen', status: 'in_progress' },
114+
],
87115
},
88116
{
89117
id: 'cloud-assistant',
@@ -93,6 +121,14 @@ export default function App() {
93121
language: 'TypeScript',
94122
lastRun: '30 sec ago',
95123
executionCount: 4521,
124+
currentTask: 'Erstelle: TaskInput Komponente',
125+
stopScore: 15,
126+
slackChannel: '#assistant',
127+
dailyTasks: [
128+
{ id: '1', date: '25.12.', task: '9 Cloud Agents erstellt', status: 'completed' },
129+
{ id: '2', date: '25.12.', task: 'MCP Server konfiguriert', status: 'completed' },
130+
{ id: '3', date: '25.12.', task: 'UI Dashboard erweitert', status: 'in_progress' },
131+
],
96132
},
97133
{
98134
id: 'memory-server',
@@ -102,6 +138,12 @@ export default function App() {
102138
language: 'TypeScript',
103139
lastRun: '5 sec ago',
104140
executionCount: 8934,
141+
currentTask: 'Speichere: Decision → Pinecone',
142+
stopScore: 5,
143+
dailyTasks: [
144+
{ id: '1', date: '25.12.', task: 'Index erstellt: assistant-memory', status: 'completed' },
145+
{ id: '2', date: '25.12.', task: '15 Erinnerungen gespeichert', status: 'completed' },
146+
],
105147
},
106148
{
107149
id: 'research-agent',
@@ -111,6 +153,12 @@ export default function App() {
111153
language: 'TypeScript',
112154
lastRun: '3 min ago',
113155
executionCount: 1247,
156+
currentTask: 'Analysiere: Cursor Rules Dokumentation',
157+
stopScore: 18,
158+
dailyTasks: [
159+
{ id: '1', date: '25.12.', task: 'Qonto API Docs gelesen', status: 'completed' },
160+
{ id: '2', date: '25.12.', task: 'Codebase analysiert: 35 Dateien', status: 'completed' },
161+
],
114162
},
115163
{
116164
id: 'deployment-agent',
@@ -120,6 +168,11 @@ export default function App() {
120168
language: 'TypeScript',
121169
lastRun: '15 min ago',
122170
executionCount: 456,
171+
stopScore: 22,
172+
dailyTasks: [
173+
{ id: '1', date: '25.12.', task: 'npm run build erfolgreich', status: 'completed' },
174+
{ id: '2', date: '25.12.', task: 'Dev Server gestartet', status: 'completed' },
175+
],
123176
},
124177
{
125178
id: 'monitoring-agent',
@@ -129,6 +182,12 @@ export default function App() {
129182
language: 'TypeScript',
130183
lastRun: '10 sec ago',
131184
executionCount: 12847,
185+
currentTask: 'Health Check: Alle 9 Agents',
186+
stopScore: 8,
187+
dailyTasks: [
188+
{ id: '1', date: '25.12.', task: 'Health Check: 847 Prüfungen', status: 'completed' },
189+
{ id: '2', date: '25.12.', task: 'Alert: Accounting Agent pausiert', status: 'completed' },
190+
],
132191
},
133192
{
134193
id: 'backup-agent',
@@ -138,6 +197,10 @@ export default function App() {
138197
language: 'TypeScript',
139198
lastRun: '30 min ago',
140199
executionCount: 892,
200+
stopScore: 10,
201+
dailyTasks: [
202+
{ id: '1', date: '25.12.', task: 'Tägliches Backup: 12.3 MB', status: 'completed' },
203+
],
141204
},
142205
{
143206
id: 'accounting-agent',
@@ -147,6 +210,7 @@ export default function App() {
147210
language: 'TypeScript',
148211
lastRun: 'Zurückgestellt',
149212
executionCount: 0,
213+
stopScore: 0,
150214
},
151215
]);
152216

@@ -499,6 +563,17 @@ export default function App() {
499563
</Button>
500564
</div>
501565

566+
{/* Task Input */}
567+
<div className="mb-6">
568+
<TaskInput
569+
agents={agents.map(a => ({ id: a.id, name: a.name }))}
570+
onSubmit={(task) => {
571+
toast.success(`Task erstellt: ${task.description}`);
572+
// TODO: Route to Meta Supervisor
573+
}}
574+
/>
575+
</div>
576+
502577
{/* Agents Grid */}
503578
{filteredAgents.length > 0 ? (
504579
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
@@ -510,6 +585,7 @@ export default function App() {
510585
onPause={handlePauseAgent}
511586
onConfigure={handleConfigureAgent}
512587
onDelete={handleDeleteAgent}
588+
onSlackOpen={(channel) => window.open(`slack://channel?team=T123&id=${channel}`, '_blank')}
513589
/>
514590
))}
515591
</div>

src/components/AgentCard.tsx

Lines changed: 120 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from './ui/card';
22
import { Badge } from './ui/badge';
33
import { 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

614
interface 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

2033
export 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

Comments
 (0)