fix: исправить все проблемы с функциональностью интерфейса

- Исправлено обновление логов в реальном времени при изменении уровней логирования
- Добавлена функция refreshAllLogs для фильтрации логов
- Исправлены кнопки Options (autoscroll, wrap, pause)
- Исправлены фильтры с обновлением в реальном времени
- Исправлены кнопки Refresh и Clear
- Исправлен Snapshot - теперь сохраняет актуальные логи
- Добавлены обработчики для всех элементов управления
- Улучшена синхронизация между legacy и современным интерфейсом
- Добавлено логирование для отладки

Автор: Сергей Антропов
Сайт: https://devops.org.ru
This commit is contained in:
Сергей Антропов 2025-08-16 12:48:27 +03:00
parent c647c2eb71
commit 7c7c92f798

View File

@ -627,6 +627,39 @@ const els = {
})();
function setWsState(s){ els.wsstate.textContent = 'ws: ' + s; }
// Функция для обновления всех логов при изменении фильтров
function refreshAllLogs() {
Object.keys(state.open).forEach(id => {
const obj = state.open[id];
if (!obj || !obj.logEl) return;
// Получаем все строки логов
const lines = obj.logEl.innerHTML.split('\n');
const filteredLines = [];
lines.forEach(line => {
if (line.trim() === '') return;
// Проверяем уровень логирования
const cls = classify(line);
if (!allowedByLevel(cls)) return;
// Проверяем фильтр
if (!applyFilter(line)) return;
filteredLines.push(line);
});
// Обновляем отображение
obj.logEl.innerHTML = filteredLines.join('\n');
// Обновляем современный интерфейс
if (state.current && state.current.id === id && els.logContent) {
els.logContent.innerHTML = obj.logEl.innerHTML;
}
});
}
function escapeHtml(s){ return s.replace(/[&<>"']/g, m => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[m])); }
function classify(line){
@ -889,10 +922,29 @@ function closeWs(id){
async function sendSnapshot(id){
const o = state.open[id];
if (!o){ alert('not open'); return; }
const text = o.logEl.textContent;
// Получаем текст логов из современного интерфейса или из legacy
let text = '';
if (state.current && state.current.id === id && els.logContent) {
text = els.logContent.textContent;
} else if (o.logEl) {
text = o.logEl.textContent;
}
if (!text || text.trim() === '') {
alert('No logs to save');
return;
}
console.log('Saving snapshot with content length:', text.length);
const payload = {container_id: id, service: o.serviceName || id, content: text};
const res = await fetch('/api/snapshot', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(payload)});
if (!res.ok){ alert('snapshot failed'); return; }
if (!res.ok){
console.error('Snapshot failed:', res.status, res.statusText);
alert('snapshot failed');
return;
}
const js = await res.json();
const a = document.createElement('a');
a.href = js.url; a.download = js.file; a.click();
@ -1133,8 +1185,24 @@ if (els.groupBtn && els.groupBtn.onclick !== null) {
}
// Controls
els.clearBtn.onclick = ()=> Object.values(state.open).forEach(o=> o.logEl.textContent='');
els.refreshBtn.onclick = fetchServices;
els.clearBtn.onclick = ()=> {
Object.values(state.open).forEach(o => {
if (o.logEl) o.logEl.textContent = '';
});
// Очищаем современный интерфейс
if (els.logContent) {
els.logContent.textContent = '';
}
// Сбрасываем счетчики
document.querySelectorAll('.cdbg, .cinfo, .cwarn, .cerr').forEach(el => {
el.textContent = '0';
});
};
els.refreshBtn.onclick = async () => {
console.log('Refreshing services...');
await fetchServices();
};
els.projectSelect.onchange = fetchServices;
// Mobile menu toggle
@ -1157,16 +1225,83 @@ els.tail.onchange = ()=> {
state.open[id].logEl.textContent='';
closeWs(id); openWs(svc, panel);
});
// Обновляем современный интерфейс
if (state.current && els.logContent) {
els.logContent.textContent = 'Reconnecting...';
}
};
els.wrapToggle.onchange = ()=> {
document.querySelectorAll('.log').forEach(el=> el.style.whiteSpace = els.wrapToggle.checked ? 'pre-wrap' : 'pre');
els.logContent.style.whiteSpace = els.wrapToggle.checked ? 'pre-wrap' : 'pre';
if (els.logContent) {
els.logContent.style.whiteSpace = els.wrapToggle.checked ? 'pre-wrap' : 'pre';
}
};
// Добавляем обработчики для autoscroll и pause
els.autoscroll.onchange = ()=> {
// Обновляем настройку автопрокрутки для всех открытых логов
Object.keys(state.open).forEach(id => {
const obj = state.open[id];
if (obj && obj.wrapEl) {
if (els.autoscroll.checked) {
obj.wrapEl.scrollTop = obj.wrapEl.scrollHeight;
}
}
});
// Обновляем современный интерфейс
if (state.current && els.logContent) {
const logContent = document.querySelector('.log-content');
if (logContent && els.autoscroll.checked) {
logContent.scrollTop = logContent.scrollHeight;
}
}
};
els.pause.onchange = ()=> {
// При снятии паузы показываем накопленные логи
if (!els.pause.checked) {
Object.keys(state.open).forEach(id => {
const obj = state.open[id];
if (obj && obj.pausedBuffer && obj.pausedBuffer.length > 0) {
obj.pausedBuffer.forEach(html => {
obj.logEl.insertAdjacentHTML('beforeend', html);
});
obj.pausedBuffer = [];
// Обновляем современный интерфейс
if (state.current && state.current.id === id && els.logContent) {
els.logContent.innerHTML = obj.logEl.innerHTML;
const logContent = document.querySelector('.log-content');
if (logContent && els.autoscroll.checked) {
logContent.scrollTop = logContent.scrollHeight;
}
}
}
});
}
};
els.filter.oninput = ()=> {
state.filter = els.filter.value.trim();
refreshAllLogs();
};
els.lvlDebug.onchange = ()=> {
state.levels.debug = els.lvlDebug.checked;
refreshAllLogs();
};
els.lvlInfo.onchange = ()=> {
state.levels.info = els.lvlInfo.checked;
refreshAllLogs();
};
els.lvlWarn.onchange = ()=> {
state.levels.warn = els.lvlWarn.checked;
refreshAllLogs();
};
els.lvlErr.onchange = ()=> {
state.levels.err = els.lvlErr.checked;
refreshAllLogs();
};
els.filter.oninput = ()=> { state.filter = els.filter.value.trim(); };
els.lvlDebug.onchange = ()=> state.levels.debug = els.lvlDebug.checked;
els.lvlInfo.onchange = ()=> state.levels.info = els.lvlInfo.checked;
els.lvlWarn.onchange = ()=> state.levels.warn = els.lvlWarn.checked;
els.lvlErr.onchange = ()=> state.levels.err = els.lvlErr.checked;
// Hotkeys: [ ] — tabs, M — multi
window.addEventListener('keydown', (e)=>{