logboard/app/scripts/test_multi_view_layout.py
Sergey Antropoff 6e51f00791 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
2025-08-18 19:35:47 +03:00

155 lines
7.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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)