v1.7.0: pick server first, then protocol in create flows.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
orohi
2026-07-26 09:00:09 +03:00
co-authored by Cursor
parent 64aa1850a0
commit a9a0eea61d
7 changed files with 266 additions and 68 deletions
+58 -20
View File
@@ -143,9 +143,10 @@
<select class="form-select" id="newUserServer">
<option value="">{{ _('no_create_conn') }}</option>
{% for s in servers %}
<option value="{{ loop.index0 }}">{{ s.name }} ({{ s.host }})</option>
<option value="{{ loop.index0 }}">{{ s.name or s.host }} ({{ s.host }})</option>
{% endfor %}
</select>
<div class="form-hint">{{ _('server_then_protocol_hint') }}</div>
</div>
<div class="form-group" id="newUserProtoGroup" style="display:none;">
@@ -293,10 +294,14 @@
<div class="form-group" id="ucServerGroup">
<label class="form-label">{{ _('server_label') }}</label>
<select class="form-select" id="ucServer">
{% if xui_servers %}
<option value="xui">3x-ui</option>
{% endif %}
{% for s in servers %}
<option value="{{ loop.index0 }}">{{ s.name }} ({{ s.host }})</option>
<option value="{{ loop.index0 }}">{{ s.name or s.host }} ({{ s.host }})</option>
{% endfor %}
</select>
<div class="form-hint">{{ _('server_then_protocol_hint') }}</div>
</div>
<div class="form-group" id="ucProtoGroup">
@@ -626,30 +631,55 @@
const select = document.getElementById(selectId);
const group = groupId ? document.getElementById(groupId) : null;
select.innerHTML = '';
const vpnBases = new Set(['awg', 'awg2', 'awg_legacy', 'xray', 'telemt', 'wireguard']);
const vpnOrder = ['awg2', 'awg', 'awg_legacy', 'wireguard', 'xray', 'telemt'];
const titles = {
awg2: 'AmneziaWG 2.0',
awg: 'AmneziaWG',
awg_legacy: 'AWG Legacy',
wireguard: 'WireGuard',
xray: 'Xray (VLESS-Reality)',
telemt: 'Telemt',
xui: '3x-ui VLESS',
};
const protoTitle = (key) => {
const base = String(key || '').split('__')[0];
const title = titles[base] || base.toUpperCase();
const m = String(key || '').match(/__(\d+)$/);
return m ? `${title} #${m[1]}` : title;
};
let count = 0;
// Special source: 3x-ui (server picker value "xui")
if (String(serverId) === 'xui') {
const opt = document.createElement('option');
opt.value = 'xui';
opt.textContent = titles.xui;
select.appendChild(opt);
count = 1;
if (group) group.style.display = '';
if (selectId === 'ucProtocol') updateXuiInboundVisibility();
return;
}
const server = (serverId !== '' && serversData[serverId]) ? serversData[serverId] : null;
const protocols = (server && server.protocols) || {};
const installed = Object.keys(protocols).filter(key => {
const info = protocols[key] || {};
if (!info.installed) return false;
return vpnOrder.includes(key.split('__')[0]);
}).sort((a, b) => {
const ia = vpnOrder.indexOf(a.split('__')[0]);
const ib = vpnOrder.indexOf(b.split('__')[0]);
return (ia < 0 ? 99 : ia) - (ib < 0 ? 99 : ib) || a.localeCompare(b);
});
for (const [key, info] of Object.entries(protocols)) {
if (!info.installed) continue;
const base = key.split('__')[0];
if (!vpnBases.has(base)) continue;
installed.forEach(key => {
const opt = document.createElement('option');
opt.value = key;
opt.textContent = key === 'awg' ? 'AmneziaWG' : (key === 'awg2' ? 'AmneziaWG 2.0' : (key === 'awg_legacy' ? 'AWG Legacy' : (key === 'xray' ? 'Xray' : (key === 'wireguard' ? 'WireGuard' : (key === 'telemt' ? 'Telemt' : key.toUpperCase())))));
opt.textContent = protoTitle(key);
select.appendChild(opt);
count++;
}
if (xuiConfigured && selectId === 'ucProtocol') {
const opt = document.createElement('option');
opt.value = 'xui';
opt.textContent = '3x-ui VLESS';
select.appendChild(opt);
count++;
}
});
if (count > 0) {
if (group) group.style.display = '';
@@ -724,9 +754,12 @@
document.getElementById('ucServer').addEventListener('change', (e) => {
updateProtocols(e.target.value, 'ucProtocol');
if (document.getElementById('ucMode').value === 'existing') {
const mode = document.getElementById('ucMode').value;
if (mode === 'existing' && e.target.value !== 'xui') {
fetchExistingClients();
}
updateTelemtOptions('ucProtocol', 'ucTelemtOptions');
updateXuiInboundVisibility();
});
document.getElementById('ucProtocol').addEventListener('change', (e) => {
@@ -898,13 +931,18 @@
spinner.classList.remove('hidden');
try {
const serverRaw = document.getElementById('ucServer').value;
const protocol = document.getElementById('ucProtocol').value;
const body = {
server_id: parseInt(document.getElementById('ucServer').value) || 0,
protocol: document.getElementById('ucProtocol').value,
server_id: serverRaw === 'xui' ? 0 : (parseInt(serverRaw, 10) || 0),
protocol: protocol,
name: document.getElementById('ucName').value || 'VPN Connection',
};
if (mode === 'existing') {
if (serverRaw === 'xui' || protocol === 'xui') {
throw new Error(_('link_existing_xui_unsupported') || 'Link existing is only for Amnezia server protocols');
}
const clientId = document.getElementById('ucExistingClient').value;
if (!clientId) throw new Error(_('select_connection'));
body.client_id = clientId;