Files
panel-vpn/web/templates/profile_view.html
T

185 lines
7.6 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>{{.Title}} · VPN Panel</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/static/css/app.css">
</head>
<body class="page-admin">
<aside class="sidebar">
<a class="brand" href="/admin">VPN Panel</a>
<nav>
<a href="/admin">Обзор</a>
<a href="/admin/clients">Пользователи</a>
<a href="/admin/nodes">Ноды</a>
<a class="active" href="/admin/profiles">Профили</a>
<a href="/admin/protocols">Протоколы</a>
</nav>
<div class="sidebar-foot">
<span class="user-chip">{{.UserName}}</span>
<form method="POST" action="/logout"><button type="submit" class="link-btn">Выйти</button></form>
</div>
</aside>
<main class="admin-main">
<header class="admin-header row-head">
<div>
<h1>{{.Profile.Name}}</h1>
<p class="muted">{{.Profile.InboundCount}} inbound(s) · {{.Profile.NodeCount}} node(s)</p>
</div>
<a class="btn btn-ghost" href="/admin/profiles">К списку</a>
</header>
{{if .Flash}}<div class="alert ok">{{.Flash}}</div>{{end}}
{{if .Error}}<div class="alert">{{.Error}}</div>{{end}}
<section class="panel-section">
<h2>Профиль</h2>
<form class="form-card" method="POST" action="/admin/profiles/{{.Profile.ID}}">
<div class="form-grid">
<label>Имя
<input name="name" required value="{{.Profile.Name}}">
</label>
<label>Описание
<input name="description" value="{{.Profile.Description}}">
</label>
</div>
<div class="cta-row">
<button class="btn btn-primary" type="submit">Сохранить</button>
<button class="btn btn-ghost" type="submit" form="delete-profile" onclick="return confirm('Удалить профиль и все инбаунды?');">Удалить</button>
</div>
</form>
<form id="delete-profile" method="POST" action="/admin/profiles/{{.Profile.ID}}/delete"></form>
</section>
<section class="panel-section">
<h2>Инбаунды</h2>
<div class="table-wrap">
<table class="data-table">
<thead>
<tr>
<th>Tag</th>
<th>Протокол</th>
<th>Порт</th>
<th>Network</th>
<th>Security</th>
<th>В профиле</th>
<th></th>
</tr>
</thead>
<tbody>
{{range .Profile.Inbounds}}
<tr>
<td><code>{{.Tag}}</code>{{if .Remark}}<div class="cell-desc">{{.Remark}}</div>{{end}}</td>
<td>{{.ProtocolName}} <code>{{.ProtocolCode}}</code></td>
<td>{{.Port}}</td>
<td>{{.Network}}</td>
<td>{{.Security}}</td>
<td><span class="badge {{if .Enabled}}on{{else}}off{{end}}">{{if .Enabled}}ON{{else}}OFF{{end}}</span></td>
<td class="actions actions-multi">
<a class="btn btn-sm btn-ghost" href="/admin/profiles/{{$.Profile.ID}}/inbounds/{{.ID}}">Изменить</a>
<form method="POST" action="/admin/profiles/{{$.Profile.ID}}/inbounds/{{.ID}}/toggle">
<button class="btn btn-sm btn-ghost" type="submit">{{if .Enabled}}Выкл{{else}}Вкл{{end}}</button>
</form>
<form method="POST" action="/admin/profiles/{{$.Profile.ID}}/inbounds/{{.ID}}/delete" onsubmit="return confirm('Удалить inbound?');">
<button class="btn btn-sm btn-ghost" type="submit">Удалить</button>
</form>
</td>
</tr>
{{else}}
<tr><td colspan="7"><span class="muted">Инбаундов пока нет — добавьте ниже</span></td></tr>
{{end}}
</tbody>
</table>
</div>
</section>
<section class="panel-section">
<h2>Добавить inbound</h2>
<form class="form-card" method="POST" action="/admin/profiles/{{.Profile.ID}}/inbounds">
<div class="form-grid">
<label>Протокол
<select name="protocol_id" required>
{{range .Protocols}}
<option value="{{.ID}}" {{if eq .Code "vless"}}selected{{end}}>{{.Name}} ({{.Code}})</option>
{{end}}
</select>
</label>
<label>Tag
<input name="tag" placeholder="VLESS-443 (авто если пусто)">
</label>
<label>Порт
<input name="port" type="number" value="443" placeholder="443">
</label>
<label>Listen
<input name="listen" value="0.0.0.0">
</label>
<label>Network
<select name="network">
<option value="tcp" selected>tcp</option>
<option value="ws">ws</option>
<option value="grpc">grpc</option>
<option value="httpupgrade">httpupgrade</option>
<option value="xhttp">xhttp</option>
<option value="kcp">kcp</option>
</select>
</label>
<label>Security
<select name="security">
<option value="none">none</option>
<option value="tls">tls</option>
<option value="reality" selected>reality</option>
</select>
</label>
<label>Path / serviceName
<input name="path" placeholder="/ws или grpc service">
</label>
<label>Host header
<input name="host" placeholder="для ws/xhttp">
</label>
<label>SNI
<input name="sni" placeholder="авто из reality names">
</label>
<label>Fingerprint (клиент)
<input name="fingerprint" value="chrome">
</label>
<label>Flow
<input name="flow" value="xtls-rprx-vision" placeholder="xtls-rprx-vision">
</label>
<label>ALPN
<input name="alpn" placeholder="h2,http/1.1">
</label>
<label>Порядок
<input name="sort_order" type="number" value="0">
</label>
<label>Заметка
<input name="remark" placeholder="Sweden RU (имя в подписке)">
</label>
<label>Reality dest
<input name="reality_dest" value="www.microsoft.com:443">
</label>
<label>Reality server names
<input name="reality_server_names" value="www.microsoft.com">
</label>
<label>SpiderX
<input name="spider_x" value="/">
</label>
<label>Fallback dest
<input name="fallback_dest" placeholder="127.0.0.1:80">
</label>
<label>SS method
<input name="ss_method" value="aes-128-gcm">
</label>
</div>
<p class="muted">Xray-core (XTLS/Xray-core): Reality-ключи и shortId генерируются автоматически. На ноде поднимается официальный образ ghcr.io/xtls/xray-core.</p>
<button class="btn btn-primary" type="submit">Добавить inbound</button>
</form>
</section>
</main>
</body>
</html>