claude-mpm 4.2.13__py3-none-any.whl → 4.2.15__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/cli/commands/analyze_code.py +0 -1
- claude_mpm/cli/commands/dashboard.py +0 -1
- claude_mpm/cli/commands/monitor.py +0 -1
- claude_mpm/core/constants.py +65 -0
- claude_mpm/core/error_handler.py +625 -0
- claude_mpm/core/file_utils.py +770 -0
- claude_mpm/core/logging_utils.py +502 -0
- claude_mpm/dashboard/static/dist/components/code-tree.js +1 -1
- claude_mpm/dashboard/static/dist/components/file-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/dashboard.js +1 -1
- claude_mpm/dashboard/static/dist/socket-client.js +1 -1
- claude_mpm/dashboard/static/js/components/code-simple.js +44 -1
- claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +353 -0
- claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +235 -0
- claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +409 -0
- claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +435 -0
- claude_mpm/dashboard/static/js/components/code-tree.js +29 -5
- claude_mpm/dashboard/static/js/components/file-viewer.js +69 -27
- claude_mpm/dashboard/static/js/components/session-manager.js +7 -7
- claude_mpm/dashboard/static/js/components/working-directory.js +18 -9
- claude_mpm/dashboard/static/js/dashboard.js +91 -9
- claude_mpm/dashboard/static/js/shared/dom-helpers.js +396 -0
- claude_mpm/dashboard/static/js/shared/event-bus.js +330 -0
- claude_mpm/dashboard/static/js/shared/logger.js +385 -0
- claude_mpm/dashboard/static/js/shared/tooltip-service.js +253 -0
- claude_mpm/dashboard/static/js/socket-client.js +18 -0
- claude_mpm/dashboard/templates/index.html +22 -9
- claude_mpm/services/cli/unified_dashboard_manager.py +2 -1
- claude_mpm/services/monitor/handlers/__init__.py +2 -1
- claude_mpm/services/monitor/handlers/file.py +263 -0
- claude_mpm/services/monitor/handlers/hooks.py +25 -1
- claude_mpm/services/monitor/server.py +111 -1
- claude_mpm/services/socketio/handlers/file.py +40 -5
- {claude_mpm-4.2.13.dist-info → claude_mpm-4.2.15.dist-info}/METADATA +1 -1
- {claude_mpm-4.2.13.dist-info → claude_mpm-4.2.15.dist-info}/RECORD +39 -27
- {claude_mpm-4.2.13.dist-info → claude_mpm-4.2.15.dist-info}/WHEEL +0 -0
- {claude_mpm-4.2.13.dist-info → claude_mpm-4.2.15.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.2.13.dist-info → claude_mpm-4.2.15.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.2.13.dist-info → claude_mpm-4.2.15.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tree Utility Functions
|
|
3
|
+
*
|
|
4
|
+
* Common utility functions extracted from code-tree.js
|
|
5
|
+
* Provides formatting, file type detection, and other helper functions.
|
|
6
|
+
*
|
|
7
|
+
* @module tree-utils
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const treeUtils = {
|
|
11
|
+
/**
|
|
12
|
+
* Get complexity level from numeric complexity
|
|
13
|
+
* @param {number} complexity - Complexity value
|
|
14
|
+
* @returns {string} Complexity level (low/medium/high)
|
|
15
|
+
*/
|
|
16
|
+
getComplexityLevel(complexity) {
|
|
17
|
+
if (complexity <= 5) return 'low';
|
|
18
|
+
if (complexity <= 10) return 'medium';
|
|
19
|
+
return 'high';
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Format file size for display
|
|
24
|
+
* @param {number} bytes - Size in bytes
|
|
25
|
+
* @returns {string} Formatted size string
|
|
26
|
+
*/
|
|
27
|
+
formatFileSize(bytes) {
|
|
28
|
+
if (bytes === 0) return '0 B';
|
|
29
|
+
const k = 1024;
|
|
30
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
31
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
32
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get file extension from path
|
|
37
|
+
* @param {string} filePath - File path
|
|
38
|
+
* @returns {string} File extension (lowercase)
|
|
39
|
+
*/
|
|
40
|
+
getFileExtension(filePath) {
|
|
41
|
+
if (!filePath) return '';
|
|
42
|
+
const parts = filePath.split('.');
|
|
43
|
+
return parts.length > 1 ? parts.pop().toLowerCase() : '';
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get descriptive file type for user messages
|
|
48
|
+
* @param {string} fileName - File name
|
|
49
|
+
* @returns {string} Human-readable file type description
|
|
50
|
+
*/
|
|
51
|
+
getFileTypeDescription(fileName) {
|
|
52
|
+
if (!fileName) return 'File';
|
|
53
|
+
|
|
54
|
+
const ext = this.getFileExtension(fileName);
|
|
55
|
+
const baseName = fileName.toLowerCase();
|
|
56
|
+
|
|
57
|
+
// Special cases
|
|
58
|
+
if (baseName.endsWith('__init__.py')) {
|
|
59
|
+
return 'Python package initialization';
|
|
60
|
+
}
|
|
61
|
+
if (baseName === 'makefile') {
|
|
62
|
+
return 'Build configuration';
|
|
63
|
+
}
|
|
64
|
+
if (baseName.includes('config') || baseName.includes('settings')) {
|
|
65
|
+
return 'Configuration file';
|
|
66
|
+
}
|
|
67
|
+
if (baseName.includes('test') || baseName.includes('spec')) {
|
|
68
|
+
return 'Test file';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// By extension
|
|
72
|
+
const typeMap = {
|
|
73
|
+
'py': 'Python file',
|
|
74
|
+
'js': 'JavaScript file',
|
|
75
|
+
'ts': 'TypeScript file',
|
|
76
|
+
'jsx': 'React component',
|
|
77
|
+
'tsx': 'React TypeScript component',
|
|
78
|
+
'html': 'HTML document',
|
|
79
|
+
'css': 'Stylesheet',
|
|
80
|
+
'scss': 'SCSS stylesheet',
|
|
81
|
+
'sass': 'Sass stylesheet',
|
|
82
|
+
'less': 'LESS stylesheet',
|
|
83
|
+
'json': 'JSON data',
|
|
84
|
+
'md': 'Markdown document',
|
|
85
|
+
'txt': 'Text file',
|
|
86
|
+
'yml': 'YAML configuration',
|
|
87
|
+
'yaml': 'YAML configuration',
|
|
88
|
+
'xml': 'XML document',
|
|
89
|
+
'sql': 'SQL script',
|
|
90
|
+
'sh': 'Shell script',
|
|
91
|
+
'bash': 'Bash script',
|
|
92
|
+
'toml': 'TOML configuration',
|
|
93
|
+
'ini': 'INI configuration',
|
|
94
|
+
'env': 'Environment variables',
|
|
95
|
+
'dockerfile': 'Docker configuration',
|
|
96
|
+
'makefile': 'Build configuration',
|
|
97
|
+
'gitignore': 'Git ignore rules',
|
|
98
|
+
'readme': 'Documentation'
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
return typeMap[ext] || typeMap[baseName] || 'File';
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get file icon based on file type
|
|
106
|
+
* @param {string} filePath - File path
|
|
107
|
+
* @returns {string} Unicode emoji icon
|
|
108
|
+
*/
|
|
109
|
+
getFileIcon(filePath) {
|
|
110
|
+
if (!filePath) return '📄';
|
|
111
|
+
|
|
112
|
+
const ext = this.getFileExtension(filePath);
|
|
113
|
+
const fileName = filePath.toLowerCase().split('/').pop();
|
|
114
|
+
|
|
115
|
+
const iconMap = {
|
|
116
|
+
// Programming languages
|
|
117
|
+
'py': '🐍',
|
|
118
|
+
'js': '📜',
|
|
119
|
+
'ts': '📘',
|
|
120
|
+
'jsx': '⚛️',
|
|
121
|
+
'tsx': '⚛️',
|
|
122
|
+
'java': '☕',
|
|
123
|
+
'c': '🔷',
|
|
124
|
+
'cpp': '🔷',
|
|
125
|
+
'cs': '🔷',
|
|
126
|
+
'go': '🐹',
|
|
127
|
+
'rs': '🦀',
|
|
128
|
+
'rb': '💎',
|
|
129
|
+
'php': '🐘',
|
|
130
|
+
'swift': '🦉',
|
|
131
|
+
'kt': '🎯',
|
|
132
|
+
|
|
133
|
+
// Web files
|
|
134
|
+
'html': '🌐',
|
|
135
|
+
'css': '🎨',
|
|
136
|
+
'scss': '🎨',
|
|
137
|
+
'sass': '🎨',
|
|
138
|
+
'less': '🎨',
|
|
139
|
+
|
|
140
|
+
// Data files
|
|
141
|
+
'json': '📋',
|
|
142
|
+
'xml': '📰',
|
|
143
|
+
'csv': '📊',
|
|
144
|
+
'sql': '🗃️',
|
|
145
|
+
|
|
146
|
+
// Documentation
|
|
147
|
+
'md': '📝',
|
|
148
|
+
'txt': '📄',
|
|
149
|
+
'pdf': '📑',
|
|
150
|
+
'doc': '📃',
|
|
151
|
+
'docx': '📃',
|
|
152
|
+
|
|
153
|
+
// Configuration
|
|
154
|
+
'yml': '⚙️',
|
|
155
|
+
'yaml': '⚙️',
|
|
156
|
+
'toml': '⚙️',
|
|
157
|
+
'ini': '⚙️',
|
|
158
|
+
'env': '🔐',
|
|
159
|
+
|
|
160
|
+
// Scripts
|
|
161
|
+
'sh': '🐚',
|
|
162
|
+
'bash': '🐚',
|
|
163
|
+
'bat': '🖥️',
|
|
164
|
+
'ps1': '🖥️',
|
|
165
|
+
|
|
166
|
+
// Special files
|
|
167
|
+
'dockerfile': '🐳',
|
|
168
|
+
'docker-compose.yml': '🐳',
|
|
169
|
+
'makefile': '🔨',
|
|
170
|
+
'package.json': '📦',
|
|
171
|
+
'requirements.txt': '📦',
|
|
172
|
+
'gitignore': '🚫',
|
|
173
|
+
'.gitignore': '🚫',
|
|
174
|
+
'readme': '📖',
|
|
175
|
+
'readme.md': '📖',
|
|
176
|
+
'license': '📜',
|
|
177
|
+
'license.md': '📜'
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// Check full filename first, then extension
|
|
181
|
+
return iconMap[fileName] || iconMap[ext] || '📄';
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Count different types of AST elements
|
|
186
|
+
* @param {Array} elements - AST elements
|
|
187
|
+
* @returns {Object} Element counts
|
|
188
|
+
*/
|
|
189
|
+
getElementCounts(elements) {
|
|
190
|
+
const counts = {
|
|
191
|
+
classes: 0,
|
|
192
|
+
functions: 0,
|
|
193
|
+
methods: 0,
|
|
194
|
+
total: elements.length
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
elements.forEach(elem => {
|
|
198
|
+
if (elem.type === 'class') {
|
|
199
|
+
counts.classes++;
|
|
200
|
+
if (elem.methods) {
|
|
201
|
+
counts.methods += elem.methods.length;
|
|
202
|
+
}
|
|
203
|
+
} else if (elem.type === 'function') {
|
|
204
|
+
counts.functions++;
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
return counts;
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Format element counts into a readable summary
|
|
213
|
+
* @param {Object} counts - Element counts
|
|
214
|
+
* @returns {string} Formatted summary
|
|
215
|
+
*/
|
|
216
|
+
formatElementSummary(counts) {
|
|
217
|
+
const parts = [];
|
|
218
|
+
|
|
219
|
+
if (counts.classes > 0) {
|
|
220
|
+
parts.push(`${counts.classes} class${counts.classes !== 1 ? 'es' : ''}`);
|
|
221
|
+
}
|
|
222
|
+
if (counts.functions > 0) {
|
|
223
|
+
parts.push(`${counts.functions} function${counts.functions !== 1 ? 's' : ''}`);
|
|
224
|
+
}
|
|
225
|
+
if (counts.methods > 0) {
|
|
226
|
+
parts.push(`${counts.methods} method${counts.methods !== 1 ? 's' : ''}`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (parts.length === 0) {
|
|
230
|
+
return 'Structural elements for tree view';
|
|
231
|
+
} else if (parts.length === 1) {
|
|
232
|
+
return parts[0] + ' found';
|
|
233
|
+
} else if (parts.length === 2) {
|
|
234
|
+
return parts.join(' and ') + ' found';
|
|
235
|
+
} else {
|
|
236
|
+
return parts.slice(0, -1).join(', ') + ', and ' + parts[parts.length - 1] + ' found';
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Get node type from data
|
|
242
|
+
* @param {Object} node - Node data
|
|
243
|
+
* @returns {string} Node type
|
|
244
|
+
*/
|
|
245
|
+
getNodeType(node) {
|
|
246
|
+
if (!node) return 'unknown';
|
|
247
|
+
if (node.type) return node.type;
|
|
248
|
+
if (node.children && node.children.length > 0) return 'directory';
|
|
249
|
+
if (node.path) return 'file';
|
|
250
|
+
return 'unknown';
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Check if node is a directory
|
|
255
|
+
* @param {Object} node - Node or node data
|
|
256
|
+
* @returns {boolean} True if directory
|
|
257
|
+
*/
|
|
258
|
+
isNodeDirectory(node) {
|
|
259
|
+
if (!node) return false;
|
|
260
|
+
|
|
261
|
+
// Handle D3 node structure
|
|
262
|
+
if (node.data) {
|
|
263
|
+
node = node.data;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return node.type === 'directory' ||
|
|
267
|
+
node.type === 'folder' ||
|
|
268
|
+
(node.children && node.children.length > 0) ||
|
|
269
|
+
node.isDirectory === true;
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Get node icon for tree visualization
|
|
274
|
+
* @param {string} type - Node type
|
|
275
|
+
* @returns {string} Unicode icon
|
|
276
|
+
*/
|
|
277
|
+
getNodeIcon(type) {
|
|
278
|
+
const icons = {
|
|
279
|
+
'module': '📦',
|
|
280
|
+
'class': '🏗️',
|
|
281
|
+
'function': '⚡',
|
|
282
|
+
'method': '🔧',
|
|
283
|
+
'property': '📌',
|
|
284
|
+
'directory': '📁',
|
|
285
|
+
'folder': '📁',
|
|
286
|
+
'file': '📄',
|
|
287
|
+
'python': '🐍',
|
|
288
|
+
'javascript': '📜',
|
|
289
|
+
'unknown': '❓'
|
|
290
|
+
};
|
|
291
|
+
return icons[type] || icons['unknown'];
|
|
292
|
+
},
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Sort nodes for tree display
|
|
296
|
+
* @param {Array} nodes - Array of nodes
|
|
297
|
+
* @returns {Array} Sorted nodes
|
|
298
|
+
*/
|
|
299
|
+
sortNodes(nodes) {
|
|
300
|
+
return nodes.sort((a, b) => {
|
|
301
|
+
// Directories first
|
|
302
|
+
const aIsDir = this.isNodeDirectory(a);
|
|
303
|
+
const bIsDir = this.isNodeDirectory(b);
|
|
304
|
+
|
|
305
|
+
if (aIsDir && !bIsDir) return -1;
|
|
306
|
+
if (!aIsDir && bIsDir) return 1;
|
|
307
|
+
|
|
308
|
+
// Then alphabetically
|
|
309
|
+
const aName = (a.name || a.data?.name || '').toLowerCase();
|
|
310
|
+
const bName = (b.name || b.data?.name || '').toLowerCase();
|
|
311
|
+
|
|
312
|
+
return aName.localeCompare(bName);
|
|
313
|
+
});
|
|
314
|
+
},
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Filter nodes based on criteria
|
|
318
|
+
* @param {Array} nodes - Array of nodes
|
|
319
|
+
* @param {Object} criteria - Filter criteria
|
|
320
|
+
* @returns {Array} Filtered nodes
|
|
321
|
+
*/
|
|
322
|
+
filterNodes(nodes, criteria = {}) {
|
|
323
|
+
return nodes.filter(node => {
|
|
324
|
+
// Language filter
|
|
325
|
+
if (criteria.language && node.language !== criteria.language) {
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Search term filter
|
|
330
|
+
if (criteria.searchTerm) {
|
|
331
|
+
const term = criteria.searchTerm.toLowerCase();
|
|
332
|
+
const name = (node.name || '').toLowerCase();
|
|
333
|
+
const path = (node.path || '').toLowerCase();
|
|
334
|
+
|
|
335
|
+
if (!name.includes(term) && !path.includes(term)) {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Complexity filter
|
|
341
|
+
if (criteria.minComplexity && node.complexity < criteria.minComplexity) {
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
if (criteria.maxComplexity && node.complexity > criteria.maxComplexity) {
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return true;
|
|
349
|
+
});
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Calculate tree statistics
|
|
354
|
+
* @param {Object} node - Root node
|
|
355
|
+
* @returns {Object} Tree statistics
|
|
356
|
+
*/
|
|
357
|
+
calculateTreeStats(node) {
|
|
358
|
+
const stats = {
|
|
359
|
+
files: 0,
|
|
360
|
+
directories: 0,
|
|
361
|
+
classes: 0,
|
|
362
|
+
functions: 0,
|
|
363
|
+
methods: 0,
|
|
364
|
+
lines: 0,
|
|
365
|
+
maxDepth: 0
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
const traverse = (n, depth = 0) => {
|
|
369
|
+
stats.maxDepth = Math.max(stats.maxDepth, depth);
|
|
370
|
+
|
|
371
|
+
if (this.isNodeDirectory(n)) {
|
|
372
|
+
stats.directories++;
|
|
373
|
+
} else {
|
|
374
|
+
stats.files++;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (n.type === 'class') stats.classes++;
|
|
378
|
+
if (n.type === 'function') stats.functions++;
|
|
379
|
+
if (n.type === 'method') stats.methods++;
|
|
380
|
+
if (n.lines) stats.lines += n.lines;
|
|
381
|
+
|
|
382
|
+
if (n.children) {
|
|
383
|
+
n.children.forEach(child => traverse(child, depth + 1));
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
traverse(node);
|
|
388
|
+
return stats;
|
|
389
|
+
},
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Get color based on complexity
|
|
393
|
+
* @param {number} complexity - Complexity value
|
|
394
|
+
* @returns {string} Color hex code
|
|
395
|
+
*/
|
|
396
|
+
getComplexityColor(complexity) {
|
|
397
|
+
if (!complexity || complexity <= 5) {
|
|
398
|
+
return '#52c41a'; // Green - low complexity
|
|
399
|
+
} else if (complexity <= 10) {
|
|
400
|
+
return '#faad14'; // Orange - medium complexity
|
|
401
|
+
} else {
|
|
402
|
+
return '#f5222d'; // Red - high complexity
|
|
403
|
+
}
|
|
404
|
+
},
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Format node path for display
|
|
408
|
+
* @param {Object} node - Node object
|
|
409
|
+
* @returns {string} Formatted path
|
|
410
|
+
*/
|
|
411
|
+
formatNodePath(node) {
|
|
412
|
+
const parts = [];
|
|
413
|
+
let current = node;
|
|
414
|
+
|
|
415
|
+
while (current) {
|
|
416
|
+
if (current.data?.name) {
|
|
417
|
+
parts.unshift(current.data.name);
|
|
418
|
+
} else if (current.name) {
|
|
419
|
+
parts.unshift(current.name);
|
|
420
|
+
}
|
|
421
|
+
current = current.parent;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return parts.join(' / ');
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
// Support both module and global usage
|
|
429
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
430
|
+
module.exports = treeUtils;
|
|
431
|
+
} else if (typeof define === 'function' && define.amd) {
|
|
432
|
+
define([], () => treeUtils);
|
|
433
|
+
} else {
|
|
434
|
+
window.treeUtils = treeUtils;
|
|
435
|
+
}
|
|
@@ -13,10 +13,34 @@
|
|
|
13
13
|
*
|
|
14
14
|
* Version: 2025-08-29T15:30:00Z - ALL CENTERING REMOVED
|
|
15
15
|
* Last Update: Completely disabled tree centering/movement on node clicks
|
|
16
|
+
*
|
|
17
|
+
* REFACTORED: 2025-09-05 - Extracted utilities, constants, search, and breadcrumb modules
|
|
16
18
|
*/
|
|
17
19
|
|
|
20
|
+
// Load dependencies - these should be loaded in the HTML before this file
|
|
21
|
+
// Shared services
|
|
22
|
+
// <script src="/static/js/shared/tooltip-service.js"></script>
|
|
23
|
+
// <script src="/static/js/shared/dom-helpers.js"></script>
|
|
24
|
+
// <script src="/static/js/shared/event-bus.js"></script>
|
|
25
|
+
// <script src="/static/js/shared/logger.js"></script>
|
|
26
|
+
// Tree modules
|
|
27
|
+
// <script src="/static/js/components/code-tree/tree-utils.js"></script>
|
|
28
|
+
// <script src="/static/js/components/code-tree/tree-constants.js"></script>
|
|
29
|
+
// <script src="/static/js/components/code-tree/tree-search.js"></script>
|
|
30
|
+
// <script src="/static/js/components/code-tree/tree-breadcrumb.js"></script>
|
|
31
|
+
|
|
18
32
|
class CodeTree {
|
|
19
33
|
constructor() {
|
|
34
|
+
// Initialize services
|
|
35
|
+
this.tooltipService = window.tooltipService || null;
|
|
36
|
+
this.domHelpers = window.domHelpers || null;
|
|
37
|
+
this.eventBus = window.eventBus || null;
|
|
38
|
+
this.logger = window.logger ? window.logger.createComponentLogger('CodeTree') : console;
|
|
39
|
+
this.treeUtils = window.treeUtils || null;
|
|
40
|
+
this.treeConstants = window.treeConstants || {};
|
|
41
|
+
this.treeSearch = window.treeSearch || null;
|
|
42
|
+
this.treeBreadcrumb = window.treeBreadcrumb || null;
|
|
43
|
+
|
|
20
44
|
this.container = null;
|
|
21
45
|
this.svg = null;
|
|
22
46
|
this.treeData = null;
|
|
@@ -31,14 +55,14 @@ class CodeTree {
|
|
|
31
55
|
methods: 0,
|
|
32
56
|
lines: 0
|
|
33
57
|
};
|
|
34
|
-
// Radial layout settings
|
|
58
|
+
// Radial layout settings - use constants if available
|
|
35
59
|
this.isRadialLayout = false; // Toggle for radial vs linear layout - defaulting to linear for better readability
|
|
36
|
-
this.margin = {top: 20, right: 20, bottom: 20, left: 20};
|
|
37
|
-
this.width = 960 - this.margin.left - this.margin.right;
|
|
38
|
-
this.height = 600 - this.margin.top - this.margin.bottom;
|
|
60
|
+
this.margin = this.treeConstants.DEFAULT_MARGIN || {top: 20, right: 20, bottom: 20, left: 20};
|
|
61
|
+
this.width = (this.treeConstants.DEFAULT_WIDTH || 960) - this.margin.left - this.margin.right;
|
|
62
|
+
this.height = (this.treeConstants.DEFAULT_HEIGHT || 600) - this.margin.top - this.margin.bottom;
|
|
39
63
|
this.radius = Math.min(this.width, this.height) / 2;
|
|
40
64
|
this.nodeId = 0;
|
|
41
|
-
this.duration = 750;
|
|
65
|
+
this.duration = this.treeConstants.ANIMATION_DURATION || 750;
|
|
42
66
|
this.languageFilter = 'all';
|
|
43
67
|
this.searchTerm = '';
|
|
44
68
|
this.tooltip = null;
|
|
@@ -248,7 +248,11 @@ class FileViewer {
|
|
|
248
248
|
* Show the file viewer with file content
|
|
249
249
|
*/
|
|
250
250
|
async show(filePath) {
|
|
251
|
+
console.log('[FileViewer] show() called with path:', filePath);
|
|
252
|
+
console.log('[FileViewer] initialized:', this.initialized);
|
|
253
|
+
|
|
251
254
|
if (!this.initialized) {
|
|
255
|
+
console.log('[FileViewer] Not initialized, initializing now...');
|
|
252
256
|
this.initialize();
|
|
253
257
|
}
|
|
254
258
|
|
|
@@ -258,6 +262,7 @@ class FileViewer {
|
|
|
258
262
|
// Update path
|
|
259
263
|
document.getElementById('file-viewer-path').textContent = filePath;
|
|
260
264
|
|
|
265
|
+
console.log('[FileViewer] Modal shown, loading file content...');
|
|
261
266
|
// Load file content
|
|
262
267
|
await this.loadFileContent(filePath);
|
|
263
268
|
}
|
|
@@ -276,8 +281,11 @@ class FileViewer {
|
|
|
276
281
|
async loadFileContent(filePath) {
|
|
277
282
|
const codeContent = document.getElementById('file-viewer-code-content');
|
|
278
283
|
|
|
284
|
+
console.log('[FileViewer] loadFileContent called with path:', filePath);
|
|
285
|
+
|
|
279
286
|
// Check cache first
|
|
280
287
|
if (this.contentCache.has(filePath)) {
|
|
288
|
+
console.log('[FileViewer] Using cached content for:', filePath);
|
|
281
289
|
this.displayContent(this.contentCache.get(filePath));
|
|
282
290
|
return;
|
|
283
291
|
}
|
|
@@ -286,35 +294,62 @@ class FileViewer {
|
|
|
286
294
|
codeContent.textContent = 'Loading file content...';
|
|
287
295
|
|
|
288
296
|
try {
|
|
289
|
-
//
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
297
|
+
// Check if we have a socket connection available
|
|
298
|
+
if (window.socket && window.socket.connected) {
|
|
299
|
+
console.log('[FileViewer] Using Socket.IO to load file:', filePath);
|
|
300
|
+
|
|
301
|
+
// Create a promise to wait for the response
|
|
302
|
+
const responsePromise = new Promise((resolve, reject) => {
|
|
303
|
+
const timeoutId = setTimeout(() => {
|
|
304
|
+
console.error('[FileViewer] Socket.IO request timed out for:', filePath);
|
|
305
|
+
reject(new Error('Socket.IO request timed out'));
|
|
306
|
+
}, 10000); // 10 second timeout
|
|
307
|
+
|
|
308
|
+
// Set up one-time listener for the response
|
|
309
|
+
window.socket.once('file_content_response', (data) => {
|
|
310
|
+
clearTimeout(timeoutId);
|
|
311
|
+
console.log('[FileViewer] Received file_content_response:', data);
|
|
312
|
+
resolve(data);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// Emit the read_file event
|
|
316
|
+
console.log('[FileViewer] Emitting read_file event with data:', {
|
|
317
|
+
file_path: filePath,
|
|
318
|
+
working_dir: window.workingDirectory || '/',
|
|
319
|
+
max_size: 5 * 1024 * 1024 // 5MB limit
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
window.socket.emit('read_file', {
|
|
323
|
+
file_path: filePath,
|
|
324
|
+
working_dir: window.workingDirectory || '/',
|
|
325
|
+
max_size: 5 * 1024 * 1024 // 5MB limit
|
|
326
|
+
});
|
|
327
|
+
});
|
|
307
328
|
|
|
308
|
-
//
|
|
309
|
-
|
|
329
|
+
// Wait for the response
|
|
330
|
+
const data = await responsePromise;
|
|
310
331
|
|
|
311
|
-
|
|
312
|
-
|
|
332
|
+
if (data.success && data.content !== undefined) {
|
|
333
|
+
console.log('[FileViewer] Successfully loaded file content, caching...');
|
|
334
|
+
// Cache the content
|
|
335
|
+
this.contentCache.set(filePath, data.content);
|
|
336
|
+
|
|
337
|
+
// Display the content
|
|
338
|
+
this.displayContent(data.content);
|
|
339
|
+
|
|
340
|
+
// Update file info
|
|
341
|
+
this.updateFileInfo(data);
|
|
342
|
+
} else {
|
|
343
|
+
console.error('[FileViewer] Server returned error:', data.error);
|
|
344
|
+
throw new Error(data.error || 'Failed to load file content');
|
|
345
|
+
}
|
|
313
346
|
} else {
|
|
314
|
-
|
|
347
|
+
console.error('[FileViewer] No Socket.IO connection available');
|
|
348
|
+
throw new Error('No socket connection available. Please ensure the dashboard is connected to the monitoring server.');
|
|
315
349
|
}
|
|
316
350
|
} catch (error) {
|
|
317
|
-
console.error('Error loading file:', error);
|
|
351
|
+
console.error('[FileViewer] Error loading file:', error);
|
|
352
|
+
console.error('[FileViewer] Error stack:', error.stack);
|
|
318
353
|
|
|
319
354
|
// If API fails, show error message with helpful information
|
|
320
355
|
this.displayError(filePath, error.message);
|
|
@@ -516,9 +551,16 @@ class FileViewer {
|
|
|
516
551
|
const fileViewer = new FileViewer();
|
|
517
552
|
|
|
518
553
|
// Create global function for easy access
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
554
|
+
// Only set if not already defined by dashboard.js
|
|
555
|
+
if (!window.showFileViewerModal) {
|
|
556
|
+
window.showFileViewerModal = (filePath) => {
|
|
557
|
+
console.log('[FileViewer] showFileViewerModal called with path:', filePath);
|
|
558
|
+
fileViewer.show(filePath);
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// Expose the singleton for debugging
|
|
563
|
+
window.fileViewerInstance = fileViewer;
|
|
522
564
|
|
|
523
565
|
// Export for use in other modules
|
|
524
566
|
if (typeof window !== 'undefined') {
|
|
@@ -93,7 +93,7 @@ class SessionManager {
|
|
|
93
93
|
const currentSelection = sessionSelect.value;
|
|
94
94
|
|
|
95
95
|
// Get the default working directory from various sources
|
|
96
|
-
let defaultWorkingDir = '/
|
|
96
|
+
let defaultWorkingDir = '/';
|
|
97
97
|
|
|
98
98
|
// Try to get from working directory manager
|
|
99
99
|
if (window.dashboard && window.dashboard.workingDirectoryManager) {
|
|
@@ -219,10 +219,10 @@ class SessionManager {
|
|
|
219
219
|
let sessionInfo = 'All Sessions';
|
|
220
220
|
// Use browser-compatible fallback for working directory
|
|
221
221
|
// WHY: Removed process.cwd() Node.js reference - not available in browser
|
|
222
|
-
// BROWSER FIX: Use dashboard manager or
|
|
222
|
+
// BROWSER FIX: Use dashboard manager or server-provided config
|
|
223
223
|
let workingDir = window.dashboard?.workingDirectoryManager?.getDefaultWorkingDir() ||
|
|
224
|
-
window.
|
|
225
|
-
'
|
|
224
|
+
window.dashboardConfig?.workingDirectory ||
|
|
225
|
+
'.';
|
|
226
226
|
let gitBranch = 'Unknown';
|
|
227
227
|
|
|
228
228
|
console.log('[SESSION-DEBUG] Initial values - sessionInfo:', sessionInfo, 'workingDir:', workingDir, 'gitBranch:', gitBranch);
|
|
@@ -238,8 +238,8 @@ class SessionManager {
|
|
|
238
238
|
// Browser-compatible working directory fallback
|
|
239
239
|
workingDir = sessionData.workingDir ||
|
|
240
240
|
window.dashboard?.workingDirectoryManager?.getDefaultWorkingDir() ||
|
|
241
|
-
window.
|
|
242
|
-
'
|
|
241
|
+
window.dashboardConfig?.workingDirectory ||
|
|
242
|
+
'.';
|
|
243
243
|
gitBranch = sessionData.gitBranch || 'Unknown';
|
|
244
244
|
}
|
|
245
245
|
} else if (this.selectedSessionId) {
|
|
@@ -253,7 +253,7 @@ class SessionManager {
|
|
|
253
253
|
if (!workingDir || !gitBranch) {
|
|
254
254
|
const sessionData = this.extractSessionInfoFromEvents(this.selectedSessionId);
|
|
255
255
|
// Browser-compatible fallback - no process.cwd()
|
|
256
|
-
workingDir = workingDir || sessionData.workingDir || window.
|
|
256
|
+
workingDir = workingDir || sessionData.workingDir || window.dashboardConfig?.workingDirectory || '.';
|
|
257
257
|
gitBranch = gitBranch || sessionData.gitBranch || '';
|
|
258
258
|
}
|
|
259
259
|
}
|