fix: исправить все проблемы с функциональностью интерфейса
- Исправлено обновление логов в реальном времени при изменении уровней логирования - Добавлена функция refreshAllLogs для фильтрации логов - Исправлены кнопки Options (autoscroll, wrap, pause) - Исправлены фильтры с обновлением в реальном времени - Исправлены кнопки Refresh и Clear - Исправлен Snapshot - теперь сохраняет актуальные логи - Добавлены обработчики для всех элементов управления - Улучшена синхронизация между legacy и современным интерфейсом - Добавлено логирование для отладки Автор: Сергей Антропов Сайт: https://devops.org.ru
This commit is contained in:
parent
c647c2eb71
commit
7c7c92f798
@ -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 => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[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)=>{
|
||||
|
Loading…
x
Reference in New Issue
Block a user