Исправление скролла в Multi View режиме и проблемы с wrap text
- Универсальное исправление скролла для всех контейнеров в Multi View режиме - Более специфичные CSS селекторы для предотвращения влияния на другие элементы - Исправление проблемы с wrap text в options - Добавление вызовов applyWrapSettings() в ключевых местах - Обновление документации с описанием всех исправлений - Добавление CHANGELOG.md и SCROLL_FIX_SUMMARY.md - Добавление документации в app/docs/
This commit is contained in:
parent
36569c79f0
commit
7cd7ba0653
41
CHANGELOG.md
Normal file
41
CHANGELOG.md
Normal file
@ -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
|
182
SCROLL_FIX_SUMMARY.md
Normal file
182
SCROLL_FIX_SUMMARY.md
Normal file
@ -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
|
47
app/docs/README.md
Normal file
47
app/docs/README.md
Normal file
@ -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
|
77
app/docs/features.md
Normal file
77
app/docs/features.md
Normal file
@ -0,0 +1,77 @@
|
||||
# Новые функции интерфейса LogBoard+
|
||||
|
||||
## Сворачивание панелей
|
||||
|
||||
### Sidebar (боковая панель)
|
||||
- **Кнопка сворачивания**: <i class="fas fa-chevron-left"></i> на границе sidebar и основного контента
|
||||
- **Горячая клавиша**: `Ctrl+B` / `Ctrl+И`
|
||||
- **Свернутое состояние**: ширина 60px
|
||||
- **Логотип**: показывает <i class="fas fa-terminal"></i> в свернутом состоянии
|
||||
- **Кнопка помощи**: <i class="fas fa-question-circle"></i> между options и logout
|
||||
|
||||
## Управление
|
||||
|
||||
### Кнопка сворачивания
|
||||
- **Кнопка на границе**: сворачивает боковую панель
|
||||
- **Расположение**: посередине экрана по высоте на границе sidebar и основного контента
|
||||
- **Состояние сохраняется** в localStorage
|
||||
|
||||
### Горячая клавиша
|
||||
- **Ctrl+B** / **Ctrl+И**: сворачивает/разворачивает sidebar и header
|
||||
- Удобно для быстрого освобождения места на экране
|
||||
|
||||
### Header (заголовок)
|
||||
- **Сворачивается вместе с sidebar**
|
||||
- **В свернутом состоянии**: тонкая полоска 40px высотой
|
||||
- **Содержит**: фильтр логов, кнопки уровней логирования, кнопку обновления
|
||||
- **Стили**: кнопки выглядят точно так же, как в развернутом состоянии
|
||||
- **log-header**: полностью скрывается в свернутом режиме
|
||||
- **log-content**: минимальный padding 2px в свернутом состоянии
|
||||
- **multi-view-panel**: показывает название контейнера в Single View режиме
|
||||
|
||||
## Визуальные элементы
|
||||
|
||||
### Логотип в свернутом sidebar
|
||||
```
|
||||
<i class="fas fa-terminal"></i>
|
||||
```
|
||||
- Отображается только когда sidebar свернут
|
||||
- Расположен в самом верху sidebar
|
||||
- Стилизован в цвете акцента
|
||||
- Занимает минимальное место
|
||||
|
||||
### Модальное окно с горячими клавишами
|
||||
- **Открытие**: кнопка <i class="fas fa-question-circle"></i> в свернутом 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
|
66
app/docs/hotkeys.md
Normal file
66
app/docs/hotkeys.md
Normal file
@ -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
|
||||
|
||||
### Кнопка сворачивания
|
||||
- **Кнопка на границе** (<i class="fas fa-chevron-left"></i>) - сворачивание 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
|
@ -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": "Список контейнеров, которые генерируют слишком много логов и исключаются из отображения"
|
||||
}
|
||||
}
|
@ -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()');
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user