diff --git a/templates/index.html b/templates/index.html
index 918d2ee..edc3fad 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -2464,7 +2464,15 @@ async function fetchServices(){
state.services = data;
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();
@@ -2498,21 +2506,6 @@ async function sendSnapshot(id){
const o = state.open[id];
if (!o){ alert('not open'); return; }
- // Получаем текст логов из современного интерфейса или из 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 token = localStorage.getItem('access_token');
if (!token) {
console.error('No access token found');
@@ -2520,28 +2513,108 @@ async function sendSnapshot(id){
return;
}
- const payload = {container_id: id, service: o.serviceName || id, content: text};
- 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';
+ 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;
}
- console.error('Snapshot failed:', res.status, res.statusText);
- alert('snapshot failed');
- return;
+
+ } else {
+ // Обычный режим просмотра
+ 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 serviceName = o.serviceName || id;
+ const payload = {container_id: id, service: serviceName, content: text};
+
+ 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:', 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();
}
- const js = await res.json();
- const a = document.createElement('a');
- a.href = js.url; a.download = js.file; a.click();
}
function openWs(svc, panel){
@@ -3926,8 +3999,18 @@ async function refreshLogsAndCounters() {
// Обновляем мультипросмотр
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 соединения для всех выбранных контейнеров
state.selectedContainers.forEach(containerId => {
@@ -3938,20 +4021,19 @@ async function refreshLogsAndCounters() {
}
});
- // Очищаем логи в мультипросмотре
- state.selectedContainers.forEach(containerId => {
- const multiViewLog = document.querySelector(`.multi-view-log[data-container-id="${containerId}"]`);
- if (multiViewLog) {
- multiViewLog.textContent = 'Refreshing...';
- }
- });
+ // Пересчитываем счетчики на основе отображаемых логов
+ setTimeout(() => {
+ recalculateMultiViewCounters();
+ }, 1000); // Небольшая задержка для завершения переподключения
} else if (state.current) {
// Обычный режим просмотра
console.log('Refreshing logs and counters for:', state.current.id);
- // Пересчитываем счетчики на основе отображаемых логов
- recalculateCounters();
+ // Очищаем логи перед обновлением
+ if (els.logContent) {
+ els.logContent.textContent = 'Refreshing...';
+ }
// Перезапускаем WebSocket соединение для получения свежих логов
const currentId = state.current.id;
@@ -3969,6 +4051,12 @@ async function refreshLogsAndCounters() {
cleanDuplicateLines(els.logContent);
}
}
+
+ // Пересчитываем счетчики на основе отображаемых логов
+ setTimeout(() => {
+ recalculateCounters();
+ }, 1000); // Небольшая задержка для завершения переподключения
+
} else {
console.log('No container selected');
}
@@ -4022,8 +4110,33 @@ els.refreshBtn.onclick = async () => {
console.log('Refreshing services...');
await fetchServices();
- // Если есть текущий контейнер, перезапускаем его WebSocket соединение
- if (state.current) {
+ if (state.multiViewMode && state.selectedContainers.length > 0) {
+ // В 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);
const currentId = state.current.id;
@@ -4339,7 +4452,11 @@ document.addEventListener('DOMContentLoaded', () => {
});
if (els.snapshotBtn) {
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);
} else {
alert('No container selected');