Исправлены проблемы с Multi View режимом: кнопка Download logs создает отдельные файлы, кнопка Refresh работает в обоих режимах

- Исправлена функция sendSnapshot для создания отдельных файлов в Multi View режиме
- Исправлена функция fetchServices для корректной работы кнопки Refresh в Multi View режиме
- Улучшена функция refreshLogsAndCounters для лучшей работы с Multi View
- Добавлена поддержка Multi View режима в обработчики кнопок
This commit is contained in:
Сергей Антропов 2025-08-17 19:00:38 +03:00
parent d0a4b57233
commit a490c41b76

View File

@ -2464,7 +2464,15 @@ async function fetchServices(){
state.services = data; state.services = data;
buildTabs(); buildTabs();
if (!state.current && state.services.length) await switchToSingle(state.services[0]);
// Проверяем, находимся ли мы в Multi View режиме
if (state.multiViewMode && state.selectedContainers.length > 0) {
// В Multi View режиме не переключаемся в single view
console.log('fetchServices: Staying in Multi View mode');
} else if (!state.current && state.services.length) {
// Только если не в Multi View режиме и нет текущего контейнера
await switchToSingle(state.services[0]);
}
// Добавляем обработчики для счетчиков после загрузки сервисов // Добавляем обработчики для счетчиков после загрузки сервисов
addCounterClickHandlers(); addCounterClickHandlers();
@ -2498,7 +2506,76 @@ async function sendSnapshot(id){
const o = state.open[id]; const o = state.open[id];
if (!o){ alert('not open'); return; } if (!o){ alert('not open'); return; }
// Получаем текст логов из современного интерфейса или из legacy const token = localStorage.getItem('access_token');
if (!token) {
console.error('No access token found');
window.location.href = '/login';
return;
}
if (state.multiViewMode && state.selectedContainers.length > 0) {
// В Multi View режиме создаем отдельный файл для каждого контейнера
console.log('Creating snapshots for Multi View mode with containers:', state.selectedContainers);
let hasLogs = false;
// Создаем отдельный файл для каждого выбранного контейнера
for (const containerId of state.selectedContainers) {
const multiViewLog = document.querySelector(`.multi-view-log[data-container-id="${containerId}"]`);
if (multiViewLog && multiViewLog.textContent.trim()) {
const service = state.services.find(s => s.id === containerId);
const serviceName = service ? (service.service || service.name) : containerId;
const text = multiViewLog.textContent;
console.log(`Saving snapshot for ${serviceName} with content length:`, text.length);
const payload = {container_id: containerId, service: serviceName, content: text};
try {
const res = await fetch('/api/snapshot', {
method:'POST',
headers:{
'Content-Type':'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify(payload)
});
if (!res.ok){
if (res.status === 401) {
console.error('Unauthorized, redirecting to login');
window.location.href = '/login';
return;
}
console.error(`Snapshot failed for ${serviceName}:`, res.status, res.statusText);
alert(`snapshot failed for ${serviceName}`);
return;
}
const js = await res.json();
const a = document.createElement('a');
a.href = js.url; a.download = js.file; a.click();
hasLogs = true;
// Небольшая задержка между скачиваниями файлов
await new Promise(resolve => setTimeout(resolve, 100));
} catch (error) {
console.error(`Error saving snapshot for ${serviceName}:`, error);
alert(`Error saving snapshot for ${serviceName}`);
return;
}
}
}
if (!hasLogs) {
alert('No logs to save in Multi View mode');
return;
}
} else {
// Обычный режим просмотра
let text = ''; let text = '';
if (state.current && state.current.id === id && els.logContent) { if (state.current && state.current.id === id && els.logContent) {
text = els.logContent.textContent; text = els.logContent.textContent;
@ -2513,14 +2590,9 @@ async function sendSnapshot(id){
console.log('Saving snapshot with content length:', text.length); console.log('Saving snapshot with content length:', text.length);
const token = localStorage.getItem('access_token'); const serviceName = o.serviceName || id;
if (!token) { const payload = {container_id: id, service: serviceName, content: text};
console.error('No access token found');
window.location.href = '/login';
return;
}
const payload = {container_id: id, service: o.serviceName || id, content: text};
const res = await fetch('/api/snapshot', { const res = await fetch('/api/snapshot', {
method:'POST', method:'POST',
headers:{ headers:{
@ -2543,6 +2615,7 @@ async function sendSnapshot(id){
const a = document.createElement('a'); const a = document.createElement('a');
a.href = js.url; a.download = js.file; a.click(); a.href = js.url; a.download = js.file; a.click();
} }
}
function openWs(svc, panel){ function openWs(svc, panel){
const id = svc.id; const id = svc.id;
@ -3926,8 +3999,18 @@ async function refreshLogsAndCounters() {
// Обновляем мультипросмотр // Обновляем мультипросмотр
console.log('Refreshing multi-view for containers:', state.selectedContainers); console.log('Refreshing multi-view for containers:', state.selectedContainers);
// Пересчитываем счетчики на основе отображаемых логов // Очищаем логи в мультипросмотре перед обновлением
recalculateMultiViewCounters(); state.selectedContainers.forEach(containerId => {
const multiViewLog = document.querySelector(`.multi-view-log[data-container-id="${containerId}"]`);
if (multiViewLog) {
multiViewLog.textContent = 'Refreshing...';
}
// Очищаем буфер логов для мультипросмотра
const obj = state.open[containerId];
if (obj && obj.allLogs) {
obj.allLogs = [];
}
});
// Перезапускаем WebSocket соединения для всех выбранных контейнеров // Перезапускаем WebSocket соединения для всех выбранных контейнеров
state.selectedContainers.forEach(containerId => { state.selectedContainers.forEach(containerId => {
@ -3938,20 +4021,19 @@ async function refreshLogsAndCounters() {
} }
}); });
// Очищаем логи в мультипросмотре // Пересчитываем счетчики на основе отображаемых логов
state.selectedContainers.forEach(containerId => { setTimeout(() => {
const multiViewLog = document.querySelector(`.multi-view-log[data-container-id="${containerId}"]`); recalculateMultiViewCounters();
if (multiViewLog) { }, 1000); // Небольшая задержка для завершения переподключения
multiViewLog.textContent = 'Refreshing...';
}
});
} else if (state.current) { } else if (state.current) {
// Обычный режим просмотра // Обычный режим просмотра
console.log('Refreshing logs and counters for:', state.current.id); console.log('Refreshing logs and counters for:', state.current.id);
// Пересчитываем счетчики на основе отображаемых логов // Очищаем логи перед обновлением
recalculateCounters(); if (els.logContent) {
els.logContent.textContent = 'Refreshing...';
}
// Перезапускаем WebSocket соединение для получения свежих логов // Перезапускаем WebSocket соединение для получения свежих логов
const currentId = state.current.id; const currentId = state.current.id;
@ -3969,6 +4051,12 @@ async function refreshLogsAndCounters() {
cleanDuplicateLines(els.logContent); cleanDuplicateLines(els.logContent);
} }
} }
// Пересчитываем счетчики на основе отображаемых логов
setTimeout(() => {
recalculateCounters();
}, 1000); // Небольшая задержка для завершения переподключения
} else { } else {
console.log('No container selected'); console.log('No container selected');
} }
@ -4022,8 +4110,33 @@ els.refreshBtn.onclick = async () => {
console.log('Refreshing services...'); console.log('Refreshing services...');
await fetchServices(); await fetchServices();
// Если есть текущий контейнер, перезапускаем его WebSocket соединение if (state.multiViewMode && state.selectedContainers.length > 0) {
if (state.current) { // В Multi View режиме обновляем все выбранные контейнеры
console.log('Refreshing Multi View mode with containers:', state.selectedContainers);
// Закрываем все текущие соединения
state.selectedContainers.forEach(containerId => {
closeWs(containerId);
});
// Перезапускаем соединения для всех выбранных контейнеров
state.selectedContainers.forEach(containerId => {
const service = state.services.find(s => s.id === containerId);
if (service) {
openMultiViewWs(service);
}
});
// Очищаем логи в мультипросмотре
state.selectedContainers.forEach(containerId => {
const multiViewLog = document.querySelector(`.multi-view-log[data-container-id="${containerId}"]`);
if (multiViewLog) {
multiViewLog.textContent = 'Refreshing...';
}
});
} else if (state.current) {
// Обычный режим просмотра
console.log('Reconnecting to current container:', state.current.id); console.log('Reconnecting to current container:', state.current.id);
const currentId = state.current.id; const currentId = state.current.id;
@ -4339,7 +4452,11 @@ document.addEventListener('DOMContentLoaded', () => {
}); });
if (els.snapshotBtn) { if (els.snapshotBtn) {
els.snapshotBtn.onclick = ()=>{ els.snapshotBtn.onclick = ()=>{
if (state.current) { if (state.multiViewMode && state.selectedContainers.length > 0) {
// В Multi View режиме используем первый выбранный контейнер как ID для sendSnapshot
// Функция sendSnapshot сама определит, что нужно скачать логи всех контейнеров
sendSnapshot(state.selectedContainers[0]);
} else if (state.current) {
sendSnapshot(state.current.id); sendSnapshot(state.current.id);
} else { } else {
alert('No container selected'); alert('No container selected');