/**
* Logs page — registers the dashboard with the background to receive live log events,
* renders a filterable/searchable log list with level filtering and auto-scroll toggle.
* Depends on: core/utils.js ($, escapeHtml), ui/toast.js (showToast)
*/
let _logsSetup = false;
/**
* Set up the Logs page: register for live log broadcasts, wire up filter/search/scroll controls.
* Guarded by `_logsSetup` to prevent duplicate registration.
*/
function setupLogsEvents() {
if (_logsSetup) return;
_logsSetup = true;
let logs = [];
let autoScroll = true;
let logFilter = '';
let logLevel = 'all'; // 'all' | 'info' | 'warn' | 'error' | 'debug'
chrome.runtime.sendMessage(
{ target: 'holesail-native', action: 'registerDashboard' },
(response) => {
if (response && response.logs) { logs = response.logs; updateLogsDisplay(); }
}
);
function _onLogsMessage(message) {
if (message.type === 'holesail-logs' && message.logs) {
logs = message.logs;
updateLogsDisplay();
}
}
chrome.runtime.onMessage.addListener(_onLogsMessage);
function getLogClass(level) {
if (level === 'error') return 'is-error';
if (level === 'warn') return 'is-warn';
return '';
}
function normalizeLogLevel(level) {
return level === 'debug' ? 'debug' : (level || 'info');
}
function updateLogsDisplay() {
const container = $('logsContainer');
if (!container) return;
let filtered = logs;
if (logFilter) {
filtered = filtered.filter(e => (e.message || '').toLowerCase().includes(logFilter.toLowerCase()));
}
if (logLevel !== 'all') {
filtered = filtered.filter(e => normalizeLogLevel(e.level) === logLevel);
}
if (filtered.length === 0) {
container.innerHTML = `
${(logFilter || logLevel !== 'all') ? 'No matching logs' : 'No logs yet'}
${(logFilter || logLevel !== 'all') ? 'Try a different filter' : 'Logs will appear here as the extension runs'}
`;
return;
}
container.innerHTML = filtered.map(entry => {
const rawTs = entry && entry.timestamp;
const d = new Date(typeof rawTs === 'number' ? rawTs : (typeof rawTs === 'string' ? rawTs : Date.now()));
const time = Number.isNaN(d.getTime()) ? '--:--:--' : d.toLocaleTimeString();
const level = normalizeLogLevel(entry.level);
const cls = getLogClass(level);
const msg = typeof entry === 'string' ? entry : (entry && entry.message != null ? entry.message : String(entry));
return `
${time}
${escapeHtml(msg)}
`;
}).join('');
if (autoScroll) container.scrollTop = container.scrollHeight;
}
$('btnClearLogs')?.addEventListener('click', () => { logs = []; updateLogsDisplay(); });
$('btnAutoScroll')?.addEventListener('click', () => {
autoScroll = !autoScroll;
const btn = $('btnAutoScroll');
if (btn) {
const svgPart = btn.querySelector('svg')?.outerHTML || '';
btn.innerHTML = svgPart + ' Auto-scroll: ' + (autoScroll ? 'ON' : 'OFF');
}
});
$('logsFilter')?.addEventListener('input', (e) => {
logFilter = e.target.value;
updateLogsDisplay();
});
// Severity filter buttons
document.querySelectorAll('.log-level-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.log-level-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
logLevel = btn.dataset.level;
updateLogsDisplay();
});
});
// Download logs as .txt
$('btnDownloadLogs')?.addEventListener('click', () => {
if (!logs.length) { showToast('No logs to download', 'default'); return; }
const lines = logs.map(e => {
const rawTs = e && e.timestamp;
const d = new Date(typeof rawTs === 'number' ? rawTs : (typeof rawTs === 'string' ? rawTs : Date.now()));
const time = Number.isNaN(d.getTime()) ? new Date().toISOString() : d.toISOString();
const level = normalizeLogLevel(e && e.level).toUpperCase();
const msg = typeof e === 'string' ? e : (e && e.message != null ? e.message : String(e));
return `[${time}] [${level}] ${msg}`;
}).join('\n');
const blob = new Blob([lines], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'holesail-logs-' + new Date().toISOString().slice(0, 19).replace(/:/g, '-') + '.txt';
a.click();
setTimeout(() => URL.revokeObjectURL(url), 5000);
showToast('Logs downloaded', 'success');
});
window.addEventListener('beforeunload', () => {
chrome.runtime.onMessage.removeListener(_onLogsMessage);
chrome.runtime.sendMessage({ target: 'holesail-native', action: 'unregisterDashboard' }, () => {});
}, { once: true });
}