claude-mpm 3.4.13__py3-none-any.whl → 3.4.14__py3-none-any.whl
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.
- claude_mpm/dashboard/index.html +13 -0
- claude_mpm/dashboard/static/css/dashboard.css +2722 -0
- claude_mpm/dashboard/static/js/components/agent-inference.js +619 -0
- claude_mpm/dashboard/static/js/components/event-processor.js +641 -0
- claude_mpm/dashboard/static/js/components/event-viewer.js +914 -0
- claude_mpm/dashboard/static/js/components/export-manager.js +362 -0
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +611 -0
- claude_mpm/dashboard/static/js/components/hud-library-loader.js +211 -0
- claude_mpm/dashboard/static/js/components/hud-manager.js +671 -0
- claude_mpm/dashboard/static/js/components/hud-visualizer.js +1718 -0
- claude_mpm/dashboard/static/js/components/module-viewer.js +2701 -0
- claude_mpm/dashboard/static/js/components/session-manager.js +520 -0
- claude_mpm/dashboard/static/js/components/socket-manager.js +343 -0
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +427 -0
- claude_mpm/dashboard/static/js/components/working-directory.js +866 -0
- claude_mpm/dashboard/static/js/dashboard-original.js +4134 -0
- claude_mpm/dashboard/static/js/dashboard.js +1978 -0
- claude_mpm/dashboard/static/js/socket-client.js +537 -0
- claude_mpm/dashboard/templates/index.html +346 -0
- claude_mpm/dashboard/test_dashboard.html +372 -0
- claude_mpm/services/socketio_server.py +41 -5
- {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.14.dist-info}/METADATA +2 -1
- {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.14.dist-info}/RECORD +27 -7
- {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.14.dist-info}/WHEEL +0 -0
- {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.14.dist-info}/entry_points.txt +0 -0
- {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.14.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.14.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Manager Component
|
|
3
|
+
* Handles session selection and management
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
class SessionManager {
|
|
7
|
+
constructor(socketClient) {
|
|
8
|
+
this.socketClient = socketClient;
|
|
9
|
+
this.sessions = new Map();
|
|
10
|
+
this.currentSessionId = null;
|
|
11
|
+
this.selectedSessionId = '';
|
|
12
|
+
|
|
13
|
+
this.init();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Initialize the session manager
|
|
18
|
+
*/
|
|
19
|
+
init() {
|
|
20
|
+
this.setupEventHandlers();
|
|
21
|
+
this.setupSocketListeners();
|
|
22
|
+
this.updateSessionSelect();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Setup event handlers for UI controls
|
|
27
|
+
*/
|
|
28
|
+
setupEventHandlers() {
|
|
29
|
+
// Session selection dropdown
|
|
30
|
+
const sessionSelect = document.getElementById('session-select');
|
|
31
|
+
if (sessionSelect) {
|
|
32
|
+
sessionSelect.addEventListener('change', (e) => {
|
|
33
|
+
this.selectedSessionId = e.target.value;
|
|
34
|
+
this.onSessionFilterChanged();
|
|
35
|
+
|
|
36
|
+
// Load working directory for this session
|
|
37
|
+
if (window.dashboard && window.dashboard.loadWorkingDirectoryForSession) {
|
|
38
|
+
window.dashboard.loadWorkingDirectoryForSession(e.target.value);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Refresh sessions button
|
|
44
|
+
const refreshBtn = document.querySelector('button[onclick="refreshSessions()"]');
|
|
45
|
+
if (refreshBtn) {
|
|
46
|
+
refreshBtn.addEventListener('click', () => {
|
|
47
|
+
this.refreshSessions();
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Setup socket event listeners
|
|
54
|
+
*/
|
|
55
|
+
setupSocketListeners() {
|
|
56
|
+
// Listen for socket event updates
|
|
57
|
+
this.socketClient.onEventUpdate((events, sessions) => {
|
|
58
|
+
this.sessions = sessions;
|
|
59
|
+
this.updateSessionSelect();
|
|
60
|
+
// Update footer info when new events arrive
|
|
61
|
+
this.updateFooterInfo();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Listen for connection status changes
|
|
65
|
+
document.addEventListener('socketConnectionStatus', (e) => {
|
|
66
|
+
if (e.detail.type === 'connected') {
|
|
67
|
+
// Request fresh session data when connected
|
|
68
|
+
setTimeout(() => this.refreshSessions(), 1000);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Update the session selection dropdown
|
|
75
|
+
*/
|
|
76
|
+
updateSessionSelect() {
|
|
77
|
+
const sessionSelect = document.getElementById('session-select');
|
|
78
|
+
if (!sessionSelect) return;
|
|
79
|
+
|
|
80
|
+
// Store current selection
|
|
81
|
+
const currentSelection = sessionSelect.value;
|
|
82
|
+
|
|
83
|
+
// Clear existing options except default ones
|
|
84
|
+
sessionSelect.innerHTML = `
|
|
85
|
+
<option value="">All Sessions</option>
|
|
86
|
+
`;
|
|
87
|
+
|
|
88
|
+
// Add sessions from the sessions map
|
|
89
|
+
if (this.sessions && this.sessions.size > 0) {
|
|
90
|
+
const sortedSessions = Array.from(this.sessions.values())
|
|
91
|
+
.sort((a, b) => new Date(b.lastActivity || b.startTime) - new Date(a.lastActivity || a.startTime));
|
|
92
|
+
|
|
93
|
+
sortedSessions.forEach(session => {
|
|
94
|
+
const option = document.createElement('option');
|
|
95
|
+
option.value = session.id;
|
|
96
|
+
|
|
97
|
+
// Format session display text
|
|
98
|
+
const startTime = new Date(session.startTime || session.last_activity).toLocaleString();
|
|
99
|
+
const eventCount = session.eventCount || session.event_count || 0;
|
|
100
|
+
const isActive = session.id === this.currentSessionId;
|
|
101
|
+
|
|
102
|
+
option.textContent = `${session.id.substring(0, 8)}... (${eventCount} events, ${startTime})${isActive ? ' [ACTIVE]' : ''}`;
|
|
103
|
+
sessionSelect.appendChild(option);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Restore selection if it still exists
|
|
108
|
+
if (currentSelection && Array.from(sessionSelect.options).some(opt => opt.value === currentSelection)) {
|
|
109
|
+
sessionSelect.value = currentSelection;
|
|
110
|
+
this.selectedSessionId = currentSelection;
|
|
111
|
+
// Trigger events for restored selection
|
|
112
|
+
this.onSessionFilterChanged();
|
|
113
|
+
} else {
|
|
114
|
+
this.selectedSessionId = sessionSelect.value;
|
|
115
|
+
// Trigger events for new selection
|
|
116
|
+
if (this.selectedSessionId) {
|
|
117
|
+
this.onSessionFilterChanged();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Handle session filter change
|
|
124
|
+
*/
|
|
125
|
+
onSessionFilterChanged() {
|
|
126
|
+
// Notify event viewer about filter change
|
|
127
|
+
const eventViewer = window.eventViewer;
|
|
128
|
+
if (eventViewer) {
|
|
129
|
+
eventViewer.setSessionFilter(this.selectedSessionId);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Update footer information
|
|
133
|
+
this.updateFooterInfo();
|
|
134
|
+
|
|
135
|
+
// Dispatch custom event for other components
|
|
136
|
+
document.dispatchEvent(new CustomEvent('sessionFilterChanged', {
|
|
137
|
+
detail: { sessionId: this.selectedSessionId }
|
|
138
|
+
}));
|
|
139
|
+
|
|
140
|
+
// Also dispatch sessionChanged for backward compatibility with other components
|
|
141
|
+
document.dispatchEvent(new CustomEvent('sessionChanged', {
|
|
142
|
+
detail: { sessionId: this.selectedSessionId }
|
|
143
|
+
}));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Refresh sessions from server
|
|
148
|
+
*/
|
|
149
|
+
refreshSessions() {
|
|
150
|
+
if (this.socketClient && this.socketClient.getConnectionState().isConnected) {
|
|
151
|
+
console.log('Refreshing sessions...');
|
|
152
|
+
this.socketClient.requestStatus();
|
|
153
|
+
} else {
|
|
154
|
+
console.warn('Cannot refresh sessions: not connected to server');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Update footer information based on selected session
|
|
160
|
+
*/
|
|
161
|
+
updateFooterInfo() {
|
|
162
|
+
console.log('[SESSION-DEBUG] updateFooterInfo called, selectedSessionId:', this.selectedSessionId);
|
|
163
|
+
|
|
164
|
+
const footerSessionEl = document.getElementById('footer-session');
|
|
165
|
+
const footerWorkingDirEl = document.getElementById('footer-working-dir');
|
|
166
|
+
const footerGitBranchEl = document.getElementById('footer-git-branch');
|
|
167
|
+
|
|
168
|
+
if (!footerSessionEl) {
|
|
169
|
+
console.warn('[SESSION-DEBUG] footer-session element not found');
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
let sessionInfo = 'All Sessions';
|
|
174
|
+
let workingDir = window.dashboard?.workingDirectoryManager?.getDefaultWorkingDir() || process?.cwd?.() || '/Users/masa/Projects/claude-mpm';
|
|
175
|
+
let gitBranch = 'Unknown';
|
|
176
|
+
|
|
177
|
+
console.log('[SESSION-DEBUG] Initial values - sessionInfo:', sessionInfo, 'workingDir:', workingDir, 'gitBranch:', gitBranch);
|
|
178
|
+
|
|
179
|
+
if (this.selectedSessionId === 'current') {
|
|
180
|
+
sessionInfo = this.currentSessionId ?
|
|
181
|
+
`Current: ${this.currentSessionId.substring(0, 8)}...` :
|
|
182
|
+
'Current: None';
|
|
183
|
+
|
|
184
|
+
// For current session, try to extract info from recent events
|
|
185
|
+
if (this.currentSessionId) {
|
|
186
|
+
const sessionData = this.extractSessionInfoFromEvents(this.currentSessionId);
|
|
187
|
+
workingDir = sessionData.workingDir || window.dashboard?.workingDirectoryManager?.getDefaultWorkingDir() || '/Users/masa/Projects/claude-mpm';
|
|
188
|
+
gitBranch = sessionData.gitBranch || 'Unknown';
|
|
189
|
+
}
|
|
190
|
+
} else if (this.selectedSessionId) {
|
|
191
|
+
const session = this.sessions.get(this.selectedSessionId);
|
|
192
|
+
if (session) {
|
|
193
|
+
sessionInfo = `${this.selectedSessionId.substring(0, 8)}...`;
|
|
194
|
+
workingDir = session.working_directory || session.workingDirectory || '';
|
|
195
|
+
gitBranch = session.git_branch || session.gitBranch || '';
|
|
196
|
+
|
|
197
|
+
// If session doesn't have these values, extract from events
|
|
198
|
+
if (!workingDir || !gitBranch) {
|
|
199
|
+
const sessionData = this.extractSessionInfoFromEvents(this.selectedSessionId);
|
|
200
|
+
workingDir = workingDir || sessionData.workingDir || '.';
|
|
201
|
+
gitBranch = gitBranch || sessionData.gitBranch || '';
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
console.log('[SESSION-DEBUG] Final values before setting footer - sessionInfo:', sessionInfo, 'workingDir:', workingDir, 'gitBranch:', gitBranch);
|
|
207
|
+
|
|
208
|
+
footerSessionEl.textContent = sessionInfo;
|
|
209
|
+
if (footerWorkingDirEl) {
|
|
210
|
+
console.log('[SESSION-DEBUG] Setting footer working dir to:', workingDir);
|
|
211
|
+
footerWorkingDirEl.textContent = workingDir;
|
|
212
|
+
} else {
|
|
213
|
+
console.warn('[SESSION-DEBUG] footer-working-dir element not found');
|
|
214
|
+
}
|
|
215
|
+
if (footerGitBranchEl) {
|
|
216
|
+
console.log('[SESSION-DEBUG] Setting footer git branch to:', gitBranch);
|
|
217
|
+
footerGitBranchEl.textContent = gitBranch;
|
|
218
|
+
} else {
|
|
219
|
+
console.warn('[SESSION-DEBUG] footer-git-branch element not found');
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Extract working directory and git branch from events for a specific session
|
|
225
|
+
* @param {string} sessionId - Session ID to extract info for
|
|
226
|
+
* @returns {Object} Object with workingDir and gitBranch properties
|
|
227
|
+
*/
|
|
228
|
+
extractSessionInfoFromEvents(sessionId) {
|
|
229
|
+
let workingDir = '';
|
|
230
|
+
let gitBranch = '';
|
|
231
|
+
|
|
232
|
+
console.log(`[DEBUG] extractSessionInfoFromEvents called for sessionId: ${sessionId}`);
|
|
233
|
+
|
|
234
|
+
// Get events from the socket client
|
|
235
|
+
const socketClient = this.socketClient;
|
|
236
|
+
if (socketClient && socketClient.events) {
|
|
237
|
+
console.log(`[DEBUG] Total events available: ${socketClient.events.length}`);
|
|
238
|
+
|
|
239
|
+
// Look for session start events or recent events with this session ID
|
|
240
|
+
const sessionEvents = socketClient.events.filter(event =>
|
|
241
|
+
event.data && event.data.session_id === sessionId
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
console.log(`[DEBUG] Events matching sessionId ${sessionId}: ${sessionEvents.length}`);
|
|
245
|
+
|
|
246
|
+
// Log a few sample events to see their structure
|
|
247
|
+
if (sessionEvents.length > 0) {
|
|
248
|
+
console.log(`[DEBUG] Sample events for session ${sessionId}:`);
|
|
249
|
+
|
|
250
|
+
// Show first 3 events
|
|
251
|
+
sessionEvents.slice(0, 3).forEach((event, index) => {
|
|
252
|
+
console.log(`[DEBUG] Event ${index + 1}:`, {
|
|
253
|
+
type: event.type,
|
|
254
|
+
timestamp: event.timestamp,
|
|
255
|
+
data_keys: event.data ? Object.keys(event.data) : 'no data',
|
|
256
|
+
full_event: event
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Show last 3 events if different from first 3
|
|
261
|
+
if (sessionEvents.length > 3) {
|
|
262
|
+
console.log(`[DEBUG] Last 3 events for session ${sessionId}:`);
|
|
263
|
+
sessionEvents.slice(-3).forEach((event, index) => {
|
|
264
|
+
console.log(`[DEBUG] Last Event ${index + 1}:`, {
|
|
265
|
+
type: event.type,
|
|
266
|
+
timestamp: event.timestamp,
|
|
267
|
+
data_keys: event.data ? Object.keys(event.data) : 'no data',
|
|
268
|
+
full_event: event
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Find the most recent event with working directory and git branch info
|
|
275
|
+
for (let i = sessionEvents.length - 1; i >= 0; i--) {
|
|
276
|
+
const event = sessionEvents[i];
|
|
277
|
+
if (event.data) {
|
|
278
|
+
console.log(`[DEBUG] Examining event ${i} data:`, event.data);
|
|
279
|
+
|
|
280
|
+
// Check for working directory info
|
|
281
|
+
if (!workingDir) {
|
|
282
|
+
if (event.data.working_directory) {
|
|
283
|
+
workingDir = event.data.working_directory;
|
|
284
|
+
console.log(`[DEBUG] Found working_directory: ${workingDir}`);
|
|
285
|
+
} else if (event.data.cwd) {
|
|
286
|
+
workingDir = event.data.cwd;
|
|
287
|
+
console.log(`[DEBUG] Found cwd: ${workingDir}`);
|
|
288
|
+
} else if (event.data.instance_info && event.data.instance_info.working_dir) {
|
|
289
|
+
workingDir = event.data.instance_info.working_dir;
|
|
290
|
+
console.log(`[DEBUG] Found instance_info.working_dir: ${workingDir}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Check for git branch info - check all possible field names
|
|
295
|
+
if (!gitBranch) {
|
|
296
|
+
const possibleBranchFields = [
|
|
297
|
+
'git_branch',
|
|
298
|
+
'gitBranch',
|
|
299
|
+
'branch',
|
|
300
|
+
'git.branch',
|
|
301
|
+
'vcs_branch',
|
|
302
|
+
'current_branch'
|
|
303
|
+
];
|
|
304
|
+
|
|
305
|
+
for (const field of possibleBranchFields) {
|
|
306
|
+
if (event.data[field]) {
|
|
307
|
+
gitBranch = event.data[field];
|
|
308
|
+
console.log(`[DEBUG] Found git branch in field '${field}': ${gitBranch}`);
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Check nested locations
|
|
314
|
+
if (!gitBranch) {
|
|
315
|
+
if (event.data.instance_info) {
|
|
316
|
+
console.log(`[DEBUG] Checking instance_info for branch:`, event.data.instance_info);
|
|
317
|
+
for (const field of possibleBranchFields) {
|
|
318
|
+
if (event.data.instance_info[field]) {
|
|
319
|
+
gitBranch = event.data.instance_info[field];
|
|
320
|
+
console.log(`[DEBUG] Found git branch in instance_info.${field}: ${gitBranch}`);
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (!gitBranch && event.data.git) {
|
|
327
|
+
console.log(`[DEBUG] Checking git object:`, event.data.git);
|
|
328
|
+
if (event.data.git.branch) {
|
|
329
|
+
gitBranch = event.data.git.branch;
|
|
330
|
+
console.log(`[DEBUG] Found git branch in git.branch: ${gitBranch}`);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// If we have both, we can stop looking
|
|
337
|
+
if (workingDir && gitBranch) {
|
|
338
|
+
console.log(`[DEBUG] Found both workingDir and gitBranch, stopping search`);
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
} else {
|
|
344
|
+
console.log(`[DEBUG] No socket client or events available`);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
console.log(`[DEBUG] Final results - workingDir: '${workingDir}', gitBranch: '${gitBranch}'`);
|
|
348
|
+
return { workingDir, gitBranch };
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Set current session ID (from server status)
|
|
353
|
+
* @param {string} sessionId - Current session ID
|
|
354
|
+
*/
|
|
355
|
+
setCurrentSessionId(sessionId) {
|
|
356
|
+
this.currentSessionId = sessionId;
|
|
357
|
+
this.updateSessionSelect();
|
|
358
|
+
this.updateFooterInfo();
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Add or update a session
|
|
363
|
+
* @param {Object} sessionData - Session data
|
|
364
|
+
*/
|
|
365
|
+
addSession(sessionData) {
|
|
366
|
+
if (!sessionData.id) return;
|
|
367
|
+
|
|
368
|
+
const existingSession = this.sessions.get(sessionData.id);
|
|
369
|
+
if (existingSession) {
|
|
370
|
+
// Update existing session
|
|
371
|
+
Object.assign(existingSession, sessionData);
|
|
372
|
+
} else {
|
|
373
|
+
// Add new session
|
|
374
|
+
this.sessions.set(sessionData.id, {
|
|
375
|
+
id: sessionData.id,
|
|
376
|
+
startTime: sessionData.startTime || sessionData.start_time || new Date().toISOString(),
|
|
377
|
+
lastActivity: sessionData.lastActivity || sessionData.last_activity || new Date().toISOString(),
|
|
378
|
+
eventCount: sessionData.eventCount || sessionData.event_count || 0,
|
|
379
|
+
working_directory: sessionData.working_directory || sessionData.workingDirectory || '',
|
|
380
|
+
git_branch: sessionData.git_branch || sessionData.gitBranch || '',
|
|
381
|
+
agent_type: sessionData.agent_type || sessionData.agentType || '',
|
|
382
|
+
...sessionData
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
this.updateSessionSelect();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Remove a session
|
|
391
|
+
* @param {string} sessionId - Session ID to remove
|
|
392
|
+
*/
|
|
393
|
+
removeSession(sessionId) {
|
|
394
|
+
if (this.sessions.has(sessionId)) {
|
|
395
|
+
this.sessions.delete(sessionId);
|
|
396
|
+
|
|
397
|
+
// If the removed session was selected, reset to all sessions
|
|
398
|
+
if (this.selectedSessionId === sessionId) {
|
|
399
|
+
this.selectedSessionId = '';
|
|
400
|
+
const sessionSelect = document.getElementById('session-select');
|
|
401
|
+
if (sessionSelect) {
|
|
402
|
+
sessionSelect.value = '';
|
|
403
|
+
}
|
|
404
|
+
this.onSessionFilterChanged();
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
this.updateSessionSelect();
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Get current session filter
|
|
413
|
+
* @returns {string} Current session filter
|
|
414
|
+
*/
|
|
415
|
+
getCurrentFilter() {
|
|
416
|
+
return this.selectedSessionId;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Get session information
|
|
421
|
+
* @param {string} sessionId - Session ID
|
|
422
|
+
* @returns {Object|null} Session data or null if not found
|
|
423
|
+
*/
|
|
424
|
+
getSession(sessionId) {
|
|
425
|
+
return this.sessions.get(sessionId) || null;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Get all sessions
|
|
430
|
+
* @returns {Map} All sessions
|
|
431
|
+
*/
|
|
432
|
+
getAllSessions() {
|
|
433
|
+
return this.sessions;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Get current active session ID
|
|
438
|
+
* @returns {string|null} Current session ID
|
|
439
|
+
*/
|
|
440
|
+
getCurrentSessionId() {
|
|
441
|
+
return this.currentSessionId;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Clear all sessions
|
|
446
|
+
*/
|
|
447
|
+
clearSessions() {
|
|
448
|
+
this.sessions.clear();
|
|
449
|
+
this.currentSessionId = null;
|
|
450
|
+
this.selectedSessionId = '';
|
|
451
|
+
this.updateSessionSelect();
|
|
452
|
+
this.updateFooterInfo();
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Export session data
|
|
457
|
+
* @returns {Object} Session export data
|
|
458
|
+
*/
|
|
459
|
+
exportSessionData() {
|
|
460
|
+
return {
|
|
461
|
+
sessions: Array.from(this.sessions.entries()),
|
|
462
|
+
currentSessionId: this.currentSessionId,
|
|
463
|
+
selectedSessionId: this.selectedSessionId
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Import session data
|
|
469
|
+
* @param {Object} data - Session import data
|
|
470
|
+
*/
|
|
471
|
+
importSessionData(data) {
|
|
472
|
+
if (data.sessions && Array.isArray(data.sessions)) {
|
|
473
|
+
this.sessions.clear();
|
|
474
|
+
data.sessions.forEach(([id, sessionData]) => {
|
|
475
|
+
this.sessions.set(id, sessionData);
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
if (data.currentSessionId) {
|
|
480
|
+
this.currentSessionId = data.currentSessionId;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (data.selectedSessionId !== undefined) {
|
|
484
|
+
this.selectedSessionId = data.selectedSessionId;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
this.updateSessionSelect();
|
|
488
|
+
this.updateFooterInfo();
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Get events for a specific session
|
|
493
|
+
* @param {string} sessionId - Session ID to get events for
|
|
494
|
+
* @returns {Array} - Filtered events for the session
|
|
495
|
+
*/
|
|
496
|
+
getEventsForSession(sessionId) {
|
|
497
|
+
if (!sessionId || !this.socketClient) {
|
|
498
|
+
return [];
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
const allEvents = this.socketClient.events || [];
|
|
502
|
+
return allEvents.filter(event => {
|
|
503
|
+
// Check for session ID in various possible locations
|
|
504
|
+
const eventSessionId = event.session_id ||
|
|
505
|
+
(event.data && event.data.session_id) ||
|
|
506
|
+
null;
|
|
507
|
+
return eventSessionId === sessionId;
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// Global functions for backward compatibility
|
|
513
|
+
window.refreshSessions = function() {
|
|
514
|
+
if (window.sessionManager) {
|
|
515
|
+
window.sessionManager.refreshSessions();
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
// Export for global use
|
|
520
|
+
window.SessionManager = SessionManager;
|