/** * ds-console-viewer.js * Console log viewer with real-time streaming and filtering */ import toolBridge from '../../services/tool-bridge.js'; class DSConsoleViewer extends HTMLElement { constructor() { super(); this.logs = []; this.currentFilter = 'all'; this.autoScroll = true; this.refreshInterval = null; } connectedCallback() { this.render(); this.startAutoRefresh(); } disconnectedCallback() { this.stopAutoRefresh(); } render() { const filteredLogs = this.currentFilter === 'all' ? this.logs : this.logs.filter(log => log.level === this.currentFilter); this.innerHTML = `
${filteredLogs.length === 0 ? `
No console logs${this.currentFilter !== 'all' ? ` (${this.currentFilter})` : ''}
` : filteredLogs.map(log => this.renderLogEntry(log)).join('')}
`; this.setupEventListeners(); if (this.autoScroll) { this.scrollToBottom(); } } renderLogEntry(log) { const levelColors = { log: 'var(--vscode-text)', warn: '#ff9800', error: '#f44336', info: '#2196f3', debug: 'var(--vscode-text-dim)' }; const color = levelColors[log.level] || 'var(--vscode-text)'; return `
${log.timestamp} [${log.level.toUpperCase()}] ${this.escapeHtml(log.message)}
`; } setupEventListeners() { // Filter buttons this.querySelectorAll('.filter-btn').forEach(btn => { btn.addEventListener('click', (e) => { this.currentFilter = e.target.dataset.filter; this.render(); }); }); // Auto-scroll toggle const autoScrollToggle = this.querySelector('#auto-scroll-toggle'); if (autoScrollToggle) { autoScrollToggle.addEventListener('change', (e) => { this.autoScroll = e.target.checked; }); } // Clear button const clearBtn = this.querySelector('#clear-logs-btn'); if (clearBtn) { clearBtn.addEventListener('click', () => { this.logs = []; this.render(); }); } // Refresh button const refreshBtn = this.querySelector('#refresh-logs-btn'); if (refreshBtn) { refreshBtn.addEventListener('click', () => { this.fetchLogs(); }); } } async fetchLogs() { try { const result = await toolBridge.getBrowserLogs(this.currentFilter, 100); if (result && result.logs) { this.logs = result.logs.map(log => ({ timestamp: new Date(log.timestamp).toLocaleTimeString(), level: log.level || 'log', message: log.message || JSON.stringify(log) })); this.render(); } } catch (error) { console.error('Failed to fetch logs:', error); this.addLog('error', `Failed to fetch logs: ${error.message}`); } } addLog(level, message) { const now = new Date(); this.logs.push({ timestamp: now.toLocaleTimeString(), level, message }); // Keep only last 100 logs if (this.logs.length > 100) { this.logs = this.logs.slice(-100); } this.render(); } startAutoRefresh() { // Fetch logs every 2 seconds this.fetchLogs(); this.refreshInterval = setInterval(() => { this.fetchLogs(); }, 2000); } stopAutoRefresh() { if (this.refreshInterval) { clearInterval(this.refreshInterval); this.refreshInterval = null; } } scrollToBottom() { const output = this.querySelector('#console-output'); if (output) { output.scrollTop = output.scrollHeight; } } escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } } customElements.define('ds-console-viewer', DSConsoleViewer); export default DSConsoleViewer;