claude-mpm 3.4.13__py3-none-any.whl → 3.4.16__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 +111 -7
- {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.16.dist-info}/METADATA +2 -1
- {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.16.dist-info}/RECORD +27 -7
- {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.16.dist-info}/WHEEL +0 -0
- {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.16.dist-info}/entry_points.txt +0 -0
- {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.16.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.16.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI State Manager Module
|
|
3
|
+
*
|
|
4
|
+
* Manages UI state including tab switching, card selection, keyboard navigation,
|
|
5
|
+
* and visual feedback across the dashboard interface.
|
|
6
|
+
*
|
|
7
|
+
* WHY: Extracted from main dashboard to centralize UI state management and
|
|
8
|
+
* provide better separation between business logic and UI state. This makes
|
|
9
|
+
* the UI behavior more predictable and easier to test.
|
|
10
|
+
*
|
|
11
|
+
* DESIGN DECISION: Maintains centralized state for current tab, selected cards,
|
|
12
|
+
* and navigation context while providing a clean API for other modules to
|
|
13
|
+
* interact with UI state changes.
|
|
14
|
+
*/
|
|
15
|
+
class UIStateManager {
|
|
16
|
+
constructor() {
|
|
17
|
+
// Current active tab
|
|
18
|
+
this.currentTab = 'events';
|
|
19
|
+
|
|
20
|
+
// Auto-scroll behavior
|
|
21
|
+
this.autoScroll = true;
|
|
22
|
+
|
|
23
|
+
// Selection state - tracks the currently selected card across all tabs
|
|
24
|
+
this.selectedCard = {
|
|
25
|
+
tab: null, // which tab the selection is in
|
|
26
|
+
index: null, // index of selected item in that tab
|
|
27
|
+
type: null, // 'event', 'agent', 'tool', 'file'
|
|
28
|
+
data: null // the actual data object
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Navigation state for each tab
|
|
32
|
+
this.tabNavigation = {
|
|
33
|
+
events: { selectedIndex: -1, items: [] },
|
|
34
|
+
agents: { selectedIndex: -1, items: [] },
|
|
35
|
+
tools: { selectedIndex: -1, items: [] },
|
|
36
|
+
files: { selectedIndex: -1, items: [] }
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
this.setupEventHandlers();
|
|
40
|
+
console.log('UI state manager initialized');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Set up event handlers for UI interactions
|
|
45
|
+
*/
|
|
46
|
+
setupEventHandlers() {
|
|
47
|
+
this.setupTabNavigation();
|
|
48
|
+
this.setupUnifiedKeyboardNavigation();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Set up tab navigation event listeners
|
|
53
|
+
*/
|
|
54
|
+
setupTabNavigation() {
|
|
55
|
+
// Tab buttons
|
|
56
|
+
document.querySelectorAll('.tab-button').forEach(button => {
|
|
57
|
+
button.addEventListener('click', () => {
|
|
58
|
+
const tabName = this.getTabNameFromButton(button);
|
|
59
|
+
this.switchTab(tabName);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Set up unified keyboard navigation across all tabs
|
|
66
|
+
*/
|
|
67
|
+
setupUnifiedKeyboardNavigation() {
|
|
68
|
+
document.addEventListener('keydown', (e) => {
|
|
69
|
+
// Only handle if not in an input field
|
|
70
|
+
if (document.activeElement &&
|
|
71
|
+
['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement.tagName)) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
|
76
|
+
e.preventDefault();
|
|
77
|
+
this.handleUnifiedArrowNavigation(e.key === 'ArrowDown' ? 1 : -1);
|
|
78
|
+
} else if (e.key === 'Enter') {
|
|
79
|
+
e.preventDefault();
|
|
80
|
+
this.handleUnifiedEnterKey();
|
|
81
|
+
} else if (e.key === 'Escape') {
|
|
82
|
+
this.clearUnifiedSelection();
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Get tab name from button element
|
|
89
|
+
* @param {HTMLElement} button - Tab button element
|
|
90
|
+
* @returns {string} - Tab name
|
|
91
|
+
*/
|
|
92
|
+
getTabNameFromButton(button) {
|
|
93
|
+
const text = button.textContent.toLowerCase();
|
|
94
|
+
if (text.includes('events')) return 'events';
|
|
95
|
+
if (text.includes('agents')) return 'agents';
|
|
96
|
+
if (text.includes('tools')) return 'tools';
|
|
97
|
+
if (text.includes('files')) return 'files';
|
|
98
|
+
return 'events';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Switch to specified tab
|
|
103
|
+
* @param {string} tabName - Name of tab to switch to
|
|
104
|
+
*/
|
|
105
|
+
switchTab(tabName) {
|
|
106
|
+
console.log(`[DEBUG] switchTab called with tabName: ${tabName}`);
|
|
107
|
+
const previousTab = this.currentTab;
|
|
108
|
+
this.currentTab = tabName;
|
|
109
|
+
|
|
110
|
+
// Update tab button active states
|
|
111
|
+
document.querySelectorAll('.tab-button').forEach(btn => {
|
|
112
|
+
btn.classList.remove('active');
|
|
113
|
+
if (this.getTabNameFromButton(btn) === tabName) {
|
|
114
|
+
btn.classList.add('active');
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Show/hide tab content using CSS classes
|
|
119
|
+
document.querySelectorAll('.tab-content').forEach(content => {
|
|
120
|
+
content.classList.remove('active');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const activeTab = document.getElementById(`${tabName}-tab`);
|
|
124
|
+
if (activeTab) {
|
|
125
|
+
activeTab.classList.add('active');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Clear previous selections when switching tabs
|
|
129
|
+
this.clearUnifiedSelection();
|
|
130
|
+
|
|
131
|
+
// Trigger tab change event for other modules
|
|
132
|
+
document.dispatchEvent(new CustomEvent('tabChanged', {
|
|
133
|
+
detail: {
|
|
134
|
+
newTab: tabName,
|
|
135
|
+
previousTab: previousTab
|
|
136
|
+
}
|
|
137
|
+
}));
|
|
138
|
+
|
|
139
|
+
// Auto-scroll to bottom after a brief delay to ensure content is rendered
|
|
140
|
+
setTimeout(() => {
|
|
141
|
+
if (this.autoScroll) {
|
|
142
|
+
this.scrollCurrentTabToBottom();
|
|
143
|
+
}
|
|
144
|
+
}, 100);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Handle unified arrow navigation across tabs
|
|
149
|
+
* @param {number} direction - Navigation direction (1 for down, -1 for up)
|
|
150
|
+
*/
|
|
151
|
+
handleUnifiedArrowNavigation(direction) {
|
|
152
|
+
const tabNav = this.tabNavigation[this.currentTab];
|
|
153
|
+
if (!tabNav) return;
|
|
154
|
+
|
|
155
|
+
let newIndex = tabNav.selectedIndex + direction;
|
|
156
|
+
|
|
157
|
+
// Handle bounds
|
|
158
|
+
if (tabNav.items.length === 0) return;
|
|
159
|
+
|
|
160
|
+
if (newIndex < 0) {
|
|
161
|
+
newIndex = tabNav.items.length - 1;
|
|
162
|
+
} else if (newIndex >= tabNav.items.length) {
|
|
163
|
+
newIndex = 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
this.selectCardByIndex(this.currentTab, newIndex);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Handle unified Enter key across all tabs
|
|
171
|
+
*/
|
|
172
|
+
handleUnifiedEnterKey() {
|
|
173
|
+
const tabNav = this.tabNavigation[this.currentTab];
|
|
174
|
+
if (!tabNav || tabNav.selectedIndex === -1) return;
|
|
175
|
+
|
|
176
|
+
const selectedElement = tabNav.items[tabNav.selectedIndex];
|
|
177
|
+
if (selectedElement && selectedElement.onclick) {
|
|
178
|
+
selectedElement.onclick();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Clear all unified selection states
|
|
184
|
+
*/
|
|
185
|
+
clearUnifiedSelection() {
|
|
186
|
+
// Clear all tab navigation states
|
|
187
|
+
Object.keys(this.tabNavigation).forEach(tabName => {
|
|
188
|
+
this.tabNavigation[tabName].selectedIndex = -1;
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Clear card selection
|
|
192
|
+
this.clearCardSelection();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Update tab navigation items for current tab
|
|
197
|
+
* Should be called after tab content is rendered
|
|
198
|
+
*/
|
|
199
|
+
updateTabNavigationItems() {
|
|
200
|
+
const tabNav = this.tabNavigation[this.currentTab];
|
|
201
|
+
if (!tabNav) return;
|
|
202
|
+
|
|
203
|
+
let containerSelector;
|
|
204
|
+
switch (this.currentTab) {
|
|
205
|
+
case 'events':
|
|
206
|
+
containerSelector = '#events-list .event-item';
|
|
207
|
+
break;
|
|
208
|
+
case 'agents':
|
|
209
|
+
containerSelector = '#agents-list .event-item';
|
|
210
|
+
break;
|
|
211
|
+
case 'tools':
|
|
212
|
+
containerSelector = '#tools-list .event-item';
|
|
213
|
+
break;
|
|
214
|
+
case 'files':
|
|
215
|
+
containerSelector = '#files-list .event-item';
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (containerSelector) {
|
|
220
|
+
tabNav.items = Array.from(document.querySelectorAll(containerSelector));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Select card by index for specified tab
|
|
226
|
+
* @param {string} tabName - Tab name
|
|
227
|
+
* @param {number} index - Index of item to select
|
|
228
|
+
*/
|
|
229
|
+
selectCardByIndex(tabName, index) {
|
|
230
|
+
const tabNav = this.tabNavigation[tabName];
|
|
231
|
+
if (!tabNav || index < 0 || index >= tabNav.items.length) return;
|
|
232
|
+
|
|
233
|
+
// Update navigation state
|
|
234
|
+
tabNav.selectedIndex = index;
|
|
235
|
+
|
|
236
|
+
// Update visual selection
|
|
237
|
+
this.updateUnifiedSelectionUI();
|
|
238
|
+
|
|
239
|
+
// If this is a different tab selection, record the card selection
|
|
240
|
+
const selectedElement = tabNav.items[index];
|
|
241
|
+
if (selectedElement) {
|
|
242
|
+
// Extract data from the element to populate selectedCard
|
|
243
|
+
this.selectCard(tabName, index, this.getCardType(tabName), index);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Show details for the selected item
|
|
247
|
+
this.showCardDetails(tabName, index);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Update visual selection UI for unified navigation
|
|
252
|
+
*/
|
|
253
|
+
updateUnifiedSelectionUI() {
|
|
254
|
+
// Clear all existing selections
|
|
255
|
+
document.querySelectorAll('.event-item.keyboard-selected').forEach(el => {
|
|
256
|
+
el.classList.remove('keyboard-selected');
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// Apply selection to current tab's selected item
|
|
260
|
+
const tabNav = this.tabNavigation[this.currentTab];
|
|
261
|
+
if (tabNav && tabNav.selectedIndex !== -1 && tabNav.items[tabNav.selectedIndex]) {
|
|
262
|
+
tabNav.items[tabNav.selectedIndex].classList.add('keyboard-selected');
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Show card details for specified tab and index
|
|
268
|
+
* @param {string} tabName - Tab name
|
|
269
|
+
* @param {number} index - Item index
|
|
270
|
+
*/
|
|
271
|
+
showCardDetails(tabName, index) {
|
|
272
|
+
// Dispatch event for other modules to handle
|
|
273
|
+
document.dispatchEvent(new CustomEvent('showCardDetails', {
|
|
274
|
+
detail: {
|
|
275
|
+
tabName: tabName,
|
|
276
|
+
index: index
|
|
277
|
+
}
|
|
278
|
+
}));
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Select a specific card
|
|
283
|
+
* @param {string} tabName - Tab name
|
|
284
|
+
* @param {number} index - Item index
|
|
285
|
+
* @param {string} type - Item type
|
|
286
|
+
* @param {*} data - Item data
|
|
287
|
+
*/
|
|
288
|
+
selectCard(tabName, index, type, data) {
|
|
289
|
+
// Clear previous selection
|
|
290
|
+
this.clearCardSelection();
|
|
291
|
+
|
|
292
|
+
// Update selection state
|
|
293
|
+
this.selectedCard = {
|
|
294
|
+
tab: tabName,
|
|
295
|
+
index: index,
|
|
296
|
+
type: type,
|
|
297
|
+
data: data
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
this.updateCardSelectionUI();
|
|
301
|
+
|
|
302
|
+
console.log('Card selected:', this.selectedCard);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Clear card selection
|
|
307
|
+
*/
|
|
308
|
+
clearCardSelection() {
|
|
309
|
+
// Clear visual selection from all tabs
|
|
310
|
+
document.querySelectorAll('.event-item.selected, .file-item.selected').forEach(el => {
|
|
311
|
+
el.classList.remove('selected');
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// Reset selection state
|
|
315
|
+
this.selectedCard = {
|
|
316
|
+
tab: null,
|
|
317
|
+
index: null,
|
|
318
|
+
type: null,
|
|
319
|
+
data: null
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Update card selection UI
|
|
325
|
+
*/
|
|
326
|
+
updateCardSelectionUI() {
|
|
327
|
+
if (!this.selectedCard.tab || this.selectedCard.index === null) return;
|
|
328
|
+
|
|
329
|
+
// Get the list container for the selected tab
|
|
330
|
+
let listContainer;
|
|
331
|
+
switch (this.selectedCard.tab) {
|
|
332
|
+
case 'events':
|
|
333
|
+
listContainer = document.getElementById('events-list');
|
|
334
|
+
break;
|
|
335
|
+
case 'agents':
|
|
336
|
+
listContainer = document.getElementById('agents-list');
|
|
337
|
+
break;
|
|
338
|
+
case 'tools':
|
|
339
|
+
listContainer = document.getElementById('tools-list');
|
|
340
|
+
break;
|
|
341
|
+
case 'files':
|
|
342
|
+
listContainer = document.getElementById('files-list');
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (listContainer) {
|
|
347
|
+
const items = listContainer.querySelectorAll('.event-item, .file-item');
|
|
348
|
+
if (items[this.selectedCard.index]) {
|
|
349
|
+
items[this.selectedCard.index].classList.add('selected');
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Get card type based on tab name
|
|
356
|
+
* @param {string} tabName - Tab name
|
|
357
|
+
* @returns {string} - Card type
|
|
358
|
+
*/
|
|
359
|
+
getCardType(tabName) {
|
|
360
|
+
switch (tabName) {
|
|
361
|
+
case 'events': return 'event';
|
|
362
|
+
case 'agents': return 'agent';
|
|
363
|
+
case 'tools': return 'tool';
|
|
364
|
+
case 'files': return 'file';
|
|
365
|
+
default: return 'unknown';
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Scroll current tab to bottom
|
|
371
|
+
*/
|
|
372
|
+
scrollCurrentTabToBottom() {
|
|
373
|
+
const tabId = `${this.currentTab}-list`;
|
|
374
|
+
const element = document.getElementById(tabId);
|
|
375
|
+
if (element && this.autoScroll) {
|
|
376
|
+
element.scrollTop = element.scrollHeight;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Clear selection for cleanup
|
|
382
|
+
*/
|
|
383
|
+
clearSelection() {
|
|
384
|
+
this.clearCardSelection();
|
|
385
|
+
this.clearUnifiedSelection();
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Get current tab name
|
|
390
|
+
* @returns {string} - Current tab name
|
|
391
|
+
*/
|
|
392
|
+
getCurrentTab() {
|
|
393
|
+
return this.currentTab;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Get selected card info
|
|
398
|
+
* @returns {Object} - Selected card state
|
|
399
|
+
*/
|
|
400
|
+
getSelectedCard() {
|
|
401
|
+
return { ...this.selectedCard };
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Get tab navigation state
|
|
406
|
+
* @returns {Object} - Tab navigation state
|
|
407
|
+
*/
|
|
408
|
+
getTabNavigation() {
|
|
409
|
+
return { ...this.tabNavigation };
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Set auto-scroll behavior
|
|
414
|
+
* @param {boolean} enabled - Whether to enable auto-scroll
|
|
415
|
+
*/
|
|
416
|
+
setAutoScroll(enabled) {
|
|
417
|
+
this.autoScroll = enabled;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Get auto-scroll state
|
|
422
|
+
* @returns {boolean} - Auto-scroll enabled state
|
|
423
|
+
*/
|
|
424
|
+
getAutoScroll() {
|
|
425
|
+
return this.autoScroll;
|
|
426
|
+
}
|
|
427
|
+
}
|