Files
vps_monitoring/server/templates/dashboard.html
Андрей Бобырев cc01667879 feat: add Synology NAS, Home Assistant monitoring, multi-channel notifications
New tabs:
- Synology NAS: CPU, RAM, temp, volumes, VMs, Docker containers
- Home Assistant: sensors, automations, persons, climate, battery, doors

New features:
- Personalized PC agent download with custom name
- Notification settings: per-category Telegram/Email/WhatsApp toggles
- Email via SMTP, WhatsApp via CallMeBot API
- Test notification buttons for each channel
- Unified notifier replaces direct Telegram calls in alerter

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-20 13:59:57 +03:00

462 lines
23 KiB
HTML
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.

<!DOCTYPE html>
<html lang="ru" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>VPS Monitoring</title>
<link rel="stylesheet" href="/static/css/style.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.min.css">
<script src="/static/js/theme.js"></script>
<script src="/static/js/i18n.js"></script>
</head>
<body>
<header>
<div class="header-left">
<h1 id="pageTitle">🖥 VPS Monitoring</h1>
</div>
<div class="header-right">
<button class="lang-btn" id="langBtn" onclick="toggleLang()">RU</button>
<button class="btn-icon" id="themeToggleBtn" onclick="toggleTheme()" title="Theme">🌙</button>
<button class="btn-icon" onclick="refreshAll()" title="Refresh">🔄</button>
<button class="btn-icon" onclick="showInstructions()" title="Instructions">📖</button>
<button class="btn-icon" onclick="showNotificationSettings()" title="Notifications">🔔</button>
<button class="btn-icon" onclick="showSettings()" title="Settings">⚙️</button>
<button class="btn-icon" onclick="logout()" title="Logout">🚪</button>
</div>
</header>
<main>
<div class="stats-bar">
<div class="stat-item" id="stat-total">
<span class="stat-label" data-i18n="total">Всего</span>
<span class="stat-value" id="total-count">0</span>
</div>
<div class="stat-item online" id="stat-online">
<span class="stat-label" data-i18n="online">Online</span>
<span class="stat-value" id="online-count">0</span>
</div>
<div class="stat-item offline" id="stat-offline">
<span class="stat-label" data-i18n="offline">Offline</span>
<span class="stat-value" id="offline-count">0</span>
</div>
</div>
<!-- Tabs -->
<div class="tabs">
<button class="tab active" id="tab-servers" onclick="switchTab('servers')">🖥 <span data-i18n="tabServers">Серверы</span></button>
<button class="tab" id="tab-pc" onclick="switchTab('pc')">💻 <span data-i18n="tabPC">ПК</span></button>
<button class="tab" id="tab-synology" onclick="switchTab('synology')">📦 Synology</button>
<button class="tab" id="tab-ha" onclick="switchTab('ha')">🏠 Home Assistant</button>
</div>
<!-- Servers Tab -->
<div id="panel-servers">
<div class="toolbar">
<button class="btn-primary" id="addServerBtn" onclick="showAddServer()">+ Добавить сервер</button>
</div>
<div class="servers-grid" id="servers-grid"></div>
</div>
<!-- PC Tab -->
<div id="panel-pc" style="display:none">
<div class="toolbar">
<button class="btn-primary" onclick="showPCDownload()">📥 Скачать агент</button>
<button class="btn-secondary" onclick="showPCSetup()">📋 Инструкция</button>
<button class="btn-secondary" onclick="loadPCs()">🔄 Обновить</button>
</div>
<div class="servers-grid" id="pc-grid"></div>
</div>
<!-- Synology Tab -->
<div id="panel-synology" style="display:none">
<div class="toolbar">
<button class="btn-primary" onclick="showAddSynology()">+ Добавить NAS</button>
<button class="btn-secondary" onclick="refreshAllSynology()">🔄 Обновить все</button>
</div>
<div class="servers-grid" id="synology-grid"></div>
</div>
<!-- Home Assistant Tab -->
<div id="panel-ha" style="display:none">
<div class="toolbar">
<button class="btn-primary" onclick="showAddHA()">+ Добавить HA</button>
<button class="btn-secondary" onclick="refreshAllHA()">🔄 Обновить все</button>
</div>
<div class="servers-grid" id="ha-grid"></div>
</div>
</main>
<!-- Add Server Modal -->
<div class="modal" id="addServerModal" style="display:none">
<div class="modal-content">
<div class="modal-header">
<h2 data-i18n="addServer">Добавить сервер</h2>
<button class="btn-close" onclick="closeModal('addServerModal')">&times;</button>
</div>
<form id="addServerForm">
<div class="form-group">
<label data-i18n="serverName">Название</label>
<input type="text" name="name" required placeholder="My Server">
</div>
<div class="form-group">
<label data-i18n="host">IP / Host</label>
<input type="text" name="host" required placeholder="192.168.1.1">
</div>
<div class="form-group">
<label data-i18n="sshPort">Порт SSH</label>
<input type="number" name="port" value="22">
</div>
<div class="form-group">
<label data-i18n="sshLogin">Логин</label>
<input type="text" name="username" value="root">
</div>
<div class="form-group">
<label data-i18n="sshPassword">Пароль</label>
<input type="password" name="password" placeholder="SSH Password">
</div>
<div class="form-group">
<label data-i18n="description">Описание</label>
<input type="text" name="description" placeholder="">
</div>
<button type="submit" class="btn-primary" data-i18n="add">Добавить</button>
</form>
</div>
</div>
<!-- Add Synology Modal -->
<div class="modal" id="addSynologyModal" style="display:none">
<div class="modal-content">
<div class="modal-header">
<h2>📦 Добавить Synology NAS</h2>
<button class="btn-close" onclick="closeModal('addSynologyModal')">&times;</button>
</div>
<form id="addSynologyForm">
<div class="form-group">
<label>Название</label>
<input type="text" name="name" required placeholder="My NAS">
</div>
<div class="form-group">
<label>IP / Host</label>
<input type="text" name="host" required placeholder="192.168.1.50">
</div>
<div class="form-group">
<label>Порт DSM</label>
<input type="number" name="port" value="5000">
</div>
<div class="form-group" style="display:flex;align-items:center;gap:8px">
<input type="checkbox" name="https" id="syn-https" style="width:auto">
<label for="syn-https" style="margin:0">HTTPS</label>
</div>
<div class="form-group">
<label>Логин DSM</label>
<input type="text" name="username" required placeholder="admin">
</div>
<div class="form-group">
<label>Пароль DSM</label>
<input type="password" name="password" required>
</div>
<button type="submit" class="btn-primary">Добавить</button>
</form>
</div>
</div>
<!-- Add HA Modal -->
<div class="modal" id="addHAModal" style="display:none">
<div class="modal-content">
<div class="modal-header">
<h2>🏠 Добавить Home Assistant</h2>
<button class="btn-close" onclick="closeModal('addHAModal')">&times;</button>
</div>
<form id="addHAForm">
<div class="form-group">
<label>Название</label>
<input type="text" name="name" required placeholder="Home">
</div>
<div class="form-group">
<label>URL</label>
<input type="text" name="url" required placeholder="http://192.168.1.100:8123">
</div>
<div class="form-group">
<label>Long-Lived Access Token</label>
<textarea name="token" required rows="3" placeholder="Профиль → Безопасность → Долгоживущие токены доступа" style="resize:vertical"></textarea>
</div>
<button type="submit" class="btn-primary">Добавить</button>
</form>
</div>
</div>
<!-- PC Download Modal -->
<div class="modal" id="pcDownloadModal" style="display:none">
<div class="modal-content">
<div class="modal-header">
<h2>📥 Скачать агент для ПК</h2>
<button class="btn-close" onclick="closeModal('pcDownloadModal')">&times;</button>
</div>
<div class="form-group">
<label>Имя компьютера (агента)</label>
<input type="text" id="pc-agent-name" placeholder="MyPC" value="">
</div>
<button class="btn-primary" onclick="generatePCCommand()" style="margin-bottom:16px">🔧 Сгенерировать команду</button>
<div id="pc-generated-cmd" style="display:none">
<div class="instr-card">
<h4>📋 Команда установки (PowerShell от Администратора)</h4>
<code id="pc-gen-code" style="cursor:pointer" onclick="copyToClipboard(this.textContent)" title="Нажмите чтобы скопировать"></code>
<p style="margin-top:8px;font-size:11px;color:var(--text-secondary)">Нажмите на команду чтобы скопировать</p>
</div>
</div>
</div>
</div>
<!-- Notification Settings Modal -->
<div class="modal" id="notifyModal" style="display:none">
<div class="modal-content modal-wide">
<div class="modal-header">
<h2>🔔 Настройки уведомлений</h2>
<button class="btn-close" onclick="closeModal('notifyModal')">&times;</button>
</div>
<!-- Channel configs -->
<h3>📨 Каналы доставки</h3>
<div class="notify-channels">
<div class="instr-card">
<h4>📱 Telegram</h4>
<p style="font-size:12px;color:var(--text-secondary)">Настраивается в Настройках (⚙️) — Bot Token и Chat ID</p>
<div id="tg-status" style="margin-top:8px"></div>
<button class="btn-sm" onclick="testNotification('telegram')" style="margin-top:8px">🧪 Тест</button>
</div>
<div class="instr-card">
<h4>📧 Email (SMTP)</h4>
<div class="form-group" style="margin-top:8px">
<label>SMTP сервер</label>
<input type="text" id="n-smtp-host" placeholder="smtp.gmail.com">
</div>
<div class="form-group">
<label>Порт</label>
<input type="number" id="n-smtp-port" value="587">
</div>
<div class="form-group">
<label>Email (логин)</label>
<input type="text" id="n-smtp-user" placeholder="user@gmail.com">
</div>
<div class="form-group">
<label>Пароль приложения</label>
<input type="password" id="n-smtp-pass" placeholder="App Password">
</div>
<div class="form-group">
<label>Получатель</label>
<input type="text" id="n-email-to" placeholder="alerts@example.com">
</div>
<button class="btn-sm" onclick="testNotification('email')" style="margin-top:4px">🧪 Тест</button>
</div>
<div class="instr-card">
<h4>💬 WhatsApp (CallMeBot)</h4>
<p style="font-size:12px;color:var(--text-secondary);margin-bottom:8px">
1. Отправьте "I allow callmebot to send me messages" на <b>+34 644 71 85 23</b> в WhatsApp<br>
2. Получите apikey в ответном сообщении<br>
3. Введите данные ниже
</p>
<div class="form-group">
<label>Телефон (с кодом страны)</label>
<input type="text" id="n-wa-phone" placeholder="+79001234567">
</div>
<div class="form-group">
<label>API Key</label>
<input type="text" id="n-wa-apikey" placeholder="От CallMeBot">
</div>
<button class="btn-sm" onclick="testNotification('whatsapp')" style="margin-top:4px">🧪 Тест</button>
</div>
</div>
<!-- Per-category toggles -->
<h3>📊 Какие уведомления отправлять</h3>
<div class="notify-matrix">
<table class="notify-table">
<thead>
<tr>
<th>Категория</th>
<th>📱 Telegram</th>
<th>📧 Email</th>
<th>💬 WhatsApp</th>
</tr>
</thead>
<tbody>
<tr>
<td>🖥 Серверы</td>
<td><input type="checkbox" id="n-servers-tg" checked></td>
<td><input type="checkbox" id="n-servers-email"></td>
<td><input type="checkbox" id="n-servers-wa"></td>
</tr>
<tr>
<td>💻 ПК</td>
<td><input type="checkbox" id="n-pc-tg" checked></td>
<td><input type="checkbox" id="n-pc-email"></td>
<td><input type="checkbox" id="n-pc-wa"></td>
</tr>
<tr>
<td>📦 Synology</td>
<td><input type="checkbox" id="n-synology-tg" checked></td>
<td><input type="checkbox" id="n-synology-email"></td>
<td><input type="checkbox" id="n-synology-wa"></td>
</tr>
<tr>
<td>🏠 Home Assistant</td>
<td><input type="checkbox" id="n-ha-tg" checked></td>
<td><input type="checkbox" id="n-ha-email"></td>
<td><input type="checkbox" id="n-ha-wa"></td>
</tr>
</tbody>
</table>
</div>
<button class="btn-primary" onclick="saveNotificationSettings()" style="margin-top:20px">💾 Сохранить</button>
</div>
</div>
<!-- Settings Modal -->
<div class="modal" id="settingsModal" style="display:none">
<div class="modal-content">
<div class="modal-header">
<h2 data-i18n="settings">Настройки</h2>
<button class="btn-close" onclick="closeModal('settingsModal')">&times;</button>
</div>
<form id="settingsForm">
<h3 data-i18n="auth">Авторизация</h3>
<div class="form-group">
<label data-i18n="username">Логин</label>
<input type="text" name="admin_login" id="set_login">
</div>
<div class="form-group">
<label data-i18n="newPassword">Новый пароль</label>
<input type="password" name="admin_password" id="set_password" placeholder="">
</div>
<h3 data-i18n="telegram">Telegram</h3>
<div class="form-group">
<label data-i18n="botToken">Bot Token</label>
<input type="text" name="telegram_bot_token" id="set_tg_token">
</div>
<div class="form-group">
<label data-i18n="chatId">Chat ID</label>
<input type="text" name="telegram_chat_id" id="set_tg_chat">
</div>
<h3 data-i18n="monitoring">Мониторинг</h3>
<div class="form-group">
<label data-i18n="pollInterval">Интервал опроса (сек)</label>
<input type="number" name="monitor_interval" id="set_interval" value="60">
</div>
<div class="form-group">
<label data-i18n="cpuThreshold">Порог CPU (%)</label>
<input type="number" name="alert_cpu_threshold" id="set_cpu" value="90">
</div>
<div class="form-group">
<label data-i18n="ramThreshold">Порог RAM (%)</label>
<input type="number" name="alert_ram_threshold" id="set_ram" value="90">
</div>
<div class="form-group">
<label data-i18n="diskThreshold">Порог Disk (%)</label>
<input type="number" name="alert_disk_threshold" id="set_disk" value="90">
</div>
<button type="submit" class="btn-primary" data-i18n="save">Сохранить</button>
</form>
</div>
</div>
<!-- Instructions Modal -->
<div class="modal" id="instructionsModal" style="display:none">
<div class="modal-content modal-wide">
<div class="modal-header">
<h2 data-i18n="instructions_title">Инструкции и шпаргалки</h2>
<button class="btn-close" onclick="closeModal('instructionsModal')">&times;</button>
</div>
<div id="instructions-content"></div>
</div>
</div>
<!-- SSH Terminal Modal -->
<div class="modal" id="sshModal" style="display:none">
<div class="modal-content modal-large">
<div class="modal-header">
<h2 id="ssh-title">SSH Terminal</h2>
<button class="btn-close" onclick="closeSSH()">&times;</button>
</div>
<div id="terminal-container"></div>
</div>
</div>
<!-- Server Detail Modal -->
<div class="modal" id="serverDetailModal" style="display:none">
<div class="modal-content">
<div class="modal-header">
<h2 id="detail-title">Server</h2>
<button class="btn-close" onclick="closeModal('serverDetailModal')">&times;</button>
</div>
<div id="detail-content"></div>
</div>
</div>
<!-- Synology Detail Modal -->
<div class="modal" id="synDetailModal" style="display:none">
<div class="modal-content modal-wide">
<div class="modal-header">
<h2 id="syn-detail-title">Synology</h2>
<button class="btn-close" onclick="closeModal('synDetailModal')">&times;</button>
</div>
<div id="syn-detail-content"></div>
</div>
</div>
<!-- HA Detail Modal -->
<div class="modal" id="haDetailModal" style="display:none">
<div class="modal-content modal-wide">
<div class="modal-header">
<h2 id="ha-detail-title">Home Assistant</h2>
<button class="btn-close" onclick="closeModal('haDetailModal')">&times;</button>
</div>
<div id="ha-detail-content"></div>
</div>
</div>
<!-- PC Setup Modal -->
<div class="modal" id="pcSetupModal" style="display:none">
<div class="modal-content modal-wide">
<div class="modal-header">
<h2>💻 Установка агента на ПК</h2>
<button class="btn-close" onclick="closeModal('pcSetupModal')">&times;</button>
</div>
<div class="instructions-section">
<div class="instr-card">
<h4>📥 Быстрая установка (PowerShell от Администратора)</h4>
<code id="pc-install-cmd">powershell -ExecutionPolicy Bypass -Command "Invoke-WebRequest -Uri 'http://77.239.126.123:7272/static/downloads/install_agent.ps1' -OutFile install_agent.ps1; .\install_agent.ps1 -ServerUrl 'http://77.239.126.123:7272' -AgentName 'MyPC'"</code>
</div>
<div class="instr-card">
<h4>⚙️ Параметры</h4>
<p><b>-ServerUrl</b> — адрес сервера мониторинга<br>
<b>-AgentName</b> — имя ПК (по умолчанию hostname)<br>
<b>-Interval</b> — интервал отправки в секундах (по умолчанию 60)</p>
</div>
<div class="instr-card">
<h4>📊 Что мониторится</h4>
<p>CPU, RAM, Disk (все диски), Network, GPU, Uptime, Top 5 процессов</p>
</div>
<div class="instr-card">
<h4>🔧 Управление</h4>
<ul class="cmd-list">
<li>Get-ScheduledTask 'VPS-Monitor-Agent'</li>
<li>Stop-ScheduledTask 'VPS-Monitor-Agent'</li>
<li>Start-ScheduledTask 'VPS-Monitor-Agent'</li>
<li>Unregister-ScheduledTask 'VPS-Monitor-Agent'</li>
</ul>
</div>
</div>
</div>
</div>
<footer class="app-footer">
автор:&ensp;<a href="https://github.com/andrey271192" target="_blank">GitHub</a>&ensp;·&ensp;<a href="https://boosty.to/iot_andrey" target="_blank">Boosty</a>&ensp;·&ensp;<a href="https://t.me/Iot_andrey" target="_blank">Поддержка</a>&ensp;·&ensp;<a href="https://t.me/Iot_andrey" target="_blank">@Iot_andrey</a>
</footer>
<script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.min.js"></script>
<script src="/static/js/app.js"></script>
</body>
</html>