claude-mpm 4.2.13__py3-none-any.whl → 4.2.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/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 +1 -1
- claude_mpm/dashboard/static/js/components/working-directory.js +18 -9
- claude_mpm/dashboard/static/js/dashboard.js +55 -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 +21 -8
- claude_mpm/services/monitor/handlers/__init__.py +2 -1
- claude_mpm/services/monitor/handlers/file.py +263 -0
- claude_mpm/services/monitor/server.py +81 -1
- claude_mpm/services/socketio/handlers/file.py +40 -5
- {claude_mpm-4.2.13.dist-info → claude_mpm-4.2.14.dist-info}/METADATA +1 -1
- {claude_mpm-4.2.13.dist-info → claude_mpm-4.2.14.dist-info}/RECORD +34 -22
- {claude_mpm-4.2.13.dist-info → claude_mpm-4.2.14.dist-info}/WHEEL +0 -0
- {claude_mpm-4.2.13.dist-info → claude_mpm-4.2.14.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.2.13.dist-info → claude_mpm-4.2.14.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.2.13.dist-info → claude_mpm-4.2.14.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) {
|
|
@@ -355,12 +355,21 @@ class WorkingDirectoryManager {
|
|
|
355
355
|
// Fallback to a reasonable default - try to get the current project directory
|
|
356
356
|
// This should be set when the dashboard initializes
|
|
357
357
|
|
|
358
|
-
// Try getting from
|
|
359
|
-
if (window.
|
|
360
|
-
//
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
|
|
358
|
+
// Try getting from events that have a working directory
|
|
359
|
+
if (window.socketClient && window.socketClient.events) {
|
|
360
|
+
// Look for the most recent event with a working directory
|
|
361
|
+
const eventsWithDir = window.socketClient.events
|
|
362
|
+
.filter(e => e.data && (e.data.working_directory || e.data.cwd || e.data.working_dir))
|
|
363
|
+
.reverse();
|
|
364
|
+
|
|
365
|
+
if (eventsWithDir.length > 0) {
|
|
366
|
+
const recentEvent = eventsWithDir[0];
|
|
367
|
+
const dir = recentEvent.data.working_directory ||
|
|
368
|
+
recentEvent.data.cwd ||
|
|
369
|
+
recentEvent.data.working_dir;
|
|
370
|
+
console.log('[WORKING-DIR-DEBUG] Using working directory from recent event:', dir);
|
|
371
|
+
return dir;
|
|
372
|
+
}
|
|
364
373
|
}
|
|
365
374
|
const workingDirPath = document.getElementById('working-dir-path');
|
|
366
375
|
if (workingDirPath?.textContent?.trim()) {
|
|
@@ -372,9 +381,9 @@ class WorkingDirectoryManager {
|
|
|
372
381
|
}
|
|
373
382
|
}
|
|
374
383
|
|
|
375
|
-
// Final fallback to
|
|
376
|
-
const fallback =
|
|
377
|
-
console.log('[WORKING-DIR-DEBUG] Using
|
|
384
|
+
// Final fallback to a generic path
|
|
385
|
+
const fallback = window.location.hostname === 'localhost' ? '/' : '/';
|
|
386
|
+
console.log('[WORKING-DIR-DEBUG] Using generic fallback directory:', this.repr(fallback));
|
|
378
387
|
return fallback;
|
|
379
388
|
}
|
|
380
389
|
|