Merge pull request #2807 from yangluxin613/feat/log-ui

feat(log): add level coloring, multiline inherit, and filter checkboxes
This commit is contained in:
zhayujie
2026-05-10 18:59:05 +08:00
committed by GitHub
3 changed files with 78 additions and 2 deletions

View File

@@ -907,6 +907,28 @@
</div>
<span class="text-xs text-slate-400 ml-2 font-mono">run.log</span>
<div class="flex-1"></div>
<div class="flex items-center gap-3 mr-2">
<label class="flex items-center gap-1 cursor-pointer select-none">
<input type="checkbox" class="log-filter-cb" data-level="debug" checked>
<span class="text-xs text-slate-400">DEBUG</span>
</label>
<label class="flex items-center gap-1 cursor-pointer select-none">
<input type="checkbox" class="log-filter-cb" data-level="info" checked>
<span class="text-xs text-blue-400">INFO</span>
</label>
<label class="flex items-center gap-1 cursor-pointer select-none">
<input type="checkbox" class="log-filter-cb" data-level="warning" checked>
<span class="text-xs text-yellow-400">WARNING</span>
</label>
<label class="flex items-center gap-1 cursor-pointer select-none">
<input type="checkbox" class="log-filter-cb" data-level="error" checked>
<span class="text-xs text-red-400">ERROR</span>
</label>
<label class="flex items-center gap-1 cursor-pointer select-none">
<input type="checkbox" class="log-filter-cb" data-level="critical" checked>
<span class="text-xs text-white font-bold">CRITICAL</span>
</label>
</div>
<div class="flex items-center gap-1.5">
<span class="w-2 h-2 rounded-full bg-emerald-500 animate-pulse"></span>
<span class="text-xs text-slate-500" data-i18n="logs_live">实时</span>

View File

@@ -606,6 +606,14 @@
}
.tool-error-text { color: #f87171; }
/* Log level highlighting */
.log-line { display: block; }
.log-line-debug { color: #94a3b8; }
.log-line-info { background-color: rgba(59, 130, 246, 0.08); }
.log-line-warning { background-color: rgba(234, 179, 8, 0.15); color: #fde68a; }
.log-line-error { background-color: rgba(239, 68, 68, 0.15); color: #fca5a5; }
.log-line-critical { background-color: rgba(239, 68, 68, 0.35); color: #ff4444; font-weight: bold; }
/* Tool failed state */
.agent-tool-step.tool-failed .tool-name { color: #f87171; }

View File

@@ -4022,6 +4022,51 @@ function loadTasksView() {
// =====================================================================
let logEventSource = null;
function logLevelClass(line) {
if (/\[CRITICAL\]/.test(line)) return 'log-line-critical';
if (/\[ERROR\]/.test(line)) return 'log-line-error';
if (/\[WARNING\]/.test(line)) return 'log-line-warning';
if (/\[INFO\]/.test(line)) return 'log-line-info';
if (/\[DEBUG\]/.test(line)) return 'log-line-debug';
return '';
}
function getHiddenLevels() {
const hidden = new Set();
document.querySelectorAll('.log-filter-cb').forEach(function(cb) {
if (!cb.checked) hidden.add('log-line-' + cb.dataset.level);
});
return hidden;
}
function applyLogFilter() {
const hidden = getHiddenLevels();
document.querySelectorAll('#log-output .log-line').forEach(function(span) {
const level = span.classList[1] || '';
span.style.display = hidden.has(level) ? 'none' : '';
});
}
function appendLogLines(output, text) {
const hidden = getHiddenLevels();
let lastLevelClass = '';
const lines = text.split('\n');
lines.forEach(function(line, i) {
if (i === lines.length - 1 && line === '') return;
const span = document.createElement('span');
const levelClass = logLevelClass(line) || lastLevelClass;
if (logLevelClass(line)) lastLevelClass = levelClass;
span.className = 'log-line ' + levelClass;
span.textContent = line + '\n';
if (hidden.has(levelClass)) span.style.display = 'none';
output.appendChild(span);
});
}
document.addEventListener('change', function(e) {
if (e.target.classList.contains('log-filter-cb')) applyLogFilter();
});
function startLogStream() {
if (logEventSource) return;
const output = document.getElementById('log-output');
@@ -4033,10 +4078,11 @@ function startLogStream() {
try { item = JSON.parse(e.data); } catch (_) { return; }
if (item.type === 'init') {
output.textContent = item.content || '';
output.innerHTML = '';
appendLogLines(output, item.content || '');
output.scrollTop = output.scrollHeight;
} else if (item.type === 'line') {
output.textContent += item.content;
appendLogLines(output, item.content);
output.scrollTop = output.scrollHeight;
} else if (item.type === 'error') {
output.textContent = item.message || 'Error loading logs';