/**
* 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;