Files
Amnezia-Web-Panel-main/templates/my_connections.html
T

164 lines
6.8 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.
{% extends "base.html" %}
{% from "macros/icons.html" import icon %}
{% block title_extra %} — {{ _('my_connections_title') }}{% endblock %}
{% block content %}
<section>
<h1 class="section-title">
<span class="icon">{{ icon('layers') }}</span>
{{ _('my_connections_title') }}
</h1>
{% if connections %}
<div class="clients-list" id="myConnectionsList">
{% for c in connections %}
<div class="client-item">
<div class="client-info">
<div class="client-avatar">{{ icon('link') }}</div>
<div>
<div class="client-name">{{ c.name or 'VPN Connection' }}</div>
<div class="client-meta">
<span style="display:inline-flex;align-items:center;gap:4px;">{{ icon('server') }} {{ c.server_name }}</span>
<span class="badge badge-info" style="font-size:0.65rem;">
{{ 'AmneziaWG' if c.protocol == 'awg' else ('AmneziaWG 2.0' if c.protocol == 'awg2' else ('AWG Legacy' if c.protocol == 'awg_legacy' else
('Xray' if c.protocol == 'xray' else c.protocol | upper))) }}
</span>
{% if c.created_at %}
<span>📅 {{ c.created_at[:10] }}</span>
{% endif %}
</div>
</div>
</div>
<div class="client-actions">
<button class="btn btn-primary btn-sm"
onclick="showMyConfig('{{ c.id }}', '{{ c.name or 'Connection' }}', '{{ c.protocol }}')">
{{ _('show_config') }}
</button>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="empty-state">
<div class="empty-icon">{{ icon('link') }}</div>
<div class="empty-title">{{ _('no_connections') }}</div>
<div class="empty-desc">{{ _('no_connections_user_desc') }}</div>
</div>
{% endif %}
</section>
<!-- ===== Config Modal ===== -->
<div class="modal-backdrop" id="configModal">
<div class="modal" style="max-width: 600px;">
<div class="modal-header">
<h2 class="modal-title" id="configModalTitle">{{ _('config') }}</h2>
<button class="modal-close" onclick="closeModal('configModal')">×</button>
</div>
<div class="config-tabs">
<button class="config-tab active" onclick="switchConfigTab('conf')">{{ _('config_tab') }}</button>
<button class="config-tab" onclick="switchConfigTab('vpn')">{{ _('vpn_key_tab') }}</button>
<button class="config-tab" onclick="switchConfigTab('qr')">{{ _('qr_code_tab') }}</button>
</div>
<div class="config-panel active" id="panel-conf">
<div class="config-display">
<div class="config-text" id="configText"></div>
<div class="config-actions">
<button class="btn btn-secondary btn-sm" onclick="copyToClipboard(currentConfig)" style="flex:1">
{{ _('copy_config') }}
</button>
<button class="btn btn-primary btn-sm"
onclick="downloadFile(currentConfig, currentConfigName + '.conf')" style="flex:1">
{{ _('download_conf') }}
</button>
</div>
</div>
</div>
<div class="config-panel" id="panel-vpn">
<div class="vpn-link-box" id="vpnLinkText"></div>
<div class="config-actions" style="margin-top: var(--space-sm);">
<button class="btn btn-secondary btn-sm" onclick="copyToClipboard(currentVpnLink)" style="flex:1">
{{ _('copy_key') }}
</button>
</div>
<div class="form-hint" style="margin-top: var(--space-sm);">
{{ _('vpn_link_hint') }}
</div>
</div>
<div class="config-panel" id="panel-qr">
<div class="qr-container">
<div id="qrCode"></div>
<div class="qr-hint">{{ _('qr_hint') }}</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
let currentConfig = '';
let currentVpnLink = '';
let currentConfigName = 'connection';
async function showMyConfig(connectionId, name, proto) {
try {
showToast(_('loading_connections'), 'info');
const result = await apiCall(`/api/my/connections/${connectionId}/config`, 'POST');
if (result.config) {
currentConfig = result.config;
currentVpnLink = result.vpn_link || '';
currentConfigName = name.replace(/\s+/g, '_');
document.getElementById('configModalTitle').textContent = `${_('config')}${name}`;
document.getElementById('configText').textContent = result.config;
document.getElementById('vpnLinkText').textContent = currentVpnLink;
// Telemt / Hysteria / NaiveProxy use share links, not vpn:// Amnezia format
const vpnTab = document.querySelectorAll('.config-tab')[1];
const vpnPanel = document.getElementById('panel-vpn');
const base = String(proto || '').split('__')[0];
if (proto === 'telemt' || base === 'hysteria' || base === 'naiveproxy' || base === 'mieru') {
vpnTab.style.display = 'none';
} else {
vpnTab.style.display = '';
}
switchConfigTab('conf');
openModal('configModal');
generateQR(result.config);
}
} catch (err) {
showToast(`${_('error')}: ` + err.message, 'error');
}
}
function switchConfigTab(tab) {
document.querySelectorAll('.config-tab').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.config-panel').forEach(p => p.classList.remove('active'));
const tabs = document.querySelectorAll('.config-tab');
const panels = { conf: 'panel-conf', vpn: 'panel-vpn', qr: 'panel-qr' };
const tabIdx = { conf: 0, vpn: 1, qr: 2 };
tabs[tabIdx[tab]].classList.add('active');
document.getElementById(panels[tab]).classList.add('active');
}
function generateQR(text) {
const container = document.getElementById('qrCode');
container.innerHTML = '';
try {
new QRCode(container, {
text: text, width: 280, height: 280,
colorDark: '#000000', colorLight: '#ffffff',
correctLevel: QRCode.CorrectLevel.L
});
} catch (e) {
container.innerHTML = `<div style="color:var(--text-muted);font-size:0.85rem;">${_('qr_error')}</div>`;
}
}
</script>
{% endblock %}