Update network UI for port ranges

Этот коммит содержится в:
Виктор
2026-05-07 00:50:41 +09:00
родитель 1e911782a2
Коммит 473d410bc4
+23 -10
Просмотреть файл
@@ -11,7 +11,7 @@
<header class="topbar"> <header class="topbar">
<div> <div>
<div class="brand">Сеть</div> <div class="brand">Сеть</div>
<div class="muted">NAT Router для VPS и проброс портов к VM</div> <div class="muted">NAT Router для VPS, проброс одиночных портов и диапазонов к VM</div>
</div> </div>
<div class="top-meta"> <div class="top-meta">
<span>user: {{ user }}</span> <span>user: {{ user }}</span>
@@ -76,17 +76,17 @@
<article class="card"> <article class="card">
<div class="card-head"> <div class="card-head">
<h2>Добавить проброс порта</h2> <h2>Добавить проброс порта</h2>
<span class="pill">DNAT auto IP</span> <span class="pill">DNAT auto IP · ranges</span>
</div> </div>
<form method="post" action="/network/forward/add" class="form-grid"> <form method="post" action="/network/forward/add" class="form-grid">
<label> <label>
<span>Описание</span> <span>Описание</span>
<input type="text" name="note" placeholder="Например: сайт, SSH, SIP, панель управления"> <input type="text" name="note" placeholder="Например: сайт, SSH, SIP, RTP MikoPBX">
</label> </label>
<label> <label>
<span>Внешний порт</span> <span>Внешний порт или диапазон</span>
<input type="number" name="external_port" min="1" max="65535" placeholder="Например: 80, 443, 2222" required> <input type="text" name="external_port" pattern="[0-9]{1,5}([:-][0-9]{1,5})?" placeholder="80, 443, 2222 или 10000-20000" required>
</label> </label>
<label> <label>
@@ -101,8 +101,8 @@
<input type="hidden" name="guest_ip" value="auto"> <input type="hidden" name="guest_ip" value="auto">
<label> <label>
<span>Внутренний порт</span> <span>Внутренний порт или диапазон</span>
<input type="number" name="guest_port" list="standard-ports" min="1" max="65535" placeholder="Выбери стандартный или введи вручную" required> <input type="text" name="guest_port" list="standard-ports" pattern="[0-9]{1,5}([:-][0-9]{1,5})?" placeholder="Выбери стандартный или введи 10000-20000" required>
<datalist id="standard-ports"> <datalist id="standard-ports">
<option value="20" label="FTP data"></option> <option value="20" label="FTP data"></option>
<option value="21" label="FTP"></option> <option value="21" label="FTP"></option>
@@ -133,6 +133,7 @@
<option value="8080" label="HTTP alternative"></option> <option value="8080" label="HTTP alternative"></option>
<option value="8443" label="HTTPS alternative"></option> <option value="8443" label="HTTPS alternative"></option>
<option value="10000" label="Webmin / RTP start"></option> <option value="10000" label="Webmin / RTP start"></option>
<option value="10000-20000" label="RTP / VoIP media range"></option>
</datalist> </datalist>
</label> </label>
@@ -145,7 +146,7 @@
</label> </label>
<div class="notice"> <div class="notice">
Внутренний IP VM подставится автоматически. Внутренний порт можно выбрать из списка или вписать любой вручную. Можно указать одиночный порт или диапазон. Для VoIP/RTP обычно: внешний 10000-20000 → внутренний 10000-20000, протокол udp. Длины диапазонов должны совпадать.
</div> </div>
<button class="primary wide">Добавить и применить</button> <button class="primary wide">Добавить и применить</button>
@@ -232,20 +233,32 @@
</div> </div>
<table> <table>
<thead> <thead>
<tr><th>Внешний порт</th><th>VM</th><th>Внутренний адрес</th><th>Протокол</th><th>Описание</th><th></th></tr> <tr><th>Проброс</th><th>VM</th><th>Внутренний адрес</th><th>Протокол</th><th>Описание</th><th>Действия</th></tr>
</thead> </thead>
<tbody> <tbody>
{% for item in ctx.forwards %} {% for item in ctx.forwards %}
<tr> <tr>
<td class="strong">{{ item.external_port }} → {{ item.guest_port }}</td> <td class="strong">
{{ item.external_port_label|default(item.external_port) }} → {{ item.guest_port_label|default(item.guest_port) }}
{% if item.is_range %}<span class="status warn">range</span>{% endif %}
</td>
<td>{{ item.vm_name }}</td> <td>{{ item.vm_name }}</td>
<td>{{ item.guest_ip }}</td> <td>{{ item.guest_ip }}</td>
<td><span class="status ok">{{ item.protocol }}</span></td> <td><span class="status ok">{{ item.protocol }}</span></td>
<td>{{ item.note }}</td> <td>{{ item.note }}</td>
<td> <td>
<div class="actions">
<form method="post" action="/network/diagnose">
<input type="hidden" name="vm_name" value="{{ item.vm_name }}">
<input type="hidden" name="external_port" value="{{ item.external_port }}">
<input type="hidden" name="guest_port" value="{{ item.guest_port }}">
<input type="hidden" name="protocol" value="{{ item.protocol }}">
<button>Диагностика</button>
</form>
<form method="post" action="/network/forward/{{ item.id }}/delete"> <form method="post" action="/network/forward/{{ item.id }}/delete">
<button class="danger">Удалить</button> <button class="danger">Удалить</button>
</form> </form>
</div>
</td> </td>
</tr> </tr>
{% else %} {% else %}