Template
Remove Hysteria 2 from the panel for now.
Drop the protocol manager, UI, API routes, and related translations until it can be reintroduced cleanly. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -128,7 +128,7 @@
|
||||
{% for s in servers %}
|
||||
{% set server_idx = loop.index0 %}
|
||||
{% for key, info in (s.protocols or {}).items() %}
|
||||
{% if info.installed and key.split('__')[0] in ['awg','awg2','awg_legacy','xray','wireguard','telemt','hysteria'] %}
|
||||
{% if info.installed and key.split('__')[0] in ['awg','awg2','awg_legacy','xray','wireguard','telemt'] %}
|
||||
<option value="{{ key }}|{{ server_idx }}">{{ s.name or s.host }} — {{ key }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
@@ -117,10 +117,10 @@
|
||||
document.getElementById('configText').textContent = result.config;
|
||||
document.getElementById('vpnLinkText').textContent = currentVpnLink;
|
||||
|
||||
// Telemt / Hysteria use share links, not vpn:// Amnezia format
|
||||
// Telemt uses share links, not vpn:// Amnezia format
|
||||
const vpnTab = document.querySelectorAll('.config-tab')[1];
|
||||
const vpnPanel = document.getElementById('panel-vpn');
|
||||
if (proto === 'telemt' || String(proto || '').split('__')[0] === 'hysteria') {
|
||||
if (proto === 'telemt') {
|
||||
vpnTab.style.display = 'none';
|
||||
} else {
|
||||
vpnTab.style.display = '';
|
||||
|
||||
+8
-227
@@ -294,30 +294,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hysteria Card -->
|
||||
<div class="card card-hover protocol-card protocol-hysteria" id="proto-hysteria">
|
||||
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--space-sm);">
|
||||
<div class="protocol-icon">🌀</div>
|
||||
<div class="flex gap-sm" id="hysteria-ctrl" style="display:none!important;"></div>
|
||||
</div>
|
||||
<div class="protocol-name">Hysteria 2</div>
|
||||
<div class="protocol-desc">
|
||||
{{ _('hysteria_desc') }}
|
||||
</div>
|
||||
<div class="protocol-status" id="hysteria-status">
|
||||
<span class="badge badge-warn"><span class="badge-dot"></span> {{ _('not_checked') }}</span>
|
||||
</div>
|
||||
<div id="hysteria-info" class="hidden">
|
||||
<div class="protocol-info" id="hysteria-info-grid"></div>
|
||||
</div>
|
||||
<div class="flex gap-sm" id="hysteria-actions">
|
||||
<button class="btn btn-primary btn-sm" onclick="openInstallModal('hysteria')" id="hysteria-install-btn"
|
||||
style="flex:1">
|
||||
{{ _('install') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- WireGuard Card -->
|
||||
<div class="card card-hover protocol-card protocol-wireguard" id="proto-wireguard">
|
||||
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--space-sm);">
|
||||
@@ -679,25 +655,6 @@
|
||||
<div class="form-hint">{{ _('nginx_install_hint') }}</div>
|
||||
</div>
|
||||
|
||||
<div id="hysteriaOptions"
|
||||
style="display:none; padding: var(--space-md); background: rgba(0,0,0,0.03); border-radius: var(--radius-md); margin-bottom: var(--space-md);">
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ _('port') }} (UDP) *</label>
|
||||
<input class="form-input" type="number" id="installHysteriaPort" value="8998" min="1" max="65535">
|
||||
<div class="form-hint">{{ _('hysteria_port_hint') }}</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ _('hysteria_domain') }}</label>
|
||||
<input class="form-input" type="text" id="installHysteriaDomain" placeholder="vpn.example.com" oninput="updateHysteriaDnsHint()">
|
||||
<div class="form-hint" id="hysteriaDnsHint"></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ _('hysteria_email') }}</label>
|
||||
<input class="form-input" type="email" id="installHysteriaEmail" placeholder="admin@example.com">
|
||||
</div>
|
||||
<div class="form-hint">{{ _('hysteria_install_hint') }}</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" onclick="closeModal('installModal')">{{ _('cancel') }}</button>
|
||||
<button class="btn btn-primary" onclick="installProtocol()" id="installBtn">
|
||||
@@ -752,33 +709,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===== Hysteria Settings Modal ===== -->
|
||||
<div class="modal-backdrop" id="hysteriaSettingsModal">
|
||||
<div class="modal">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="hysteriaSettingsTitle">{{ _('hysteria_settings_title') }}</h2>
|
||||
<button class="modal-close" onclick="closeModal('hysteriaSettingsModal')">×</button>
|
||||
</div>
|
||||
<input type="hidden" id="hysteriaSetProto" value="hysteria" />
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ _('hysteria_domain') }}</label>
|
||||
<input class="form-input" type="text" id="hysteriaSetDomain" disabled>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ _('port') }} (UDP)</label>
|
||||
<input class="form-input" type="number" id="hysteriaSetPort" min="1" max="65535" value="8998">
|
||||
<div class="form-hint">{{ _('hysteria_port_change_hint') }}</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" onclick="closeModal('hysteriaSettingsModal')">{{ _('cancel') }}</button>
|
||||
<button class="btn btn-primary" onclick="saveHysteriaSettings()" id="hysteriaSaveBtn">
|
||||
<span id="hysteriaSaveBtnText">{{ _('save') }}</span>
|
||||
<div class="spinner hidden" id="hysteriaSaveSpinner"></div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===== NGINX Site Modal ===== -->
|
||||
<div class="modal-backdrop" id="siteConfigModal">
|
||||
<div class="modal" style="max-width:680px;">
|
||||
@@ -1027,7 +957,6 @@
|
||||
{ proto: 'awg_legacy', category: 'protocols', icon: '📡', title: 'AmneziaWG Legacy', descKey: 'awg_legacy_desc' },
|
||||
{ proto: 'xray', category: 'protocols', icon: '⚡', title: 'Xray (VLESS-Reality)', descKey: 'xray_desc' },
|
||||
{ proto: 'telemt', category: 'protocols', icon: '✈', title: 'Telemt (Telegram Proxy)', descKey: 'telemt_desc' },
|
||||
{ proto: 'hysteria', category: 'protocols', icon: '🌀', title: 'Hysteria 2', descKey: 'hysteria_desc' },
|
||||
{ proto: 'wireguard', category: 'protocols', icon: '🔒', title: 'WireGuard', descKey: 'wireguard_desc' },
|
||||
{ proto: 'dns', category: 'services', icon: '🔍', title: 'AmneziaDNS', descKey: 'dns_desc' },
|
||||
{ proto: 'adguard', category: 'services', icon: '🛡️', title: 'AdGuard Home', descKey: 'adguard_desc' },
|
||||
@@ -1063,7 +992,7 @@
|
||||
}
|
||||
|
||||
function isMultiInstanceBase(proto) {
|
||||
return ['awg', 'awg2', 'awg_legacy', 'xray', 'telemt', 'hysteria', 'socks5'].includes(protoBase(proto));
|
||||
return ['awg', 'awg2', 'awg_legacy', 'xray', 'telemt', 'socks5'].includes(protoBase(proto));
|
||||
}
|
||||
|
||||
function nextSuggestedPort(base, fallback) {
|
||||
@@ -1268,7 +1197,6 @@
|
||||
case 'awg_legacy': title = 'AmneziaWG Legacy'; break;
|
||||
case 'xray': title = 'Xray'; break;
|
||||
case 'telemt': title = 'Telemt'; break;
|
||||
case 'hysteria': title = 'Hysteria 2'; break;
|
||||
case 'wireguard': title = 'WireGuard'; break;
|
||||
case 'dns': title = 'AmneziaDNS'; break;
|
||||
case 'socks5': title = 'SOCKS5 Proxy'; break;
|
||||
@@ -1328,7 +1256,7 @@
|
||||
|
||||
for (const [proto, info] of orderedProtocolEntries(data.protocols)) {
|
||||
updateProtocolCard(proto, info);
|
||||
const isVPN = ['awg', 'awg2', 'awg_legacy', 'xray', 'telemt', 'hysteria', 'wireguard'].includes(protoBase(proto));
|
||||
const isVPN = ['awg', 'awg2', 'awg_legacy', 'xray', 'telemt', 'wireguard'].includes(protoBase(proto));
|
||||
if (info.container_running && isVPN) {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = proto;
|
||||
@@ -1557,9 +1485,6 @@
|
||||
grid = buildServiceInfoGrid(proto, info);
|
||||
} else if (info.port) {
|
||||
grid += `<div class="protocol-info-item"><span class="protocol-info-label">${_('port')}</span><span class="protocol-info-value">${info.port}/${(['xray', 'telemt'].includes(protoBase(proto))) ? 'TCP' : 'UDP'}</span></div>`;
|
||||
if (protoBase(proto) === 'hysteria' && info.domain) {
|
||||
grid += `<div class="protocol-info-item"><span class="protocol-info-label">${_('hysteria_domain')}</span><span class="protocol-info-value">${info.domain}</span></div>`;
|
||||
}
|
||||
}
|
||||
if (!isService && info.clients_count !== undefined) {
|
||||
grid += `<div class="protocol-info-item"><span class="protocol-info-label">${_('connections')}</span><span class="protocol-info-value">${info.clients_count}</span></div>`;
|
||||
@@ -1594,14 +1519,6 @@
|
||||
<button class="btn btn-secondary btn-sm" onclick="showProtocolBackups('${proto}')" style="flex:1">${_('backup')}</button>
|
||||
<button class="btn btn-danger btn-sm" onclick="uninstallProtocol('${proto}')">${_('uninstall')}</button>
|
||||
`;
|
||||
} else if (protoBase(proto) === 'hysteria') {
|
||||
actionsEl.innerHTML = `
|
||||
<button class="btn btn-secondary btn-sm" onclick="selectProtocolForConns('${proto}')" style="flex:1">${_('connections')}</button>
|
||||
<button class="btn btn-secondary btn-sm" onclick="openHysteriaSettings('${proto}')">${_('hysteria_change_port')}</button>
|
||||
<button class="btn btn-secondary btn-sm" onclick="showProtocolBackups('${proto}')">${_('backup')}</button>
|
||||
<button class="btn btn-danger btn-sm" onclick="uninstallProtocol('${proto}')">${_('uninstall')}</button>
|
||||
`;
|
||||
showConnectionsSection();
|
||||
} else {
|
||||
actionsEl.innerHTML = `
|
||||
<button class="btn btn-secondary btn-sm" onclick="selectProtocolForConns('${proto}')" style="flex:1">${_('connections')}</button>
|
||||
@@ -1638,7 +1555,6 @@
|
||||
} else if (info.container_exists) {
|
||||
installedProtocols[proto] = true;
|
||||
const errText = String(info.error || '').trim();
|
||||
const portBusy = !!info.port_busy || /address already in use|UDP port \d+ already in use|already in use/i.test(errText);
|
||||
statusEl.innerHTML = errText
|
||||
? `<span class="badge badge-danger" style="max-width:100%; white-space:normal; text-align:left; line-height:1.35;"><span class="badge-dot"></span> ${_('stop')}: ${escapeHtml(errText.slice(0, 120))}</span>`
|
||||
: `<span class="badge badge-danger"><span class="badge-dot"></span> ${_('stop')}</span>`;
|
||||
@@ -1657,26 +1573,6 @@
|
||||
if (errText) {
|
||||
grid += `<div class="protocol-info-item" style="grid-column:1/-1;"><span class="protocol-info-label">${_('error')}</span><span class="protocol-info-value" style="color:var(--danger); word-break:break-word;">${escapeHtml(errText)}</span></div>`;
|
||||
}
|
||||
// Inline port picker — always visible when Hysteria is stopped so admin can fix bind conflicts
|
||||
if (protoBase(proto) === 'hysteria') {
|
||||
const curPort = parseInt(info.port, 10) || 443;
|
||||
const suggest = (curPort === 443 || portBusy) ? 8998 : curPort;
|
||||
grid += `
|
||||
<div class="protocol-info-item" style="grid-column:1/-1; display:block; padding-top:8px;">
|
||||
<span class="protocol-info-label" style="display:block; margin-bottom:6px;">${_('hysteria_change_port')} (UDP)</span>
|
||||
<div style="display:flex; gap:8px; flex-wrap:wrap; align-items:center;">
|
||||
<input class="form-input" type="number" id="hysteriaInlinePort-${protoDomKey(proto)}"
|
||||
value="${suggest}" min="1" max="65535" style="width:120px; flex:0 0 auto;">
|
||||
<button class="btn btn-primary btn-sm" type="button"
|
||||
onclick="applyHysteriaPort('${proto}', document.getElementById('hysteriaInlinePort-${protoDomKey(proto)}').value)">
|
||||
${_('save')} & ${_('start_btn')}
|
||||
</button>
|
||||
<button class="btn btn-secondary btn-sm" type="button" onclick="openHysteriaSettings('${proto}')">${_('hysteria_settings_title')}</button>
|
||||
</div>
|
||||
<div class="form-hint" style="margin-top:6px;">${_('hysteria_port_change_hint')}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
infoGrid.innerHTML = grid;
|
||||
}
|
||||
if (isService) {
|
||||
@@ -1686,13 +1582,6 @@
|
||||
<button class="btn btn-secondary btn-sm" onclick="showProtocolBackups('${proto}')">${_('backup')}</button>
|
||||
<button class="btn btn-danger btn-sm" onclick="uninstallProtocol('${proto}')">${_('uninstall')}</button>
|
||||
`;
|
||||
} else if (protoBase(proto) === 'hysteria') {
|
||||
actionsEl.innerHTML = `
|
||||
<button class="btn btn-primary btn-sm" onclick="openHysteriaSettings('${proto}')" style="flex:1">${_('hysteria_change_port')}</button>
|
||||
<button class="btn btn-secondary btn-sm" onclick="showContainerLogs('${proto}')">${_('logs_btn')}</button>
|
||||
<button class="btn btn-secondary btn-sm" onclick="openInstallModal('${proto}')">${_('reinstall')}</button>
|
||||
<button class="btn btn-danger btn-sm" onclick="uninstallProtocol('${proto}')">${_('uninstall')}</button>
|
||||
`;
|
||||
} else {
|
||||
actionsEl.innerHTML = `
|
||||
<button class="btn btn-primary btn-sm" onclick="openInstallModal('${proto}')" style="flex:1">${_('reinstall')}</button>
|
||||
@@ -1973,14 +1862,6 @@
|
||||
hint.innerHTML = `${_('nginx_dns_hint')} <code>A ${domain} ${SERVER_HOST}</code>`;
|
||||
}
|
||||
|
||||
function updateHysteriaDnsHint() {
|
||||
const input = document.getElementById('installHysteriaDomain');
|
||||
const hint = document.getElementById('hysteriaDnsHint');
|
||||
if (!input || !hint) return;
|
||||
const domain = (input.value || '').trim() || 'vpn.example.com';
|
||||
hint.innerHTML = `${_('hysteria_dns_hint')} <code>A ${domain} ${SERVER_HOST}</code>`;
|
||||
}
|
||||
|
||||
function openInstallModal(proto, installAnother = false) {
|
||||
const base = protoBase(proto);
|
||||
currentInstallProto = installAnother ? base : proto;
|
||||
@@ -1996,13 +1877,11 @@
|
||||
const socks5Opts = document.getElementById('socks5Options');
|
||||
const adguardOpts = document.getElementById('adguardOptions');
|
||||
const nginxOpts = document.getElementById('nginxOptions');
|
||||
const hysteriaOpts = document.getElementById('hysteriaOptions');
|
||||
|
||||
telemtOpts.style.display = 'none';
|
||||
socks5Opts.style.display = 'none';
|
||||
adguardOpts.style.display = 'none';
|
||||
nginxOpts.style.display = 'none';
|
||||
hysteriaOpts.style.display = 'none';
|
||||
if (portGroup) portGroup.style.display = '';
|
||||
|
||||
if (base === 'dns') {
|
||||
@@ -2040,19 +1919,6 @@
|
||||
portHint.textContent = _('nginx_port_hint');
|
||||
nginxOpts.style.display = 'block';
|
||||
updateNginxDnsHint();
|
||||
} else if (base === 'hysteria') {
|
||||
// Port is chosen inside hysteriaOptions (dedicated UDP field)
|
||||
if (portGroup) portGroup.style.display = 'none';
|
||||
const suggested = currentInstallAnother ? nextSuggestedPort(currentInstallProto, 8998) : '8998';
|
||||
portInput.value = suggested;
|
||||
portInput.disabled = false;
|
||||
hysteriaOpts.style.display = 'block';
|
||||
const hyPort = document.getElementById('installHysteriaPort');
|
||||
if (hyPort) {
|
||||
hyPort.value = suggested;
|
||||
hyPort.oninput = () => { portInput.value = hyPort.value; };
|
||||
}
|
||||
updateHysteriaDnsHint();
|
||||
} else {
|
||||
portLabel.textContent = _('port') + ' (UDP)';
|
||||
portInput.value = currentInstallAnother ? nextSuggestedPort(currentInstallProto, 55424) : '55424';
|
||||
@@ -2119,13 +1985,6 @@
|
||||
} else if (protoBase(currentInstallProto) === 'nginx') {
|
||||
params.nginx_domain = document.getElementById('installNginxDomain').value.trim();
|
||||
params.nginx_email = document.getElementById('installNginxEmail').value.trim();
|
||||
} else if (protoBase(currentInstallProto) === 'hysteria') {
|
||||
const hyPortEl = document.getElementById('installHysteriaPort');
|
||||
if (hyPortEl && hyPortEl.value) {
|
||||
params.port = hyPortEl.value;
|
||||
}
|
||||
params.hysteria_domain = document.getElementById('installHysteriaDomain').value.trim();
|
||||
params.hysteria_email = document.getElementById('installHysteriaEmail').value.trim();
|
||||
}
|
||||
const result = await apiCall(`/api/servers/${SERVER_ID}/install`, 'POST', params);
|
||||
clearInterval(progressInterval);
|
||||
@@ -2299,84 +2158,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ========== Hysteria Settings (port) ==========
|
||||
async function applyHysteriaPort(proto, portValue) {
|
||||
const port = parseInt(portValue, 10);
|
||||
if (!port || port < 1 || port > 65535) {
|
||||
showToast(_('error') + ': invalid port', 'error');
|
||||
return;
|
||||
}
|
||||
if (port === 80) {
|
||||
showToast(_('error') + ': port 80 reserved', 'error');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
showToast(_('saving') || 'Saving...', 'info');
|
||||
const res = await apiCall(`/api/servers/${SERVER_ID}/hysteria/settings`, 'POST', {
|
||||
protocol: proto || 'hysteria', port,
|
||||
});
|
||||
showToast(res.message || _('hysteria_settings_saved'), 'success');
|
||||
setTimeout(() => checkServer(), 800);
|
||||
} catch (err) {
|
||||
showToast(_('error') + ': ' + err.message, 'error');
|
||||
// Still open settings so admin can try another port
|
||||
openHysteriaSettings(proto);
|
||||
}
|
||||
}
|
||||
|
||||
async function openHysteriaSettings(proto = 'hysteria') {
|
||||
const live = currentProtocolStatus[proto] || {};
|
||||
const livePort = live.port || 443;
|
||||
const suggest = (parseInt(livePort, 10) === 443) ? 8998 : (livePort || 8998);
|
||||
document.getElementById('hysteriaSetProto').value = proto;
|
||||
document.getElementById('hysteriaSettingsTitle').textContent =
|
||||
`${_('hysteria_settings_title')} — ${getProtoTitle(proto)}`;
|
||||
document.getElementById('hysteriaSetDomain').value = live.domain || '';
|
||||
document.getElementById('hysteriaSetPort').value = suggest;
|
||||
openModal('hysteriaSettingsModal');
|
||||
// Enrich from server when possible (don't block UI if SSH is slow/fails)
|
||||
try {
|
||||
const data = await apiCall(`/api/servers/${SERVER_ID}/hysteria/settings?protocol=${encodeURIComponent(proto)}`);
|
||||
if (data.domain) document.getElementById('hysteriaSetDomain').value = data.domain;
|
||||
const p = parseInt(data.port, 10);
|
||||
if (p && p !== 443) document.getElementById('hysteriaSetPort').value = p;
|
||||
else if (p === 443) document.getElementById('hysteriaSetPort').value = 8998;
|
||||
} catch (_) { /* modal already open with local values */ }
|
||||
}
|
||||
|
||||
async function saveHysteriaSettings() {
|
||||
const btn = document.getElementById('hysteriaSaveBtn');
|
||||
const text = document.getElementById('hysteriaSaveBtnText');
|
||||
const spinner = document.getElementById('hysteriaSaveSpinner');
|
||||
const proto = document.getElementById('hysteriaSetProto').value || 'hysteria';
|
||||
const port = parseInt(document.getElementById('hysteriaSetPort').value, 10);
|
||||
if (!port || port < 1 || port > 65535) {
|
||||
showToast(_('error') + ': invalid port', 'error');
|
||||
return;
|
||||
}
|
||||
if (port === 80) {
|
||||
showToast(_('error') + ': port 80 reserved', 'error');
|
||||
return;
|
||||
}
|
||||
btn.disabled = true;
|
||||
text.textContent = _('saving') || 'Saving...';
|
||||
spinner.classList.remove('hidden');
|
||||
try {
|
||||
const res = await apiCall(`/api/servers/${SERVER_ID}/hysteria/settings`, 'POST', {
|
||||
protocol: proto, port,
|
||||
});
|
||||
showToast(res.message || _('hysteria_settings_saved'), 'success');
|
||||
closeModal('hysteriaSettingsModal');
|
||||
setTimeout(() => checkServer(), 800);
|
||||
} catch (err) {
|
||||
showToast(_('error') + ': ' + err.message, 'error');
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
text.textContent = _('save');
|
||||
spinner.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
// ========== Connection Management ==========
|
||||
function selectProtocolForConns(proto) {
|
||||
document.getElementById('connectionsSection').style.display = '';
|
||||
@@ -2417,7 +2198,7 @@
|
||||
const sent = userData.dataSent || '';
|
||||
const initial = name.charAt(0).toUpperCase();
|
||||
const enabled = (client.enabled !== undefined) ? client.enabled : (userData.enabled !== false);
|
||||
const hasPrivKey = !!userData.clientPrivateKey || proto === 'xray' || proto === 'telemt' || protoBase(proto) === 'hysteria';
|
||||
const hasPrivKey = !!userData.clientPrivateKey || proto === 'xray' || proto === 'telemt';
|
||||
const assignedUser = client.assigned_user || '';
|
||||
|
||||
let metaHtml = '';
|
||||
@@ -2455,7 +2236,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="client-actions">
|
||||
<button class="btn btn-secondary btn-sm btn-icon" onclick="showConnectionConfig('${escapeJs(client.clientId)}', '${escapeJs(name)}', ${!!userData.clientPrivateKey || proto === 'xray' || proto === 'telemt' || protoBase(proto) === 'hysteria'})" title="${_('config')}">📄</button>
|
||||
<button class="btn btn-secondary btn-sm btn-icon" onclick="showConnectionConfig('${escapeJs(client.clientId)}', '${escapeJs(name)}', ${!!userData.clientPrivateKey || proto === 'xray' || proto === 'telemt'})" title="${_('config')}">📄</button>
|
||||
${proto === 'telemt' ? `<button class="btn btn-secondary btn-sm btn-icon" onclick="editConnection('${escapeJs(client.clientId)}')" title="${_('edit')}">✏️</button>` : ''}
|
||||
<button class="btn btn-secondary btn-sm btn-icon" onclick="toggleConnection('${escapeJs(client.clientId)}', ${!enabled})" title="${toggleTitle}">${toggleIcon}</button>
|
||||
<button class="btn btn-danger btn-sm btn-icon" onclick="removeConnection('${escapeJs(client.clientId)}')" title="${_('delete')}">🗑</button>
|
||||
@@ -2507,8 +2288,8 @@
|
||||
document.getElementById('configModalTitle').textContent = `${_('config')} — ${connName}`;
|
||||
document.getElementById('configText').textContent = result.config;
|
||||
document.getElementById('vpnLinkText').textContent = currentVpnLink;
|
||||
document.getElementById('panel-vpn').style.display = (proto === 'telemt' || protoBase(proto) === 'hysteria' ? 'none' : '');
|
||||
document.querySelectorAll('.config-tab')[1].style.display = (proto === 'telemt' || protoBase(proto) === 'hysteria' ? 'none' : '');
|
||||
document.getElementById('panel-vpn').style.display = (proto === 'telemt' ? 'none' : '');
|
||||
document.querySelectorAll('.config-tab')[1].style.display = (proto === 'telemt' ? 'none' : '');
|
||||
switchConfigTab('conf');
|
||||
openModal('configModal');
|
||||
generateQR(result.config);
|
||||
@@ -2586,9 +2367,9 @@
|
||||
const proto = document.getElementById('connProtoSelect').value;
|
||||
|
||||
// Restore tabs visibility first
|
||||
document.getElementById('panel-vpn').style.display = (proto === 'telemt' || protoBase(proto) === 'hysteria' ? 'none' : '');
|
||||
document.getElementById('panel-vpn').style.display = (proto === 'telemt' ? 'none' : '');
|
||||
document.getElementById('panel-qr').style.display = '';
|
||||
document.querySelectorAll('.config-tab')[1].style.display = (proto === 'telemt' || protoBase(proto) === 'hysteria' ? 'none' : '');
|
||||
document.querySelectorAll('.config-tab')[1].style.display = (proto === 'telemt' ? 'none' : '');
|
||||
document.querySelectorAll('.config-tab')[2].style.display = '';
|
||||
|
||||
// Client was created via native Amnezia app — private key is not stored server-side
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
{% for s in servers %}
|
||||
{% set server_idx = loop.index0 %}
|
||||
{% for key, info in (s.protocols or {}).items() %}
|
||||
{% if info.installed and key.split('__')[0] in ['awg','awg2','awg_legacy','xray','wireguard','telemt','hysteria'] %}
|
||||
{% if info.installed and key.split('__')[0] in ['awg','awg2','awg_legacy','xray','wireguard','telemt'] %}
|
||||
<option value="{{ key }}|{{ server_idx }}"
|
||||
{% if settings.guest.create_protocol == key and settings.guest.create_server_id == server_idx %}selected{% endif %}>
|
||||
{{ s.name or s.host }} — {{ key }}
|
||||
|
||||
@@ -596,7 +596,7 @@
|
||||
const select = document.getElementById(selectId);
|
||||
const group = groupId ? document.getElementById(groupId) : null;
|
||||
select.innerHTML = '';
|
||||
const vpnBases = new Set(['awg', 'awg2', 'awg_legacy', 'xray', 'telemt', 'hysteria', 'wireguard']);
|
||||
const vpnBases = new Set(['awg', 'awg2', 'awg_legacy', 'xray', 'telemt', 'wireguard']);
|
||||
let count = 0;
|
||||
|
||||
const server = (serverId !== '' && serversData[serverId]) ? serversData[serverId] : null;
|
||||
@@ -608,7 +608,7 @@
|
||||
if (!vpnBases.has(base)) continue;
|
||||
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 === 'hysteria' ? 'Hysteria 2' : key.toUpperCase()))))));
|
||||
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())))));
|
||||
select.appendChild(opt);
|
||||
count++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user