diff --git a/templates/index.html b/templates/index.html index bd72d5d..1fcf188 100644 --- a/templates/index.html +++ b/templates/index.html @@ -2148,6 +2148,9 @@ async function setupMultiView() { }); console.log(`setupMultiView: Multi-view setup completed for ${state.selectedContainers.length} containers`); + + // Обновляем счетчики для multi view + await updateMultiViewCounters(); } function createMultiViewPanel(service) { @@ -2181,6 +2184,8 @@ function createMultiViewPanel(service) { function openMultiViewWs(service) { const containerId = service.id; console.log(`openMultiViewWs: Starting WebSocket setup for ${service.name} (${containerId})`); + console.log(`openMultiViewWs: Current multiViewMode: ${state.multiViewMode}`); + console.log(`openMultiViewWs: Selected containers: ${state.selectedContainers.join(', ')}`); // Закрываем существующее соединение closeWs(containerId); @@ -2379,6 +2384,9 @@ async function sendSnapshot(id){ function openWs(svc, panel){ const id = svc.id; + console.log(`openWs: Called for ${svc.name} (${id}) in multiViewMode: ${state.multiViewMode}`); + console.log(`openWs: Selected containers: ${state.selectedContainers.join(', ')}`); + const logEl = panel.querySelector('.log'); const wrapEl = panel.querySelector('.logwrap'); @@ -2494,15 +2502,41 @@ function handleLine(id, line){ const multiViewLog = document.querySelector(`.multi-view-log[data-container-id="${id}"]`); if (multiViewLog) { if (shouldShow) { + // Применяем ограничение tail lines в multi view + const tailLines = parseInt(els.tail.value) || 50; + + // Добавляем новую строку multiViewLog.insertAdjacentHTML('beforeend', html); + + // Ограничиваем количество отображаемых строк + const logLines = Array.from(multiViewLog.querySelectorAll('.line')); + if (logLines.length > tailLines) { + // Удаляем лишние строки с начала + const linesToRemove = logLines.length - tailLines; + console.log(`handleLine: Trimming ${linesToRemove} lines from container ${id} (tail: ${tailLines})`); + + // Удаляем первые N строк + logLines.slice(0, linesToRemove).forEach(line => { + line.remove(); + }); + } + if (els.autoscroll && els.autoscroll.checked) { multiViewLog.scrollTop = multiViewLog.scrollHeight; } - console.log(`handleLine: Updated multi-view for container ${id}, log element found: true`); + console.log(`handleLine: Updated multi-view for container ${id}, log element found: true, tail lines: ${tailLines}`); } } else { console.error(`handleLine: Multi-view log element not found for container ${id}`); } + + // Обновляем счетчики в multi view периодически (каждые 10 строк) + if (!state.multiViewCounterUpdateTimer) { + state.multiViewCounterUpdateTimer = setTimeout(() => { + updateMultiViewCounters(); + state.multiViewCounterUpdateTimer = null; + }, 1000); // Обновляем каждую секунду + } } } @@ -2794,6 +2828,61 @@ async function updateCounters(containerId) { } } +// Функция для обновления счетчиков в multi view (суммирует статистику всех контейнеров) +async function updateMultiViewCounters() { + if (!state.multiViewMode || state.selectedContainers.length === 0) { + return; + } + + try { + console.log('Updating multi-view counters for containers:', state.selectedContainers); + + // Суммируем статистику всех выбранных контейнеров + let totalDebug = 0; + let totalInfo = 0; + let totalWarn = 0; + let totalError = 0; + + // Получаем статистику для каждого контейнера + for (const containerId of state.selectedContainers) { + try { + const response = await fetch(`/api/logs/stats/${containerId}`); + if (response.ok) { + const stats = await response.json(); + totalDebug += stats.debug || 0; + totalInfo += stats.info || 0; + totalWarn += stats.warn || 0; + totalError += stats.error || 0; + } + } catch (error) { + console.error(`Error fetching stats for container ${containerId}:`, error); + } + } + + // Обновляем счетчики в интерфейсе + const cdbg = document.querySelector('.cdbg'); + const cinfo = document.querySelector('.cinfo'); + const cwarn = document.querySelector('.cwarn'); + const cerr = document.querySelector('.cerr'); + + if (cdbg) cdbg.textContent = totalDebug; + if (cinfo) cinfo.textContent = totalInfo; + if (cwarn) cwarn.textContent = totalWarn; + if (cerr) cerr.textContent = totalError; + + console.log('Multi-view counters updated:', { totalDebug, totalInfo, totalWarn, totalError }); + + // Обновляем видимость счетчиков + updateCounterVisibility(); + + // Добавляем обработчики для счетчиков + addCounterClickHandlers(); + + } catch (error) { + console.error('Error updating multi-view counters:', error); + } +} + // Функция для обновления видимости счетчиков function updateCounterVisibility() { const debugBtn = document.querySelector('.debug-btn'); @@ -2821,10 +2910,8 @@ async function refreshLogsAndCounters() { // Обновляем мультипросмотр console.log('Refreshing multi-view for containers:', state.selectedContainers); - // Обновляем счетчики для всех выбранных контейнеров - for (const containerId of state.selectedContainers) { - await updateCounters(containerId); - } + // Обновляем счетчики для всех выбранных контейнеров (суммируем статистику) + await updateMultiViewCounters(); // Перезапускаем WebSocket соединения для всех выбранных контейнеров state.selectedContainers.forEach(containerId => { @@ -3203,10 +3290,20 @@ if (els.tail) { Object.keys(state.open).forEach(id=>{ const svc = state.services.find(s=> s.id===id); if (!svc) return; - const panel = els.grid.querySelector(`.panel[data-cid="${id}"]`); - if (!panel) return; - state.open[id].logEl.textContent=''; - closeWs(id); openWs(svc, panel); + + // В multi view режиме используем openMultiViewWs + if (state.multiViewMode && state.selectedContainers.includes(id)) { + console.log(`Refresh: Using openMultiViewWs for ${svc.name} in multi view mode`); + closeWs(id); + openMultiViewWs(svc); + } else { + // В обычном режиме используем openWs + const panel = els.grid.querySelector(`.panel[data-cid="${id}"]`); + if (!panel) return; + state.open[id].logEl.textContent=''; + closeWs(id); + openWs(svc, panel); + } }); // Обновляем современный интерфейс @@ -3407,6 +3504,64 @@ window.addEventListener('keydown', async (e)=>{ const containerId = e.target.getAttribute('data-container-id'); toggleContainerSelection(containerId); } + + // Обработчик изменения tail lines + if (e.target.id === 'tail') { + console.log('Tail lines changed to:', e.target.value); + if (state.multiViewMode) { + // В multi view применяем новое ограничение к уже отображаемым логам + const tailLines = parseInt(e.target.value) || 50; + console.log(`Applying tail lines limit ${tailLines} to ${state.selectedContainers.length} containers:`, state.selectedContainers); + + // Проверяем все элементы multi-view-log на странице + const allMultiViewLogs = document.querySelectorAll('.multi-view-log'); + console.log(`Found ${allMultiViewLogs.length} multi-view-log elements on page:`, Array.from(allMultiViewLogs).map(el => el.getAttribute('data-container-id'))); + + state.selectedContainers.forEach(containerId => { + console.log(`Processing container ${containerId}...`); + + // Ищем элемент несколькими способами + let multiViewLog = document.querySelector(`.multi-view-log[data-container-id="${containerId}"]`); + + if (!multiViewLog) { + console.warn(`Container ${containerId} not found with data-container-id, trying alternative search...`); + // Попробуем найти по другому селектору + multiViewLog = document.querySelector(`[data-container-id="${containerId}"]`); + } + + if (multiViewLog) { + console.log(`Found multi-view-log for container ${containerId}, current lines:`, multiViewLog.querySelectorAll('.line').length); + + // Получаем все строки логов + const logLines = Array.from(multiViewLog.querySelectorAll('.line')); + console.log(`Container ${containerId}: ${logLines.length} log lines found`); + + if (logLines.length > tailLines) { + // Удаляем лишние строки с начала + const linesToRemove = logLines.length - tailLines; + console.log(`Removing ${linesToRemove} lines from container ${containerId}`); + + // Удаляем первые N строк + logLines.slice(0, linesToRemove).forEach(line => { + line.remove(); + }); + + const remainingLines = multiViewLog.querySelectorAll('.line').length; + console.log(`Container ${containerId} now has ${remainingLines} lines after trimming`); + } else { + console.log(`Container ${containerId} has ${logLines.length} lines, no trimming needed (limit: ${tailLines})`); + } + } else { + console.error(`Multi-view log element not found for container ${containerId}`); + console.error(`Available multi-view-log elements:`, Array.from(document.querySelectorAll('.multi-view-log')).map(el => ({ + containerId: el.getAttribute('data-container-id'), + className: el.className, + parent: el.parentElement?.className + }))); + } + }); + } + } }); // Добавляем обработчики кликов на label чекбоксов