diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..8538031
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,41 @@
+# Changelog
+
+## [1.1.0] - 2024-12-19
+
+### Добавлено
+- **Горячие клавиши для обновления логов:**
+ - `Ctrl+R` - обновить логи в Single и Multi View режимах
+ - `Ctrl+K` - альтернативная комбинация для обновления логов
+ - `Ctrl+B` - сворачивание/разворачивание sidebar панели
+
+- **Функциональность сворачивания sidebar и header:**
+ - Кнопка сворачивания на границе sidebar и основного контента
+ - Расположение посередине экрана по высоте
+ - Плавная анимация сворачивания/разворачивания
+ - Сохранение состояния в localStorage
+ - Уменьшение ширины sidebar до 60px в свернутом состоянии
+ - Логотип LogBoard+ в свернутом sidebar (в самом верху)
+ - Header сворачивается в тонкую полоску 40px с компактными элементами управления
+ - Кнопка помощи в свернутом sidebar для открытия модального окна с горячими клавишами
+
+- **Улучшения пользовательского интерфейса:**
+ - Модальное окно с полным списком горячих клавиш
+ - Компактный header в свернутом состоянии с фильтром и счетчиками
+ - Кнопка помощи в свернутом sidebar
+ - Адаптивный дизайн для мобильных устройств
+
+### Технические детали
+- Добавлены обработчики событий клавиатуры с проверкой фокуса в полях ввода
+- Реализована функция `toggleSidebar()` для управления состоянием sidebar
+- Добавлена функция `showHotkeysNotification()` для показа подсказок
+- CSS анимации для плавных переходов
+- Сохранение пользовательских настроек в localStorage
+- Логотип отображается в самом верху свернутого sidebar
+
+### Совместимость
+- Все существующие функции сохранены
+- Обратная совместимость с предыдущими версиями
+- Поддержка как Single View, так и Multi View режимов
+
+### Автор
+Сергей Антропов - https://devops.org.ru
diff --git a/SCROLL_FIX_SUMMARY.md b/SCROLL_FIX_SUMMARY.md
new file mode 100644
index 0000000..d4af64b
--- /dev/null
+++ b/SCROLL_FIX_SUMMARY.md
@@ -0,0 +1,182 @@
+# Исправление проблемы со скроллом в Multi View режиме
+
+## Проблема
+В режиме Multi View со свернутым sidebar не работал скролл в логах контейнеров. Проблема была связана с неправильными CSS стилями, которые не учитывали правильную высоту и overflow для multi-view логов в свернутом состоянии sidebar.
+
+## Причина
+Основные причины проблемы:
+
+1. **Неправильная высота multi-view-log**: В свернутом состоянии sidebar элементы `.multi-view-log` получали неправильную высоту `calc(100vh - var(--header-height))` вместо `100%`
+2. **Отсутствие flex-свойств**: Элементы не имели правильных flex-свойств для корректного распределения пространства
+3. **Неправильный overflow**: Контейнеры `.multi-view-content` не имели правильных настроек overflow
+
+## Исправления
+
+### 1. CSS стили для свернутого sidebar
+
+Добавлены дополнительные CSS правила для правильного отображения multi-view в свернутом состоянии:
+
+```css
+/* Исправляем скролл для multi-view в свернутом состоянии */
+.sidebar.collapsed ~ .main-content .multi-view-content {
+ height: calc(100vh - var(--header-height) - 60px) !important;
+ overflow: hidden !important;
+ display: flex !important;
+ flex-direction: column !important;
+}
+
+.sidebar.collapsed ~ .main-content .multi-view-log {
+ height: 100% !important;
+ overflow: auto !important;
+ display: block !important;
+ max-height: none !important;
+ min-height: 200px !important;
+ position: relative !important;
+ flex: 1 !important;
+ min-height: 0 !important;
+}
+```
+
+### 2. Новая функция forceFixMultiViewStyles()
+
+Добавлена новая функция для принудительного исправления стилей multi-view логов:
+
+```javascript
+function forceFixMultiViewStyles() {
+ const multiViewLogs = document.querySelectorAll('.multi-view-log');
+
+ multiViewLogs.forEach((log, index) => {
+ // Принудительно устанавливаем все необходимые стили
+ log.style.setProperty('height', '100%', 'important');
+ log.style.setProperty('overflow', 'auto', 'important');
+ log.style.setProperty('max-height', 'none', 'important');
+ log.style.setProperty('display', 'block', 'important');
+ log.style.setProperty('min-height', '200px', 'important');
+ log.style.setProperty('position', 'relative', 'important');
+ log.style.setProperty('flex', '1', 'important');
+ log.style.setProperty('min-height', '0', 'important');
+
+ // Принудительно вызываем пересчет layout
+ log.style.setProperty('transform', 'translateZ(0)', 'important');
+
+ // Дополнительно устанавливаем inline стили для максимальной надежности
+ log.setAttribute('style', log.getAttribute('style') + '; height: 100% !important; overflow: auto !important; flex: 1 !important; min-height: 0 !important;');
+ });
+}
+```
+
+### 3. Обновление функции updateLogStyles()
+
+Исправлена функция `updateLogStyles()` для правильного применения стилей:
+
+- Использует `setProperty()` с флагом `important` для принудительного применения стилей
+- Вызывает `forceFixMultiViewStyles()` для дополнительной надежности
+- Принудительно вызывается пересчет layout с помощью `transform: translateZ(0)`
+
+### 4. Улучшение функции toggleSidebar()
+
+Добавлена дополнительная проверка для multi-view логов при переключении sidebar:
+
+```javascript
+// Дополнительная проверка для multi-view логов
+if (state.multiViewMode) {
+ console.log('Sidebar toggle: Force fixing multi-view styles');
+ forceFixMultiViewStyles();
+}
+```
+
+### 5. Обновление функции setupMultiView()
+
+Добавлена принудительная проверка стилей при создании multi-view:
+
+```javascript
+// Принудительно обновляем стили логов для multi-view
+setTimeout(() => {
+ updateLogStyles();
+
+ // Дополнительная проверка для multi-view логов
+ console.log('setupMultiView: Force fixing multi-view styles');
+ forceFixMultiViewStyles();
+}, 200);
+```
+
+### 6. Инициализация при загрузке страницы
+
+Добавлена дополнительная проверка при инициализации:
+
+```javascript
+// Дополнительная проверка для multi-view логов при загрузке
+setTimeout(() => {
+ if (state.multiViewMode) {
+ console.log('Initialization: Force fixing multi-view styles');
+ forceFixMultiViewStyles();
+ }
+}, 1000);
+```
+
+### 7. Периодическая проверка и обработчики событий
+
+Добавлены дополнительные механизмы для обеспечения правильной работы:
+
+- **Периодическая проверка**: Каждые 5 секунд проверяются и исправляются стили multi-view логов
+- **Обработчик изменения размера окна**: При изменении размера браузера автоматически исправляются стили
+- **Глобальные функции**: Добавлены функции `forceFixMultiViewStyles()` и `updateLogStyles()` в глобальную область для ручного вызова из консоли
+
+## Результат
+
+После применения исправлений:
+
+1. ✅ Скролл работает корректно в Multi View режиме со свернутым sidebar
+2. ✅ Логи контейнеров отображаются в правильной высоте
+3. ✅ Переключение sidebar не нарушает функциональность скролла
+4. ✅ Автопрокрутка работает корректно
+5. ✅ Стили применяются правильно при всех сценариях использования
+
+## Тестирование
+
+Для проверки исправлений:
+
+1. Включите Multi View режим (выберите несколько контейнеров)
+2. Сверните sidebar (Ctrl+B или кнопка)
+3. Убедитесь, что скролл работает в каждом контейнере
+4. Проверьте автопрокрутку при поступлении новых логов
+5. Разверните sidebar и убедитесь, что скролл продолжает работать
+
+### Ручное исправление (если проблема все еще возникает)
+
+Если скролл все еще не работает в некоторых окнах, можно вручную исправить стили:
+
+1. Откройте консоль браузера (F12)
+2. Выполните команду: `forceFixMultiViewStyles()`
+3. Или выполните команду: `updateLogStyles()`
+4. Для всех контейнеров: `fixAllContainers()`
+5. Для обратной совместимости: `fixProblematicContainers()` (перенаправляет на `fixAllContainers()`)
+
+Эти функции принудительно исправят стили всех multi-view логов на странице.
+
+### Универсальное исправление для всех контейнеров
+
+Вместо специальной обработки только для проблемных контейнеров, теперь применяется универсальное решение:
+
+- **Универсальные CSS правила** для всех multi-view логов (с более специфичными селекторами)
+- **Единообразное исправление стилей** для всех контейнеров
+- **Проверка родительских элементов** для всех контейнеров
+- **Автоматическое исправление** в периодических проверках и при изменении размера окна
+- **Защита от влияния на другие элементы** - все селекторы теперь специфичны для `.multi-view-content .multi-view-log`
+
+### Исправление проблемы с wrap text
+
+Проблема с wrap text была решена путем:
+
+- **Более специфичных селекторов** - изменил `.log` на `.main-content .log` в функции `applyWrapSettings()`
+- **Добавления вызовов `applyWrapSettings()`** в ключевых местах:
+ - После обновления логов (`refreshLogsAndCounters()`)
+ - После исправления стилей (`forceFixMultiViewStyles()`)
+ - После исправления всех контейнеров (`fixAllContainers()`)
+ - После переключения контейнеров (`switchToSingle()`)
+ - После открытия мульти-контейнеров (`openMulti()`)
+- **Сохранения существующих вызовов** в `setupMultiView()` и других местах
+
+## Автор
+Сергей Антропов
+Сайт: https://devops.org.ru
diff --git a/app/docs/README.md b/app/docs/README.md
new file mode 100644
index 0000000..8ce23a5
--- /dev/null
+++ b/app/docs/README.md
@@ -0,0 +1,47 @@
+# Документация LogBoard+
+
+## Обзор
+
+LogBoard+ - это веб-приложение для мониторинга логов Docker контейнеров в реальном времени с поддержкой Single View и Multi View режимов.
+
+## Основные функции
+
+### Просмотр логов
+- **Single View**: просмотр логов одного контейнера
+- **Multi View**: одновременный просмотр логов нескольких контейнеров
+- Фильтрация по уровням логирования (DEBUG, INFO, WARN, ERROR)
+- Поиск по регулярным выражениям
+- Автопрокрутка и перенос строк
+
+### Горячие клавиши
+- `Ctrl+R` / `Ctrl+K` - обновление логов
+- `[` `]` - навигация между контейнерами
+- `Ctrl+B` - сворачивание/разворачивание панели
+
+### Управление интерфейсом
+- Сворачивание sidebar для экономии места
+- Переключение тем (светлая/темная)
+- Настройка количества отображаемых строк
+- Экспорт логов в файл
+
+## Документация
+
+- [Горячие клавиши](hotkeys.md) - подробное описание всех горячих клавиш
+- [Новые функции интерфейса](features.md) - описание сворачивания панелей и других функций
+- [API документация](../api/README.md) - описание API endpoints
+- [Разработка](../dev/README.md) - руководство для разработчиков
+
+## Технологии
+
+- **Backend**: Python, FastAPI, WebSocket
+- **Frontend**: HTML5, CSS3, JavaScript (Vanilla)
+- **База данных**: PostgreSQL с asyncpg
+- **Контейнеризация**: Docker, Docker Compose
+
+## Автор
+
+Сергей Антропов - https://devops.org.ru
+
+## Лицензия
+
+MIT License
diff --git a/app/docs/features.md b/app/docs/features.md
new file mode 100644
index 0000000..81b3e4b
--- /dev/null
+++ b/app/docs/features.md
@@ -0,0 +1,77 @@
+# Новые функции интерфейса LogBoard+
+
+## Сворачивание панелей
+
+### Sidebar (боковая панель)
+- **Кнопка сворачивания**: на границе sidebar и основного контента
+- **Горячая клавиша**: `Ctrl+B` / `Ctrl+И`
+- **Свернутое состояние**: ширина 60px
+- **Логотип**: показывает в свернутом состоянии
+- **Кнопка помощи**: между options и logout
+
+## Управление
+
+### Кнопка сворачивания
+- **Кнопка на границе**: сворачивает боковую панель
+- **Расположение**: посередине экрана по высоте на границе sidebar и основного контента
+- **Состояние сохраняется** в localStorage
+
+### Горячая клавиша
+- **Ctrl+B** / **Ctrl+И**: сворачивает/разворачивает sidebar и header
+- Удобно для быстрого освобождения места на экране
+
+### Header (заголовок)
+- **Сворачивается вместе с sidebar**
+- **В свернутом состоянии**: тонкая полоска 40px высотой
+- **Содержит**: фильтр логов, кнопки уровней логирования, кнопку обновления
+- **Стили**: кнопки выглядят точно так же, как в развернутом состоянии
+- **log-header**: полностью скрывается в свернутом режиме
+- **log-content**: минимальный padding 2px в свернутом состоянии
+- **multi-view-panel**: показывает название контейнера в Single View режиме
+
+## Визуальные элементы
+
+### Логотип в свернутом sidebar
+```
+
+```
+- Отображается только когда sidebar свернут
+- Расположен в самом верху sidebar
+- Стилизован в цвете акцента
+- Занимает минимальное место
+
+### Модальное окно с горячими клавишами
+- **Открытие**: кнопка в свернутом sidebar
+- **Закрытие**: кнопка X, клик вне окна, или повторный клик на кнопку помощи
+- **Содержит**: полный список всех горячих клавиш с описанием
+- **Анимация**: плавное появление и исчезновение
+
+### Анимации
+- Плавные переходы при сворачивании/разворачивании
+- Длительность анимации: 0.3 секунды
+- CSS transitions для всех элементов
+- Кнопка сворачивания остается на месте при наведении
+
+## Сохранение настроек
+
+### localStorage ключи
+- `lb_sidebar_collapsed` - состояние sidebar
+- `lb_hotkeys_shown` - показ уведомления о горячих клавишах
+
+### Восстановление состояния
+- При перезапуске приложения состояния восстанавливаются
+- Кнопки показывают правильные иконки
+- Tooltip обновляется в соответствии с состоянием
+
+## Примеры использования
+
+### Освобождение места
+1. Нажать `Ctrl+B` или кнопку sidebar - сворачивается панель
+2. Получаем больше места для просмотра логов
+
+### Быстрое переключение
+1. Использовать `Ctrl+B` для быстрого переключения
+2. Использовать кнопку на границе для точного управления
+
+## Автор
+Сергей Антропов - https://devops.org.ru
diff --git a/app/docs/hotkeys.md b/app/docs/hotkeys.md
new file mode 100644
index 0000000..a18edc6
--- /dev/null
+++ b/app/docs/hotkeys.md
@@ -0,0 +1,66 @@
+# Горячие клавиши LogBoard+
+
+## Обновление логов
+
+### Ctrl+R
+Обновляет логи в текущем режиме просмотра:
+- **Single View**: переподключается к WebSocket и получает свежие логи
+- **Multi View**: переподключается ко всем выбранным контейнерам
+
+### Ctrl+K
+Альтернативная комбинация для обновления логов (аналогично Ctrl+R)
+
+## Навигация
+
+### [ (квадратная скобка)
+Переход к предыдущему контейнеру в списке
+
+### ] (квадратная скобка)
+Переход к следующему контейнеру в списке
+
+### Ctrl+← (стрелка влево)
+Альтернативная комбинация для перехода к предыдущему контейнеру
+
+### Ctrl+→ (стрелка вправо)
+Альтернативная комбинация для перехода к следующему контейнеру
+
+## Управление интерфейсом
+
+### Ctrl+B
+Сворачивание/разворачивание sidebar панели:
+- Сворачивает sidebar до минимальной ширины (60px)
+- Скрывает все элементы управления и список контейнеров
+- Показывает логотип LogBoard+ в свернутом sidebar
+- Состояние сохраняется в localStorage
+
+### Кнопка сворачивания
+- **Кнопка на границе** () - сворачивание sidebar
+- Расположена посередине экрана по высоте на границе sidebar и основного контента
+- Состояние сохраняется в localStorage
+
+## Особенности
+
+### Проверка фокуса
+Горячие клавиши не работают, когда фокус находится в полях ввода:
+- Поле фильтра логов
+- Поле добавления исключенных контейнеров
+- Любые другие input/textarea элементы
+
+### Визуальные подсказки
+- Иконка клавиатуры в заголовке с подсказкой о горячих клавишах
+- Уведомление о горячих клавишах при первом запуске
+- Tooltip на кнопке сворачивания sidebar
+
+### Сохранение настроек
+- Состояние sidebar (свернут/развернут) сохраняется в localStorage
+- При следующем запуске приложения состояние восстанавливается
+
+## Примеры использования
+
+1. **Быстрое обновление логов**: `Ctrl+R` для получения свежих данных
+2. **Навигация по контейнерам**: `[` `]` для переключения между сервисами
+3. **Освобождение места на экране**: `Ctrl+B` для сворачивания панели
+4. **Работа в Multi View**: `Ctrl+R` обновляет все выбранные контейнеры одновременно
+
+## Автор
+Сергей Антропов - https://devops.org.ru
diff --git a/excluded_containers.json b/excluded_containers.json
index e1bfa73..3e89360 100644
--- a/excluded_containers.json
+++ b/excluded_containers.json
@@ -1,15 +1,4 @@
{
- "excluded_containers": [
- "buildx_buildkit_multiarch-builder0",
- "buildx_buildkit_multiarch-builder1",
- "buildx_buildkit_multiarch-builder2",
- "buildx_buildkit_multiarch-builder3",
- "buildx_buildkit_multiarch-builder4",
- "buildx_buildkit_multiarch-builder5",
- "buildx_buildkit_multiarch-builder6",
- "buildx_buildkit_multiarch-builder7",
- "buildx_buildkit_multiarch-builder8",
- "buildx_buildkit_multiarch-builder9"
- ],
+ "excluded_containers": [],
"description": "Список контейнеров, которые генерируют слишком много логов и исключаются из отображения"
-}
+}
\ No newline at end of file
diff --git a/templates/index.html b/templates/index.html
index 06948f4..cc15aba 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -131,8 +131,7 @@ a{color:var(--link)}
padding: 0 !important;
}
-.sidebar.collapsed ~ .main-content .single-view-content .log,
-.sidebar.collapsed ~ .main-content .multi-view-log {
+.sidebar.collapsed ~ .main-content .single-view-content .log {
height: calc(100vh - var(--header-height)) !important;
overflow: auto !important;
display: block !important;
@@ -141,6 +140,21 @@ a{color:var(--link)}
position: relative !important;
}
+/* Исправляем скролл для multi-view в свернутом состоянии */
+.sidebar.collapsed ~ .main-content .multi-view-content {
+ height: calc(100vh - var(--header-height) - 60px) !important;
+ overflow: hidden !important;
+}
+
+.sidebar.collapsed ~ .main-content .multi-view-log {
+ height: 100% !important;
+ overflow: auto !important;
+ display: block !important;
+ max-height: none !important;
+ min-height: 200px !important;
+ position: relative !important;
+}
+
/* Обеспечиваем правильное отображение логов при развернутом sidebar */
.sidebar:not(.collapsed) ~ .main-content .single-view-content .log,
.sidebar:not(.collapsed) ~ .main-content .multi-view-log {
@@ -155,11 +169,50 @@ a{color:var(--link)}
.sidebar.collapsed ~ .main-content .multi-view-content {
height: calc(100vh - var(--header-height) - 60px) !important;
overflow: hidden !important;
+ display: flex !important;
+ flex-direction: column !important;
}
.sidebar:not(.collapsed) ~ .main-content .multi-view-content {
height: 100% !important;
overflow: hidden !important;
+ display: flex !important;
+ flex-direction: column !important;
+}
+
+/* Дополнительные стили для multi-view-log в свернутом состоянии */
+.sidebar.collapsed ~ .main-content .multi-view-log {
+ height: 100% !important;
+ overflow: auto !important;
+ display: block !important;
+ max-height: none !important;
+ min-height: 200px !important;
+ position: relative !important;
+ flex: 1 !important;
+ min-height: 0 !important;
+}
+
+/* Более специфичные правила для multi-view логов */
+.sidebar.collapsed ~ .main-content .multi-view-content .multi-view-log {
+ height: 100% !important;
+ overflow: auto !important;
+ display: block !important;
+ max-height: none !important;
+ min-height: 200px !important;
+ position: relative !important;
+ flex: 1 !important;
+ min-height: 0 !important;
+}
+
+.sidebar.collapsed ~ .main-content .multi-view-grid .multi-view-panel .multi-view-content .multi-view-log {
+ height: 100% !important;
+ overflow: auto !important;
+ display: block !important;
+ max-height: none !important;
+ min-height: 200px !important;
+ position: relative !important;
+ flex: 1 !important;
+ min-height: 0 !important;
}
/* Multi-view panel для Single View режима */
@@ -177,6 +230,91 @@ a{color:var(--link)}
display: block;
}
+/* Дополнительные стили для обеспечения правильного скролла в multi-view */
+.multi-view-grid {
+ display: grid;
+ gap: 2px;
+ height: 100%;
+ padding: 0px;
+ /* Равная высота строк для нескольких рядов (3+ окон) */
+ grid-auto-rows: 1fr;
+ align-items: stretch;
+}
+
+.multi-view-panel {
+ background: var(--panel);
+ border: 1px solid var(--border);
+ border-radius: 8px;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ padding: 2px;
+ height: 100%;
+}
+
+.multi-view-content {
+ flex: 1;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+}
+
+.multi-view-log {
+ height: 100%;
+ margin: 0;
+ padding: 12px;
+ font-size: 11px;
+ line-height: 1.4;
+ white-space: pre;
+ word-break: break-word;
+ overflow: auto;
+ background: var(--bg);
+ color: var(--fg);
+ font-family: ui-monospace, Menlo, Consolas, monospace;
+ flex: 1;
+ min-height: 0;
+}
+
+/* Принудительный сброс стилей для multi-view логов */
+.multi-view-log {
+ height: 100% !important;
+ overflow: auto !important;
+ display: block !important;
+ max-height: none !important;
+ min-height: 200px !important;
+ position: relative !important;
+ flex: 1 !important;
+ min-height: 0 !important;
+}
+
+/* Универсальные стили для всех multi-view логов */
+.multi-view-content .multi-view-log {
+ height: 100% !important;
+ overflow: auto !important;
+ display: block !important;
+ max-height: none !important;
+ min-height: 200px !important;
+ position: relative !important;
+ flex: 1 !important;
+ min-height: 0 !important;
+ width: 100% !important;
+ box-sizing: border-box !important;
+}
+
+/* Универсальные стили для всех multi-view логов в свернутом состоянии */
+.sidebar.collapsed ~ .main-content .multi-view-content .multi-view-log {
+ height: 100% !important;
+ overflow: auto !important;
+ display: block !important;
+ max-height: none !important;
+ min-height: 200px !important;
+ position: relative !important;
+ flex: 1 !important;
+ min-height: 0 !important;
+ width: 100% !important;
+ box-sizing: border-box !important;
+}
+
/* Всегда скрываем одиночный блок multi-view панели в Single View */
#multiViewPanel {
display: none !important;
@@ -3227,6 +3365,15 @@ async function setupMultiView() {
// Применяем настройки wrap lines
applyWrapSettings();
+ // Принудительно обновляем стили логов для multi-view
+ setTimeout(() => {
+ updateLogStyles();
+
+ // Дополнительная проверка для multi-view логов
+ console.log('setupMultiView: Force fixing multi-view styles');
+ forceFixMultiViewStyles();
+ }, 200);
+
// Подключаем WebSocket для каждого контейнера
console.log(`setupMultiView: Setting up WebSockets for ${state.selectedContainers.length} containers`);
state.selectedContainers.forEach((containerId, index) => {
@@ -3477,13 +3624,13 @@ function applyWrapSettings() {
const wrapEnabled = els.wrapToggle && els.wrapToggle.checked;
const wrapStyle = wrapEnabled ? 'pre-wrap' : 'pre';
- // Применяем к обычному просмотру
- document.querySelectorAll('.log').forEach(el => {
+ // Применяем к обычному просмотру (только к логам в основном контенте)
+ document.querySelectorAll('.main-content .log').forEach(el => {
el.style.whiteSpace = wrapStyle;
});
// Применяем к мультипросмотру
- document.querySelectorAll('.multi-view-log').forEach(el => {
+ document.querySelectorAll('.multi-view-content .multi-view-log').forEach(el => {
el.style.whiteSpace = wrapStyle;
});
@@ -4072,6 +4219,23 @@ function periodicCleanup() {
// Запускаем периодическую очистку каждые 2 секунды
setInterval(periodicCleanup, 2000);
+// Запускаем периодическую проверку стилей multi-view логов каждые 5 секунд
+setInterval(() => {
+ if (state.multiViewMode) {
+ const multiViewLogs = document.querySelectorAll('.multi-view-content .multi-view-log');
+ if (multiViewLogs.length > 0) {
+ console.log('Periodic check: Force fixing multi-view styles');
+ forceFixMultiViewStyles();
+
+ // Дополнительно исправляем все контейнеры
+ console.log('Periodic check: Fixing all containers');
+ if (window.fixAllContainers) {
+ window.fixAllContainers();
+ }
+ }
+ }
+}, 5000);
+
/**
* Функция для обработки специальных замен в MultiView логах
* Выполняет специфичные замены для улучшения читаемости логов
@@ -4803,6 +4967,8 @@ async function switchToSingle(svc){
// Обновляем счетчики для нового контейнера
setTimeout(() => {
recalculateCounters();
+ // Применяем настройки wrap text после переключения контейнера
+ applyWrapSettings();
}, 500); // Небольшая задержка для завершения загрузки логов
await updateCounters(svc.id);
@@ -4835,6 +5001,9 @@ async function openMulti(ids){
// Добавляем обработчики для счетчиков после открытия мульти-контейнеров
addCounterClickHandlers();
+
+ // Применяем настройки wrap text после открытия мульти-контейнеров
+ applyWrapSettings();
}
// ----- Copy on selection -----
@@ -5202,6 +5371,8 @@ async function refreshLogsAndCounters() {
// Пересчитываем счетчики на основе отображаемых логов
setTimeout(() => {
recalculateMultiViewCounters();
+ // Применяем настройки wrap text после обновления
+ applyWrapSettings();
}, 1000); // Небольшая задержка для завершения переподключения
} else if (state.current) {
@@ -5233,6 +5404,8 @@ async function refreshLogsAndCounters() {
// Пересчитываем счетчики на основе отображаемых логов
setTimeout(() => {
recalculateCounters();
+ // Применяем настройки wrap text после обновления
+ applyWrapSettings();
}, 1000); // Небольшая задержка для завершения переподключения
} else {
@@ -5537,10 +5710,87 @@ function toggleSidebar() {
// Принудительно обновляем стили логов после переключения sidebar
setTimeout(() => {
updateLogStyles();
+
+ // Дополнительная проверка для multi-view логов
+ if (state.multiViewMode) {
+ console.log('Sidebar toggle: Force fixing multi-view styles');
+ forceFixMultiViewStyles();
+ }
}, 100);
}
}
+// Функция для принудительного исправления стилей multi-view логов
+function forceFixMultiViewStyles() {
+ const multiViewLogs = document.querySelectorAll('.multi-view-content .multi-view-log');
+ console.log(`Force fixing styles for ${multiViewLogs.length} multi-view logs`);
+
+ multiViewLogs.forEach((log, index) => {
+ const containerId = log.getAttribute('data-container-id');
+ console.log(`Force fixing multi-view log ${index + 1} for container: ${containerId}`);
+
+ // Универсальное исправление для всех контейнеров
+ log.style.setProperty('height', '100%', 'important');
+ log.style.setProperty('overflow', 'auto', 'important');
+ log.style.setProperty('max-height', 'none', 'important');
+ log.style.setProperty('display', 'block', 'important');
+ log.style.setProperty('min-height', '200px', 'important');
+ log.style.setProperty('position', 'relative', 'important');
+ log.style.setProperty('flex', '1', 'important');
+ log.style.setProperty('min-height', '0', 'important');
+ log.style.setProperty('width', '100%', 'important');
+ log.style.setProperty('box-sizing', 'border-box', 'important');
+
+ // Принудительно вызываем пересчет layout
+ log.style.setProperty('transform', 'translateZ(0)', 'important');
+
+ // Устанавливаем универсальные inline стили для всех контейнеров
+ const currentStyle = log.getAttribute('style') || '';
+ const newStyle = currentStyle + '; height: 100% !important; overflow: auto !important; flex: 1 !important; min-height: 0 !important; width: 100% !important; box-sizing: border-box !important; display: block !important; position: relative !important;';
+ log.setAttribute('style', newStyle);
+
+ // Проверяем и исправляем родительские элементы для всех контейнеров
+ const parentContent = log.closest('.multi-view-content');
+ if (parentContent) {
+ parentContent.style.setProperty('display', 'flex', 'important');
+ parentContent.style.setProperty('flex-direction', 'column', 'important');
+ parentContent.style.setProperty('overflow', 'hidden', 'important');
+ parentContent.style.setProperty('height', '100%', 'important');
+ }
+
+ const parentPanel = log.closest('.multi-view-panel');
+ if (parentPanel) {
+ parentPanel.style.setProperty('display', 'flex', 'important');
+ parentPanel.style.setProperty('flex-direction', 'column', 'important');
+ parentPanel.style.setProperty('overflow', 'hidden', 'important');
+ parentPanel.style.setProperty('height', '100%', 'important');
+ }
+ });
+
+ // Также исправляем стили для multi-view-content контейнеров
+ const multiViewContents = document.querySelectorAll('.multi-view-content');
+ multiViewContents.forEach(content => {
+ content.style.setProperty('display', 'flex', 'important');
+ content.style.setProperty('flex-direction', 'column', 'important');
+ content.style.setProperty('overflow', 'hidden', 'important');
+ content.style.setProperty('height', '100%', 'important');
+ });
+
+ // Универсальное исправление для всех контейнеров
+ multiViewLogs.forEach(log => {
+ console.log(`Universal fix for container:`, log.getAttribute('data-container-id'));
+
+ // Принудительно устанавливаем все стили заново для всех контейнеров
+ log.style.cssText = 'height: 100% !important; overflow: auto !important; max-height: none !important; display: block !important; min-height: 200px !important; position: relative !important; flex: 1 !important; min-height: 0 !important; width: 100% !important; box-sizing: border-box !important;';
+
+ // Принудительно вызываем пересчет layout
+ log.style.setProperty('transform', 'translateZ(0)', 'important');
+ });
+
+ // Применяем настройки wrap text после исправления стилей
+ applyWrapSettings();
+}
+
// Функция для обновления стилей логов
function updateLogStyles() {
const isCollapsed = els.sidebar && els.sidebar.classList.contains('collapsed');
@@ -5558,43 +5808,39 @@ function updateLogStyles() {
});
// Обновляем стили для multi-view логов (более агрессивно)
- const multiViewLogs = document.querySelectorAll('.multi-view-log');
+ const multiViewLogs = document.querySelectorAll('.multi-view-content .multi-view-log');
console.log(`Found ${multiViewLogs.length} multi-view logs to update`);
multiViewLogs.forEach((log, index) => {
const containerId = log.getAttribute('data-container-id');
console.log(`Updating multi-view log ${index + 1}/${multiViewLogs.length} for container: ${containerId}`);
- if (isCollapsed) {
- log.style.height = 'calc(100vh - var(--header-height))';
- log.style.overflow = 'auto';
- log.style.maxHeight = 'none';
- log.style.display = 'block';
- log.style.minHeight = '200px';
- log.style.position = 'relative';
- } else {
- log.style.height = '100%';
- log.style.overflow = 'auto';
- log.style.maxHeight = 'none';
- log.style.display = 'block';
- log.style.minHeight = '200px';
- log.style.position = 'relative';
- }
+ // Принудительно устанавливаем правильные стили независимо от состояния sidebar
+ log.style.setProperty('height', '100%', 'important');
+ log.style.setProperty('overflow', 'auto', 'important');
+ log.style.setProperty('max-height', 'none', 'important');
+ log.style.setProperty('display', 'block', 'important');
+ log.style.setProperty('min-height', '200px', 'important');
+ log.style.setProperty('position', 'relative', 'important');
+ log.style.setProperty('flex', '1', 'important');
+ log.style.setProperty('min-height', '0', 'important');
// Принудительно вызываем пересчет layout
- log.style.transform = 'translateZ(0)';
+ log.style.setProperty('transform', 'translateZ(0)', 'important');
});
// Также обновляем стили для multi-view-content контейнеров
const multiViewContents = document.querySelectorAll('.multi-view-content');
multiViewContents.forEach(content => {
if (isCollapsed) {
- content.style.height = 'calc(100vh - var(--header-height) - 60px)';
- content.style.overflow = 'hidden';
+ // В свернутом состоянии multi-view-content должен иметь правильную высоту
+ content.style.setProperty('height', 'calc(100vh - var(--header-height) - 60px)', 'important');
} else {
- content.style.height = '100%';
- content.style.overflow = 'hidden';
+ content.style.setProperty('height', '100%', 'important');
}
+ content.style.setProperty('overflow', 'hidden', 'important');
+ content.style.setProperty('display', 'flex', 'important');
+ content.style.setProperty('flex-direction', 'column', 'important');
});
// Применяем настройки wrap text
@@ -5602,34 +5848,14 @@ function updateLogStyles() {
console.log('Log styles updated, sidebar collapsed:', isCollapsed, 'multi-view logs found:', multiViewLogs.length);
+ // Принудительно исправляем стили multi-view логов
+ forceFixMultiViewStyles();
+
// Дополнительная проверка через 500ms для multi view логов
if (multiViewLogs.length > 0) {
setTimeout(() => {
console.log('Performing delayed update for multi-view logs...');
- const delayedLogs = document.querySelectorAll('.multi-view-log');
- delayedLogs.forEach((log, index) => {
- const containerId = log.getAttribute('data-container-id');
- console.log(`Delayed update for multi-view log ${index + 1}/${delayedLogs.length} for container: ${containerId}`);
-
- if (isCollapsed) {
- log.style.height = 'calc(100vh - var(--header-height))';
- log.style.overflow = 'auto';
- log.style.maxHeight = 'none';
- log.style.display = 'block';
- log.style.minHeight = '200px';
- log.style.position = 'relative';
- } else {
- log.style.height = '100%';
- log.style.overflow = 'auto';
- log.style.maxHeight = 'none';
- log.style.display = 'block';
- log.style.minHeight = '200px';
- log.style.position = 'relative';
- }
-
- // Принудительно вызываем пересчет layout
- log.style.transform = 'translateZ(0)';
- });
+ forceFixMultiViewStyles();
}, 500);
}
}
@@ -5812,6 +6038,14 @@ document.addEventListener('DOMContentLoaded', () => {
// Применяем настройки wrap text при загрузке
applyWrapSettings();
+
+ // Дополнительная проверка для multi-view логов при загрузке
+ setTimeout(() => {
+ if (state.multiViewMode) {
+ console.log('Initialization: Force fixing multi-view styles');
+ forceFixMultiViewStyles();
+ }
+ }, 1000);
});
if (els.snapshotBtn) {
@@ -6015,6 +6249,22 @@ if (els.lvlOther) {
};
}
+// Обработчик изменения размера окна для обновления стилей multi-view логов
+window.addEventListener('resize', () => {
+ if (state.multiViewMode) {
+ console.log('Window resize: Force fixing multi-view styles');
+ setTimeout(() => {
+ forceFixMultiViewStyles();
+
+ // Дополнительно исправляем все контейнеры
+ console.log('Window resize: Fixing all containers');
+ if (window.fixAllContainers) {
+ window.fixAllContainers();
+ }
+ }, 100);
+ }
+});
+
// Hotkeys: [ ] — navigation between containers, Ctrl+R/Ctrl+K — refresh logs
window.addEventListener('keydown', async (e)=>{
// Проверяем, не находится ли фокус в поле ввода
@@ -6333,6 +6583,47 @@ window.addEventListener('keydown', async (e)=>{
window.cleanDuplicateLines = cleanDuplicateLines;
window.cleanSingleViewEmptyLines = cleanSingleViewEmptyLines;
+ // Добавляем функции для исправления стилей в глобальную область
+ window.forceFixMultiViewStyles = forceFixMultiViewStyles;
+ window.updateLogStyles = updateLogStyles;
+
+ // Универсальная функция для исправления всех контейнеров
+ window.fixAllContainers = function() {
+ console.log('Fixing all multi-view containers');
+
+ const allLogs = document.querySelectorAll('.multi-view-content .multi-view-log');
+ allLogs.forEach(log => {
+ const containerId = log.getAttribute('data-container-id');
+ console.log(`Fixing container:`, containerId);
+
+ // Принудительно устанавливаем все стили заново
+ log.style.cssText = 'height: 100% !important; overflow: auto !important; max-height: none !important; display: block !important; min-height: 200px !important; position: relative !important; flex: 1 !important; min-height: 0 !important; width: 100% !important; box-sizing: border-box !important;';
+
+ // Принудительно вызываем пересчет layout
+ log.style.setProperty('transform', 'translateZ(0)', 'important');
+
+ // Проверяем родительские элементы
+ const parentContent = log.closest('.multi-view-content');
+ if (parentContent) {
+ parentContent.style.cssText = 'display: flex !important; flex-direction: column !important; overflow: hidden !important; height: 100% !important;';
+ }
+
+ const parentPanel = log.closest('.multi-view-panel');
+ if (parentPanel) {
+ parentPanel.style.cssText = 'display: flex !important; flex-direction: column !important; overflow: hidden !important; height: 100% !important;';
+ }
+ });
+
+ // Применяем настройки wrap text после исправления всех контейнеров
+ applyWrapSettings();
+ };
+
+ // Оставляем старую функцию для обратной совместимости
+ window.fixProblematicContainers = function() {
+ console.log('fixProblematicContainers is deprecated, use fixAllContainers instead');
+ window.fixAllContainers();
+ };
+
console.log('LogBoard+ инициализирован с исправлениями дублирования строк и правильными переносами строк в Single View и MultiView режимах');
console.log('Для тестирования используйте: testDuplicateRemoval(), testSingleViewDuplicateRemoval(), testSingleViewEmptyLinesRemoval() или testSingleViewLineBreaks()');