443 lines
22 KiB
HTML
443 lines
22 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Hermes Hub — Панель управления</title>
|
||
<link rel="stylesheet" href="style.css">
|
||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
|
||
</head>
|
||
<body>
|
||
<div id="app" class="app-layout">
|
||
<!-- Sidebar Navigation (9 Full Views) -->
|
||
<aside class="sidebar">
|
||
<div class="brand">
|
||
<div class="brand-logo">⚡</div>
|
||
<div class="brand-text">
|
||
<span class="brand-title">HERMES HUB</span>
|
||
<span class="brand-subtitle">Multi-Account Router</span>
|
||
</div>
|
||
</div>
|
||
|
||
<nav class="nav-menu">
|
||
<button class="nav-item active" data-view="overview">
|
||
<span class="nav-icon">📊</span>
|
||
<span class="nav-label">Обзор</span>
|
||
</button>
|
||
<button class="nav-item" data-view="accounts">
|
||
<span class="nav-icon">👥</span>
|
||
<span class="nav-label">Аккаунты</span>
|
||
<span class="nav-badge" id="nav-accounts-count">0</span>
|
||
</button>
|
||
<button class="nav-item" data-view="routing">
|
||
<span class="nav-icon">🔀</span>
|
||
<span class="nav-label">Маршрутизация</span>
|
||
</button>
|
||
<button class="nav-item" data-view="analytics">
|
||
<span class="nav-icon">📈</span>
|
||
<span class="nav-label">Аналитика</span>
|
||
</button>
|
||
<button class="nav-item" data-view="health">
|
||
<span class="nav-icon">🩺</span>
|
||
<span class="nav-label">Состояние</span>
|
||
</button>
|
||
<button class="nav-item" data-view="logs">
|
||
<span class="nav-icon">📜</span>
|
||
<span class="nav-label">Журнал событий</span>
|
||
</button>
|
||
<button class="nav-item" data-view="settings">
|
||
<span class="nav-icon">⚙️</span>
|
||
<span class="nav-label">Настройки</span>
|
||
</button>
|
||
</nav>
|
||
|
||
<div class="sidebar-footer">
|
||
<div class="source-indicator" id="source-indicator">
|
||
<span class="status-dot healthy"></span>
|
||
<span class="source-text" id="source-text">Загрузка данных...</span>
|
||
</div>
|
||
<div class="version-tag" id="version-tag">Hermes Hub Web v0.1.1</div>
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- Main Content Container -->
|
||
<main class="main-wrapper">
|
||
<!-- Top Header -->
|
||
<header class="top-header">
|
||
<div class="header-left">
|
||
<h1 class="header-title" id="page-title">Обзор системы</h1>
|
||
<span class="header-readiness-badge" id="header-readiness-badge">
|
||
<span class="status-dot"></span>
|
||
<span id="header-readiness-text">Инициализация...</span>
|
||
</span>
|
||
</div>
|
||
<div class="header-actions">
|
||
<button class="btn btn-secondary" id="btn-refresh-all" title="Обновить квоты всех профилей">
|
||
<span class="btn-icon">↻</span>
|
||
<span>Обновить всё</span>
|
||
</button>
|
||
<button class="btn btn-primary" id="btn-add-account">
|
||
<span class="btn-icon">+</span>
|
||
<span>Добавить аккаунт</span>
|
||
</button>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- Dynamic Views (7 Control Sections) -->
|
||
<div class="content-scroll">
|
||
<!-- 1. OVERVIEW VIEW -->
|
||
<section id="view-overview" class="view-pane active">
|
||
<div class="overview-grid">
|
||
<div class="kpi-card">
|
||
<div class="kpi-label">Состояние системы</div>
|
||
<div class="kpi-value text-healthy" id="kpi-system-readiness">—</div>
|
||
<div class="kpi-sub" id="kpi-readiness-summary">—</div>
|
||
</div>
|
||
<div class="kpi-card">
|
||
<div class="kpi-label">Подключено аккаунтов</div>
|
||
<div class="kpi-value text-accent" id="kpi-total-accounts">—</div>
|
||
<div class="kpi-sub" id="kpi-accounts-sub">—</div>
|
||
</div>
|
||
<div class="kpi-card">
|
||
<div class="kpi-label">Готовых ролей</div>
|
||
<div class="kpi-value text-healthy" id="kpi-ready-roles">—</div>
|
||
<div class="kpi-sub" id="kpi-roles-sub">—</div>
|
||
</div>
|
||
<div class="kpi-card">
|
||
<div class="kpi-label">Провайдеры ИИ</div>
|
||
<div class="kpi-value text-info" id="kpi-providers-count">—</div>
|
||
<div class="kpi-sub" id="kpi-providers-sub">5 поддерживаемых систем</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section-card">
|
||
<div class="section-card-header">
|
||
<div class="section-card-title">Схема маршрутизации запросов</div>
|
||
<div class="section-card-subtitle">Распределение агентов и цепочки отказоустойчивости</div>
|
||
</div>
|
||
<div class="route-diagram-container" id="overview-route-diagram">
|
||
<!-- Rendered by app.js -->
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section-card">
|
||
<div class="section-card-header">
|
||
<div class="section-card-title">Провайдеры и доступность runtime</div>
|
||
<div class="section-card-subtitle">Статус локальных адаптеров и обнаруженные модели</div>
|
||
</div>
|
||
<div class="providers-grid" id="overview-providers-summary">
|
||
<!-- Rendered by app.js -->
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 2. ACCOUNTS VIEW -->
|
||
<section id="view-accounts" class="view-pane">
|
||
<div class="toolbar">
|
||
<div class="search-box">
|
||
<span class="search-icon">🔍</span>
|
||
<input type="text" id="accounts-search" placeholder="Поиск по аккаунту, почте, роли или модели...">
|
||
</div>
|
||
<div class="filters-row">
|
||
<select id="filter-provider" class="select-filter">
|
||
<option value="all">Все провайдеры</option>
|
||
<option value="antigravity">Google Antigravity</option>
|
||
<option value="openai-codex">OpenAI Codex</option>
|
||
<option value="opencode-go">OpenCode Go</option>
|
||
<option value="claude">Claude (Anthropic)</option>
|
||
<option value="grok">Grok (xAI)</option>
|
||
</select>
|
||
<select id="filter-health" class="select-filter">
|
||
<option value="all">Все состояния</option>
|
||
<option value="healthy">Работает</option>
|
||
<option value="warning">Предупреждение</option>
|
||
<option value="quota_exhausted">Квота исчерпана</option>
|
||
<option value="auth_required">Требуется вход</option>
|
||
<option value="disabled">Отключён / Резерв</option>
|
||
</select>
|
||
<div class="toolbar-stats" id="accounts-stats-summary">
|
||
Показано: <strong>0</strong> из <strong>0</strong> аккаунтов
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="accounts-container" class="accounts-groups-container">
|
||
<!-- Rendered by app.js -->
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 3. ROUTING VIEW (Main Control Center) -->
|
||
<section id="view-routing" class="view-pane">
|
||
<div class="view-header-note">
|
||
Главный центр управления маршрутизацией: перетаскивайте узлы для смены приоритета (Основной → Резерв 1 → Резерв 2), настраивайте рабочие модели и управляйте составом цепочек.
|
||
</div>
|
||
<div class="routing-pipelines-list" id="routing-pipelines-container">
|
||
<!-- Rendered by app.js -->
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 4. ANALYTICS VIEW (P0-1 & P0-5) -->
|
||
<section id="view-analytics" class="view-pane">
|
||
<div class="view-header-note">
|
||
Телеметрия вызовов и отказоустойчивости за 24 часа. Метрики отражают реальные замеры задержки и частоты ошибок при маршрутизации.
|
||
</div>
|
||
<div class="overview-grid">
|
||
<div class="kpi-card">
|
||
<div class="kpi-label">Всего вызовов (24ч)</div>
|
||
<div class="kpi-value text-accent" id="analytics-total-calls">—</div>
|
||
<div class="kpi-sub" id="analytics-calls-breakdown">—</div>
|
||
</div>
|
||
<div class="kpi-card">
|
||
<div class="kpi-label">Доля отказов / ошибок</div>
|
||
<div class="kpi-value" id="analytics-error-rate">—</div>
|
||
<div class="kpi-sub" id="analytics-error-rate-sub">—</div>
|
||
</div>
|
||
<div class="kpi-card">
|
||
<div class="kpi-label">Латентность (p50 / p95 / max)</div>
|
||
<div class="kpi-value text-info" id="analytics-latency-p50">—</div>
|
||
<div class="kpi-sub" id="analytics-latency-sub">—</div>
|
||
</div>
|
||
<div class="kpi-card">
|
||
<div class="kpi-label">Расход токенов</div>
|
||
<div class="kpi-value text-muted" id="analytics-tokens-total">Н/Д</div>
|
||
<div class="kpi-sub" id="analytics-tokens-sub">Н/Д: провайдеры не отдают токены</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section-card">
|
||
<div class="section-card-header">
|
||
<div class="section-card-title">Телеметрия по провайдерам ИИ</div>
|
||
<div class="section-card-subtitle">Распределение запросов, отказов и задержек в окне измерений</div>
|
||
</div>
|
||
<div class="table-responsive" id="analytics-providers-table">
|
||
<!-- Rendered by app.js -->
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section-card">
|
||
<div class="section-card-header">
|
||
<div class="section-card-title">Телеметрия по ролям агентов</div>
|
||
<div class="section-card-subtitle">Нагрузка по ролям команды, частота сбоев и тайминги</div>
|
||
</div>
|
||
<div class="table-responsive" id="analytics-roles-table">
|
||
<!-- Rendered by app.js -->
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 7. HEALTH VIEW (P0-2) -->
|
||
<section id="view-health" class="view-pane">
|
||
<div class="readiness-banner" id="health-readiness-banner">
|
||
<!-- Readiness state banner rendered by app.js -->
|
||
</div>
|
||
|
||
<div class="section-card">
|
||
<div class="section-card-header">
|
||
<div class="section-card-title">Ресурсы хост-системы</div>
|
||
<div class="section-card-subtitle">Мониторинг CPU, памяти, диска и сетевых параметров</div>
|
||
</div>
|
||
<div class="host-resources-grid" id="health-host-resources">
|
||
<!-- Rendered by app.js -->
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section-card">
|
||
<div class="section-card-header">
|
||
<div class="section-card-title">Предупреждения и диагностика</div>
|
||
<div class="section-card-subtitle">Анализ рисков, отсутствие резервов и деградация маршрутов</div>
|
||
</div>
|
||
<div class="warnings-list" id="health-warnings-list">
|
||
<!-- Rendered by app.js -->
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 8. LOGS / EVENTS VIEW (P0-3) -->
|
||
<section id="view-logs" class="view-pane">
|
||
<div class="toolbar">
|
||
<div class="search-box">
|
||
<span class="search-icon">🔍</span>
|
||
<input type="text" id="logs-search" placeholder="Поиск по событиям или деталям...">
|
||
</div>
|
||
<div class="filters-row">
|
||
<select id="logs-filter-level" class="select-filter">
|
||
<option value="all">Все уровни</option>
|
||
<option value="info">INFO</option>
|
||
<option value="success">SUCCESS</option>
|
||
<option value="warning">WARNING</option>
|
||
<option value="error">ERROR</option>
|
||
</select>
|
||
<select id="logs-filter-category" class="select-filter">
|
||
<option value="all">Все категории</option>
|
||
<option value="system">Система (system)</option>
|
||
<option value="account">Аккаунты (account)</option>
|
||
<option value="quota">Квоты (quota)</option>
|
||
<option value="routing">Маршрутизация (routing)</option>
|
||
<option value="auth">Авторизация (auth)</option>
|
||
</select>
|
||
<button class="btn btn-secondary btn-sm" id="btn-refresh-logs">↻ Обновить журнал</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section-card" style="margin-top:12px;">
|
||
<div class="section-card-header">
|
||
<div class="section-card-title">Журнал событий Hermes Hub</div>
|
||
<div class="section-card-subtitle">События маршрутизатора, обновления квот, авторизации и тестов</div>
|
||
</div>
|
||
<div class="logs-container" id="logs-container">
|
||
<!-- Rendered by app.js from /api/events -->
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 9. SETTINGS VIEW (P0-4) -->
|
||
<section id="view-settings" class="view-pane">
|
||
<!-- Hub Server Settings -->
|
||
<div class="settings-card">
|
||
<h2 class="settings-group-title">Параметры сервера Hermes Hub</h2>
|
||
<div class="setting-row">
|
||
<div class="setting-info">
|
||
<div class="setting-label">Хост и порт веб-сервера</div>
|
||
<div class="setting-desc">Сетевой адрес и порт для HTTP/REST API и веб-интерфейса</div>
|
||
</div>
|
||
<div class="setting-control" style="display:flex; gap:8px;">
|
||
<input type="text" id="setting-server-host" class="input-text" style="width:140px;" placeholder="127.0.0.1">
|
||
<input type="number" id="setting-server-port" class="input-text" style="width:90px;" placeholder="5800">
|
||
</div>
|
||
</div>
|
||
<div class="setting-row">
|
||
<div class="setting-info">
|
||
<div class="setting-label">Токен безопасности сервера</div>
|
||
<div class="setting-desc">Обязателен при внешнем подключении (host != 127.0.0.1)</div>
|
||
</div>
|
||
<div class="setting-control" style="display:flex; align-items:center; gap:8px;">
|
||
<span id="setting-token-status-badge" class="badge">Токен не задан</span>
|
||
<input type="password" id="setting-server-token-input" class="input-text" placeholder="Задать новый токен...">
|
||
</div>
|
||
</div>
|
||
<div class="setting-row">
|
||
<div class="setting-info">
|
||
<div class="setting-label">Интервал обновления квот</div>
|
||
<div class="setting-desc">Период фонового опроса квот провайдеров (секунды)</div>
|
||
</div>
|
||
<div class="setting-control">
|
||
<select id="setting-quota-interval" class="select-filter">
|
||
<option value="60">60 секунд (1 мин)</option>
|
||
<option value="120">120 секунд (2 мин)</option>
|
||
<option value="300">300 секунд (5 мин — стандарт)</option>
|
||
<option value="600">600 секунд (10 мин)</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="setting-row">
|
||
<div class="setting-info">
|
||
<div class="setting-label">Тема оформления</div>
|
||
<div class="setting-desc">Цветовая схема интерфейса Hub</div>
|
||
</div>
|
||
<div class="setting-control">
|
||
<select id="setting-theme" class="select-filter">
|
||
<option value="system">Системная (по умолчанию)</option>
|
||
<option value="dark">Тёмная (Dark)</option>
|
||
<option value="light">Светлая (Light)</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="settings-actions">
|
||
<button class="btn btn-primary" id="btn-save-hub-settings">Сохранить настройки сервера</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Read-Only System Paths -->
|
||
<div class="settings-card" style="margin-top:16px;">
|
||
<h2 class="settings-group-title">Системные пути и окружение</h2>
|
||
<div class="setting-row">
|
||
<div class="setting-info">
|
||
<div class="setting-label">Каталог данных Hermes</div>
|
||
<div class="setting-desc mono-path" id="path-hermes-home">—</div>
|
||
</div>
|
||
</div>
|
||
<div class="setting-row">
|
||
<div class="setting-info">
|
||
<div class="setting-label">Каталог конфигурации</div>
|
||
<div class="setting-desc mono-path" id="path-config-dir">—</div>
|
||
</div>
|
||
</div>
|
||
<div class="setting-row">
|
||
<div class="setting-info">
|
||
<div class="setting-label">Файл журнала событий</div>
|
||
<div class="setting-desc mono-path" id="path-log-file">—</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Client Local Settings -->
|
||
<div class="settings-card" style="margin-top:16px;">
|
||
<h2 class="settings-group-title">Параметры веб-клиента (Браузер)</h2>
|
||
<div class="setting-row">
|
||
<div class="setting-info">
|
||
<div class="setting-label">Источник данных в браузере</div>
|
||
<div class="setting-desc">Автоматическое переключение между Live API и фикстурой</div>
|
||
</div>
|
||
<div class="setting-control">
|
||
<select id="setting-source-mode" class="select-filter">
|
||
<option value="auto">Авто (Live API с fallback)</option>
|
||
<option value="live">Строго Live API (/api/snapshot)</option>
|
||
<option value="fixture">Строго фикстура (snapshot.example.json)</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="setting-row">
|
||
<div class="setting-info">
|
||
<div class="setting-label">Интервал авто-опроса UI</div>
|
||
<div class="setting-desc">Частота обновления снимка состояния в окне браузера</div>
|
||
</div>
|
||
<div class="setting-control">
|
||
<select id="setting-poll-interval" class="select-filter">
|
||
<option value="3000">3 секунды</option>
|
||
<option value="5000" selected>5 секунд (стандарт)</option>
|
||
<option value="10000">10 секунд</option>
|
||
<option value="0">Отключить авто-опрос</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="setting-row">
|
||
<div class="setting-info">
|
||
<div class="setting-label">Локальный токен клиента (X-Hub-Token)</div>
|
||
<div class="setting-desc">Токен для заголовка X-Hub-Token при внешних вызовах</div>
|
||
</div>
|
||
<div class="setting-control">
|
||
<input type="password" id="setting-client-token-input" class="input-text" placeholder="Введите токен...">
|
||
</div>
|
||
</div>
|
||
<div class="settings-actions">
|
||
<button class="btn btn-secondary" id="btn-save-client-settings">Сохранить локальные параметры</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</main>
|
||
</div>
|
||
|
||
<!-- Modal Layer -->
|
||
<div id="modal-backdrop" class="modal-backdrop hidden">
|
||
<div id="modal-container" class="modal-card">
|
||
<div class="modal-header">
|
||
<h2 id="modal-title" class="modal-title">Модальное окно</h2>
|
||
<button id="modal-close-btn" class="modal-close" title="Закрыть">✕</button>
|
||
</div>
|
||
<div id="modal-body" class="modal-body">
|
||
<!-- Injected dynamically -->
|
||
</div>
|
||
<div id="modal-footer" class="modal-footer">
|
||
<!-- Injected dynamically -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Toast Notification Container -->
|
||
<div id="toast-container" class="toast-container"></div>
|
||
|
||
<!-- Application Logic -->
|
||
<script src="app.js"></script>
|
||
</body>
|
||
</html>
|