Show protocol enable state and which nodes have each protocol installed.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+31
-2
@@ -274,8 +274,37 @@ input:focus {
|
||||
padding: 0.25rem 0.55rem;
|
||||
border-radius: 999px;
|
||||
}
|
||||
.badge.on { background: rgba(61,214,198,0.15); color: var(--ok); }
|
||||
.badge.off { background: rgba(122,135,156,0.18); color: var(--off); }
|
||||
.chip-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.2rem 0.55rem;
|
||||
border-radius: 999px;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
background: rgba(122,135,156,0.16);
|
||||
color: var(--muted);
|
||||
border: 1px solid var(--line);
|
||||
}
|
||||
.chip.on { background: rgba(61,214,198,0.15); color: var(--ok); border-color: rgba(61,214,198,0.3); }
|
||||
.chip.warn { background: rgba(255,196,87,0.14); color: #ffc457; }
|
||||
.chip.err { background: rgba(255,107,122,0.14); color: #ff8a96; }
|
||||
.chip.off { opacity: 0.85; }
|
||||
|
||||
.actions-multi {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.35rem;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.row-off { opacity: 0.78; }
|
||||
.proto-servers { margin-top: 0.75rem; }
|
||||
.proto-servers .stat-label { margin-bottom: 0.35rem; }
|
||||
|
||||
.badge.warn { background: rgba(255, 196, 87, 0.16); color: #ffc457; }
|
||||
.badge.err { background: rgba(255,107,122,0.15); color: #ff8a96; }
|
||||
|
||||
|
||||
@@ -88,13 +88,25 @@
|
||||
<article class="proto-card {{if .Enabled}}is-on{{else}}is-off{{end}}">
|
||||
<div class="proto-top">
|
||||
<h3>{{.Name}}</h3>
|
||||
<span class="badge {{if .Enabled}}on{{else}}off{{end}}">{{if .Enabled}}ON{{else}}OFF{{end}}</span>
|
||||
<span class="badge {{if .Enabled}}on{{else}}off{{end}}">{{.EnabledLabel}}</span>
|
||||
</div>
|
||||
<p>{{.Description}}</p>
|
||||
<div class="proto-meta">
|
||||
<code>{{.Code}}</code>
|
||||
<span>порт {{.Port}}</span>
|
||||
</div>
|
||||
<div class="proto-servers">
|
||||
{{if .InstalledOn}}
|
||||
<span class="stat-label">Серверы</span>
|
||||
<div class="chip-list">
|
||||
{{range .InstalledOn}}
|
||||
<a class="chip {{statusClass (printf "%s" .Status)}}" href="/admin/nodes/{{.NodeID}}">{{.NodeName}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
{{else}}
|
||||
<span class="muted">Не установлен ни на одной ноде</span>
|
||||
{{end}}
|
||||
</div>
|
||||
</article>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
@@ -46,12 +46,69 @@
|
||||
<form method="POST" action="/admin/nodes/{{.Node.ID}}/check">
|
||||
<button class="btn btn-ghost" type="submit">Проверить online</button>
|
||||
</form>
|
||||
<form method="POST" action="/admin/nodes/{{.Node.ID}}/sync">
|
||||
<button class="btn btn-ghost" type="submit">Синхронизировать протоколы</button>
|
||||
</form>
|
||||
<form method="POST" action="/admin/nodes/{{.Node.ID}}/delete" onsubmit="return confirm('Удалить ноду из панели?');">
|
||||
<button class="btn btn-ghost" type="submit">Удалить</button>
|
||||
</form>
|
||||
<a class="btn btn-ghost" href="/admin/nodes">К списку</a>
|
||||
</div>
|
||||
|
||||
<section class="panel-section">
|
||||
<h2>Протоколы на этом сервере</h2>
|
||||
<div class="table-wrap">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Протокол</th>
|
||||
<th>Порт</th>
|
||||
<th>Установлен</th>
|
||||
<th>Включён</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .NodeProtocols}}
|
||||
<tr>
|
||||
<td>
|
||||
<strong>{{.ProtocolName}}</strong>
|
||||
<div><code>{{.ProtocolCode}}</code></div>
|
||||
</td>
|
||||
<td>{{.Port}}</td>
|
||||
<td><span class="badge {{if .Installed}}on{{else}}off{{end}}">{{if .Installed}}Да{{else}}Нет{{end}}</span></td>
|
||||
<td><span class="badge {{if .Enabled}}on{{else}}off{{end}}">{{if .Enabled}}ON{{else}}OFF{{end}}</span></td>
|
||||
<td class="actions actions-multi">
|
||||
{{if not .Installed}}
|
||||
<form method="POST" action="/admin/nodes/{{$.Node.ID}}/protocols/{{.ProtocolID}}">
|
||||
<input type="hidden" name="action" value="install">
|
||||
<button class="btn btn-sm btn-primary" type="submit">Установить</button>
|
||||
</form>
|
||||
{{else}}
|
||||
{{if .Enabled}}
|
||||
<form method="POST" action="/admin/nodes/{{$.Node.ID}}/protocols/{{.ProtocolID}}">
|
||||
<input type="hidden" name="action" value="disable">
|
||||
<button class="btn btn-sm btn-ghost" type="submit">Выключить</button>
|
||||
</form>
|
||||
{{else}}
|
||||
<form method="POST" action="/admin/nodes/{{$.Node.ID}}/protocols/{{.ProtocolID}}">
|
||||
<input type="hidden" name="action" value="enable">
|
||||
<button class="btn btn-sm btn-primary" type="submit">Включить</button>
|
||||
</form>
|
||||
{{end}}
|
||||
<form method="POST" action="/admin/nodes/{{$.Node.ID}}/protocols/{{.ProtocolID}}">
|
||||
<input type="hidden" name="action" value="uninstall">
|
||||
<button class="btn btn-sm btn-ghost" type="submit">Снять</button>
|
||||
</form>
|
||||
{{end}}
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel-section">
|
||||
<h2>Важно</h2>
|
||||
<p class="muted">Откройте порт <strong>{{.Node.NodePort}}</strong> на ноде <em>только</em> для IP панели (как NODE_PORT в Remnawave).</p>
|
||||
|
||||
@@ -26,31 +26,57 @@
|
||||
<main class="admin-main">
|
||||
<header class="admin-header">
|
||||
<h1>Протоколы</h1>
|
||||
<p class="muted">Включение и отключение VPN-протоколов</p>
|
||||
<p class="muted">Статус в панели и на каких серверах протокол установлен / включён</p>
|
||||
</header>
|
||||
|
||||
{{if .Flash}}<div class="alert ok">{{.Flash}}</div>{{end}}
|
||||
{{if .Error}}<div class="alert">{{.Error}}</div>{{end}}
|
||||
|
||||
<div class="table-wrap">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Протокол</th>
|
||||
<th>Код</th>
|
||||
<th>Порт</th>
|
||||
<th>Статус</th>
|
||||
<th>В панели</th>
|
||||
<th>Установлен на</th>
|
||||
<th>Включён на</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .Protocols}}
|
||||
<tr>
|
||||
<tr class="{{if .Enabled}}row-on{{else}}row-off{{end}}">
|
||||
<td>
|
||||
<strong>{{.Name}}</strong>
|
||||
<div class="cell-desc">{{.Description}}</div>
|
||||
<code>{{.Code}}</code>
|
||||
</td>
|
||||
<td><code>{{.Code}}</code></td>
|
||||
<td>{{.Port}}</td>
|
||||
<td>
|
||||
<span class="badge {{if .Enabled}}on{{else}}off{{end}}">{{if .Enabled}}Включён{{else}}Выключен{{end}}</span>
|
||||
<span class="badge {{if .Enabled}}on{{else}}off{{end}}">{{.EnabledLabel}}</span>
|
||||
</td>
|
||||
<td>
|
||||
{{if .InstalledOn}}
|
||||
<div class="chip-list">
|
||||
{{range .InstalledOn}}
|
||||
<a class="chip {{statusClass (printf "%s" .Status)}}" href="/admin/nodes/{{.NodeID}}" title="{{.Host}}">{{.NodeName}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
{{else}}
|
||||
<span class="muted">нигде</span>
|
||||
{{end}}
|
||||
</td>
|
||||
<td>
|
||||
{{if .EnabledOn}}
|
||||
<div class="chip-list">
|
||||
{{range .EnabledOn}}
|
||||
<a class="chip on" href="/admin/nodes/{{.NodeID}}" title="{{.Host}}">{{.NodeName}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
{{else}}
|
||||
<span class="muted">нигде</span>
|
||||
{{end}}
|
||||
</td>
|
||||
<td class="actions">
|
||||
<form method="POST" action="/admin/protocols/{{.ID}}/toggle">
|
||||
@@ -64,6 +90,11 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<p class="hint" style="margin-top:1rem">
|
||||
Установка на сервер — на странице ноды. «В панели» = доступен в каталоге;
|
||||
«Установлен / Включён на» = фактическое состояние на серверах.
|
||||
</p>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user