fix: improve log panel with auto-scroll and color-coded lines

This commit is contained in:
2026-02-28 23:05:26 +02:00
parent 8ca94fbafc
commit e2077705de

View File

@@ -27,6 +27,31 @@
overflow-y: scroll; overflow-y: scroll;
font-size: 0.85rem; font-size: 0.85rem;
border-left: 2px solid #333; border-left: 2px solid #333;
position: relative;
}
#logs-content {
white-space: pre-wrap;
word-break: break-word;
}
.log-line { line-height: 1.4; }
.log-line.log-error { color: #ff6b6b; }
.log-line.log-warning { color: #ffd93d; }
.log-line.log-info { color: #0f0; }
.log-line.log-debug { color: #888; }
.logs-paused-indicator {
position: sticky;
top: 0;
background: rgba(50, 50, 0, 0.9);
color: #ffd93d;
text-align: center;
padding: 0.25rem;
font-size: 0.75rem;
cursor: pointer;
z-index: 10;
display: none;
} }
select, button, input { select, button, input {
@@ -1717,8 +1742,9 @@
</div> </div>
</div> </div>
<div class="logs"> <div class="logs" id="logs-panel">
<h3>Logs</h3> <h3>Logs</h3>
<div id="logs-paused-banner" class="logs-paused-indicator" onclick="scrollLogsToBottom()">⏸ Auto-scroll paused — click to resume</div>
<div id="logs-content"></div> <div id="logs-content"></div>
</div> </div>
@@ -1867,6 +1893,7 @@ document.addEventListener('DOMContentLoaded', function() {
console.log('🚀 DOMContentLoaded - initializing figurine subscribers list'); console.log('🚀 DOMContentLoaded - initializing figurine subscribers list');
refreshFigurineSubscribers(); refreshFigurineSubscribers();
loadProfilePictureMetadata(); loadProfilePictureMetadata();
initLogsScrollDetection(); // Set up log auto-scroll tracking
// Set up periodic updates // Set up periodic updates
setInterval(loadStatus, 10000); setInterval(loadStatus, 10000);
@@ -3994,10 +4021,60 @@ async function loadLastPrompt() {
} }
} }
// Log auto-scroll state
let logsAutoScroll = true;
function initLogsScrollDetection() {
const logsPanel = document.getElementById('logs-panel');
if (!logsPanel) return;
logsPanel.addEventListener('scroll', function() {
// If user is within 50px of the bottom, re-enable auto-scroll
const atBottom = logsPanel.scrollHeight - logsPanel.scrollTop - logsPanel.clientHeight < 50;
logsAutoScroll = atBottom;
const banner = document.getElementById('logs-paused-banner');
if (banner) banner.style.display = atBottom ? 'none' : 'block';
});
}
function scrollLogsToBottom() {
const logsPanel = document.getElementById('logs-panel');
if (logsPanel) {
logsPanel.scrollTop = logsPanel.scrollHeight;
logsAutoScroll = true;
const banner = document.getElementById('logs-paused-banner');
if (banner) banner.style.display = 'none';
}
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
function classifyLogLine(line) {
const upper = line.toUpperCase();
if (upper.includes(' ERROR ') || upper.includes(' CRITICAL ') || upper.startsWith('ERROR') || upper.startsWith('CRITICAL') || upper.includes('TRACEBACK')) return 'log-error';
if (upper.includes(' WARNING ') || upper.startsWith('WARNING')) return 'log-warning';
if (upper.includes(' DEBUG ') || upper.startsWith('DEBUG')) return 'log-debug';
return 'log-info';
}
async function loadLogs() { async function loadLogs() {
try { try {
const result = await apiCall('/logs'); const result = await apiCall('/logs');
document.getElementById('logs-content').textContent = result; const logsContent = document.getElementById('logs-content');
const lines = (result || '').split('\n');
logsContent.innerHTML = lines.map(line => {
if (!line.trim()) return '';
const cls = classifyLogLine(line);
return `<div class="log-line ${cls}">${escapeHtml(line)}</div>`;
}).join('');
// Auto-scroll to bottom if user hasn't scrolled up
if (logsAutoScroll) {
scrollLogsToBottom();
}
} catch (error) { } catch (error) {
console.error('Failed to load logs:', error); console.error('Failed to load logs:', error);
} }