Files
rmm-openwrt/web/index.html
2026-06-04 17:25:50 +03:00

447 lines
18 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">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>OpenWrt RMM</title>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<main id="loginView" class="login-view">
<form id="loginForm" class="login-form">
<div class="brand login-brand">
<div class="brand-mark">R</div>
<div>
<h1>OpenWrt RMM</h1>
<p>Operator access</p>
</div>
</div>
<label>
Username
<input id="loginUsername" type="text" autocomplete="username" value="admin" required>
</label>
<label>
Password
<input id="loginPassword" type="password" autocomplete="current-password" required>
</label>
<button class="primary" type="submit">Sign in</button>
<p id="loginError" class="login-error"></p>
</form>
</main>
<div id="appShell" class="app-shell is-hidden">
<aside class="sidebar">
<div class="brand">
<div class="brand-mark">R</div>
<div>
<h1>OpenWrt RMM</h1>
<p id="apiState">API: checking</p>
</div>
</div>
<section class="panel auth-panel">
<div class="operator-row">
<div>
<small>Signed in as</small>
<strong id="operatorName">operator</strong>
</div>
<button id="logoutBtn" type="button">Sign out</button>
</div>
</section>
<section class="panel">
<div class="section-title">
<h2>Devices</h2>
<button id="refreshBtn" type="button">Refresh</button>
</div>
<div class="filters">
<button class="filter is-active" data-filter="all" type="button">Все</button>
<button class="filter" data-filter="online" type="button">Онлайн</button>
<button class="filter" data-filter="offline" type="button">Офлайн</button>
<button class="filter" data-filter="alerts" type="button">Проблемы</button>
</div>
<div class="fleet-filter-grid">
<input id="fleetSearch" type="search" placeholder="Поиск по имени, ID, тегу">
<input id="fleetGroupFilter" type="text" placeholder="Группа">
<input id="fleetTagFilter" type="text" placeholder="Тег">
</div>
<div class="bulk-command-grid">
<select id="bulkCommandType">
<option value="ping">ping</option>
<option value="traceroute">traceroute</option>
<option value="pkg_list_installed">pkg_list_installed</option>
</select>
<input id="bulkCommandTarget" type="text" placeholder="цель">
<button id="sendBulkCommandBtn" type="button">Запустить для выбранных</button>
</div>
<div id="deviceList" class="device-list"></div>
</section>
</aside>
<main class="workspace">
<header class="topbar">
<div>
<p class="eyebrow">Fleet</p>
<h2 id="pageTitle">Devices</h2>
</div>
<div id="statusLine" class="status-line">Idle</div>
</header>
<section id="emptyState" class="empty-state">
<h2>No device selected</h2>
<p>Waiting for agent check-in.</p>
</section>
<section id="deviceView" class="device-view is-hidden">
<div class="device-header">
<div>
<p class="eyebrow">Device</p>
<h2 id="deviceName"></h2>
<p id="deviceMeta"></p>
</div>
<span id="deviceBadge" class="badge"></span>
</div>
<section class="panel">
<div class="section-title">
<h2>Состояние роутера</h2>
<span class="summary-pill">кратко</span>
</div>
<div id="healthSummary" class="health-summary"></div>
</section>
<section class="panel">
<div class="section-title">
<h2>Группа и теги</h2>
<button id="saveFleetBtn" type="button">Сохранить</button>
</div>
<div class="fleet-form">
<label>
Group
<input id="fleetGroup" type="text" placeholder="core, lab, home">
</label>
<label>
Tags
<input id="fleetTags" type="text" placeholder="edge, vpn, test">
</label>
</div>
</section>
<div class="metrics-grid">
<div class="metric">
<span>Last seen</span>
<strong id="lastSeen">-</strong>
</div>
<div class="metric">
<span>Load average</span>
<strong id="loadAvg">-</strong>
</div>
<div class="metric">
<span>Uptime</span>
<strong id="uptime">-</strong>
</div>
<div class="metric">
<span>Default route</span>
<strong id="defaultRoute">-</strong>
</div>
<div class="metric">
<span>WAN IP</span>
<strong id="wanIp">-</strong>
</div>
<div class="metric">
<span>Memory</span>
<strong id="memoryUsage">-</strong>
</div>
<div class="metric">
<span>Disk</span>
<strong id="diskUsage">-</strong>
</div>
<div class="metric">
<span>Clients</span>
<strong id="clientCounts">-</strong>
</div>
<div class="metric">
<span>Connectivity</span>
<strong id="connectivityStatus">-</strong>
</div>
</div>
<div class="two-column">
<section class="panel">
<div class="section-title">
<h2>Inventory</h2>
</div>
<pre id="inventoryJson" class="code-block"></pre>
</section>
<section class="panel">
<div class="section-title">
<h2>Команда вручную</h2>
</div>
<div class="command-form">
<select id="commandType">
<option value="ping">ping</option>
<option value="traceroute">traceroute</option>
<option value="route_show">show routes</option>
<option value="interfaces_show">show interfaces</option>
<option value="pkg_list_installed">pkg_list_installed</option>
<option value="reboot">reboot</option>
</select>
<input id="commandTarget" type="text" placeholder="1.1.1.1">
<button id="sendCommandBtn" type="button">Запустить</button>
</div>
</section>
</div>
<section class="panel">
<div class="section-title">
<h2>Быстрая диагностика</h2>
<span class="summary-pill">без SSH</span>
</div>
<div class="diagnostic-grid">
<button class="diagnostic-btn" data-diagnostic="ping_server" type="button">Проверить связь с сервером</button>
<button class="diagnostic-btn" data-diagnostic="ping_internet" type="button">Проверить интернет</button>
<button class="diagnostic-btn" data-diagnostic="traceroute_internet" type="button">Маршрут до интернета</button>
<button class="diagnostic-btn" data-diagnostic="show_routes" type="button">Показать маршруты</button>
<button class="diagnostic-btn" data-diagnostic="show_interfaces" type="button">Показать интерфейсы</button>
</div>
</section>
<div class="two-column">
<section class="panel">
<div class="section-title">
<h2>Leases and Wi-Fi</h2>
</div>
<div id="clientList" class="table-list"></div>
</section>
<section class="panel">
<div class="section-title">
<h2>Interface counters</h2>
</div>
<div id="interfaceCounters" class="table-list"></div>
</section>
</div>
<section class="panel">
<div class="section-title">
<h2>Проблемы</h2>
<div class="section-actions">
<span id="alertSummary" class="summary-pill">0 active</span>
<button id="reloadAlertsBtn" type="button">Обновить</button>
</div>
</div>
<div id="alertList" class="table-list"></div>
</section>
<section class="panel">
<div class="section-title">
<h2>История мониторинга</h2>
<button id="reloadMetricsHistoryBtn" type="button">Обновить</button>
</div>
<div id="metricsHistory" class="table-list"></div>
</section>
<section class="panel">
<div class="section-title">
<h2>UCI configuration</h2>
</div>
<div class="uci-grid">
<label>
Package
<select id="uciConfig">
<option value="network">network</option>
<option value="wireless">wireless</option>
<option value="dhcp">dhcp</option>
<option value="firewall">firewall</option>
<option value="system">system</option>
</select>
</label>
<label>
Section
<input id="uciSection" type="text" placeholder="lan or @wifi-iface[0]">
</label>
<label>
Option
<input id="uciOption" type="text" placeholder="ipaddr">
</label>
<label>
Value
<input id="uciValue" type="text" placeholder="192.168.1.1">
</label>
<label class="check-row">
<input id="uciCommitNow" type="checkbox">
Commit immediately
</label>
</div>
<div class="uci-actions">
<button id="uciBackupBtn" type="button">Backup</button>
<button id="uciPreviewBtn" type="button">Preview</button>
<button id="uciShowBtn" type="button">Show</button>
<button id="uciSetBtn" type="button">Stage set</button>
<button id="uciCommitBtn" type="button">Commit</button>
<button id="uciCommitConfirmedBtn" type="button">Commit + check</button>
<button id="uciRevertBtn" type="button">Revert</button>
<button id="uciRestoreBtn" type="button">Restore backup</button>
</div>
</section>
<section class="panel">
<div class="section-title">
<h2>Packages</h2>
</div>
<div class="package-grid">
<select id="packageCommand">
<option value="pkg_list_installed">List installed</option>
<option value="pkg_update">Update package index</option>
<option value="pkg_list_upgradable">List upgradable</option>
<option value="pkg_install">Install package</option>
<option value="pkg_remove">Remove package</option>
</select>
<input id="packageName" type="text" placeholder="package name">
<button id="sendPackageCommandBtn" type="button">Queue</button>
</div>
</section>
<section class="panel">
<div class="section-title">
<h2>Remote access</h2>
<div class="section-actions">
<span id="remoteSummary" class="summary-pill">0 sessions</span>
<button id="reloadRemoteSessionsBtn" type="button">Reload</button>
</div>
</div>
<div class="remote-form">
<label>
Tunnel server
<input id="remoteServerHost" type="text" placeholder="10.10.10.2">
</label>
<label>
Server SSH port
<input id="remoteServerPort" type="number" min="1" max="65535" value="2222">
</label>
<label>
Remote port
<input id="remotePort" type="number" min="1" max="65535" placeholder="auto">
</label>
<label>
Router SSH port
<input id="remoteLocalPort" type="number" min="1" max="65535" value="22">
</label>
<label>
LuCI protocol
<select id="remoteLuCIScheme">
<option value="http">HTTP</option>
<option value="https">HTTPS</option>
</select>
</label>
<label>
Duration
<select id="remoteDuration">
<option value="900">15 min</option>
<option value="1800">30 min</option>
<option value="3600">1 hour</option>
<option value="7200">2 hours</option>
</select>
</label>
<button id="createRemoteSessionBtn" type="button">Open remote access</button>
</div>
<div class="remote-hint">
Active sessions provide SSH and an authenticated Open LuCI button. Choose the protocol used by this router.
</div>
<div id="remoteSessionList" class="table-list remote-session-list"></div>
</section>
<section id="commandsPanel" class="panel">
<div class="section-title">
<h2>UCI presets</h2>
</div>
<div class="preset-grid">
<div class="preset">
<h3>LAN IP</h3>
<input id="presetLanIp" type="text" placeholder="10.10.10.1/24">
<div>
<button class="preset-btn" data-preset="lan_ip" data-action="preview" type="button">Preview</button>
<button class="preset-btn" data-preset="lan_ip" data-action="stage" type="button">Stage</button>
</div>
</div>
<div class="preset">
<h3>Hostname</h3>
<input id="presetHostname" type="text" placeholder="OpenWrt">
<div>
<button class="preset-btn" data-preset="hostname" data-action="preview" type="button">Preview</button>
<button class="preset-btn" data-preset="hostname" data-action="stage" type="button">Stage</button>
</div>
</div>
<div class="preset">
<h3>Wi-Fi</h3>
<input id="presetWifiSsid" type="text" placeholder="SSID">
<input id="presetWifiKey" type="password" placeholder="Password">
<div>
<button class="preset-btn" data-preset="wifi_ssid" data-action="preview" type="button">SSID preview</button>
<button class="preset-btn" data-preset="wifi_ssid" data-action="stage" type="button">SSID stage</button>
<button class="preset-btn" data-preset="wifi_key" data-action="preview" type="button">Key preview</button>
<button class="preset-btn" data-preset="wifi_key" data-action="stage" type="button">Key stage</button>
</div>
</div>
<div class="preset">
<h3>DHCP LAN</h3>
<select id="presetDhcpLan">
<option value="0">enabled</option>
<option value="1">disabled</option>
</select>
<div>
<button class="preset-btn" data-preset="dhcp_lan" data-action="preview" type="button">Preview</button>
<button class="preset-btn" data-preset="dhcp_lan" data-action="stage" type="button">Stage</button>
</div>
</div>
</div>
</section>
<section class="panel">
<div class="section-title">
<h2>История команд</h2>
<div class="section-actions">
<span id="commandSummary" class="summary-pill">0 total</span>
<button id="reloadCommandsBtn" type="button">Обновить</button>
</div>
</div>
<div class="filters command-filters">
<button class="command-filter is-active" data-command-filter="all" type="button">All</button>
<button class="command-filter" data-command-filter="queued" type="button">Queued</button>
<button class="command-filter" data-command-filter="claimed" type="button">Running</button>
<button class="command-filter" data-command-filter="completed" type="button">Done</button>
<button class="command-filter" data-command-filter="failed" type="button">Failed</button>
<button class="command-filter" data-command-filter="expired" type="button">Expired</button>
<button class="command-filter" data-command-filter="cancelled" type="button">Cancelled</button>
</div>
<div id="commandList" class="table-list"></div>
</section>
<section id="commandDetailPanel" class="panel is-hidden">
<div class="section-title">
<h2>Command detail</h2>
<button id="copyCommandOutputBtn" type="button">Copy output</button>
</div>
<div id="commandDetailMeta" class="detail-meta"></div>
<pre id="commandDetailOutput" class="command-detail-output"></pre>
</section>
<section class="panel">
<div class="section-title">
<h2>Audit</h2>
<div class="section-actions">
<span id="auditSummary" class="summary-pill">0 events</span>
<button id="reloadAuditBtn" type="button">Reload</button>
</div>
</div>
<div id="auditList" class="table-list"></div>
</section>
</section>
</main>
</div>
<script src="/app.js?v=8" defer></script>
</body>
</html>