@agent-relay/dashboard 2.0.81 → 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.
- package/out/404.html +1 -1
- package/out/_next/static/chunks/{118-4c8241b0218335de.js → 118-ae2b650136a5a5fc.js} +1 -1
- package/out/_next/static/chunks/407-0c82986cf79c8ecb.js +1 -0
- package/out/_next/static/chunks/app/app/[[...slug]]/{page-1e81c047cff17212.js → page-f7eca1b66fb4249b.js} +1 -1
- package/out/_next/static/chunks/app/{page-6892fe2dd07fb48b.js → page-0ee604f7070d14c0.js} +1 -1
- package/out/_next/static/css/8968d98ed4c4d33f.css +1 -0
- package/out/about.html +2 -2
- package/out/about.txt +1 -1
- package/out/app/onboarding.html +1 -1
- package/out/app/onboarding.txt +1 -1
- package/out/app.html +1 -1
- package/out/app.txt +2 -2
- package/out/blog/go-to-bed-wake-up-to-a-finished-product.html +2 -2
- package/out/blog/go-to-bed-wake-up-to-a-finished-product.txt +1 -1
- package/out/blog/let-them-cook-multi-agent-orchestration.html +2 -2
- package/out/blog/let-them-cook-multi-agent-orchestration.txt +2 -2
- package/out/blog.html +2 -2
- package/out/blog.txt +1 -1
- package/out/careers.html +2 -2
- package/out/careers.txt +1 -1
- package/out/changelog.html +2 -2
- package/out/changelog.txt +1 -1
- package/out/cloud/link.html +1 -1
- package/out/cloud/link.txt +2 -2
- package/out/complete-profile.html +2 -2
- package/out/complete-profile.txt +1 -1
- package/out/connect-repos.html +1 -1
- package/out/connect-repos.txt +1 -1
- package/out/contact.html +2 -2
- package/out/contact.txt +1 -1
- package/out/docs.html +2 -2
- package/out/docs.txt +1 -1
- package/out/history.html +1 -1
- package/out/history.txt +2 -2
- package/out/index.html +1 -1
- package/out/index.txt +2 -2
- package/out/login.html +2 -2
- package/out/login.txt +1 -1
- package/out/metrics.html +1 -1
- package/out/metrics.txt +2 -2
- package/out/pricing.html +2 -2
- package/out/pricing.txt +1 -1
- package/out/privacy.html +2 -2
- package/out/privacy.txt +1 -1
- package/out/providers/setup/claude.html +1 -1
- package/out/providers/setup/claude.txt +1 -1
- package/out/providers/setup/codex.html +1 -1
- package/out/providers/setup/codex.txt +1 -1
- package/out/providers/setup/cursor.html +1 -1
- package/out/providers/setup/cursor.txt +1 -1
- package/out/providers.html +1 -1
- package/out/providers.txt +1 -1
- package/out/security.html +2 -2
- package/out/security.txt +1 -1
- package/out/signup.html +2 -2
- package/out/signup.txt +1 -1
- package/out/terms.html +2 -2
- package/out/terms.txt +1 -1
- package/package.json +7 -1
- package/src/app/about/page.tsx +7 -0
- package/src/app/app/[[...slug]]/DashboardPageClient.tsx +853 -0
- package/src/app/app/[[...slug]]/page.tsx +23 -0
- package/src/app/app/onboarding/page.tsx +394 -0
- package/src/app/apple-icon.png +0 -0
- package/src/app/blog/go-to-bed-wake-up-to-a-finished-product/page.tsx +88 -0
- package/src/app/blog/let-them-cook-multi-agent-orchestration/page.tsx +93 -0
- package/src/app/blog/page.tsx +15 -0
- package/src/app/careers/page.tsx +7 -0
- package/src/app/changelog/page.tsx +7 -0
- package/src/app/cloud/link/page.tsx +464 -0
- package/src/app/complete-profile/page.tsx +204 -0
- package/src/app/connect-repos/page.tsx +410 -0
- package/src/app/contact/page.tsx +7 -0
- package/src/app/docs/page.tsx +7 -0
- package/src/app/favicon.png +0 -0
- package/src/app/globals.css +200 -0
- package/src/app/history/page.tsx +658 -0
- package/src/app/layout.tsx +25 -0
- package/src/app/login/page.tsx +424 -0
- package/src/app/metrics/page.tsx +781 -0
- package/src/app/page.tsx +59 -0
- package/src/app/pricing/page.tsx +7 -0
- package/src/app/privacy/page.tsx +7 -0
- package/src/app/providers/page.tsx +193 -0
- package/src/app/providers/setup/[provider]/ProviderSetupClient.tsx +197 -0
- package/src/app/providers/setup/[provider]/constants.ts +35 -0
- package/src/app/providers/setup/[provider]/page.tsx +42 -0
- package/src/app/security/page.tsx +7 -0
- package/src/app/signup/page.tsx +533 -0
- package/src/app/terms/page.tsx +7 -0
- package/src/components/ActivityFeed.tsx +216 -0
- package/src/components/AddWorkspaceModal.tsx +170 -0
- package/src/components/AgentCard.test.tsx +134 -0
- package/src/components/AgentCard.tsx +585 -0
- package/src/components/AgentList.test.tsx +147 -0
- package/src/components/AgentList.tsx +419 -0
- package/src/components/AgentLogPreview.tsx +173 -0
- package/src/components/AgentProfilePanel.tsx +569 -0
- package/src/components/App.tsx +3424 -0
- package/src/components/BillingPanel.tsx +922 -0
- package/src/components/BillingResult.tsx +447 -0
- package/src/components/BroadcastComposer.tsx +690 -0
- package/src/components/ChannelAdminPanel.tsx +773 -0
- package/src/components/ChannelBrowser.tsx +385 -0
- package/src/components/ChannelChat.tsx +261 -0
- package/src/components/ChannelSidebar.tsx +399 -0
- package/src/components/CloudSessionProvider.tsx +130 -0
- package/src/components/CommandPalette.tsx +815 -0
- package/src/components/ConfirmationDialog.tsx +133 -0
- package/src/components/ConversationHistory.tsx +518 -0
- package/src/components/CoordinatorPanel.tsx +956 -0
- package/src/components/DecisionQueue.tsx +717 -0
- package/src/components/DirectMessageView.tsx +164 -0
- package/src/components/FileAutocomplete.tsx +368 -0
- package/src/components/FleetOverview.tsx +278 -0
- package/src/components/LogViewer.tsx +310 -0
- package/src/components/LogViewerPanel.tsx +482 -0
- package/src/components/Logo.tsx +284 -0
- package/src/components/MentionAutocomplete.tsx +384 -0
- package/src/components/MessageComposer.tsx +473 -0
- package/src/components/MessageList.tsx +725 -0
- package/src/components/MessageSenderName.tsx +91 -0
- package/src/components/MessageStatusIndicator.tsx +142 -0
- package/src/components/NewConversationModal.tsx +400 -0
- package/src/components/NotificationToast.tsx +488 -0
- package/src/components/OnlineUsersIndicator.tsx +164 -0
- package/src/components/Pagination.tsx +124 -0
- package/src/components/PricingPlans.tsx +386 -0
- package/src/components/ProjectList.tsx +711 -0
- package/src/components/ProviderAuthFlow.tsx +343 -0
- package/src/components/ProviderConnectionList.tsx +375 -0
- package/src/components/ProvisioningProgress.tsx +730 -0
- package/src/components/ReactionChips.tsx +70 -0
- package/src/components/ReactionPicker.tsx +121 -0
- package/src/components/RepoAccessPanel.tsx +787 -0
- package/src/components/RepositoriesPanel.tsx +901 -0
- package/src/components/ServerCard.tsx +202 -0
- package/src/components/SessionExpiredModal.tsx +128 -0
- package/src/components/SpawnModal.test.tsx +190 -0
- package/src/components/SpawnModal.tsx +1001 -0
- package/src/components/TaskAssignmentUI.tsx +375 -0
- package/src/components/TerminalProviderSetup.tsx +517 -0
- package/src/components/ThemeProvider.tsx +159 -0
- package/src/components/ThinkingIndicator.tsx +231 -0
- package/src/components/ThreadList.tsx +198 -0
- package/src/components/ThreadPanel.tsx +405 -0
- package/src/components/TrajectoryViewer.tsx +698 -0
- package/src/components/TypingIndicator.tsx +69 -0
- package/src/components/UsageBanner.tsx +231 -0
- package/src/components/UserProfilePanel.tsx +233 -0
- package/src/components/WorkspaceContext.tsx +95 -0
- package/src/components/WorkspaceSelector.tsx +234 -0
- package/src/components/WorkspaceStatusIndicator.tsx +396 -0
- package/src/components/XTermInteractive.tsx +516 -0
- package/src/components/XTermLogViewer.tsx +719 -0
- package/src/components/channels/ChannelDialogs.tsx +1411 -0
- package/src/components/channels/ChannelHeader.tsx +317 -0
- package/src/components/channels/ChannelMessageList.tsx +463 -0
- package/src/components/channels/ChannelViewV1.tsx +146 -0
- package/src/components/channels/MessageInput.tsx +302 -0
- package/src/components/channels/SearchInput.tsx +172 -0
- package/src/components/channels/SearchResults.tsx +336 -0
- package/src/components/channels/api.test.ts +1527 -0
- package/src/components/channels/api.ts +703 -0
- package/src/components/channels/index.ts +76 -0
- package/src/components/channels/mockApi.ts +344 -0
- package/src/components/channels/types.ts +566 -0
- package/src/components/hooks/index.ts +58 -0
- package/src/components/hooks/useAgentLogs.ts +504 -0
- package/src/components/hooks/useAgents.ts +127 -0
- package/src/components/hooks/useBroadcastDedup.test.ts +371 -0
- package/src/components/hooks/useBroadcastDedup.ts +86 -0
- package/src/components/hooks/useChannelAdmin.ts +329 -0
- package/src/components/hooks/useChannelBrowser.ts +239 -0
- package/src/components/hooks/useChannelCommands.ts +138 -0
- package/src/components/hooks/useChannels.ts +367 -0
- package/src/components/hooks/useDebounce.ts +29 -0
- package/src/components/hooks/useDirectMessage.test.ts +952 -0
- package/src/components/hooks/useDirectMessage.ts +141 -0
- package/src/components/hooks/useMessages.ts +310 -0
- package/src/components/hooks/useOrchestrator.test.ts +165 -0
- package/src/components/hooks/useOrchestrator.ts +424 -0
- package/src/components/hooks/usePinnedAgents.test.ts +356 -0
- package/src/components/hooks/usePinnedAgents.ts +140 -0
- package/src/components/hooks/usePresence.test.ts +245 -0
- package/src/components/hooks/usePresence.ts +377 -0
- package/src/components/hooks/useRecentRepos.ts +130 -0
- package/src/components/hooks/useSession.ts +209 -0
- package/src/components/hooks/useThread.ts +138 -0
- package/src/components/hooks/useTrajectory.ts +265 -0
- package/src/components/hooks/useWebSocket.ts +290 -0
- package/src/components/hooks/useWorkspaceMembers.ts +132 -0
- package/src/components/hooks/useWorkspaceRepos.ts +73 -0
- package/src/components/hooks/useWorkspaceStatus.ts +237 -0
- package/src/components/index.ts +81 -0
- package/src/components/layout/Header.tsx +311 -0
- package/src/components/layout/RepoContextHeader.tsx +361 -0
- package/src/components/layout/Sidebar.archive.test.tsx +126 -0
- package/src/components/layout/Sidebar.test.tsx +691 -0
- package/src/components/layout/Sidebar.tsx +900 -0
- package/src/components/layout/index.ts +7 -0
- package/src/components/settings/BillingSettingsPanel.tsx +564 -0
- package/src/components/settings/SettingsPage.tsx +683 -0
- package/src/components/settings/TeamSettingsPanel.tsx +560 -0
- package/src/components/settings/WorkspaceSettingsPanel.tsx +1368 -0
- package/src/components/settings/index.ts +11 -0
- package/src/components/settings/types.ts +79 -0
- package/src/components/utils/messageFormatting.test.tsx +331 -0
- package/src/components/utils/messageFormatting.tsx +597 -0
- package/src/index.ts +63 -0
- package/src/landing/AboutPage.tsx +77 -0
- package/src/landing/BlogContent.tsx +187 -0
- package/src/landing/BlogPage.tsx +47 -0
- package/src/landing/CareersPage.tsx +53 -0
- package/src/landing/ChangelogPage.tsx +33 -0
- package/src/landing/ContactPage.tsx +41 -0
- package/src/landing/DocsPage.tsx +43 -0
- package/src/landing/LandingPage.tsx +702 -0
- package/src/landing/PricingPage.tsx +549 -0
- package/src/landing/PrivacyPage.tsx +117 -0
- package/src/landing/SecurityPage.tsx +42 -0
- package/src/landing/StaticPage.tsx +165 -0
- package/src/landing/TermsPage.tsx +125 -0
- package/src/landing/blogData.ts +312 -0
- package/src/landing/index.ts +18 -0
- package/src/landing/styles.css +3673 -0
- package/src/lib/agent-merge.test.ts +43 -0
- package/src/lib/agent-merge.ts +35 -0
- package/src/lib/api.ts +1294 -0
- package/src/lib/cloudApi.ts +893 -0
- package/src/lib/colors.test.ts +175 -0
- package/src/lib/colors.ts +218 -0
- package/src/lib/config.ts +109 -0
- package/src/lib/hierarchy.ts +242 -0
- package/src/lib/stuckDetection.ts +142 -0
- package/src/lib/useUrlRouting.ts +190 -0
- package/src/types/index.ts +317 -0
- package/src/types/threading.ts +7 -0
- package/out/_next/static/chunks/285-dc644487a8d6500d.js +0 -1
- package/out/_next/static/css/4c58d9cf493aa626.css +0 -1
- /package/out/_next/static/{dYlczDQI12PIQ3tqq3N4Y → IxfA6RZu4trcsEMYlkQra}/_buildManifest.js +0 -0
- /package/out/_next/static/{dYlczDQI12PIQ3tqq3N4Y → IxfA6RZu4trcsEMYlkQra}/_ssgManifest.js +0 -0
- /package/out/_next/static/chunks/{528-d375bc8b46912d2c.js → 528-f5f676996d613c25.js} +0 -0
- /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
|
+
}
|