claude-team-dashboard 1.2.2

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.

Potentially problematic release.


This version of claude-team-dashboard might be problematic. Click here for more details.

Files changed (49) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/LICENSE +21 -0
  3. package/README.md +722 -0
  4. package/cleanup.js +73 -0
  5. package/config.js +50 -0
  6. package/dist/assets/icons-Ijf8rQIc.js +1 -0
  7. package/dist/assets/index-Cqc1m1x_.css +1 -0
  8. package/dist/assets/index-jGy3ms0W.js +9 -0
  9. package/dist/assets/react-vendor-DbmSkCAF.js +1 -0
  10. package/dist/index.html +16 -0
  11. package/index.html +13 -0
  12. package/package.json +93 -0
  13. package/server.js +953 -0
  14. package/src/App.jsx +372 -0
  15. package/src/animations-enhanced.css +929 -0
  16. package/src/animations.css +783 -0
  17. package/src/components/ActivityFeed.jsx +289 -0
  18. package/src/components/AgentActivity.jsx +104 -0
  19. package/src/components/AgentCard.jsx +163 -0
  20. package/src/components/AgentOutputViewer.jsx +334 -0
  21. package/src/components/ArchiveViewer.jsx +283 -0
  22. package/src/components/ConnectionStatus.jsx +124 -0
  23. package/src/components/DetailedTaskProgress.jsx +126 -0
  24. package/src/components/ErrorBoundary.jsx +132 -0
  25. package/src/components/Header.jsx +154 -0
  26. package/src/components/LiveAgentStream.jsx +176 -0
  27. package/src/components/LiveCommunication.jsx +326 -0
  28. package/src/components/LiveMetrics.jsx +100 -0
  29. package/src/components/RealTimeMessages.jsx +298 -0
  30. package/src/components/SkeletonLoader.jsx +384 -0
  31. package/src/components/StatsOverview.jsx +209 -0
  32. package/src/components/SystemStatus.jsx +57 -0
  33. package/src/components/TaskList.jsx +306 -0
  34. package/src/components/TeamCard.jsx +126 -0
  35. package/src/components/TeamHistory.jsx +204 -0
  36. package/src/components/__tests__/ConnectionStatus.test.jsx +54 -0
  37. package/src/components/__tests__/StatsOverview.test.jsx +66 -0
  38. package/src/config/constants.js +59 -0
  39. package/src/hooks/useCounterAnimation.js +219 -0
  40. package/src/hooks/useWebSocket.js +76 -0
  41. package/src/index.css +1818 -0
  42. package/src/main.jsx +17 -0
  43. package/src/polish-enhancements.css +303 -0
  44. package/src/premium-visual-polish.css +830 -0
  45. package/src/responsive-enhancements.css +666 -0
  46. package/src/styles/theme.css +395 -0
  47. package/src/test/setup.js +19 -0
  48. package/start.js +36 -0
  49. package/vite.config.js +37 -0
package/src/App.jsx ADDED
@@ -0,0 +1,372 @@
1
+ import React, { useState, useEffect, useMemo } from 'react';
2
+ import { Activity, Github, ExternalLink, BarChart3, MessageSquare, Users, Settings, History as HistoryIcon, Archive } from 'lucide-react';
3
+ import { useWebSocket } from './hooks/useWebSocket';
4
+ import { Header } from './components/Header';
5
+ import { StatsOverview } from './components/StatsOverview';
6
+ import { TeamCard } from './components/TeamCard';
7
+ import { ActivityFeed } from './components/ActivityFeed';
8
+ import { LiveMetrics } from './components/LiveMetrics';
9
+ import { SystemStatus } from './components/SystemStatus';
10
+ import { DetailedTaskProgress } from './components/DetailedTaskProgress';
11
+ import { AgentActivity } from './components/AgentActivity';
12
+ import { RealTimeMessages } from './components/RealTimeMessages';
13
+ import { LiveAgentStream } from './components/LiveAgentStream';
14
+ import { TeamHistory } from './components/TeamHistory';
15
+ import { AgentOutputViewer } from './components/AgentOutputViewer';
16
+ import { ArchiveViewer } from './components/ArchiveViewer';
17
+
18
+ function App() {
19
+ const [teams, setTeams] = useState([]);
20
+ const [stats, setStats] = useState(null);
21
+ const [lastUpdate, setLastUpdate] = useState(null);
22
+ const [activeTab, setActiveTab] = useState('overview');
23
+ const [teamHistory, setTeamHistory] = useState([]);
24
+ const [agentOutputs, setAgentOutputs] = useState([]);
25
+
26
+ const wsUrl = `ws://${window.location.hostname}:3001`;
27
+ // lgtm[js/invocation-of-non-function] useWebSocket is a valid React hook
28
+ const { data, isConnected, error } = useWebSocket(wsUrl);
29
+
30
+ // Memoize expensive computations
31
+ const allTasks = useMemo(
32
+ () => teams.flatMap(t => t.tasks || []),
33
+ [teams]
34
+ );
35
+
36
+ useEffect(() => {
37
+ if (data) {
38
+ setLastUpdate(data);
39
+
40
+ if (data.data) {
41
+ setTeams(data.data);
42
+ }
43
+
44
+ if (data.stats) {
45
+ setStats(data.stats);
46
+ }
47
+
48
+ if (data.teamHistory) {
49
+ setTeamHistory(data.teamHistory);
50
+ }
51
+
52
+ if (data.agentOutputs) {
53
+ setAgentOutputs(data.agentOutputs);
54
+ }
55
+
56
+ if (data.outputs) {
57
+ setAgentOutputs(data.outputs);
58
+ }
59
+ }
60
+ }, [data]);
61
+
62
+ // Keyboard navigation handler for tabs
63
+ const handleTabKeyDown = (e) => {
64
+ const tabs = ['overview', 'teams', 'communication', 'monitoring', 'history', 'archive'];
65
+ const currentIndex = tabs.indexOf(activeTab);
66
+
67
+ if (e.key === 'ArrowRight') {
68
+ e.preventDefault();
69
+ const nextIndex = (currentIndex + 1) % tabs.length;
70
+ setActiveTab(tabs[nextIndex]);
71
+ // Focus the new tab button
72
+ document.getElementById(`tab-${tabs[nextIndex]}`)?.focus();
73
+ } else if (e.key === 'ArrowLeft') {
74
+ e.preventDefault();
75
+ const prevIndex = (currentIndex - 1 + tabs.length) % tabs.length;
76
+ setActiveTab(tabs[prevIndex]);
77
+ document.getElementById(`tab-${tabs[prevIndex]}`)?.focus();
78
+ } else if (e.key === 'Home') {
79
+ e.preventDefault();
80
+ setActiveTab(tabs[0]);
81
+ document.getElementById(`tab-${tabs[0]}`)?.focus();
82
+ } else if (e.key === 'End') {
83
+ e.preventDefault();
84
+ setActiveTab(tabs[tabs.length - 1]);
85
+ document.getElementById(`tab-${tabs[tabs.length - 1]}`)?.focus();
86
+ }
87
+ };
88
+
89
+ return (
90
+ <div className="min-h-screen bg-gradient-to-br from-gray-900 via-gray-800 to-gray-900">
91
+ {/* Skip Navigation Link */}
92
+ <a
93
+ href="#main-content"
94
+ className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:px-4 focus:py-2 focus:bg-claude-orange focus:text-white focus:rounded-lg"
95
+ >
96
+ Skip to main content
97
+ </a>
98
+
99
+ {/* Header - New Glassmorphism Design */}
100
+ <Header isConnected={isConnected} error={error} />
101
+
102
+ {/* Main Content */}
103
+ <main id="main-content" className="container mx-auto px-6 py-6" role="main">
104
+ {/* Statistics Overview - Always Visible */}
105
+ <div className="mb-6">
106
+ <StatsOverview stats={stats} />
107
+ </div>
108
+
109
+ {/* Navigation Tabs */}
110
+ <nav className="mb-6" role="tablist" aria-label="Dashboard sections">
111
+ <div className="flex gap-2 overflow-x-auto pb-2">
112
+ <button
113
+ id="tab-overview"
114
+ onClick={() => setActiveTab('overview')}
115
+ onKeyDown={handleTabKeyDown}
116
+ role="tab"
117
+ aria-selected={activeTab === 'overview'}
118
+ aria-controls="tab-panel-overview"
119
+ className={`flex items-center gap-2 px-4 py-2 rounded-lg font-medium transition-all whitespace-nowrap ${
120
+ activeTab === 'overview'
121
+ ? 'bg-claude-orange text-white shadow-lg'
122
+ : 'bg-gray-700/50 text-gray-300 hover:bg-gray-700'
123
+ }`}
124
+ >
125
+ <BarChart3 className="h-4 w-4" aria-hidden="true" />
126
+ Live Metrics
127
+ </button>
128
+ <button
129
+ id="tab-teams"
130
+ onClick={() => setActiveTab('teams')}
131
+ onKeyDown={handleTabKeyDown}
132
+ role="tab"
133
+ aria-selected={activeTab === 'teams'}
134
+ aria-controls="tab-panel-teams"
135
+ className={`flex items-center gap-2 px-4 py-2 rounded-lg font-medium transition-all whitespace-nowrap ${
136
+ activeTab === 'teams'
137
+ ? 'bg-claude-orange text-white shadow-lg'
138
+ : 'bg-gray-700/50 text-gray-300 hover:bg-gray-700'
139
+ }`}
140
+ >
141
+ <Users className="h-4 w-4" aria-hidden="true" />
142
+ Teams & Tasks
143
+ </button>
144
+ <button
145
+ id="tab-communication"
146
+ onClick={() => setActiveTab('communication')}
147
+ onKeyDown={handleTabKeyDown}
148
+ role="tab"
149
+ aria-selected={activeTab === 'communication'}
150
+ aria-controls="tab-panel-communication"
151
+ className={`flex items-center gap-2 px-4 py-2 rounded-lg font-medium transition-all whitespace-nowrap ${
152
+ activeTab === 'communication'
153
+ ? 'bg-claude-orange text-white shadow-lg'
154
+ : 'bg-gray-700/50 text-gray-300 hover:bg-gray-700'
155
+ }`}
156
+ >
157
+ <MessageSquare className="h-4 w-4" aria-hidden="true" />
158
+ Communication
159
+ </button>
160
+ <button
161
+ id="tab-monitoring"
162
+ onClick={() => setActiveTab('monitoring')}
163
+ onKeyDown={handleTabKeyDown}
164
+ role="tab"
165
+ aria-selected={activeTab === 'monitoring'}
166
+ aria-controls="tab-panel-monitoring"
167
+ className={`flex items-center gap-2 px-4 py-2 rounded-lg font-medium transition-all whitespace-nowrap ${
168
+ activeTab === 'monitoring'
169
+ ? 'bg-claude-orange text-white shadow-lg'
170
+ : 'bg-gray-700/50 text-gray-300 hover:bg-gray-700'
171
+ }`}
172
+ >
173
+ <Settings className="h-4 w-4" aria-hidden="true" />
174
+ Monitoring
175
+ </button>
176
+ <button
177
+ id="tab-history"
178
+ onClick={() => setActiveTab('history')}
179
+ onKeyDown={handleTabKeyDown}
180
+ role="tab"
181
+ aria-selected={activeTab === 'history'}
182
+ aria-controls="tab-panel-history"
183
+ className={`flex items-center gap-2 px-4 py-2 rounded-lg font-medium transition-all whitespace-nowrap ${
184
+ activeTab === 'history'
185
+ ? 'bg-claude-orange text-white shadow-lg'
186
+ : 'bg-gray-700/50 text-gray-300 hover:bg-gray-700'
187
+ }`}
188
+ >
189
+ <HistoryIcon className="h-4 w-4" aria-hidden="true" />
190
+ History & Outputs
191
+ </button>
192
+ <button
193
+ id="tab-archive"
194
+ onClick={() => setActiveTab('archive')}
195
+ onKeyDown={handleTabKeyDown}
196
+ role="tab"
197
+ aria-selected={activeTab === 'archive'}
198
+ aria-controls="tab-panel-archive"
199
+ className={`flex items-center gap-2 px-4 py-2 rounded-lg font-medium transition-all whitespace-nowrap ${
200
+ activeTab === 'archive'
201
+ ? 'bg-claude-orange text-white shadow-lg'
202
+ : 'bg-gray-700/50 text-gray-300 hover:bg-gray-700'
203
+ }`}
204
+ >
205
+ <Archive className="h-4 w-4" aria-hidden="true" />
206
+ Archive
207
+ </button>
208
+ </div>
209
+ </nav>
210
+
211
+ {/* Tab Content */}
212
+ <div className="tab-content">
213
+ {activeTab === 'overview' && (
214
+ <div
215
+ role="tabpanel"
216
+ id="tab-panel-overview"
217
+ aria-labelledby="tab-overview"
218
+ className="space-y-6 animate-fadeIn"
219
+ >
220
+ {/* Live Metrics */}
221
+ <LiveMetrics stats={stats} />
222
+
223
+ {/* Quick Stats Grid */}
224
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
225
+ <DetailedTaskProgress tasks={allTasks} />
226
+ <AgentActivity teams={teams} />
227
+ <SystemStatus isConnected={isConnected} lastUpdate={lastUpdate} />
228
+ </div>
229
+ </div>
230
+ )}
231
+
232
+ {activeTab === 'teams' && (
233
+ <div
234
+ role="tabpanel"
235
+ id="tab-panel-teams"
236
+ aria-labelledby="tab-teams"
237
+ className="grid grid-cols-1 lg:grid-cols-3 gap-6 animate-fadeIn"
238
+ >
239
+ {/* Teams Section */}
240
+ <div className="lg:col-span-2 space-y-6">
241
+ <div className="flex items-center justify-between mb-4">
242
+ <h2 className="text-xl font-bold text-white">Active Teams</h2>
243
+ {teams.length > 0 && (
244
+ <span className="text-sm text-gray-400">
245
+ {teams.length} team{teams.length !== 1 ? 's' : ''}
246
+ </span>
247
+ )}
248
+ </div>
249
+
250
+ {teams.length === 0 ? (
251
+ <div className="card text-center py-12">
252
+ <Activity className="h-16 w-16 text-gray-600 mx-auto mb-4" />
253
+ <h3 className="text-xl font-semibold text-white mb-2">
254
+ No Active Teams
255
+ </h3>
256
+ <p className="text-gray-400 mb-4">
257
+ Start a Claude Code agent team to see it appear here
258
+ </p>
259
+ <a
260
+ href="https://code.claude.com/docs/en/agent-teams#start-your-first-agent-team"
261
+ target="_blank"
262
+ rel="noopener noreferrer"
263
+ className="inline-flex items-center gap-2 bg-claude-orange hover:bg-orange-600 text-white px-6 py-3 rounded-lg font-medium transition-colors"
264
+ >
265
+ <ExternalLink className="h-4 w-4" />
266
+ Learn How to Start a Team
267
+ </a>
268
+ </div>
269
+ ) : (
270
+ teams.map((team, index) => (
271
+ <TeamCard key={team.name || index} team={team} />
272
+ ))
273
+ )}
274
+ </div>
275
+
276
+ {/* Activity Feed Section */}
277
+ <div className="lg:col-span-1">
278
+ <ActivityFeed updates={lastUpdate} />
279
+ </div>
280
+ </div>
281
+ )}
282
+
283
+ {activeTab === 'communication' && (
284
+ <div
285
+ role="tabpanel"
286
+ id="tab-panel-communication"
287
+ aria-labelledby="tab-communication"
288
+ className="grid grid-cols-1 lg:grid-cols-2 gap-6 animate-fadeIn"
289
+ >
290
+ <RealTimeMessages teams={teams} />
291
+ <LiveAgentStream teams={teams} />
292
+ </div>
293
+ )}
294
+
295
+ {activeTab === 'monitoring' && (
296
+ <div
297
+ role="tabpanel"
298
+ id="tab-panel-monitoring"
299
+ aria-labelledby="tab-monitoring"
300
+ className="grid grid-cols-1 lg:grid-cols-2 gap-6 animate-fadeIn"
301
+ >
302
+ <SystemStatus isConnected={isConnected} lastUpdate={lastUpdate} />
303
+ <ActivityFeed updates={lastUpdate} />
304
+ </div>
305
+ )}
306
+
307
+ {activeTab === 'history' && (
308
+ <div
309
+ role="tabpanel"
310
+ id="tab-panel-history"
311
+ aria-labelledby="tab-history"
312
+ className="space-y-6 animate-fadeIn"
313
+ >
314
+ {/* Agent Output Viewer - Full Width */}
315
+ <AgentOutputViewer agentOutputs={agentOutputs} />
316
+
317
+ {/* Team History */}
318
+ <TeamHistory teamHistory={teamHistory} />
319
+ </div>
320
+ )}
321
+
322
+ {activeTab === 'archive' && (
323
+ <div
324
+ role="tabpanel"
325
+ id="tab-panel-archive"
326
+ aria-labelledby="tab-archive"
327
+ className="animate-fadeIn"
328
+ >
329
+ {/* Archive Viewer - Full Width */}
330
+ <ArchiveViewer />
331
+ </div>
332
+ )}
333
+ </div>
334
+ </main>
335
+
336
+ {/* Footer */}
337
+ <footer className="bg-gray-800/50 border-t border-gray-700 mt-12">
338
+ <div className="container mx-auto px-6 py-6">
339
+ <div className="flex items-center justify-between text-sm text-gray-400">
340
+ <div className="flex items-center gap-2">
341
+ <Activity className="h-4 w-4 text-claude-orange" />
342
+ <span>Claude Code Agent Dashboard</span>
343
+ <span className="text-gray-600">•</span>
344
+ <span className="text-gray-500">Built by <a href="https://mahipal.engineer" target="_blank" rel="noopener noreferrer" className="text-claude-orange hover:text-orange-400 transition-colors">mahipal.engineer</a></span>
345
+ </div>
346
+ <div className="flex items-center gap-4">
347
+ <a
348
+ href="https://github.com/anthropics/claude-code"
349
+ target="_blank"
350
+ rel="noopener noreferrer"
351
+ className="flex items-center gap-2 hover:text-white transition-colors"
352
+ >
353
+ <Github className="h-4 w-4" />
354
+ <span>GitHub</span>
355
+ </a>
356
+ <a
357
+ href="https://code.claude.com"
358
+ target="_blank"
359
+ rel="noopener noreferrer"
360
+ className="hover:text-white transition-colors"
361
+ >
362
+ Documentation
363
+ </a>
364
+ </div>
365
+ </div>
366
+ </div>
367
+ </footer>
368
+ </div>
369
+ );
370
+ }
371
+
372
+ export default App;