feat: Добавлено AJAX обновление логов и улучшения интерфейса

Основные изменения:
- Добавлено AJAX обновление логов с чекбоксом 'Auto-update logs'
- Добавлена опция 'All logs' в выпадающий список tail lines
- Исправлено отображение длинных названий контейнеров в multi-view режиме
- Восстановлена загрузка истории логов при включенном AJAX обновлении

Новые функции:
- Чекбокс 'Auto-update logs' в секции Options (включен по умолчанию)
- Настройка интервала обновления через LOGBOARD_AJAX_UPDATE_INTERVAL
- API эндпоинт /api/settings для получения настроек приложения
- Поддержка параметра tail=all для загрузки всех логов
- Автоматический запуск AJAX обновления при включении чекбокса

Исправления UI:
- Кнопки LogLevels не уезжают вправо при длинных названиях контейнеров
- Добавлено обрезание длинных названий с многоточием
- Фиксированная высота заголовков в multi-view режиме
- Защита от сжатия кнопок LogLevels

Тестирование:
- Добавлены тесты для AJAX обновления (test_ajax_update.py)
- Тест multi-view AJAX обновления (test_multi_view_ajax.py)
- Тест опции 'all logs' (test_all_logs.py)
- Тест отображения длинных названий (test_multi_view_layout.py)
- Команды make test-ajax, make test-multi-view-ajax, make test-all-logs, make test-multi-view-layout

Документация:
- Создана подробная документация AJAX обновления (app/docs/ajax-update.md)
- Обновлен CHANGELOG.md с версиями 1.3.0, 1.5.0, 1.6.0
- Обновлен README.md с описанием новых функций

Автор: Сергей Антропов
Сайт: https://devops.org.ru
This commit is contained in:
2025-08-18 19:35:47 +03:00
parent 2d565d52a6
commit 6e51f00791
14 changed files with 2066 additions and 7 deletions

View File

@@ -0,0 +1,154 @@
#!/usr/bin/env python3
"""
Тест для проверки корректного отображения длинных названий контейнеров
в multi-view режиме
Автор: Сергей Антропов
Сайт: https://devops.org.ru
"""
import asyncio
import aiohttp
import json
import time
from datetime import datetime
async def test_multi_view_layout():
"""Тестирование отображения длинных названий в multi-view режиме"""
print("🧪 Тестирование отображения длинных названий в multi-view режиме")
print("=" * 70)
url = "http://localhost:9001"
username = "admin"
password = "admin"
print(f"📡 URL: {url}")
print(f"👤 Пользователь: {username}")
print("=" * 50)
async with aiohttp.ClientSession() as session:
try:
# 1. Получаем токен авторизации
print("🔐 Получение токена авторизации...")
auth_data = {'username': username, 'password': password}
async with session.post(f'{url}/api/auth/login', json=auth_data) as response:
if (response.status != 200):
print(f"❌ Ошибка авторизации: {response.status}")
return False
auth_response = await response.json()
token = auth_response.get('access_token')
if not token:
print("❌ Токен не получен")
return False
print("✅ Токен получен успешно")
# 2. Получаем список сервисов
print("\n📋 Получение списка сервисов...")
headers = {'Authorization': f'Bearer {token}'}
async with session.get(f'{url}/api/services', headers=headers) as response:
if response.status != 200:
print(f"❌ Ошибка получения сервисов: {response.status}")
return False
services = await response.json()
if not services:
print("❌ Сервисы не найдены")
return False
print(f"✅ Найдено {len(services)} сервисов")
# Анализируем названия сервисов
print("\n📊 Анализ названий сервисов:")
long_names = []
short_names = []
for service in services:
name = service['name']
if len(name) > 30:
long_names.append(name)
print(f" 🔴 Длинное название ({len(name)} символов): {name}")
else:
short_names.append(name)
print(f" 🟢 Короткое название ({len(name)} символов): {name}")
print(f"\n📈 Статистика названий:")
print(f" Всего сервисов: {len(services)}")
print(f" Коротких названий: {len(short_names)}")
print(f" Длинных названий: {len(long_names)}")
if long_names:
print(f"\n⚠️ Обнаружены длинные названия, которые могут вызвать проблемы с отображением:")
for name in long_names[:3]: # Показываем первые 3
print(f" - {name}")
print(f"\n✅ Рекомендации:")
print(f" - CSS стили должны обрезать длинные названия с многоточием")
print(f" - Кнопки LogLevels не должны уезжать вправо")
print(f" - Заголовок должен иметь фиксированную высоту")
else:
print(f"\nВсе названия сервисов имеют приемлемую длину")
# 3. Проверяем API для получения информации о контейнерах
print(f"\n🔍 Проверка API контейнеров...")
async with session.get(f'{url}/api/containers', headers=headers) as response:
if response.status == 200:
containers = await response.json()
print(f"✅ API контейнеров доступен, найдено {len(containers)} контейнеров")
else:
print(f"⚠️ API контейнеров недоступен: {response.status}")
# 4. Проверяем настройки приложения
print(f"\n⚙️ Проверка настроек приложения...")
async with session.get(f'{url}/api/settings', headers=headers) as response:
if response.status == 200:
settings = await response.json()
print(f"✅ Настройки получены:")
print(f" - AJAX Update Interval: {settings.get('ajax_update_interval')}ms")
print(f" - Default Tail: {settings.get('default_tail')}")
print(f" - Skip Unhealthy: {settings.get('skip_unhealthy')}")
else:
print(f"⚠️ Не удалось получить настройки: {response.status}")
# 5. Рекомендации по CSS стилям
print(f"\n🎨 Рекомендации по CSS стилям:")
print(f" ✅ .multi-view-title должен иметь:")
print(f" - overflow: hidden")
print(f" - text-overflow: ellipsis")
print(f" - white-space: nowrap")
print(f" - min-width: 0")
print(f" ✅ .multi-view-levels должен иметь:")
print(f" - flex-shrink: 0")
print(f" ✅ .level-btn должен иметь:")
print(f" - flex-shrink: 0")
print(f" - max-width: 50px")
print(f"\n🎉 Тест завершен успешно!")
print(f"✅ Анализ названий сервисов выполнен")
return True
except Exception as e:
print(f"❌ Ошибка тестирования: {e}")
return False
async def main():
"""Основная функция"""
print("🚀 Запуск теста отображения длинных названий в multi-view")
print("=" * 70)
result = await test_multi_view_layout()
print("\n" + "=" * 70)
if result:
print("🎉 Все тесты прошли успешно!")
print("✅ Анализ названий сервисов завершен")
else:
print("❌ Тесты завершились с ошибками")
return result
if __name__ == "__main__":
import sys
result = asyncio.run(main())
sys.exit(0 if result else 1)