From 7cd7ba065330e619e3c8a0b8a161bb06f349a7f5 Mon Sep 17 00:00:00 2001 From: Sergey Antropoff Date: Mon, 18 Aug 2025 17:03:46 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D0=BA=D1=80=D0=BE=D0=BB=D0=BB?= =?UTF-8?q?=D0=B0=20=D0=B2=20Multi=20View=20=D1=80=D0=B5=D0=B6=D0=B8=D0=BC?= =?UTF-8?q?=D0=B5=20=D0=B8=20=D0=BF=D1=80=D0=BE=D0=B1=D0=BB=D0=B5=D0=BC?= =?UTF-8?q?=D1=8B=20=D1=81=20wrap=20text?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Универсальное исправление скролла для всех контейнеров в Multi View режиме - Более специфичные CSS селекторы для предотвращения влияния на другие элементы - Исправление проблемы с wrap text в options - Добавление вызовов applyWrapSettings() в ключевых местах - Обновление документации с описанием всех исправлений - Добавление CHANGELOG.md и SCROLL_FIX_SUMMARY.md - Добавление документации в app/docs/ --- CHANGELOG.md | 41 ++++ SCROLL_FIX_SUMMARY.md | 182 ++++++++++++++++++ app/docs/README.md | 47 +++++ app/docs/features.md | 77 ++++++++ app/docs/hotkeys.md | 66 +++++++ excluded_containers.json | 15 +- templates/index.html | 391 ++++++++++++++++++++++++++++++++++----- 7 files changed, 756 insertions(+), 63 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 SCROLL_FIX_SUMMARY.md create mode 100644 app/docs/README.md create mode 100644 app/docs/features.md create mode 100644 app/docs/hotkeys.md 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()');