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
@@ -0,0 +1,219 @@
1
+ /**
2
+ * useCounterAnimation Hook
3
+ *
4
+ * Smoothly animates number changes with easing
5
+ * Perfect for stat counters, progress indicators, and real-time data updates
6
+ *
7
+ * @param {number} targetValue - The target number to animate to
8
+ * @param {number} duration - Animation duration in milliseconds (default: 600ms)
9
+ * @returns {number} - The current animated display value
10
+ *
11
+ * @example
12
+ * const animatedCount = useCounterAnimation(stats.totalTasks, 600);
13
+ * return <span>{animatedCount}</span>;
14
+ */
15
+
16
+ import { useEffect, useState, useRef } from 'react';
17
+
18
+ export function useCounterAnimation(targetValue, duration = 600) {
19
+ const [displayValue, setDisplayValue] = useState(targetValue);
20
+ const prevValueRef = useRef(targetValue);
21
+ const animationFrameRef = useRef(null);
22
+
23
+ useEffect(() => {
24
+ // Skip animation if target value is the same
25
+ if (targetValue === prevValueRef.current) {
26
+ return;
27
+ }
28
+
29
+ const startValue = prevValueRef.current;
30
+ const difference = targetValue - startValue;
31
+ const startTime = performance.now();
32
+
33
+ // Cancel any ongoing animation
34
+ if (animationFrameRef.current) {
35
+ cancelAnimationFrame(animationFrameRef.current);
36
+ }
37
+
38
+ const animate = (currentTime) => {
39
+ const elapsed = currentTime - startTime;
40
+ const progress = Math.min(elapsed / duration, 1);
41
+
42
+ // Ease-out cubic for smooth deceleration
43
+ // Formula: 1 - (1 - x)^3
44
+ const easeOutCubic = 1 - Math.pow(1 - progress, 3);
45
+
46
+ // Calculate current value
47
+ const current = Math.round(startValue + difference * easeOutCubic);
48
+
49
+ setDisplayValue(current);
50
+
51
+ if (progress < 1) {
52
+ animationFrameRef.current = requestAnimationFrame(animate);
53
+ } else {
54
+ // Animation complete - update ref
55
+ prevValueRef.current = targetValue;
56
+ animationFrameRef.current = null;
57
+ }
58
+ };
59
+
60
+ animationFrameRef.current = requestAnimationFrame(animate);
61
+
62
+ // Cleanup on unmount
63
+ return () => {
64
+ if (animationFrameRef.current) {
65
+ cancelAnimationFrame(animationFrameRef.current);
66
+ }
67
+ };
68
+ }, [targetValue, duration]);
69
+
70
+ return displayValue;
71
+ }
72
+
73
+ /**
74
+ * useCounterAnimationWithHighlight Hook
75
+ *
76
+ * Same as useCounterAnimation but also returns whether value increased/decreased
77
+ * Useful for applying visual highlights when values change
78
+ *
79
+ * @param {number} targetValue - The target number to animate to
80
+ * @param {number} duration - Animation duration in milliseconds (default: 600ms)
81
+ * @returns {object} - { value, isIncreasing, isDecreasing, hasChanged }
82
+ *
83
+ * @example
84
+ * const { value, isIncreasing } = useCounterAnimationWithHighlight(stats.totalTasks);
85
+ * return <span className={isIncreasing ? 'counter-increased' : ''}>{value}</span>;
86
+ */
87
+
88
+ export function useCounterAnimationWithHighlight(targetValue, duration = 600) {
89
+ const [displayValue, setDisplayValue] = useState(targetValue);
90
+ const [changeDirection, setChangeDirection] = useState(null); // 'increase', 'decrease', or null
91
+ const prevValueRef = useRef(targetValue);
92
+ const animationFrameRef = useRef(null);
93
+
94
+ useEffect(() => {
95
+ if (targetValue === prevValueRef.current) {
96
+ return;
97
+ }
98
+
99
+ const startValue = prevValueRef.current;
100
+ const difference = targetValue - startValue;
101
+ const startTime = performance.now();
102
+
103
+ // Determine direction
104
+ setChangeDirection(difference > 0 ? 'increase' : 'decrease');
105
+
106
+ if (animationFrameRef.current) {
107
+ cancelAnimationFrame(animationFrameRef.current);
108
+ }
109
+
110
+ const animate = (currentTime) => {
111
+ const elapsed = currentTime - startTime;
112
+ const progress = Math.min(elapsed / duration, 1);
113
+
114
+ const easeOutCubic = 1 - Math.pow(1 - progress, 3);
115
+ const current = Math.round(startValue + difference * easeOutCubic);
116
+
117
+ setDisplayValue(current);
118
+
119
+ if (progress < 1) {
120
+ animationFrameRef.current = requestAnimationFrame(animate);
121
+ } else {
122
+ prevValueRef.current = targetValue;
123
+ animationFrameRef.current = null;
124
+
125
+ // Reset change direction after a delay
126
+ setTimeout(() => setChangeDirection(null), 1000);
127
+ }
128
+ };
129
+
130
+ animationFrameRef.current = requestAnimationFrame(animate);
131
+
132
+ return () => {
133
+ if (animationFrameRef.current) {
134
+ cancelAnimationFrame(animationFrameRef.current);
135
+ }
136
+ };
137
+ }, [targetValue, duration]);
138
+
139
+ return {
140
+ value: displayValue,
141
+ isIncreasing: changeDirection === 'increase',
142
+ isDecreasing: changeDirection === 'decrease',
143
+ hasChanged: changeDirection !== null
144
+ };
145
+ }
146
+
147
+ /**
148
+ * useStaggeredAnimation Hook
149
+ *
150
+ * Returns staggered delay for list items
151
+ * Perfect for animating lists of cards, tasks, or activity items
152
+ *
153
+ * @param {number} index - Item index in the list
154
+ * @param {number} delayIncrement - Delay between items in milliseconds (default: 60ms)
155
+ * @returns {object} - { animationDelay: string }
156
+ *
157
+ * @example
158
+ * const { animationDelay } = useStaggeredAnimation(index, 80);
159
+ * return <div style={{ animationDelay }}>{item}</div>;
160
+ */
161
+
162
+ export function useStaggeredAnimation(index, delayIncrement = 60) {
163
+ const delay = index * delayIncrement;
164
+
165
+ return {
166
+ animationDelay: `${delay}ms`,
167
+ style: {
168
+ animationDelay: `${delay}ms`
169
+ }
170
+ };
171
+ }
172
+
173
+ /**
174
+ * useAnimationObserver Hook
175
+ *
176
+ * Observes when element enters viewport and triggers animation
177
+ * Perfect for lazy-loading animations on scroll
178
+ *
179
+ * @param {object} options - IntersectionObserver options
180
+ * @returns {[ref, isVisible]} - Ref to attach to element and visibility state
181
+ *
182
+ * @example
183
+ * const [ref, isVisible] = useAnimationObserver();
184
+ * return <div ref={ref} className={isVisible ? 'animate-in' : ''}>{content}</div>;
185
+ */
186
+
187
+ export function useAnimationObserver(options = {}) {
188
+ const [isVisible, setIsVisible] = useState(false);
189
+ const [hasAnimated, setHasAnimated] = useState(false);
190
+ const elementRef = useRef(null);
191
+
192
+ useEffect(() => {
193
+ const element = elementRef.current;
194
+ if (!element || hasAnimated) return;
195
+
196
+ const observer = new IntersectionObserver(
197
+ ([entry]) => {
198
+ if (entry.isIntersecting && !hasAnimated) {
199
+ setIsVisible(true);
200
+ setHasAnimated(true);
201
+ }
202
+ },
203
+ {
204
+ threshold: 0.1,
205
+ ...options
206
+ }
207
+ );
208
+
209
+ observer.observe(element);
210
+
211
+ return () => {
212
+ if (element) {
213
+ observer.unobserve(element);
214
+ }
215
+ };
216
+ }, [hasAnimated, options]);
217
+
218
+ return [elementRef, isVisible];
219
+ }
@@ -0,0 +1,76 @@
1
+ import { useEffect, useState, useRef, useCallback } from 'react';
2
+
3
+ /**
4
+ * WebSocket hook for managing WebSocket connections
5
+ * @param {string} url - WebSocket URL to connect to
6
+ * @returns {{data: any, isConnected: boolean, error: string|null}} WebSocket state
7
+ */
8
+ export function useWebSocket(url) {
9
+ const [data, setData] = useState(null);
10
+ const [isConnected, setIsConnected] = useState(false);
11
+ const [error, setError] = useState(null);
12
+ const wsRef = useRef(null);
13
+ const reconnectTimeoutRef = useRef(null);
14
+ const reconnectAttempts = useRef(0);
15
+
16
+ const connect = useCallback(() => {
17
+ try {
18
+ const ws = new WebSocket(url);
19
+ wsRef.current = ws;
20
+
21
+ ws.onopen = () => {
22
+ console.log('WebSocket connected');
23
+ setIsConnected(true);
24
+ setError(null);
25
+ reconnectAttempts.current = 0;
26
+ };
27
+
28
+ ws.onmessage = (event) => {
29
+ try {
30
+ const message = JSON.parse(event.data);
31
+ setData(message);
32
+ } catch (err) {
33
+ console.error('Error parsing WebSocket message:', err);
34
+ }
35
+ };
36
+
37
+ ws.onerror = (err) => {
38
+ console.error('WebSocket error:', err);
39
+ setError('Connection error');
40
+ };
41
+
42
+ ws.onclose = () => {
43
+ console.log('WebSocket disconnected');
44
+ setIsConnected(false);
45
+ wsRef.current = null;
46
+
47
+ // Attempt to reconnect with exponential backoff
48
+ const delay = Math.min(1000 * Math.pow(2, reconnectAttempts.current), 30000);
49
+ reconnectAttempts.current++;
50
+
51
+ reconnectTimeoutRef.current = setTimeout(() => {
52
+ console.log(`Attempting to reconnect (attempt ${reconnectAttempts.current})...`);
53
+ connect();
54
+ }, delay);
55
+ };
56
+ } catch (err) {
57
+ console.error('Error creating WebSocket:', err);
58
+ setError('Failed to connect');
59
+ }
60
+ }, [url]);
61
+
62
+ useEffect(() => {
63
+ connect();
64
+
65
+ return () => {
66
+ if (reconnectTimeoutRef.current) {
67
+ clearTimeout(reconnectTimeoutRef.current);
68
+ }
69
+ if (wsRef.current) {
70
+ wsRef.current.close();
71
+ }
72
+ };
73
+ }, [connect]);
74
+
75
+ return { data, isConnected, error };
76
+ }