claude-flow 2.0.0-alpha.99 â 2.0.0
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/.claude/agents/MIGRATION_SUMMARY.md +7 -0
- package/.claude/agents/README.md +7 -0
- package/.claude/agents/consensus/README.md +7 -0
- package/.claude/agents/flow-nexus/app-store.md +88 -0
- package/.claude/agents/flow-nexus/authentication.md +69 -0
- package/.claude/agents/flow-nexus/challenges.md +81 -0
- package/.claude/agents/flow-nexus/neural-network.md +88 -0
- package/.claude/agents/flow-nexus/payments.md +83 -0
- package/.claude/agents/flow-nexus/sandbox.md +76 -0
- package/.claude/agents/flow-nexus/swarm.md +76 -0
- package/.claude/agents/flow-nexus/user-tools.md +96 -0
- package/.claude/agents/flow-nexus/workflow.md +84 -0
- package/.claude/agents/optimization/README.md +7 -0
- package/.claude/agents/optimization/benchmark-suite.md +7 -0
- package/.claude/agents/optimization/load-balancer.md +7 -0
- package/.claude/agents/optimization/performance-monitor.md +7 -0
- package/.claude/agents/optimization/resource-allocator.md +7 -0
- package/.claude/agents/optimization/topology-optimizer.md +7 -0
- package/.claude/agents/swarm/README.md +7 -0
- package/.claude/checkpoints/1756227652.json +1 -0
- package/.claude/checkpoints/1756227653.json +1 -0
- package/.claude/checkpoints/1756227666.json +1 -0
- package/.claude/checkpoints/1756227668.json +1 -0
- package/.claude/checkpoints/1756227723.json +1 -0
- package/.claude/checkpoints/1756227725.json +1 -0
- package/.claude/checkpoints/1756227731.json +1 -0
- package/.claude/checkpoints/1756227733.json +1 -0
- package/.claude/checkpoints/1756231330.json +1 -0
- package/.claude/checkpoints/1756231331.json +1 -0
- package/.claude/checkpoints/1756231342.json +1 -0
- package/.claude/checkpoints/1756231344.json +1 -0
- package/.claude/checkpoints/1756231355.json +1 -0
- package/.claude/checkpoints/1756231357.json +1 -0
- package/.claude/checkpoints/1756231367.json +1 -0
- package/.claude/checkpoints/1756231368.json +1 -0
- package/.claude/checkpoints/1756231458.json +1 -0
- package/.claude/checkpoints/1756231459.json +1 -0
- package/.claude/checkpoints/1756231477.json +1 -0
- package/.claude/checkpoints/1756231479.json +1 -0
- package/.claude/checkpoints/1756233026.json +1 -0
- package/.claude/checkpoints/1756233028.json +1 -0
- package/.claude/checkpoints/1756233040.json +1 -0
- package/.claude/checkpoints/1756233041.json +1 -0
- package/.claude/checkpoints/1756233057.json +1 -0
- package/.claude/checkpoints/1756233059.json +1 -0
- package/.claude/checkpoints/1756233090.json +1 -0
- package/.claude/checkpoints/1756233092.json +1 -0
- package/.claude/checkpoints/1756233141.json +1 -0
- package/.claude/checkpoints/1756233143.json +1 -0
- package/.claude/checkpoints/1756475935.json +1 -0
- package/.claude/checkpoints/1756475936.json +1 -0
- package/.claude/checkpoints/1756475996.json +1 -0
- package/.claude/checkpoints/1756475998.json +1 -0
- package/.claude/checkpoints/1756476093.json +1 -0
- package/.claude/checkpoints/1756476098.json +1 -0
- package/.claude/checkpoints/1756476100.json +1 -0
- package/.claude/checkpoints/1756476101.json +1 -0
- package/.claude/checkpoints/1756476161.json +1 -0
- package/.claude/checkpoints/1756476163.json +1 -0
- package/.claude/checkpoints/1756476183.json +1 -0
- package/.claude/checkpoints/1756476184.json +1 -0
- package/.claude/checkpoints/1756476193.json +1 -0
- package/.claude/checkpoints/1756476194.json +1 -0
- package/.claude/checkpoints/1756476202.json +1 -0
- package/.claude/checkpoints/1756476204.json +1 -0
- package/.claude/checkpoints/1756476268.json +1 -0
- package/.claude/checkpoints/1756476269.json +1 -0
- package/.claude/checkpoints/1756476287.json +1 -0
- package/.claude/checkpoints/1756476288.json +1 -0
- package/.claude/checkpoints/1756997935.json +1 -0
- package/.claude/checkpoints/1756997937.json +1 -0
- package/.claude/checkpoints/1756997938.json +1 -0
- package/.claude/checkpoints/1756997940.json +1 -0
- package/.claude/checkpoints/1756997942.json +1 -0
- package/.claude/checkpoints/1756997944.json +1 -0
- package/.claude/checkpoints/1756997945.json +1 -0
- package/.claude/checkpoints/1756997947.json +1 -0
- package/.claude/checkpoints/1756997949.json +1 -0
- package/.claude/checkpoints/1756997951.json +1 -0
- package/.claude/checkpoints/1756997953.json +1 -0
- package/.claude/checkpoints/1756997955.json +1 -0
- package/.claude/checkpoints/1756997956.json +1 -0
- package/.claude/checkpoints/1756997958.json +1 -0
- package/.claude/checkpoints/1756997960.json +1 -0
- package/.claude/checkpoints/1756997962.json +1 -0
- package/.claude/checkpoints/1756997964.json +1 -0
- package/.claude/checkpoints/1756997966.json +1 -0
- package/.claude/checkpoints/1756997968.json +1 -0
- package/.claude/checkpoints/1756997970.json +1 -0
- package/.claude/checkpoints/1757190213.json +1 -0
- package/.claude/checkpoints/1757190215.json +1 -0
- package/.claude/checkpoints/1757190217.json +1 -0
- package/.claude/checkpoints/1757190219.json +1 -0
- package/.claude/checkpoints/1757190220.json +1 -0
- package/.claude/checkpoints/1757190222.json +1 -0
- package/.claude/checkpoints/1757190224.json +1 -0
- package/.claude/checkpoints/1757190225.json +1 -0
- package/.claude/checkpoints/1757190227.json +1 -0
- package/.claude/checkpoints/1757190229.json +1 -0
- package/.claude/checkpoints/1757190231.json +1 -0
- package/.claude/checkpoints/1757190232.json +1 -0
- package/.claude/checkpoints/1757190234.json +1 -0
- package/.claude/checkpoints/1757190236.json +1 -0
- package/.claude/checkpoints/1757190238.json +1 -0
- package/.claude/checkpoints/1757190240.json +1 -0
- package/.claude/checkpoints/1757190241.json +1 -0
- package/.claude/checkpoints/1757190243.json +1 -0
- package/.claude/checkpoints/1757190245.json +1 -0
- package/.claude/checkpoints/1757190247.json +1 -0
- package/.claude/checkpoints/1757190608.json +1 -0
- package/.claude/checkpoints/1757190610.json +1 -0
- package/.claude/checkpoints/1757190626.json +1 -0
- package/.claude/checkpoints/1757190628.json +1 -0
- package/.claude/checkpoints/1757190993.json +1 -0
- package/.claude/checkpoints/1757190997.json +1 -0
- package/.claude/checkpoints/1757191001.json +1 -0
- package/.claude/checkpoints/1757191004.json +1 -0
- package/.claude/checkpoints/1757191007.json +1 -0
- package/.claude/checkpoints/1757191009.json +1 -0
- package/.claude/checkpoints/1757191012.json +1 -0
- package/.claude/checkpoints/1757191014.json +1 -0
- package/.claude/checkpoints/1757191016.json +1 -0
- package/.claude/checkpoints/1757191019.json +1 -0
- package/.claude/checkpoints/1757191022.json +1 -0
- package/.claude/checkpoints/1757191024.json +1 -0
- package/.claude/checkpoints/1757191027.json +1 -0
- package/.claude/checkpoints/1757191029.json +1 -0
- package/.claude/checkpoints/1757191032.json +1 -0
- package/.claude/checkpoints/1757191034.json +1 -0
- package/.claude/checkpoints/1757191037.json +1 -0
- package/.claude/checkpoints/1757191040.json +1 -0
- package/.claude/checkpoints/1757191061.json +1 -0
- package/.claude/checkpoints/1757191063.json +1 -0
- package/.claude/checkpoints/1757191084.json +1 -0
- package/.claude/checkpoints/1757191086.json +1 -0
- package/.claude/checkpoints/1757192316.json +1 -0
- package/.claude/checkpoints/1757192318.json +1 -0
- package/.claude/checkpoints/1757192389.json +1 -0
- package/.claude/checkpoints/1757192391.json +1 -0
- package/.claude/checkpoints/1757192489.json +1 -0
- package/.claude/checkpoints/1757192491.json +1 -0
- package/.claude/checkpoints/1757192521.json +1 -0
- package/.claude/checkpoints/1757192523.json +1 -0
- package/.claude/checkpoints/1757192541.json +1 -0
- package/.claude/checkpoints/1757192543.json +1 -0
- package/.claude/checkpoints/1757193796.json +1 -0
- package/.claude/checkpoints/summary-session-20250826-165852.md +1351 -0
- package/.claude/checkpoints/summary-session-20250826-170402.md +1367 -0
- package/.claude/checkpoints/summary-session-20250826-175112.md +1327 -0
- package/.claude/checkpoints/summary-session-20250826-175609.md +1324 -0
- package/.claude/checkpoints/summary-session-20250826-175743.md +1327 -0
- package/.claude/checkpoints/summary-session-20250826-180554.md +1340 -0
- package/.claude/checkpoints/summary-session-20250826-181530.md +1344 -0
- package/.claude/checkpoints/summary-session-20250826-181633.md +1347 -0
- package/.claude/checkpoints/summary-session-20250826-182235.md +1350 -0
- package/.claude/checkpoints/summary-session-20250826-182618.md +1353 -0
- package/.claude/checkpoints/summary-session-20250826-183200.md +1372 -0
- package/.claude/checkpoints/summary-session-20250826-183232.md +1379 -0
- package/.claude/checkpoints/summary-session-20250829-133605.md +38 -0
- package/.claude/checkpoints/summary-session-20250829-134121.md +41 -0
- package/.claude/checkpoints/summary-session-20250829-134400.md +46 -0
- package/.claude/checkpoints/summary-session-20250829-134858.md +49 -0
- package/.claude/checkpoints/summary-session-20250829-135402.md +52 -0
- package/.claude/checkpoints/summary-session-20250829-135640.md +58 -0
- package/.claude/checkpoints/summary-session-20250829-135754.md +65 -0
- package/.claude/checkpoints/summary-session-20250829-135902.md +71 -0
- package/.claude/checkpoints/summary-session-20250829-140629.md +119 -0
- package/.claude/checkpoints/summary-session-20250829-140733.md +121 -0
- package/.claude/checkpoints/summary-session-20250902-190126.md +38 -0
- package/.claude/checkpoints/summary-session-20250904-150003.md +87 -0
- package/.claude/checkpoints/summary-session-20250906-202218.md +2757 -0
- package/.claude/checkpoints/summary-session-20250906-202622.md +2814 -0
- package/.claude/checkpoints/summary-session-20250906-203037.md +2826 -0
- package/.claude/checkpoints/task-1756227619.json +1 -0
- package/.claude/checkpoints/task-1756230633.json +1 -0
- package/.claude/checkpoints/task-1756230902.json +1 -0
- package/.claude/checkpoints/task-1756230993.json +1 -0
- package/.claude/checkpoints/task-1756231253.json +1 -0
- package/.claude/checkpoints/task-1756232070.json +1 -0
- package/.claude/checkpoints/task-1756232144.json +1 -0
- package/.claude/checkpoints/task-1756232251.json +1 -0
- package/.claude/checkpoints/task-1756232564.json +1 -0
- package/.claude/checkpoints/task-1756232982.json +1 -0
- package/.claude/checkpoints/task-1756233131.json +1 -0
- package/.claude/checkpoints/task-1756474562.json +1 -0
- package/.claude/checkpoints/task-1756474754.json +1 -0
- package/.claude/checkpoints/task-1756474922.json +1 -0
- package/.claude/checkpoints/task-1756475028.json +1 -0
- package/.claude/checkpoints/task-1756475307.json +1 -0
- package/.claude/checkpoints/task-1756475349.json +1 -0
- package/.claude/checkpoints/task-1756475699.json +1 -0
- package/.claude/checkpoints/task-1756475719.json +1 -0
- package/.claude/checkpoints/task-1756475828.json +1 -0
- package/.claude/checkpoints/task-1756475858.json +1 -0
- package/.claude/checkpoints/task-1756475868.json +1 -0
- package/.claude/checkpoints/task-1756476373.json +1 -0
- package/.claude/checkpoints/task-1756839595.json +1 -0
- package/.claude/checkpoints/task-1756997821.json +1 -0
- package/.claude/checkpoints/task-1757189936.json +1 -0
- package/.claude/checkpoints/task-1757190154.json +1 -0
- package/.claude/checkpoints/task-1757190301.json +1 -0
- package/.claude/checkpoints/task-1757190369.json +1 -0
- package/.claude/checkpoints/task-1757190483.json +1 -0
- package/.claude/checkpoints/task-1757190841.json +1 -0
- package/.claude/checkpoints/task-1757191219.json +1 -0
- package/.claude/checkpoints/task-1757192639.json +1 -0
- package/.claude/checkpoints/task-1757194091.json +1 -0
- package/.claude/commands/flow-nexus/app-store.md +124 -0
- package/.claude/commands/flow-nexus/challenges.md +120 -0
- package/.claude/commands/flow-nexus/login-registration.md +65 -0
- package/.claude/commands/flow-nexus/neural-network.md +134 -0
- package/.claude/commands/flow-nexus/payments.md +116 -0
- package/.claude/commands/flow-nexus/sandbox.md +83 -0
- package/.claude/commands/flow-nexus/swarm.md +87 -0
- package/.claude/commands/flow-nexus/user-tools.md +152 -0
- package/.claude/commands/flow-nexus/workflow.md +115 -0
- package/bin/claude-flow +1 -1
- package/package.json +1 -1
- package/src/api/auth-service.ts +644 -0
- package/src/api/database-schema.sql +366 -0
- package/src/api/database-service.ts +788 -0
- package/src/api/swarm-api.ts +741 -0
- package/src/cli/commands/index.ts +711 -1
- package/src/cli/simple-commands/hive-mind/session-manager.js +12 -0
- package/src/cli/simple-commands/init/agent-copier.js +129 -1
- package/src/cli/simple-commands/init/index.js +116 -1
- package/src/cli/simple-commands/init/templates/claude-md.js +295 -1
- package/src/core/version.js +1 -1
- package/src/ui/console/index.html +4 -0
- package/src/ui/console/js/real-time-dashboard.js +715 -0
- package/src/ui/console/js/swarm-integration.js +485 -0
- package/src/ui/console/js/swarm-visualizer.js +879 -0
- package/src/ui/console/styles/swarm-visualizer.css +487 -0
- package/src/cli/simple-commands/init/.claude-flow/metrics/agent-metrics.json +0 -1
- package/src/cli/simple-commands/init/.claude-flow/metrics/performance.json +0 -9
- package/src/cli/simple-commands/init/.claude-flow/metrics/task-metrics.json +0 -10
- package/src/cli/simple-commands/init/.swarm/memory.db +0 -0
|
@@ -0,0 +1,715 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RealTimeDashboard - Enhanced real-time monitoring dashboard for Claude Flow swarms
|
|
3
|
+
* Integrates multiple visualization components with live data updates
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { SwarmVisualizer } from './swarm-visualizer.js';
|
|
7
|
+
|
|
8
|
+
export class RealTimeDashboard {
|
|
9
|
+
constructor(container, componentLibrary) {
|
|
10
|
+
this.container = container;
|
|
11
|
+
this.components = componentLibrary;
|
|
12
|
+
this.swarmVisualizer = null;
|
|
13
|
+
this.isActive = false;
|
|
14
|
+
this.updateInterval = null;
|
|
15
|
+
this.websocket = null;
|
|
16
|
+
this.metrics = {
|
|
17
|
+
history: [],
|
|
18
|
+
current: null
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
this.init();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Initialize dashboard
|
|
26
|
+
*/
|
|
27
|
+
init() {
|
|
28
|
+
this.createDashboardLayout();
|
|
29
|
+
this.setupWebSocket();
|
|
30
|
+
this.startMetricsCollection();
|
|
31
|
+
console.log('đ Real-time Dashboard initialized');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Create dashboard layout
|
|
36
|
+
*/
|
|
37
|
+
createDashboardLayout() {
|
|
38
|
+
// Main dashboard container
|
|
39
|
+
const dashboard = document.createElement('div');
|
|
40
|
+
dashboard.className = 'claude-realtime-dashboard';
|
|
41
|
+
dashboard.style.cssText = `
|
|
42
|
+
display: grid;
|
|
43
|
+
grid-template-columns: 1fr 1fr;
|
|
44
|
+
grid-template-rows: auto 1fr auto;
|
|
45
|
+
gap: 16px;
|
|
46
|
+
height: 100vh;
|
|
47
|
+
padding: 16px;
|
|
48
|
+
background: #0a0a0a;
|
|
49
|
+
color: white;
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
// Header with title and controls
|
|
53
|
+
const header = this.createDashboardHeader();
|
|
54
|
+
dashboard.appendChild(header);
|
|
55
|
+
|
|
56
|
+
// Main content area
|
|
57
|
+
const content = document.createElement('div');
|
|
58
|
+
content.style.cssText = `
|
|
59
|
+
grid-column: 1 / -1;
|
|
60
|
+
display: grid;
|
|
61
|
+
grid-template-columns: 2fr 1fr;
|
|
62
|
+
gap: 16px;
|
|
63
|
+
overflow: hidden;
|
|
64
|
+
`;
|
|
65
|
+
|
|
66
|
+
// Left panel - Swarm Visualizer
|
|
67
|
+
const leftPanel = document.createElement('div');
|
|
68
|
+
leftPanel.className = 'dashboard-left-panel';
|
|
69
|
+
this.swarmVisualizer = new SwarmVisualizer(leftPanel, this.components);
|
|
70
|
+
|
|
71
|
+
// Right panel - Metrics and controls
|
|
72
|
+
const rightPanel = this.createRightPanel();
|
|
73
|
+
|
|
74
|
+
content.appendChild(leftPanel);
|
|
75
|
+
content.appendChild(rightPanel);
|
|
76
|
+
dashboard.appendChild(content);
|
|
77
|
+
|
|
78
|
+
// Footer with status information
|
|
79
|
+
const footer = this.createDashboardFooter();
|
|
80
|
+
dashboard.appendChild(footer);
|
|
81
|
+
|
|
82
|
+
this.container.appendChild(dashboard);
|
|
83
|
+
|
|
84
|
+
this.elements = {
|
|
85
|
+
dashboard,
|
|
86
|
+
header,
|
|
87
|
+
content,
|
|
88
|
+
leftPanel,
|
|
89
|
+
rightPanel,
|
|
90
|
+
footer
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Create dashboard header
|
|
96
|
+
*/
|
|
97
|
+
createDashboardHeader() {
|
|
98
|
+
const header = document.createElement('div');
|
|
99
|
+
header.style.cssText = `
|
|
100
|
+
grid-column: 1 / -1;
|
|
101
|
+
display: flex;
|
|
102
|
+
justify-content: space-between;
|
|
103
|
+
align-items: center;
|
|
104
|
+
padding: 16px;
|
|
105
|
+
background: #1a1a1a;
|
|
106
|
+
border: 1px solid #444;
|
|
107
|
+
border-radius: 8px;
|
|
108
|
+
`;
|
|
109
|
+
|
|
110
|
+
// Title and status
|
|
111
|
+
const titleSection = document.createElement('div');
|
|
112
|
+
titleSection.innerHTML = `
|
|
113
|
+
<h1 style="margin: 0; color: #00d4ff; font-size: 24px;">
|
|
114
|
+
đ Claude Flow Real-Time Dashboard
|
|
115
|
+
</h1>
|
|
116
|
+
<p style="margin: 4px 0 0 0; color: #888; font-size: 14px;">
|
|
117
|
+
Live swarm monitoring and performance analytics
|
|
118
|
+
</p>
|
|
119
|
+
`;
|
|
120
|
+
|
|
121
|
+
// Control buttons
|
|
122
|
+
const controls = document.createElement('div');
|
|
123
|
+
controls.style.display = 'flex';
|
|
124
|
+
controls.style.gap = '12px';
|
|
125
|
+
|
|
126
|
+
const startBtn = this.components.createActionButton({
|
|
127
|
+
type: 'primary',
|
|
128
|
+
text: 'Start All',
|
|
129
|
+
icon: 'âļī¸',
|
|
130
|
+
onclick: () => this.startAllMonitoring()
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const stopBtn = this.components.createActionButton({
|
|
134
|
+
type: 'secondary',
|
|
135
|
+
text: 'Stop All',
|
|
136
|
+
icon: 'âšī¸',
|
|
137
|
+
onclick: () => this.stopAllMonitoring()
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const exportBtn = this.components.createActionButton({
|
|
141
|
+
type: 'secondary',
|
|
142
|
+
text: 'Export Data',
|
|
143
|
+
icon: 'đž',
|
|
144
|
+
onclick: () => this.exportDashboardData()
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
controls.appendChild(startBtn.element);
|
|
148
|
+
controls.appendChild(stopBtn.element);
|
|
149
|
+
controls.appendChild(exportBtn.element);
|
|
150
|
+
|
|
151
|
+
header.appendChild(titleSection);
|
|
152
|
+
header.appendChild(controls);
|
|
153
|
+
|
|
154
|
+
this.headerElements = {
|
|
155
|
+
startBtn,
|
|
156
|
+
stopBtn,
|
|
157
|
+
exportBtn
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
return header;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Create right panel with metrics and controls
|
|
165
|
+
*/
|
|
166
|
+
createRightPanel() {
|
|
167
|
+
const panel = document.createElement('div');
|
|
168
|
+
panel.style.cssText = `
|
|
169
|
+
display: flex;
|
|
170
|
+
flex-direction: column;
|
|
171
|
+
gap: 16px;
|
|
172
|
+
overflow-y: auto;
|
|
173
|
+
`;
|
|
174
|
+
|
|
175
|
+
// Performance metrics chart
|
|
176
|
+
const metricsChart = this.createMetricsChart();
|
|
177
|
+
panel.appendChild(metricsChart);
|
|
178
|
+
|
|
179
|
+
// System health indicators
|
|
180
|
+
const healthPanel = this.createHealthPanel();
|
|
181
|
+
panel.appendChild(healthPanel);
|
|
182
|
+
|
|
183
|
+
// Memory usage chart
|
|
184
|
+
const memoryChart = this.createMemoryChart();
|
|
185
|
+
panel.appendChild(memoryChart);
|
|
186
|
+
|
|
187
|
+
// Task queue status
|
|
188
|
+
const queueStatus = this.createQueueStatus();
|
|
189
|
+
panel.appendChild(queueStatus);
|
|
190
|
+
|
|
191
|
+
// Recent activities log
|
|
192
|
+
const activityLog = this.createActivityLog();
|
|
193
|
+
panel.appendChild(activityLog);
|
|
194
|
+
|
|
195
|
+
return panel;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Create performance metrics chart
|
|
200
|
+
*/
|
|
201
|
+
createMetricsChart() {
|
|
202
|
+
const metricsChart = this.components.createMetricsChart({
|
|
203
|
+
title: 'Performance Metrics',
|
|
204
|
+
width: 350,
|
|
205
|
+
height: 200,
|
|
206
|
+
type: 'line'
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Sample data
|
|
210
|
+
this.updateMetricsChart(metricsChart);
|
|
211
|
+
|
|
212
|
+
this.metricsChart = metricsChart;
|
|
213
|
+
return metricsChart.element;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Create system health panel
|
|
218
|
+
*/
|
|
219
|
+
createHealthPanel() {
|
|
220
|
+
const panel = this.components.createInfoPanel({
|
|
221
|
+
title: 'đĨ System Health'
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
const healthMetrics = [
|
|
225
|
+
{ name: 'CPU Usage', value: '45%', status: 'good' },
|
|
226
|
+
{ name: 'Memory Usage', value: '2.1GB', status: 'good' },
|
|
227
|
+
{ name: 'Network I/O', value: '120 Mbps', status: 'good' },
|
|
228
|
+
{ name: 'Disk Usage', value: '67%', status: 'warning' },
|
|
229
|
+
{ name: 'Response Time', value: '234ms', status: 'good' }
|
|
230
|
+
];
|
|
231
|
+
|
|
232
|
+
const healthHTML = healthMetrics.map(metric => `
|
|
233
|
+
<div style="display: flex; justify-content: space-between; align-items: center; margin: 8px 0;">
|
|
234
|
+
<span>${metric.name}:</span>
|
|
235
|
+
<span class="health-metric health-${metric.status}" style="
|
|
236
|
+
padding: 4px 8px;
|
|
237
|
+
border-radius: 4px;
|
|
238
|
+
font-weight: bold;
|
|
239
|
+
${metric.status === 'good' ? 'background: #22c55e; color: white;' :
|
|
240
|
+
metric.status === 'warning' ? 'background: #f59e0b; color: white;' :
|
|
241
|
+
'background: #ef4444; color: white;'}
|
|
242
|
+
">${metric.value}</span>
|
|
243
|
+
</div>
|
|
244
|
+
`).join('');
|
|
245
|
+
|
|
246
|
+
panel.setContent(healthHTML);
|
|
247
|
+
this.healthPanel = panel;
|
|
248
|
+
return panel.element;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Create memory usage chart
|
|
253
|
+
*/
|
|
254
|
+
createMemoryChart() {
|
|
255
|
+
const memoryChart = this.components.createMetricsChart({
|
|
256
|
+
title: 'Memory Usage Over Time',
|
|
257
|
+
width: 350,
|
|
258
|
+
height: 150,
|
|
259
|
+
type: 'line'
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
this.updateMemoryChart(memoryChart);
|
|
263
|
+
this.memoryChart = memoryChart;
|
|
264
|
+
return memoryChart.element;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Create task queue status
|
|
269
|
+
*/
|
|
270
|
+
createQueueStatus() {
|
|
271
|
+
const panel = this.components.createInfoPanel({
|
|
272
|
+
title: 'đ Task Queue Status'
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
const queueData = {
|
|
276
|
+
pending: Math.floor(Math.random() * 20),
|
|
277
|
+
processing: Math.floor(Math.random() * 8),
|
|
278
|
+
completed: Math.floor(Math.random() * 150) + 50,
|
|
279
|
+
failed: Math.floor(Math.random() * 5)
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const queueHTML = `
|
|
283
|
+
<div class="queue-stats" style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px;">
|
|
284
|
+
<div class="queue-stat">
|
|
285
|
+
<div style="font-size: 24px; font-weight: bold; color: #f59e0b;">${queueData.pending}</div>
|
|
286
|
+
<div style="color: #888; font-size: 12px;">Pending</div>
|
|
287
|
+
</div>
|
|
288
|
+
<div class="queue-stat">
|
|
289
|
+
<div style="font-size: 24px; font-weight: bold; color: #00d4ff;">${queueData.processing}</div>
|
|
290
|
+
<div style="color: #888; font-size: 12px;">Processing</div>
|
|
291
|
+
</div>
|
|
292
|
+
<div class="queue-stat">
|
|
293
|
+
<div style="font-size: 24px; font-weight: bold; color: #22c55e;">${queueData.completed}</div>
|
|
294
|
+
<div style="color: #888; font-size: 12px;">Completed</div>
|
|
295
|
+
</div>
|
|
296
|
+
<div class="queue-stat">
|
|
297
|
+
<div style="font-size: 24px; font-weight: bold; color: #ef4444;">${queueData.failed}</div>
|
|
298
|
+
<div style="color: #888; font-size: 12px;">Failed</div>
|
|
299
|
+
</div>
|
|
300
|
+
</div>
|
|
301
|
+
`;
|
|
302
|
+
|
|
303
|
+
panel.setContent(queueHTML);
|
|
304
|
+
this.queuePanel = panel;
|
|
305
|
+
return panel.element;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Create activity log
|
|
310
|
+
*/
|
|
311
|
+
createActivityLog() {
|
|
312
|
+
const panel = this.components.createInfoPanel({
|
|
313
|
+
title: 'đ Recent Activity'
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
const activities = [
|
|
317
|
+
{ time: '14:23:15', type: 'info', message: 'Agent coder_01 completed task #127' },
|
|
318
|
+
{ time: '14:22:58', type: 'success', message: 'Swarm topology optimized (+12% efficiency)' },
|
|
319
|
+
{ time: '14:22:45', type: 'warning', message: 'Agent analyzer_03 high memory usage (89%)' },
|
|
320
|
+
{ time: '14:22:30', type: 'info', message: 'New task assigned to researcher_02' },
|
|
321
|
+
{ time: '14:22:12', type: 'error', message: 'Connection timeout to agent reviewer_01' }
|
|
322
|
+
];
|
|
323
|
+
|
|
324
|
+
const activityHTML = activities.map(activity => `
|
|
325
|
+
<div class="activity-item" style="
|
|
326
|
+
display: flex;
|
|
327
|
+
gap: 8px;
|
|
328
|
+
margin: 8px 0;
|
|
329
|
+
padding: 8px;
|
|
330
|
+
background: #2a2a2a;
|
|
331
|
+
border-radius: 4px;
|
|
332
|
+
border-left: 3px solid ${
|
|
333
|
+
activity.type === 'success' ? '#22c55e' :
|
|
334
|
+
activity.type === 'warning' ? '#f59e0b' :
|
|
335
|
+
activity.type === 'error' ? '#ef4444' : '#00d4ff'
|
|
336
|
+
};
|
|
337
|
+
">
|
|
338
|
+
<span style="color: #888; font-size: 12px; min-width: 60px;">${activity.time}</span>
|
|
339
|
+
<span style="font-size: 14px;">${activity.message}</span>
|
|
340
|
+
</div>
|
|
341
|
+
`).join('');
|
|
342
|
+
|
|
343
|
+
panel.setContent(`<div style="max-height: 200px; overflow-y: auto;">${activityHTML}</div>`);
|
|
344
|
+
this.activityPanel = panel;
|
|
345
|
+
return panel.element;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Create dashboard footer
|
|
350
|
+
*/
|
|
351
|
+
createDashboardFooter() {
|
|
352
|
+
const footer = document.createElement('div');
|
|
353
|
+
footer.style.cssText = `
|
|
354
|
+
grid-column: 1 / -1;
|
|
355
|
+
display: flex;
|
|
356
|
+
justify-content: space-between;
|
|
357
|
+
align-items: center;
|
|
358
|
+
padding: 12px 16px;
|
|
359
|
+
background: #1a1a1a;
|
|
360
|
+
border: 1px solid #444;
|
|
361
|
+
border-radius: 8px;
|
|
362
|
+
font-size: 12px;
|
|
363
|
+
color: #888;
|
|
364
|
+
`;
|
|
365
|
+
|
|
366
|
+
const leftStatus = document.createElement('div');
|
|
367
|
+
leftStatus.innerHTML = `
|
|
368
|
+
Status: <span id="dashboard-status" style="color: #22c55e;">â</span> Active |
|
|
369
|
+
Uptime: <span id="dashboard-uptime">00:00:00</span> |
|
|
370
|
+
Last Update: <span id="dashboard-last-update">Never</span>
|
|
371
|
+
`;
|
|
372
|
+
|
|
373
|
+
const rightStatus = document.createElement('div');
|
|
374
|
+
rightStatus.innerHTML = `
|
|
375
|
+
Total Messages: <span id="dashboard-messages">0</span> |
|
|
376
|
+
Data Points: <span id="dashboard-data-points">0</span> |
|
|
377
|
+
Version: Claude Flow v2.0.0
|
|
378
|
+
`;
|
|
379
|
+
|
|
380
|
+
footer.appendChild(leftStatus);
|
|
381
|
+
footer.appendChild(rightStatus);
|
|
382
|
+
|
|
383
|
+
this.footerElements = {
|
|
384
|
+
status: leftStatus.querySelector('#dashboard-status'),
|
|
385
|
+
uptime: leftStatus.querySelector('#dashboard-uptime'),
|
|
386
|
+
lastUpdate: leftStatus.querySelector('#dashboard-last-update'),
|
|
387
|
+
messages: rightStatus.querySelector('#dashboard-messages'),
|
|
388
|
+
dataPoints: rightStatus.querySelector('#dashboard-data-points')
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
return footer;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Setup WebSocket connection for real-time updates
|
|
396
|
+
*/
|
|
397
|
+
setupWebSocket() {
|
|
398
|
+
try {
|
|
399
|
+
const wsUrl = 'ws://localhost:3000/dashboard';
|
|
400
|
+
this.websocket = new WebSocket(wsUrl);
|
|
401
|
+
|
|
402
|
+
this.websocket.onopen = () => {
|
|
403
|
+
console.log('đĄ Dashboard WebSocket connected');
|
|
404
|
+
this.updateConnectionStatus(true);
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
this.websocket.onmessage = (event) => {
|
|
408
|
+
try {
|
|
409
|
+
const data = JSON.parse(event.data);
|
|
410
|
+
this.handleWebSocketMessage(data);
|
|
411
|
+
} catch (error) {
|
|
412
|
+
console.warn('Failed to parse WebSocket message:', error);
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
this.websocket.onclose = () => {
|
|
417
|
+
console.log('đĄ Dashboard WebSocket disconnected');
|
|
418
|
+
this.updateConnectionStatus(false);
|
|
419
|
+
// Attempt reconnection after 5 seconds
|
|
420
|
+
setTimeout(() => this.setupWebSocket(), 5000);
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
this.websocket.onerror = (error) => {
|
|
424
|
+
console.error('đĄ Dashboard WebSocket error:', error);
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
} catch (error) {
|
|
428
|
+
console.warn('WebSocket not available, using polling fallback');
|
|
429
|
+
this.startPollingFallback();
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Handle WebSocket messages
|
|
435
|
+
*/
|
|
436
|
+
handleWebSocketMessage(data) {
|
|
437
|
+
switch (data.type) {
|
|
438
|
+
case 'swarm_update':
|
|
439
|
+
// Forward to swarm visualizer
|
|
440
|
+
if (this.swarmVisualizer) {
|
|
441
|
+
this.swarmVisualizer.swarmData = data.payload;
|
|
442
|
+
this.swarmVisualizer.processSwarmData();
|
|
443
|
+
this.swarmVisualizer.updateStats();
|
|
444
|
+
}
|
|
445
|
+
break;
|
|
446
|
+
|
|
447
|
+
case 'metrics_update':
|
|
448
|
+
this.updateMetricsFromData(data.payload);
|
|
449
|
+
break;
|
|
450
|
+
|
|
451
|
+
case 'health_update':
|
|
452
|
+
this.updateHealthStatus(data.payload);
|
|
453
|
+
break;
|
|
454
|
+
|
|
455
|
+
case 'activity_log':
|
|
456
|
+
this.addActivityLog(data.payload);
|
|
457
|
+
break;
|
|
458
|
+
|
|
459
|
+
default:
|
|
460
|
+
console.log('Unknown WebSocket message type:', data.type);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
this.updateLastUpdateTime();
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Start polling fallback for when WebSocket isn't available
|
|
468
|
+
*/
|
|
469
|
+
startPollingFallback() {
|
|
470
|
+
this.updateInterval = setInterval(() => {
|
|
471
|
+
this.fetchDashboardData();
|
|
472
|
+
}, 2000);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Fetch dashboard data via HTTP
|
|
477
|
+
*/
|
|
478
|
+
async fetchDashboardData() {
|
|
479
|
+
try {
|
|
480
|
+
const response = await fetch('/api/claude-flow/dashboard/data');
|
|
481
|
+
if (response.ok) {
|
|
482
|
+
const data = await response.json();
|
|
483
|
+
this.handleDashboardData(data);
|
|
484
|
+
}
|
|
485
|
+
} catch (error) {
|
|
486
|
+
console.warn('Failed to fetch dashboard data:', error);
|
|
487
|
+
// Generate mock data for demo
|
|
488
|
+
this.handleDashboardData(this.generateMockDashboardData());
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Generate mock dashboard data
|
|
494
|
+
*/
|
|
495
|
+
generateMockDashboardData() {
|
|
496
|
+
return {
|
|
497
|
+
swarm: {
|
|
498
|
+
agents: 6,
|
|
499
|
+
active: 4,
|
|
500
|
+
busy: 2,
|
|
501
|
+
idle: 2,
|
|
502
|
+
errors: 0
|
|
503
|
+
},
|
|
504
|
+
metrics: {
|
|
505
|
+
cpuUsage: Math.random() * 30 + 20,
|
|
506
|
+
memoryUsage: Math.random() * 40 + 40,
|
|
507
|
+
throughput: Math.random() * 50 + 25,
|
|
508
|
+
latency: Math.random() * 200 + 100
|
|
509
|
+
},
|
|
510
|
+
health: {
|
|
511
|
+
overall: 'good',
|
|
512
|
+
services: ['swarm', 'memory', 'neural'].map(service => ({
|
|
513
|
+
name: service,
|
|
514
|
+
status: Math.random() > 0.8 ? 'warning' : 'good'
|
|
515
|
+
}))
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Update metrics charts with new data
|
|
522
|
+
*/
|
|
523
|
+
updateMetricsFromData(data) {
|
|
524
|
+
// Add to history
|
|
525
|
+
this.metrics.history.push({
|
|
526
|
+
timestamp: Date.now(),
|
|
527
|
+
...data
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
// Keep only last 50 data points
|
|
531
|
+
if (this.metrics.history.length > 50) {
|
|
532
|
+
this.metrics.history.shift();
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
this.metrics.current = data;
|
|
536
|
+
this.updateMetricsChart(this.metricsChart);
|
|
537
|
+
this.updateMemoryChart(this.memoryChart);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Update metrics chart
|
|
542
|
+
*/
|
|
543
|
+
updateMetricsChart(chart) {
|
|
544
|
+
if (!chart || !this.metrics.history.length) return;
|
|
545
|
+
|
|
546
|
+
const data = this.metrics.history.map((point, index) => ({
|
|
547
|
+
x: index,
|
|
548
|
+
value: point.throughput || Math.random() * 100
|
|
549
|
+
}));
|
|
550
|
+
|
|
551
|
+
chart.updateData(data);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Update memory chart
|
|
556
|
+
*/
|
|
557
|
+
updateMemoryChart(chart) {
|
|
558
|
+
if (!chart || !this.metrics.history.length) return;
|
|
559
|
+
|
|
560
|
+
const data = this.metrics.history.map((point, index) => ({
|
|
561
|
+
x: index,
|
|
562
|
+
value: point.memoryUsage || Math.random() * 100
|
|
563
|
+
}));
|
|
564
|
+
|
|
565
|
+
chart.updateData(data);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Start all monitoring systems
|
|
570
|
+
*/
|
|
571
|
+
startAllMonitoring() {
|
|
572
|
+
this.isActive = true;
|
|
573
|
+
|
|
574
|
+
// Start swarm visualizer
|
|
575
|
+
if (this.swarmVisualizer) {
|
|
576
|
+
this.swarmVisualizer.startMonitoring();
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// Start metrics collection
|
|
580
|
+
this.startMetricsCollection();
|
|
581
|
+
|
|
582
|
+
// Update UI state
|
|
583
|
+
this.headerElements.startBtn.setDisabled(true);
|
|
584
|
+
this.headerElements.stopBtn.setDisabled(false);
|
|
585
|
+
this.updateConnectionStatus(true);
|
|
586
|
+
|
|
587
|
+
console.log('đ All dashboard monitoring started');
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Stop all monitoring systems
|
|
592
|
+
*/
|
|
593
|
+
stopAllMonitoring() {
|
|
594
|
+
this.isActive = false;
|
|
595
|
+
|
|
596
|
+
// Stop swarm visualizer
|
|
597
|
+
if (this.swarmVisualizer) {
|
|
598
|
+
this.swarmVisualizer.stopMonitoring();
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// Stop metrics collection
|
|
602
|
+
if (this.updateInterval) {
|
|
603
|
+
clearInterval(this.updateInterval);
|
|
604
|
+
this.updateInterval = null;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Update UI state
|
|
608
|
+
this.headerElements.startBtn.setDisabled(false);
|
|
609
|
+
this.headerElements.stopBtn.setDisabled(true);
|
|
610
|
+
this.updateConnectionStatus(false);
|
|
611
|
+
|
|
612
|
+
console.log('âšī¸ All dashboard monitoring stopped');
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Start metrics collection
|
|
617
|
+
*/
|
|
618
|
+
startMetricsCollection() {
|
|
619
|
+
if (!this.websocket || this.websocket.readyState !== WebSocket.OPEN) {
|
|
620
|
+
this.startPollingFallback();
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Update connection status
|
|
626
|
+
*/
|
|
627
|
+
updateConnectionStatus(connected) {
|
|
628
|
+
if (this.footerElements.status) {
|
|
629
|
+
this.footerElements.status.style.color = connected ? '#22c55e' : '#ef4444';
|
|
630
|
+
this.footerElements.status.textContent = connected ? 'â' : 'â';
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Update last update time
|
|
636
|
+
*/
|
|
637
|
+
updateLastUpdateTime() {
|
|
638
|
+
if (this.footerElements.lastUpdate) {
|
|
639
|
+
this.footerElements.lastUpdate.textContent = new Date().toLocaleTimeString();
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Export dashboard data
|
|
645
|
+
*/
|
|
646
|
+
exportDashboardData() {
|
|
647
|
+
const exportData = {
|
|
648
|
+
timestamp: Date.now(),
|
|
649
|
+
metrics: this.metrics,
|
|
650
|
+
swarmData: this.swarmVisualizer?.swarmData,
|
|
651
|
+
version: 'Claude Flow v2.0.0'
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
const blob = new Blob([JSON.stringify(exportData, null, 2)], {
|
|
655
|
+
type: 'application/json'
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
const url = URL.createObjectURL(blob);
|
|
659
|
+
const a = document.createElement('a');
|
|
660
|
+
a.href = url;
|
|
661
|
+
a.download = `claude-flow-dashboard-${Date.now()}.json`;
|
|
662
|
+
document.body.appendChild(a);
|
|
663
|
+
a.click();
|
|
664
|
+
document.body.removeChild(a);
|
|
665
|
+
URL.revokeObjectURL(url);
|
|
666
|
+
|
|
667
|
+
console.log('đž Dashboard data exported');
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Store progress to swarm memory
|
|
672
|
+
*/
|
|
673
|
+
async storeProgressToMemory() {
|
|
674
|
+
const progressData = {
|
|
675
|
+
dashboardActive: this.isActive,
|
|
676
|
+
metricsCount: this.metrics.history.length,
|
|
677
|
+
swarmVisualizerActive: this.swarmVisualizer?.isActive || false,
|
|
678
|
+
lastUpdate: Date.now(),
|
|
679
|
+
components: {
|
|
680
|
+
swarmVisualizer: 'active',
|
|
681
|
+
metricsChart: 'active',
|
|
682
|
+
healthPanel: 'active',
|
|
683
|
+
activityLog: 'active'
|
|
684
|
+
}
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
try {
|
|
688
|
+
// This would normally call the memory API
|
|
689
|
+
console.log('đ Storing dashboard progress to memory:', progressData);
|
|
690
|
+
} catch (error) {
|
|
691
|
+
console.warn('Failed to store progress to memory:', error);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* Cleanup resources
|
|
697
|
+
*/
|
|
698
|
+
destroy() {
|
|
699
|
+
this.stopAllMonitoring();
|
|
700
|
+
|
|
701
|
+
if (this.websocket) {
|
|
702
|
+
this.websocket.close();
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
if (this.swarmVisualizer) {
|
|
706
|
+
this.swarmVisualizer.destroy();
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
if (this.container) {
|
|
710
|
+
this.container.innerHTML = '';
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
export default RealTimeDashboard;
|