claude-code-templates 1.8.0 → 1.8.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.
- package/README.md +246 -0
- package/package.json +26 -12
- package/src/analytics/core/ConversationAnalyzer.js +754 -0
- package/src/analytics/core/FileWatcher.js +285 -0
- package/src/analytics/core/ProcessDetector.js +242 -0
- package/src/analytics/core/SessionAnalyzer.js +631 -0
- package/src/analytics/core/StateCalculator.js +190 -0
- package/src/analytics/data/DataCache.js +550 -0
- package/src/analytics/notifications/NotificationManager.js +448 -0
- package/src/analytics/notifications/WebSocketServer.js +526 -0
- package/src/analytics/utils/PerformanceMonitor.js +455 -0
- package/src/analytics-web/assets/js/main.js +312 -0
- package/src/analytics-web/components/Charts.js +114 -0
- package/src/analytics-web/components/ConversationTable.js +437 -0
- package/src/analytics-web/components/Dashboard.js +573 -0
- package/src/analytics-web/components/SessionTimer.js +596 -0
- package/src/analytics-web/index.html +882 -49
- package/src/analytics-web/index.html.original +1939 -0
- package/src/analytics-web/services/DataService.js +357 -0
- package/src/analytics-web/services/StateService.js +276 -0
- package/src/analytics-web/services/WebSocketService.js +523 -0
- package/src/analytics.js +641 -2311
- package/src/analytics.log +0 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main application entry point for the modular analytics dashboard
|
|
3
|
+
* This replaces the embedded JavaScript in index.html
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* AnalyticsDashboard - Main application class
|
|
8
|
+
* Orchestrates all services and components
|
|
9
|
+
*/
|
|
10
|
+
class AnalyticsDashboard {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.services = {};
|
|
13
|
+
this.components = {};
|
|
14
|
+
this.isInitialized = false;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Initialize the application
|
|
19
|
+
*/
|
|
20
|
+
async initialize() {
|
|
21
|
+
try {
|
|
22
|
+
console.log('🚀 Initializing Analytics Dashboard...');
|
|
23
|
+
|
|
24
|
+
await this.initializeServices();
|
|
25
|
+
await this.initializeComponents();
|
|
26
|
+
await this.startApplication();
|
|
27
|
+
|
|
28
|
+
this.isInitialized = true;
|
|
29
|
+
console.log('✅ Analytics Dashboard initialized successfully');
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error('❌ Failed to initialize Analytics Dashboard:', error);
|
|
32
|
+
this.showError('Failed to initialize dashboard: ' + error.message);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Initialize all services
|
|
38
|
+
*/
|
|
39
|
+
async initializeServices() {
|
|
40
|
+
console.log('🔧 Initializing services...');
|
|
41
|
+
|
|
42
|
+
// Initialize DataService
|
|
43
|
+
this.services.data = new DataService();
|
|
44
|
+
|
|
45
|
+
// Initialize StateService
|
|
46
|
+
this.services.state = new StateService();
|
|
47
|
+
|
|
48
|
+
// Initialize Charts service (placeholder)
|
|
49
|
+
this.services.chart = new Charts(null, this.services.data, this.services.state);
|
|
50
|
+
|
|
51
|
+
// Start periodic data refresh
|
|
52
|
+
this.services.data.startPeriodicRefresh();
|
|
53
|
+
|
|
54
|
+
console.log('✅ Services initialized');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Initialize all components
|
|
59
|
+
*/
|
|
60
|
+
async initializeComponents() {
|
|
61
|
+
console.log('🎨 Initializing components...');
|
|
62
|
+
|
|
63
|
+
// Get main container
|
|
64
|
+
const container = document.getElementById('app') || document.body;
|
|
65
|
+
|
|
66
|
+
// Initialize Dashboard component
|
|
67
|
+
this.components.dashboard = new Dashboard(container, this.services);
|
|
68
|
+
await this.components.dashboard.initialize();
|
|
69
|
+
|
|
70
|
+
console.log('✅ Components initialized');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Start the application
|
|
75
|
+
*/
|
|
76
|
+
async startApplication() {
|
|
77
|
+
console.log('🎯 Starting application...');
|
|
78
|
+
|
|
79
|
+
// Setup global error handling
|
|
80
|
+
this.setupErrorHandling();
|
|
81
|
+
|
|
82
|
+
// Setup keyboard shortcuts
|
|
83
|
+
this.setupKeyboardShortcuts();
|
|
84
|
+
|
|
85
|
+
// Setup visibility change handling
|
|
86
|
+
this.setupVisibilityHandling();
|
|
87
|
+
|
|
88
|
+
console.log('✅ Application started');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Setup global error handling
|
|
93
|
+
*/
|
|
94
|
+
setupErrorHandling() {
|
|
95
|
+
window.addEventListener('error', (event) => {
|
|
96
|
+
console.error('Global error:', event.error);
|
|
97
|
+
this.services.state.setError(`Application error: ${event.error.message}`);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
window.addEventListener('unhandledrejection', (event) => {
|
|
101
|
+
console.error('Unhandled promise rejection:', event.reason);
|
|
102
|
+
this.services.state.setError(`Promise rejection: ${event.reason.message || event.reason}`);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Setup keyboard shortcuts
|
|
108
|
+
*/
|
|
109
|
+
setupKeyboardShortcuts() {
|
|
110
|
+
document.addEventListener('keydown', (event) => {
|
|
111
|
+
// Ctrl/Cmd + R - Refresh data
|
|
112
|
+
if ((event.ctrlKey || event.metaKey) && event.key === 'r') {
|
|
113
|
+
event.preventDefault();
|
|
114
|
+
this.refreshData();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Ctrl/Cmd + E - Export data
|
|
118
|
+
if ((event.ctrlKey || event.metaKey) && event.key === 'e') {
|
|
119
|
+
event.preventDefault();
|
|
120
|
+
this.exportData();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Escape - Clear errors
|
|
124
|
+
if (event.key === 'Escape') {
|
|
125
|
+
this.services.state.clearError();
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Setup visibility change handling
|
|
132
|
+
*/
|
|
133
|
+
setupVisibilityHandling() {
|
|
134
|
+
document.addEventListener('visibilitychange', () => {
|
|
135
|
+
if (document.hidden) {
|
|
136
|
+
// Page is hidden - pause updates
|
|
137
|
+
this.services.data.stopPeriodicRefresh();
|
|
138
|
+
} else {
|
|
139
|
+
// Page is visible - resume updates
|
|
140
|
+
this.services.data.startPeriodicRefresh();
|
|
141
|
+
// Immediately refresh data
|
|
142
|
+
this.refreshData();
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Refresh all data
|
|
149
|
+
*/
|
|
150
|
+
async refreshData() {
|
|
151
|
+
console.log('🔄 Refreshing data...');
|
|
152
|
+
try {
|
|
153
|
+
this.services.data.clearCache();
|
|
154
|
+
|
|
155
|
+
const [conversationsData, statesData] = await Promise.all([
|
|
156
|
+
this.services.data.getConversations(),
|
|
157
|
+
this.services.data.getConversationStates()
|
|
158
|
+
]);
|
|
159
|
+
|
|
160
|
+
this.services.state.updateConversations(conversationsData.conversations);
|
|
161
|
+
this.services.state.updateSummary(conversationsData.summary);
|
|
162
|
+
this.services.state.updateConversationStates(statesData);
|
|
163
|
+
|
|
164
|
+
console.log('✅ Data refreshed');
|
|
165
|
+
} catch (error) {
|
|
166
|
+
console.error('❌ Failed to refresh data:', error);
|
|
167
|
+
this.services.state.setError('Failed to refresh data: ' + error.message);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Export data
|
|
173
|
+
*/
|
|
174
|
+
exportData() {
|
|
175
|
+
if (this.components.dashboard) {
|
|
176
|
+
this.components.dashboard.exportData();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Show error message
|
|
182
|
+
* @param {string} message - Error message
|
|
183
|
+
*/
|
|
184
|
+
showError(message) {
|
|
185
|
+
// Create error display if components aren't ready
|
|
186
|
+
const errorDiv = document.createElement('div');
|
|
187
|
+
errorDiv.className = 'initialization-error';
|
|
188
|
+
errorDiv.style.cssText = `
|
|
189
|
+
position: fixed;
|
|
190
|
+
top: 20px;
|
|
191
|
+
right: 20px;
|
|
192
|
+
background: #f85149;
|
|
193
|
+
color: white;
|
|
194
|
+
padding: 15px 20px;
|
|
195
|
+
border-radius: 5px;
|
|
196
|
+
z-index: 10000;
|
|
197
|
+
max-width: 400px;
|
|
198
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
199
|
+
`;
|
|
200
|
+
errorDiv.innerHTML = `
|
|
201
|
+
<strong>Initialization Error</strong><br>
|
|
202
|
+
${message}
|
|
203
|
+
<button onclick="this.parentElement.remove()" style="
|
|
204
|
+
background: none;
|
|
205
|
+
border: none;
|
|
206
|
+
color: white;
|
|
207
|
+
float: right;
|
|
208
|
+
cursor: pointer;
|
|
209
|
+
font-size: 16px;
|
|
210
|
+
margin-top: -5px;
|
|
211
|
+
">×</button>
|
|
212
|
+
`;
|
|
213
|
+
document.body.appendChild(errorDiv);
|
|
214
|
+
|
|
215
|
+
// Auto-remove after 10 seconds
|
|
216
|
+
setTimeout(() => {
|
|
217
|
+
if (errorDiv.parentElement) {
|
|
218
|
+
errorDiv.remove();
|
|
219
|
+
}
|
|
220
|
+
}, 10000);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Cleanup and destroy application
|
|
225
|
+
*/
|
|
226
|
+
destroy() {
|
|
227
|
+
console.log('🧹 Cleaning up application...');
|
|
228
|
+
|
|
229
|
+
// Stop services
|
|
230
|
+
if (this.services.data) {
|
|
231
|
+
this.services.data.stopPeriodicRefresh();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Destroy components
|
|
235
|
+
Object.values(this.components).forEach(component => {
|
|
236
|
+
if (component.destroy) {
|
|
237
|
+
component.destroy();
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Clear references
|
|
242
|
+
this.services = {};
|
|
243
|
+
this.components = {};
|
|
244
|
+
this.isInitialized = false;
|
|
245
|
+
|
|
246
|
+
console.log('✅ Application cleaned up');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Get application statistics
|
|
251
|
+
*/
|
|
252
|
+
getStats() {
|
|
253
|
+
return {
|
|
254
|
+
initialized: this.isInitialized,
|
|
255
|
+
services: Object.keys(this.services).length,
|
|
256
|
+
components: Object.keys(this.components).length,
|
|
257
|
+
dataServiceStats: this.services.data ? this.services.data.getCacheStats() : null,
|
|
258
|
+
stateServiceStats: this.services.state ? this.services.state.getStateStats() : null
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Global application instance
|
|
264
|
+
let analyticsApp = null;
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Initialize the application when DOM is ready
|
|
268
|
+
*/
|
|
269
|
+
document.addEventListener('DOMContentLoaded', async () => {
|
|
270
|
+
console.log('📱 DOM Content Loaded - Starting Analytics Dashboard');
|
|
271
|
+
|
|
272
|
+
try {
|
|
273
|
+
analyticsApp = new AnalyticsDashboard();
|
|
274
|
+
await analyticsApp.initialize();
|
|
275
|
+
|
|
276
|
+
// Make app available globally for debugging
|
|
277
|
+
window.analyticsApp = analyticsApp;
|
|
278
|
+
|
|
279
|
+
// Add development helpers
|
|
280
|
+
if (window.location.hostname === 'localhost') {
|
|
281
|
+
window.refreshDashboard = () => analyticsApp.refreshData();
|
|
282
|
+
window.getAppStats = () => analyticsApp.getStats();
|
|
283
|
+
console.log('🔧 Development helpers available: refreshDashboard(), getAppStats()');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
} catch (error) {
|
|
287
|
+
console.error('❌ Failed to start Analytics Dashboard:', error);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Cleanup on page unload
|
|
293
|
+
*/
|
|
294
|
+
window.addEventListener('beforeunload', () => {
|
|
295
|
+
if (analyticsApp) {
|
|
296
|
+
analyticsApp.destroy();
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Handle browser back/forward navigation
|
|
302
|
+
*/
|
|
303
|
+
window.addEventListener('popstate', () => {
|
|
304
|
+
if (analyticsApp) {
|
|
305
|
+
analyticsApp.refreshData();
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
// Export for module use
|
|
310
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
311
|
+
module.exports = AnalyticsDashboard;
|
|
312
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Charts - Handles chart display and management
|
|
3
|
+
* Part of the modular frontend architecture
|
|
4
|
+
*/
|
|
5
|
+
class Charts {
|
|
6
|
+
constructor(container, dataService, stateService) {
|
|
7
|
+
this.container = container;
|
|
8
|
+
this.dataService = dataService;
|
|
9
|
+
this.stateService = stateService;
|
|
10
|
+
this.charts = {};
|
|
11
|
+
|
|
12
|
+
// Subscribe to state changes
|
|
13
|
+
this.unsubscribe = this.stateService.subscribe(this.handleStateChange.bind(this));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Initialize charts
|
|
18
|
+
*/
|
|
19
|
+
async initialize() {
|
|
20
|
+
await this.loadChartData();
|
|
21
|
+
this.setupCharts();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Handle state changes from StateService
|
|
26
|
+
* @param {Object} state - New state
|
|
27
|
+
* @param {string} action - Action that caused the change
|
|
28
|
+
*/
|
|
29
|
+
handleStateChange(state, action) {
|
|
30
|
+
if (action === 'update_chart_data') {
|
|
31
|
+
this.updateCharts(state.chartData);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Load chart data from API
|
|
37
|
+
*/
|
|
38
|
+
async loadChartData() {
|
|
39
|
+
try {
|
|
40
|
+
const chartData = await this.dataService.getChartData();
|
|
41
|
+
this.stateService.updateChartData(chartData);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error('Error loading chart data:', error);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Setup chart instances
|
|
49
|
+
*/
|
|
50
|
+
setupCharts() {
|
|
51
|
+
// This would be called from Dashboard component
|
|
52
|
+
// which already has Chart.js integration
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Update charts with new data
|
|
57
|
+
* @param {Object} chartData - New chart data
|
|
58
|
+
*/
|
|
59
|
+
updateCharts(chartData) {
|
|
60
|
+
// Update existing charts with new data
|
|
61
|
+
Object.keys(this.charts).forEach(chartId => {
|
|
62
|
+
const chart = this.charts[chartId];
|
|
63
|
+
if (chartData[chartId]) {
|
|
64
|
+
chart.data = chartData[chartId];
|
|
65
|
+
chart.update();
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Create a new chart
|
|
72
|
+
* @param {string} id - Chart ID
|
|
73
|
+
* @param {HTMLElement} canvas - Canvas element
|
|
74
|
+
* @param {Object} config - Chart configuration
|
|
75
|
+
*/
|
|
76
|
+
createChart(id, canvas, config) {
|
|
77
|
+
if (typeof Chart === 'undefined') {
|
|
78
|
+
console.error('Chart.js not loaded');
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.charts[id] = new Chart(canvas, config);
|
|
83
|
+
return this.charts[id];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Destroy specific chart
|
|
88
|
+
* @param {string} id - Chart ID
|
|
89
|
+
*/
|
|
90
|
+
destroyChart(id) {
|
|
91
|
+
if (this.charts[id]) {
|
|
92
|
+
this.charts[id].destroy();
|
|
93
|
+
delete this.charts[id];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Cleanup all charts
|
|
99
|
+
*/
|
|
100
|
+
destroy() {
|
|
101
|
+
Object.keys(this.charts).forEach(id => {
|
|
102
|
+
this.destroyChart(id);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
if (this.unsubscribe) {
|
|
106
|
+
this.unsubscribe();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Export for module use
|
|
112
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
113
|
+
module.exports = Charts;
|
|
114
|
+
}
|