claude-code-templates 1.8.0 → 1.8.1
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 +597 -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 +626 -2317
- package/src/analytics.log +0 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DataService - Handles API communication and data caching
|
|
3
|
+
* Part of the modular frontend architecture
|
|
4
|
+
*/
|
|
5
|
+
class DataService {
|
|
6
|
+
constructor(webSocketService = null) {
|
|
7
|
+
this.cache = new Map();
|
|
8
|
+
this.eventListeners = new Set();
|
|
9
|
+
this.baseURL = '';
|
|
10
|
+
this.lastFetch = {};
|
|
11
|
+
this.webSocketService = webSocketService;
|
|
12
|
+
this.realTimeEnabled = false;
|
|
13
|
+
|
|
14
|
+
// Setup WebSocket integration if available
|
|
15
|
+
if (this.webSocketService) {
|
|
16
|
+
this.setupWebSocketIntegration();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Add event listener for data changes
|
|
22
|
+
* @param {Function} callback - Callback function to call on data changes
|
|
23
|
+
*/
|
|
24
|
+
addEventListener(callback) {
|
|
25
|
+
this.eventListeners.add(callback);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Remove event listener
|
|
30
|
+
* @param {Function} callback - Callback function to remove
|
|
31
|
+
*/
|
|
32
|
+
removeEventListener(callback) {
|
|
33
|
+
this.eventListeners.delete(callback);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Notify all listeners of data changes
|
|
38
|
+
* @param {string} type - Type of data that changed
|
|
39
|
+
* @param {*} data - New data
|
|
40
|
+
*/
|
|
41
|
+
notifyListeners(type, data) {
|
|
42
|
+
this.eventListeners.forEach(callback => {
|
|
43
|
+
try {
|
|
44
|
+
callback(type, data);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error('Error in DataService listener:', error);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Generic fetch with caching support
|
|
53
|
+
* @param {string} endpoint - API endpoint
|
|
54
|
+
* @param {Object} options - Fetch options
|
|
55
|
+
* @returns {Promise<*>} Response data
|
|
56
|
+
*/
|
|
57
|
+
async cachedFetch(endpoint, options = {}) {
|
|
58
|
+
const cacheKey = `${endpoint}_${JSON.stringify(options)}`;
|
|
59
|
+
const now = Date.now();
|
|
60
|
+
const cacheDuration = options.cacheDuration || 30000; // 30 seconds default
|
|
61
|
+
|
|
62
|
+
// Check if we have cached data that's still valid
|
|
63
|
+
if (this.cache.has(cacheKey)) {
|
|
64
|
+
const cached = this.cache.get(cacheKey);
|
|
65
|
+
if (now - cached.timestamp < cacheDuration) {
|
|
66
|
+
return cached.data;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
const response = await fetch(this.baseURL + endpoint, {
|
|
72
|
+
method: 'GET',
|
|
73
|
+
headers: {
|
|
74
|
+
'Content-Type': 'application/json',
|
|
75
|
+
...options.headers
|
|
76
|
+
},
|
|
77
|
+
...options
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
if (!response.ok) {
|
|
81
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const data = await response.json();
|
|
85
|
+
|
|
86
|
+
// Cache the response
|
|
87
|
+
this.cache.set(cacheKey, {
|
|
88
|
+
data,
|
|
89
|
+
timestamp: now
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
return data;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error(`Error fetching ${endpoint}:`, error);
|
|
95
|
+
|
|
96
|
+
// Return cached data if available, even if stale
|
|
97
|
+
if (this.cache.has(cacheKey)) {
|
|
98
|
+
console.warn('Using stale cached data due to fetch error');
|
|
99
|
+
return this.cache.get(cacheKey).data;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Get conversations data
|
|
108
|
+
* @returns {Promise<Object>} Conversations data
|
|
109
|
+
*/
|
|
110
|
+
async getConversations() {
|
|
111
|
+
return await this.cachedFetch('/api/data');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get conversation states for real-time updates
|
|
116
|
+
* @returns {Promise<Object>} Conversation states
|
|
117
|
+
*/
|
|
118
|
+
async getConversationStates() {
|
|
119
|
+
const cacheDuration = this.realTimeEnabled ? 30000 : 5000; // Longer cache with real-time
|
|
120
|
+
return await this.cachedFetch('/api/conversation-state', {
|
|
121
|
+
cacheDuration
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get chart data for visualizations
|
|
127
|
+
* @returns {Promise<Object>} Chart data
|
|
128
|
+
*/
|
|
129
|
+
async getChartData() {
|
|
130
|
+
return await this.cachedFetch('/api/charts');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get session data for Max plan usage tracking
|
|
135
|
+
* @returns {Promise<Object>} Session data including timer and usage info
|
|
136
|
+
*/
|
|
137
|
+
async getSessionData() {
|
|
138
|
+
const cacheDuration = this.realTimeEnabled ? 30000 : 5000; // 30s with real-time, 5s without
|
|
139
|
+
return await this.cachedFetch('/api/session/data', { cacheDuration });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Get project statistics
|
|
144
|
+
* @returns {Promise<Object>} Project statistics
|
|
145
|
+
*/
|
|
146
|
+
async getProjectStats() {
|
|
147
|
+
return await this.cachedFetch('/api/session/projects');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get system health information
|
|
152
|
+
* @returns {Promise<Object>} System health data
|
|
153
|
+
*/
|
|
154
|
+
async getSystemHealth() {
|
|
155
|
+
return await this.cachedFetch('/api/system/health');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Clear all cached data
|
|
160
|
+
*/
|
|
161
|
+
clearCache() {
|
|
162
|
+
this.cache.clear();
|
|
163
|
+
console.log('DataService cache cleared');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Clear specific cache entry
|
|
168
|
+
* @param {string} endpoint - Endpoint to clear from cache
|
|
169
|
+
*/
|
|
170
|
+
clearCacheEntry(endpoint) {
|
|
171
|
+
const keysToDelete = [];
|
|
172
|
+
for (const key of this.cache.keys()) {
|
|
173
|
+
if (key.startsWith(endpoint)) {
|
|
174
|
+
keysToDelete.push(key);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
keysToDelete.forEach(key => this.cache.delete(key));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Setup WebSocket integration for real-time updates
|
|
182
|
+
*/
|
|
183
|
+
setupWebSocketIntegration() {
|
|
184
|
+
if (!this.webSocketService) return;
|
|
185
|
+
|
|
186
|
+
console.log('🔌 Setting up WebSocket integration for DataService');
|
|
187
|
+
|
|
188
|
+
// Listen for data refresh events
|
|
189
|
+
this.webSocketService.on('data_refresh', (data) => {
|
|
190
|
+
console.log('📊 Real-time data refresh received');
|
|
191
|
+
this.handleRealTimeDataRefresh(data);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// Listen for conversation state changes
|
|
195
|
+
this.webSocketService.on('conversation_state_change', (data) => {
|
|
196
|
+
console.log('🔄 Real-time conversation state change');
|
|
197
|
+
this.handleRealTimeStateChange(data);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Listen for connection status
|
|
201
|
+
this.webSocketService.on('connected', () => {
|
|
202
|
+
console.log('✅ WebSocket connected - enabling real-time updates');
|
|
203
|
+
this.realTimeEnabled = true;
|
|
204
|
+
this.subscribeToChannels();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
this.webSocketService.on('disconnected', () => {
|
|
208
|
+
console.log('❌ WebSocket disconnected - falling back to polling');
|
|
209
|
+
this.realTimeEnabled = false;
|
|
210
|
+
this.startFallbackPolling();
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Subscribe to WebSocket channels
|
|
216
|
+
*/
|
|
217
|
+
async subscribeToChannels() {
|
|
218
|
+
if (!this.webSocketService || !this.realTimeEnabled) return;
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
await this.webSocketService.subscribe('data_updates');
|
|
222
|
+
await this.webSocketService.subscribe('conversation_updates');
|
|
223
|
+
await this.webSocketService.subscribe('system_updates');
|
|
224
|
+
console.log('📡 Subscribed to real-time channels');
|
|
225
|
+
} catch (error) {
|
|
226
|
+
console.error('Error subscribing to channels:', error);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Handle real-time data refresh
|
|
232
|
+
* @param {Object} data - Fresh data from server
|
|
233
|
+
*/
|
|
234
|
+
handleRealTimeDataRefresh(data) {
|
|
235
|
+
// Clear relevant cache entries
|
|
236
|
+
this.clearCacheEntry('/api/data');
|
|
237
|
+
this.clearCacheEntry('/api/conversation-state');
|
|
238
|
+
|
|
239
|
+
// Notify listeners
|
|
240
|
+
this.notifyListeners('data_refresh', data);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Handle real-time conversation state change
|
|
245
|
+
* @param {Object} data - State change data
|
|
246
|
+
*/
|
|
247
|
+
handleRealTimeStateChange(data) {
|
|
248
|
+
// Clear conversation state cache
|
|
249
|
+
this.clearCacheEntry('/api/conversation-state');
|
|
250
|
+
|
|
251
|
+
// Notify listeners
|
|
252
|
+
this.notifyListeners('conversation_state_change', data);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Start periodic data refresh (fallback when WebSocket unavailable)
|
|
257
|
+
* @param {number} interval - Refresh interval in milliseconds
|
|
258
|
+
*/
|
|
259
|
+
startPeriodicRefresh(interval = 30000) {
|
|
260
|
+
// Don't start polling if real-time is enabled
|
|
261
|
+
if (this.realTimeEnabled) {
|
|
262
|
+
console.log('⚡ Real-time updates enabled - skipping periodic refresh');
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (this.refreshInterval) {
|
|
267
|
+
clearInterval(this.refreshInterval);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
console.log('📅 Starting periodic refresh (fallback mode)');
|
|
271
|
+
this.refreshInterval = setInterval(async () => {
|
|
272
|
+
try {
|
|
273
|
+
// Only refresh if real-time is not available
|
|
274
|
+
if (!this.realTimeEnabled) {
|
|
275
|
+
const [conversations, states] = await Promise.all([
|
|
276
|
+
this.getConversations(),
|
|
277
|
+
this.getConversationStates()
|
|
278
|
+
]);
|
|
279
|
+
|
|
280
|
+
// Notify listeners of fresh data
|
|
281
|
+
this.notifyListeners('conversations', conversations);
|
|
282
|
+
this.notifyListeners('states', states);
|
|
283
|
+
}
|
|
284
|
+
} catch (error) {
|
|
285
|
+
console.error('Error during periodic refresh:', error);
|
|
286
|
+
}
|
|
287
|
+
}, interval);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Start fallback polling when WebSocket disconnects
|
|
292
|
+
*/
|
|
293
|
+
startFallbackPolling() {
|
|
294
|
+
if (!this.refreshInterval) {
|
|
295
|
+
console.log('🔄 Starting fallback polling due to WebSocket disconnect');
|
|
296
|
+
this.startPeriodicRefresh(10000); // More frequent polling as fallback
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Stop periodic refresh
|
|
302
|
+
*/
|
|
303
|
+
stopPeriodicRefresh() {
|
|
304
|
+
if (this.refreshInterval) {
|
|
305
|
+
clearInterval(this.refreshInterval);
|
|
306
|
+
this.refreshInterval = null;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Request real-time data refresh
|
|
312
|
+
*/
|
|
313
|
+
async requestRefresh() {
|
|
314
|
+
if (this.webSocketService && this.realTimeEnabled) {
|
|
315
|
+
console.log('🔄 Requesting refresh via WebSocket');
|
|
316
|
+
try {
|
|
317
|
+
await this.webSocketService.requestRefresh();
|
|
318
|
+
return true;
|
|
319
|
+
} catch (error) {
|
|
320
|
+
console.error('Error requesting WebSocket refresh:', error);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Fallback to cache clearing
|
|
325
|
+
console.log('🔄 Falling back to cache clear for refresh');
|
|
326
|
+
this.clearCache();
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Set WebSocket service (for late initialization)
|
|
332
|
+
* @param {WebSocketService} webSocketService - WebSocket service instance
|
|
333
|
+
*/
|
|
334
|
+
setWebSocketService(webSocketService) {
|
|
335
|
+
this.webSocketService = webSocketService;
|
|
336
|
+
this.setupWebSocketIntegration();
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Get cache statistics
|
|
341
|
+
* @returns {Object} Cache statistics
|
|
342
|
+
*/
|
|
343
|
+
getCacheStats() {
|
|
344
|
+
return {
|
|
345
|
+
size: this.cache.size,
|
|
346
|
+
keys: Array.from(this.cache.keys()),
|
|
347
|
+
listeners: this.eventListeners.size,
|
|
348
|
+
realTimeEnabled: this.realTimeEnabled,
|
|
349
|
+
webSocketConnected: this.webSocketService ? this.webSocketService.getStatus().isConnected : false
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Export for module use
|
|
355
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
356
|
+
module.exports = DataService;
|
|
357
|
+
}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StateService - Manages application state and state changes
|
|
3
|
+
* Part of the modular frontend architecture
|
|
4
|
+
*/
|
|
5
|
+
class StateService {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.state = {
|
|
8
|
+
conversations: [],
|
|
9
|
+
summary: {},
|
|
10
|
+
chartData: {},
|
|
11
|
+
selectedConversation: null,
|
|
12
|
+
conversationStates: {},
|
|
13
|
+
systemHealth: {},
|
|
14
|
+
isLoading: false,
|
|
15
|
+
error: null,
|
|
16
|
+
lastUpdate: null
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
this.subscribers = new Set();
|
|
20
|
+
this.stateHistory = [];
|
|
21
|
+
this.maxHistorySize = 50;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Subscribe to state changes
|
|
26
|
+
* @param {Function} callback - Callback to call on state changes
|
|
27
|
+
* @returns {Function} Unsubscribe function
|
|
28
|
+
*/
|
|
29
|
+
subscribe(callback) {
|
|
30
|
+
this.subscribers.add(callback);
|
|
31
|
+
|
|
32
|
+
// Return unsubscribe function
|
|
33
|
+
return () => {
|
|
34
|
+
this.subscribers.delete(callback);
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get current state
|
|
40
|
+
* @returns {Object} Current state
|
|
41
|
+
*/
|
|
42
|
+
getState() {
|
|
43
|
+
return { ...this.state };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get specific state property
|
|
48
|
+
* @param {string} key - State property key
|
|
49
|
+
* @returns {*} State property value
|
|
50
|
+
*/
|
|
51
|
+
getStateProperty(key) {
|
|
52
|
+
return this.state[key];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Update state and notify subscribers
|
|
57
|
+
* @param {Object} newState - New state object
|
|
58
|
+
* @param {string} action - Action that caused the state change
|
|
59
|
+
*/
|
|
60
|
+
setState(newState, action = 'setState') {
|
|
61
|
+
// Save current state to history
|
|
62
|
+
this.saveStateToHistory(action);
|
|
63
|
+
|
|
64
|
+
// Update state
|
|
65
|
+
this.state = {
|
|
66
|
+
...this.state,
|
|
67
|
+
...newState,
|
|
68
|
+
lastUpdate: Date.now()
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Notify all subscribers
|
|
72
|
+
this.notifySubscribers(action, newState);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Update specific state property
|
|
77
|
+
* @param {string} key - State property key
|
|
78
|
+
* @param {*} value - New value
|
|
79
|
+
* @param {string} action - Action that caused the change
|
|
80
|
+
*/
|
|
81
|
+
setStateProperty(key, value, action = `set_${key}`) {
|
|
82
|
+
this.setState({ [key]: value }, action);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Save current state to history
|
|
87
|
+
* @param {string} action - Action that caused the state change
|
|
88
|
+
*/
|
|
89
|
+
saveStateToHistory(action) {
|
|
90
|
+
this.stateHistory.push({
|
|
91
|
+
state: { ...this.state },
|
|
92
|
+
action,
|
|
93
|
+
timestamp: Date.now()
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Keep history size manageable
|
|
97
|
+
if (this.stateHistory.length > this.maxHistorySize) {
|
|
98
|
+
this.stateHistory.shift();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Notify all subscribers of state changes
|
|
104
|
+
* @param {string} action - Action that caused the change
|
|
105
|
+
* @param {Object} changedState - The state that changed
|
|
106
|
+
*/
|
|
107
|
+
notifySubscribers(action, changedState) {
|
|
108
|
+
this.subscribers.forEach(callback => {
|
|
109
|
+
try {
|
|
110
|
+
callback(this.state, action, changedState);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error('Error in StateService subscriber:', error);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Update conversations data
|
|
119
|
+
* @param {Array} conversations - New conversations data
|
|
120
|
+
*/
|
|
121
|
+
updateConversations(conversations) {
|
|
122
|
+
this.setState({ conversations }, 'update_conversations');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Update conversation states for real-time updates
|
|
127
|
+
* @param {Object} states - New conversation states
|
|
128
|
+
*/
|
|
129
|
+
updateConversationStates(states) {
|
|
130
|
+
this.setState({ conversationStates: states }, 'update_conversation_states');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Update summary statistics
|
|
135
|
+
* @param {Object} summary - New summary data
|
|
136
|
+
*/
|
|
137
|
+
updateSummary(summary) {
|
|
138
|
+
this.setState({ summary }, 'update_summary');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Update chart data
|
|
143
|
+
* @param {Object} chartData - New chart data
|
|
144
|
+
*/
|
|
145
|
+
updateChartData(chartData) {
|
|
146
|
+
this.setState({ chartData }, 'update_chart_data');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Set selected conversation
|
|
151
|
+
* @param {Object} conversation - Selected conversation
|
|
152
|
+
*/
|
|
153
|
+
setSelectedConversation(conversation) {
|
|
154
|
+
this.setState({ selectedConversation: conversation }, 'select_conversation');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Set loading state
|
|
159
|
+
* @param {boolean} isLoading - Loading state
|
|
160
|
+
*/
|
|
161
|
+
setLoading(isLoading) {
|
|
162
|
+
this.setState({ isLoading }, 'set_loading');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Set error state
|
|
167
|
+
* @param {Error|string} error - Error object or message
|
|
168
|
+
*/
|
|
169
|
+
setError(error) {
|
|
170
|
+
this.setState({ error }, 'set_error');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Clear error state
|
|
175
|
+
*/
|
|
176
|
+
clearError() {
|
|
177
|
+
this.setState({ error: null }, 'clear_error');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Update system health
|
|
182
|
+
* @param {Object} health - System health data
|
|
183
|
+
*/
|
|
184
|
+
updateSystemHealth(health) {
|
|
185
|
+
this.setState({ systemHealth: health }, 'update_system_health');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Handle conversation state change notification
|
|
190
|
+
* @param {string} conversationId - ID of the conversation that changed
|
|
191
|
+
* @param {string} newState - New state of the conversation
|
|
192
|
+
*/
|
|
193
|
+
notifyConversationStateChange(conversationId, newState) {
|
|
194
|
+
const currentStates = { ...this.state.conversationStates };
|
|
195
|
+
currentStates[conversationId] = newState;
|
|
196
|
+
|
|
197
|
+
this.setState({ conversationStates: currentStates }, 'conversation_state_change');
|
|
198
|
+
|
|
199
|
+
// Also update the conversation in the conversations array
|
|
200
|
+
const updatedConversations = this.state.conversations.map(conv =>
|
|
201
|
+
conv.id === conversationId ? { ...conv, status: newState } : conv
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
this.setState({ conversations: updatedConversations }, 'update_conversation_status');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Get conversation by ID
|
|
209
|
+
* @param {string} conversationId - Conversation ID
|
|
210
|
+
* @returns {Object|null} Conversation object or null if not found
|
|
211
|
+
*/
|
|
212
|
+
getConversationById(conversationId) {
|
|
213
|
+
return this.state.conversations.find(conv => conv.id === conversationId) || null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Get conversations by status
|
|
218
|
+
* @param {string} status - Conversation status
|
|
219
|
+
* @returns {Array} Array of conversations with specified status
|
|
220
|
+
*/
|
|
221
|
+
getConversationsByStatus(status) {
|
|
222
|
+
return this.state.conversations.filter(conv => conv.status === status);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Get state history
|
|
227
|
+
* @returns {Array} State history
|
|
228
|
+
*/
|
|
229
|
+
getStateHistory() {
|
|
230
|
+
return [...this.stateHistory];
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Clear state history
|
|
235
|
+
*/
|
|
236
|
+
clearStateHistory() {
|
|
237
|
+
this.stateHistory = [];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Reset state to initial values
|
|
242
|
+
*/
|
|
243
|
+
resetState() {
|
|
244
|
+
this.setState({
|
|
245
|
+
conversations: [],
|
|
246
|
+
summary: {},
|
|
247
|
+
chartData: {},
|
|
248
|
+
selectedConversation: null,
|
|
249
|
+
conversationStates: {},
|
|
250
|
+
systemHealth: {},
|
|
251
|
+
isLoading: false,
|
|
252
|
+
error: null,
|
|
253
|
+
lastUpdate: null
|
|
254
|
+
}, 'reset_state');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Get state statistics
|
|
259
|
+
* @returns {Object} State statistics
|
|
260
|
+
*/
|
|
261
|
+
getStateStats() {
|
|
262
|
+
return {
|
|
263
|
+
subscribers: this.subscribers.size,
|
|
264
|
+
historySize: this.stateHistory.length,
|
|
265
|
+
conversationsCount: this.state.conversations.length,
|
|
266
|
+
lastUpdate: this.state.lastUpdate,
|
|
267
|
+
hasError: !!this.state.error,
|
|
268
|
+
isLoading: this.state.isLoading
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Export for module use
|
|
274
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
275
|
+
module.exports = StateService;
|
|
276
|
+
}
|