@agent-relay/dashboard 2.0.80 → 2.0.82

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/out/404.html +1 -1
  2. package/out/_next/static/chunks/{118-4c8241b0218335de.js → 118-ae2b650136a5a5fc.js} +1 -1
  3. package/out/_next/static/chunks/407-0c82986cf79c8ecb.js +1 -0
  4. package/out/_next/static/chunks/app/app/[[...slug]]/{page-1e81c047cff17212.js → page-f7eca1b66fb4249b.js} +1 -1
  5. package/out/_next/static/chunks/app/{page-6892fe2dd07fb48b.js → page-0ee604f7070d14c0.js} +1 -1
  6. package/out/_next/static/css/8968d98ed4c4d33f.css +1 -0
  7. package/out/about.html +2 -2
  8. package/out/about.txt +1 -1
  9. package/out/app/onboarding.html +1 -1
  10. package/out/app/onboarding.txt +1 -1
  11. package/out/app.html +1 -1
  12. package/out/app.txt +2 -2
  13. package/out/blog/go-to-bed-wake-up-to-a-finished-product.html +2 -2
  14. package/out/blog/go-to-bed-wake-up-to-a-finished-product.txt +1 -1
  15. package/out/blog/let-them-cook-multi-agent-orchestration.html +2 -2
  16. package/out/blog/let-them-cook-multi-agent-orchestration.txt +2 -2
  17. package/out/blog.html +2 -2
  18. package/out/blog.txt +1 -1
  19. package/out/careers.html +2 -2
  20. package/out/careers.txt +1 -1
  21. package/out/changelog.html +2 -2
  22. package/out/changelog.txt +1 -1
  23. package/out/cloud/link.html +1 -1
  24. package/out/cloud/link.txt +2 -2
  25. package/out/complete-profile.html +2 -2
  26. package/out/complete-profile.txt +1 -1
  27. package/out/connect-repos.html +1 -1
  28. package/out/connect-repos.txt +1 -1
  29. package/out/contact.html +2 -2
  30. package/out/contact.txt +1 -1
  31. package/out/docs.html +2 -2
  32. package/out/docs.txt +1 -1
  33. package/out/history.html +1 -1
  34. package/out/history.txt +2 -2
  35. package/out/index.html +1 -1
  36. package/out/index.txt +2 -2
  37. package/out/login.html +2 -2
  38. package/out/login.txt +1 -1
  39. package/out/metrics.html +1 -1
  40. package/out/metrics.txt +2 -2
  41. package/out/pricing.html +2 -2
  42. package/out/pricing.txt +1 -1
  43. package/out/privacy.html +2 -2
  44. package/out/privacy.txt +1 -1
  45. package/out/providers/setup/claude.html +1 -1
  46. package/out/providers/setup/claude.txt +1 -1
  47. package/out/providers/setup/codex.html +1 -1
  48. package/out/providers/setup/codex.txt +1 -1
  49. package/out/providers/setup/cursor.html +1 -1
  50. package/out/providers/setup/cursor.txt +1 -1
  51. package/out/providers.html +1 -1
  52. package/out/providers.txt +1 -1
  53. package/out/security.html +2 -2
  54. package/out/security.txt +1 -1
  55. package/out/signup.html +2 -2
  56. package/out/signup.txt +1 -1
  57. package/out/terms.html +2 -2
  58. package/out/terms.txt +1 -1
  59. package/package.json +7 -1
  60. package/src/app/about/page.tsx +7 -0
  61. package/src/app/app/[[...slug]]/DashboardPageClient.tsx +853 -0
  62. package/src/app/app/[[...slug]]/page.tsx +23 -0
  63. package/src/app/app/onboarding/page.tsx +394 -0
  64. package/src/app/apple-icon.png +0 -0
  65. package/src/app/blog/go-to-bed-wake-up-to-a-finished-product/page.tsx +88 -0
  66. package/src/app/blog/let-them-cook-multi-agent-orchestration/page.tsx +93 -0
  67. package/src/app/blog/page.tsx +15 -0
  68. package/src/app/careers/page.tsx +7 -0
  69. package/src/app/changelog/page.tsx +7 -0
  70. package/src/app/cloud/link/page.tsx +464 -0
  71. package/src/app/complete-profile/page.tsx +204 -0
  72. package/src/app/connect-repos/page.tsx +410 -0
  73. package/src/app/contact/page.tsx +7 -0
  74. package/src/app/docs/page.tsx +7 -0
  75. package/src/app/favicon.png +0 -0
  76. package/src/app/globals.css +200 -0
  77. package/src/app/history/page.tsx +658 -0
  78. package/src/app/layout.tsx +25 -0
  79. package/src/app/login/page.tsx +424 -0
  80. package/src/app/metrics/page.tsx +781 -0
  81. package/src/app/page.tsx +59 -0
  82. package/src/app/pricing/page.tsx +7 -0
  83. package/src/app/privacy/page.tsx +7 -0
  84. package/src/app/providers/page.tsx +193 -0
  85. package/src/app/providers/setup/[provider]/ProviderSetupClient.tsx +197 -0
  86. package/src/app/providers/setup/[provider]/constants.ts +35 -0
  87. package/src/app/providers/setup/[provider]/page.tsx +42 -0
  88. package/src/app/security/page.tsx +7 -0
  89. package/src/app/signup/page.tsx +533 -0
  90. package/src/app/terms/page.tsx +7 -0
  91. package/src/components/ActivityFeed.tsx +216 -0
  92. package/src/components/AddWorkspaceModal.tsx +170 -0
  93. package/src/components/AgentCard.test.tsx +134 -0
  94. package/src/components/AgentCard.tsx +585 -0
  95. package/src/components/AgentList.test.tsx +147 -0
  96. package/src/components/AgentList.tsx +419 -0
  97. package/src/components/AgentLogPreview.tsx +173 -0
  98. package/src/components/AgentProfilePanel.tsx +569 -0
  99. package/src/components/App.tsx +3424 -0
  100. package/src/components/BillingPanel.tsx +922 -0
  101. package/src/components/BillingResult.tsx +447 -0
  102. package/src/components/BroadcastComposer.tsx +690 -0
  103. package/src/components/ChannelAdminPanel.tsx +773 -0
  104. package/src/components/ChannelBrowser.tsx +385 -0
  105. package/src/components/ChannelChat.tsx +261 -0
  106. package/src/components/ChannelSidebar.tsx +399 -0
  107. package/src/components/CloudSessionProvider.tsx +130 -0
  108. package/src/components/CommandPalette.tsx +815 -0
  109. package/src/components/ConfirmationDialog.tsx +133 -0
  110. package/src/components/ConversationHistory.tsx +518 -0
  111. package/src/components/CoordinatorPanel.tsx +956 -0
  112. package/src/components/DecisionQueue.tsx +717 -0
  113. package/src/components/DirectMessageView.tsx +164 -0
  114. package/src/components/FileAutocomplete.tsx +368 -0
  115. package/src/components/FleetOverview.tsx +278 -0
  116. package/src/components/LogViewer.tsx +310 -0
  117. package/src/components/LogViewerPanel.tsx +482 -0
  118. package/src/components/Logo.tsx +284 -0
  119. package/src/components/MentionAutocomplete.tsx +384 -0
  120. package/src/components/MessageComposer.tsx +473 -0
  121. package/src/components/MessageList.tsx +725 -0
  122. package/src/components/MessageSenderName.tsx +91 -0
  123. package/src/components/MessageStatusIndicator.tsx +142 -0
  124. package/src/components/NewConversationModal.tsx +400 -0
  125. package/src/components/NotificationToast.tsx +488 -0
  126. package/src/components/OnlineUsersIndicator.tsx +164 -0
  127. package/src/components/Pagination.tsx +124 -0
  128. package/src/components/PricingPlans.tsx +386 -0
  129. package/src/components/ProjectList.tsx +711 -0
  130. package/src/components/ProviderAuthFlow.tsx +343 -0
  131. package/src/components/ProviderConnectionList.tsx +375 -0
  132. package/src/components/ProvisioningProgress.tsx +730 -0
  133. package/src/components/ReactionChips.tsx +70 -0
  134. package/src/components/ReactionPicker.tsx +121 -0
  135. package/src/components/RepoAccessPanel.tsx +787 -0
  136. package/src/components/RepositoriesPanel.tsx +901 -0
  137. package/src/components/ServerCard.tsx +202 -0
  138. package/src/components/SessionExpiredModal.tsx +128 -0
  139. package/src/components/SpawnModal.test.tsx +190 -0
  140. package/src/components/SpawnModal.tsx +1001 -0
  141. package/src/components/TaskAssignmentUI.tsx +375 -0
  142. package/src/components/TerminalProviderSetup.tsx +517 -0
  143. package/src/components/ThemeProvider.tsx +159 -0
  144. package/src/components/ThinkingIndicator.tsx +231 -0
  145. package/src/components/ThreadList.tsx +198 -0
  146. package/src/components/ThreadPanel.tsx +405 -0
  147. package/src/components/TrajectoryViewer.tsx +698 -0
  148. package/src/components/TypingIndicator.tsx +69 -0
  149. package/src/components/UsageBanner.tsx +231 -0
  150. package/src/components/UserProfilePanel.tsx +233 -0
  151. package/src/components/WorkspaceContext.tsx +95 -0
  152. package/src/components/WorkspaceSelector.tsx +234 -0
  153. package/src/components/WorkspaceStatusIndicator.tsx +396 -0
  154. package/src/components/XTermInteractive.tsx +516 -0
  155. package/src/components/XTermLogViewer.tsx +719 -0
  156. package/src/components/channels/ChannelDialogs.tsx +1411 -0
  157. package/src/components/channels/ChannelHeader.tsx +317 -0
  158. package/src/components/channels/ChannelMessageList.tsx +463 -0
  159. package/src/components/channels/ChannelViewV1.tsx +146 -0
  160. package/src/components/channels/MessageInput.tsx +302 -0
  161. package/src/components/channels/SearchInput.tsx +172 -0
  162. package/src/components/channels/SearchResults.tsx +336 -0
  163. package/src/components/channels/api.test.ts +1527 -0
  164. package/src/components/channels/api.ts +703 -0
  165. package/src/components/channels/index.ts +76 -0
  166. package/src/components/channels/mockApi.ts +344 -0
  167. package/src/components/channels/types.ts +566 -0
  168. package/src/components/hooks/index.ts +58 -0
  169. package/src/components/hooks/useAgentLogs.ts +504 -0
  170. package/src/components/hooks/useAgents.ts +127 -0
  171. package/src/components/hooks/useBroadcastDedup.test.ts +371 -0
  172. package/src/components/hooks/useBroadcastDedup.ts +86 -0
  173. package/src/components/hooks/useChannelAdmin.ts +329 -0
  174. package/src/components/hooks/useChannelBrowser.ts +239 -0
  175. package/src/components/hooks/useChannelCommands.ts +138 -0
  176. package/src/components/hooks/useChannels.ts +367 -0
  177. package/src/components/hooks/useDebounce.ts +29 -0
  178. package/src/components/hooks/useDirectMessage.test.ts +952 -0
  179. package/src/components/hooks/useDirectMessage.ts +141 -0
  180. package/src/components/hooks/useMessages.ts +310 -0
  181. package/src/components/hooks/useOrchestrator.test.ts +165 -0
  182. package/src/components/hooks/useOrchestrator.ts +424 -0
  183. package/src/components/hooks/usePinnedAgents.test.ts +356 -0
  184. package/src/components/hooks/usePinnedAgents.ts +140 -0
  185. package/src/components/hooks/usePresence.test.ts +245 -0
  186. package/src/components/hooks/usePresence.ts +377 -0
  187. package/src/components/hooks/useRecentRepos.ts +130 -0
  188. package/src/components/hooks/useSession.ts +209 -0
  189. package/src/components/hooks/useThread.ts +138 -0
  190. package/src/components/hooks/useTrajectory.ts +265 -0
  191. package/src/components/hooks/useWebSocket.ts +290 -0
  192. package/src/components/hooks/useWorkspaceMembers.ts +132 -0
  193. package/src/components/hooks/useWorkspaceRepos.ts +73 -0
  194. package/src/components/hooks/useWorkspaceStatus.ts +237 -0
  195. package/src/components/index.ts +81 -0
  196. package/src/components/layout/Header.tsx +311 -0
  197. package/src/components/layout/RepoContextHeader.tsx +361 -0
  198. package/src/components/layout/Sidebar.archive.test.tsx +126 -0
  199. package/src/components/layout/Sidebar.test.tsx +691 -0
  200. package/src/components/layout/Sidebar.tsx +900 -0
  201. package/src/components/layout/index.ts +7 -0
  202. package/src/components/settings/BillingSettingsPanel.tsx +564 -0
  203. package/src/components/settings/SettingsPage.tsx +683 -0
  204. package/src/components/settings/TeamSettingsPanel.tsx +560 -0
  205. package/src/components/settings/WorkspaceSettingsPanel.tsx +1368 -0
  206. package/src/components/settings/index.ts +11 -0
  207. package/src/components/settings/types.ts +79 -0
  208. package/src/components/utils/messageFormatting.test.tsx +331 -0
  209. package/src/components/utils/messageFormatting.tsx +597 -0
  210. package/src/index.ts +63 -0
  211. package/src/landing/AboutPage.tsx +77 -0
  212. package/src/landing/BlogContent.tsx +187 -0
  213. package/src/landing/BlogPage.tsx +47 -0
  214. package/src/landing/CareersPage.tsx +53 -0
  215. package/src/landing/ChangelogPage.tsx +33 -0
  216. package/src/landing/ContactPage.tsx +41 -0
  217. package/src/landing/DocsPage.tsx +43 -0
  218. package/src/landing/LandingPage.tsx +702 -0
  219. package/src/landing/PricingPage.tsx +549 -0
  220. package/src/landing/PrivacyPage.tsx +117 -0
  221. package/src/landing/SecurityPage.tsx +42 -0
  222. package/src/landing/StaticPage.tsx +165 -0
  223. package/src/landing/TermsPage.tsx +125 -0
  224. package/src/landing/blogData.ts +312 -0
  225. package/src/landing/index.ts +18 -0
  226. package/src/landing/styles.css +3673 -0
  227. package/src/lib/agent-merge.test.ts +43 -0
  228. package/src/lib/agent-merge.ts +35 -0
  229. package/src/lib/api.ts +1294 -0
  230. package/src/lib/cloudApi.ts +893 -0
  231. package/src/lib/colors.test.ts +175 -0
  232. package/src/lib/colors.ts +218 -0
  233. package/src/lib/config.ts +109 -0
  234. package/src/lib/hierarchy.ts +242 -0
  235. package/src/lib/stuckDetection.ts +142 -0
  236. package/src/lib/useUrlRouting.ts +190 -0
  237. package/src/types/index.ts +317 -0
  238. package/src/types/threading.ts +7 -0
  239. package/out/_next/static/chunks/285-dc644487a8d6500d.js +0 -1
  240. package/out/_next/static/css/4c58d9cf493aa626.css +0 -1
  241. /package/out/_next/static/{AqelRhy1vr2nBUcU0Iqcp → IxfA6RZu4trcsEMYlkQra}/_buildManifest.js +0 -0
  242. /package/out/_next/static/{AqelRhy1vr2nBUcU0Iqcp → IxfA6RZu4trcsEMYlkQra}/_ssgManifest.js +0 -0
  243. /package/out/_next/static/chunks/{528-d375bc8b46912d2c.js → 528-f5f676996d613c25.js} +0 -0
  244. /package/out/_next/static/chunks/app/blog/let-them-cook-multi-agent-orchestration/{page-a58308f43557b908.js → page-b194f207fbd91862.js} +0 -0
@@ -0,0 +1,375 @@
1
+ /**
2
+ * TaskAssignmentUI Component
3
+ *
4
+ * Allows users to assign tasks to agents with priority and description.
5
+ * Part of Dashboard V2 - Fleet Control.
6
+ */
7
+
8
+ import React, { useState, useMemo, useCallback } from 'react';
9
+ import type { Agent } from '../types';
10
+ import { getAgentColor, getAgentInitials } from '../lib/colors';
11
+
12
+ export interface TaskAssignment {
13
+ id: string;
14
+ agentName: string;
15
+ title: string;
16
+ description: string;
17
+ priority: 'low' | 'medium' | 'high' | 'critical';
18
+ status: 'pending' | 'assigned' | 'in_progress' | 'completed' | 'failed';
19
+ createdAt: string;
20
+ assignedAt?: string;
21
+ completedAt?: string;
22
+ result?: string;
23
+ }
24
+
25
+ export interface TaskAssignmentUIProps {
26
+ agents: Agent[];
27
+ tasks?: TaskAssignment[];
28
+ onAssign: (agentName: string, title: string, description: string, priority: TaskAssignment['priority']) => Promise<void>;
29
+ onCancel?: (taskId: string) => Promise<void>;
30
+ isAssigning?: boolean;
31
+ }
32
+
33
+ export function TaskAssignmentUI({
34
+ agents,
35
+ tasks = [],
36
+ onAssign,
37
+ onCancel,
38
+ isAssigning = false,
39
+ }: TaskAssignmentUIProps) {
40
+ const [selectedAgent, setSelectedAgent] = useState<string>('');
41
+ const [title, setTitle] = useState('');
42
+ const [description, setDescription] = useState('');
43
+ const [priority, setPriority] = useState<TaskAssignment['priority']>('medium');
44
+ const [showForm, setShowForm] = useState(false);
45
+
46
+ // Filter to available agents (exclude offline and error states)
47
+ const availableAgents = useMemo(() => {
48
+ return agents.filter((a) => a.status !== 'offline' && a.status !== 'error');
49
+ }, [agents]);
50
+
51
+ // Group tasks by status
52
+ const tasksByStatus = useMemo(() => {
53
+ const groups: Record<TaskAssignment['status'], TaskAssignment[]> = {
54
+ pending: [],
55
+ assigned: [],
56
+ in_progress: [],
57
+ completed: [],
58
+ failed: [],
59
+ };
60
+ tasks.forEach((t) => {
61
+ groups[t.status].push(t);
62
+ });
63
+ return groups;
64
+ }, [tasks]);
65
+
66
+ const handleSubmit = useCallback(async (e: React.FormEvent) => {
67
+ e.preventDefault();
68
+ if (!selectedAgent || !title.trim()) return;
69
+
70
+ await onAssign(selectedAgent, title.trim(), description.trim(), priority);
71
+
72
+ // Reset form
73
+ setTitle('');
74
+ setDescription('');
75
+ setPriority('medium');
76
+ setShowForm(false);
77
+ }, [selectedAgent, title, description, priority, onAssign]);
78
+
79
+ const priorityColors: Record<TaskAssignment['priority'], string> = {
80
+ low: '#6366f1',
81
+ medium: '#f59e0b',
82
+ high: '#f97316',
83
+ critical: '#ef4444',
84
+ };
85
+
86
+ return (
87
+ <div className="bg-bg-card rounded-lg border border-border overflow-hidden">
88
+ {/* Header */}
89
+ <div className="flex items-center justify-between px-4 py-3 border-b border-border bg-bg-tertiary">
90
+ <div className="flex items-center gap-2">
91
+ <TaskIcon />
92
+ <span className="font-medium text-sm text-text-primary">Task Assignment</span>
93
+ <span className="text-xs text-text-muted bg-bg-elevated px-2 py-0.5 rounded-full">
94
+ {tasks.length} tasks
95
+ </span>
96
+ </div>
97
+ <button
98
+ className="px-3 py-1.5 text-xs font-medium bg-accent text-bg-deep rounded-md hover:bg-accent/90 transition-colors"
99
+ onClick={() => setShowForm(!showForm)}
100
+ >
101
+ {showForm ? 'Cancel' : '+ New Task'}
102
+ </button>
103
+ </div>
104
+
105
+ {/* New Task Form */}
106
+ {showForm && (
107
+ <form onSubmit={handleSubmit} className="p-4 border-b border-border bg-bg-tertiary/50">
108
+ <div className="flex flex-col gap-4">
109
+ {/* Agent Selection */}
110
+ <div>
111
+ <label className="block text-xs font-medium text-text-secondary mb-1.5">
112
+ Assign to Agent
113
+ </label>
114
+ <div className="grid grid-cols-4 gap-2">
115
+ {availableAgents.map((agent) => {
116
+ const colors = getAgentColor(agent.name);
117
+ const isSelected = selectedAgent === agent.name;
118
+ return (
119
+ <button
120
+ key={agent.name}
121
+ type="button"
122
+ className={`flex items-center gap-2 p-2 rounded-md border transition-all ${
123
+ isSelected
124
+ ? 'border-accent bg-accent/10'
125
+ : 'border-border hover:border-border-medium hover:bg-bg-hover'
126
+ }`}
127
+ onClick={() => setSelectedAgent(agent.name)}
128
+ >
129
+ <div
130
+ className="w-6 h-6 rounded-md flex items-center justify-center text-[10px] font-bold"
131
+ style={{ backgroundColor: colors.primary, color: colors.text }}
132
+ >
133
+ {getAgentInitials(agent.name)}
134
+ </div>
135
+ <span className="text-xs text-text-primary truncate">{agent.name}</span>
136
+ </button>
137
+ );
138
+ })}
139
+ </div>
140
+ {availableAgents.length === 0 && (
141
+ <p className="text-xs text-text-muted italic mt-2">No agents available</p>
142
+ )}
143
+ </div>
144
+
145
+ {/* Title */}
146
+ <div>
147
+ <label className="block text-xs font-medium text-text-secondary mb-1.5">
148
+ Task Title
149
+ </label>
150
+ <input
151
+ type="text"
152
+ value={title}
153
+ onChange={(e) => setTitle(e.target.value)}
154
+ placeholder="Brief description of the task..."
155
+ className="w-full px-3 py-2 text-sm bg-bg-elevated border border-border rounded-md text-text-primary placeholder:text-text-dim focus:outline-none focus:border-accent"
156
+ required
157
+ />
158
+ </div>
159
+
160
+ {/* Description */}
161
+ <div>
162
+ <label className="block text-xs font-medium text-text-secondary mb-1.5">
163
+ Description (optional)
164
+ </label>
165
+ <textarea
166
+ value={description}
167
+ onChange={(e) => setDescription(e.target.value)}
168
+ placeholder="Detailed instructions, context, or requirements..."
169
+ className="w-full px-3 py-2 text-sm bg-bg-elevated border border-border rounded-md text-text-primary placeholder:text-text-dim focus:outline-none focus:border-accent resize-none"
170
+ rows={3}
171
+ />
172
+ </div>
173
+
174
+ {/* Priority */}
175
+ <div>
176
+ <label className="block text-xs font-medium text-text-secondary mb-1.5">
177
+ Priority
178
+ </label>
179
+ <div className="flex gap-2">
180
+ {(['low', 'medium', 'high', 'critical'] as const).map((p) => (
181
+ <button
182
+ key={p}
183
+ type="button"
184
+ className={`px-3 py-1.5 text-xs font-medium rounded-md border transition-all ${
185
+ priority === p
186
+ ? 'border-transparent text-white'
187
+ : 'border-border text-text-secondary hover:border-border-medium'
188
+ }`}
189
+ style={{
190
+ backgroundColor: priority === p ? priorityColors[p] : 'transparent',
191
+ }}
192
+ onClick={() => setPriority(p)}
193
+ >
194
+ {p.charAt(0).toUpperCase() + p.slice(1)}
195
+ </button>
196
+ ))}
197
+ </div>
198
+ </div>
199
+
200
+ {/* Submit */}
201
+ <div className="flex justify-end gap-2 pt-2">
202
+ <button
203
+ type="button"
204
+ className="px-4 py-2 text-sm text-text-secondary hover:text-text-primary transition-colors"
205
+ onClick={() => setShowForm(false)}
206
+ >
207
+ Cancel
208
+ </button>
209
+ <button
210
+ type="submit"
211
+ disabled={!selectedAgent || !title.trim() || isAssigning}
212
+ className="px-4 py-2 text-sm font-medium bg-accent text-bg-deep rounded-md hover:bg-accent/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
213
+ >
214
+ {isAssigning ? 'Assigning...' : 'Assign Task'}
215
+ </button>
216
+ </div>
217
+ </div>
218
+ </form>
219
+ )}
220
+
221
+ {/* Task List */}
222
+ <div className="max-h-[400px] overflow-y-auto">
223
+ {tasks.length === 0 ? (
224
+ <div className="flex flex-col items-center justify-center gap-3 py-10 text-text-muted">
225
+ <EmptyIcon />
226
+ <span className="text-sm">No tasks assigned yet</span>
227
+ </div>
228
+ ) : (
229
+ <div className="divide-y divide-border">
230
+ {/* Active Tasks */}
231
+ {[...tasksByStatus.assigned, ...tasksByStatus.in_progress, ...tasksByStatus.pending].map((task) => (
232
+ <TaskRow
233
+ key={task.id}
234
+ task={task}
235
+ onCancel={onCancel}
236
+ priorityColors={priorityColors}
237
+ />
238
+ ))}
239
+
240
+ {/* Completed/Failed (collapsed) */}
241
+ {(tasksByStatus.completed.length > 0 || tasksByStatus.failed.length > 0) && (
242
+ <details className="group">
243
+ <summary className="px-4 py-2 text-xs text-text-muted cursor-pointer hover:bg-bg-hover list-none flex items-center gap-2">
244
+ <ChevronIcon />
245
+ <span>
246
+ {tasksByStatus.completed.length + tasksByStatus.failed.length} completed/failed tasks
247
+ </span>
248
+ </summary>
249
+ <div className="divide-y divide-border">
250
+ {[...tasksByStatus.completed, ...tasksByStatus.failed].map((task) => (
251
+ <TaskRow
252
+ key={task.id}
253
+ task={task}
254
+ onCancel={onCancel}
255
+ priorityColors={priorityColors}
256
+ />
257
+ ))}
258
+ </div>
259
+ </details>
260
+ )}
261
+ </div>
262
+ )}
263
+ </div>
264
+ </div>
265
+ );
266
+ }
267
+
268
+ interface TaskRowProps {
269
+ task: TaskAssignment;
270
+ onCancel?: (taskId: string) => Promise<void>;
271
+ priorityColors: Record<TaskAssignment['priority'], string>;
272
+ }
273
+
274
+ function TaskRow({ task, onCancel, priorityColors }: TaskRowProps) {
275
+ const colors = getAgentColor(task.agentName);
276
+ const statusColors: Record<TaskAssignment['status'], string> = {
277
+ pending: '#6b7280',
278
+ assigned: '#3b82f6',
279
+ in_progress: '#f59e0b',
280
+ completed: '#10b981',
281
+ failed: '#ef4444',
282
+ };
283
+
284
+ return (
285
+ <div className="flex items-center gap-3 px-4 py-3 hover:bg-bg-hover transition-colors">
286
+ {/* Agent Avatar */}
287
+ <div
288
+ className="w-8 h-8 rounded-md flex items-center justify-center text-xs font-bold flex-shrink-0"
289
+ style={{ backgroundColor: colors.primary, color: colors.text }}
290
+ >
291
+ {getAgentInitials(task.agentName)}
292
+ </div>
293
+
294
+ {/* Task Info */}
295
+ <div className="flex-1 min-w-0">
296
+ <div className="flex items-center gap-2">
297
+ <span className="text-sm font-medium text-text-primary truncate">{task.title}</span>
298
+ <span
299
+ className="text-[10px] px-1.5 py-0.5 rounded font-medium"
300
+ style={{
301
+ backgroundColor: `${priorityColors[task.priority]}20`,
302
+ color: priorityColors[task.priority],
303
+ }}
304
+ >
305
+ {task.priority}
306
+ </span>
307
+ </div>
308
+ <div className="flex items-center gap-2 text-xs text-text-muted">
309
+ <span>{task.agentName}</span>
310
+ <span>•</span>
311
+ <span
312
+ className="font-medium"
313
+ style={{ color: statusColors[task.status] }}
314
+ >
315
+ {task.status.replace('_', ' ')}
316
+ </span>
317
+ </div>
318
+ </div>
319
+
320
+ {/* Cancel Button (for pending/assigned tasks) */}
321
+ {onCancel && (task.status === 'pending' || task.status === 'assigned') && (
322
+ <button
323
+ className="p-1.5 text-text-dim hover:text-error hover:bg-error/10 rounded transition-colors"
324
+ onClick={() => onCancel(task.id)}
325
+ title="Cancel task"
326
+ >
327
+ <XIcon />
328
+ </button>
329
+ )}
330
+ </div>
331
+ );
332
+ }
333
+
334
+ // Icons
335
+ function TaskIcon() {
336
+ return (
337
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className="text-text-secondary">
338
+ <path d="M9 11l3 3L22 4" />
339
+ <path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11" />
340
+ </svg>
341
+ );
342
+ }
343
+
344
+ function EmptyIcon() {
345
+ return (
346
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" className="text-text-dim">
347
+ <rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
348
+ <path d="M9 9l6 6m0-6l-6 6" />
349
+ </svg>
350
+ );
351
+ }
352
+
353
+ function XIcon() {
354
+ return (
355
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
356
+ <path d="M18 6L6 18M6 6l12 12" />
357
+ </svg>
358
+ );
359
+ }
360
+
361
+ function ChevronIcon() {
362
+ return (
363
+ <svg
364
+ width="12"
365
+ height="12"
366
+ viewBox="0 0 24 24"
367
+ fill="none"
368
+ stroke="currentColor"
369
+ strokeWidth="2"
370
+ className="transition-transform group-open:rotate-90"
371
+ >
372
+ <polyline points="9 18 15 12 9 6" />
373
+ </svg>
374
+ );
375
+ }