|
@@ -7329,66 +7329,243 @@ async function submitBgpInstance(e) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// ----------------- BGP Peer Connection Modal (RouterOS v7) -----------------
|
|
|
|
|
+function switchBgpPeerModalTab(tab) {
|
|
|
|
|
+ const tabs = ['general', 'extra', 'attributes', 'filter'];
|
|
|
|
|
+ tabs.forEach(t => {
|
|
|
|
|
+ const pane = document.getElementById(`bgp-peer-tab-${t}`);
|
|
|
|
|
+ const btn = document.getElementById(`bgp-peer-tab-btn-${t}`);
|
|
|
|
|
+ if (t === tab) {
|
|
|
|
|
+ if (pane) pane.classList.remove('hidden');
|
|
|
|
|
+ if (btn) btn.className = 'px-4 py-2 text-xs font-bold border-b-2 border-cyan-500 text-white transition';
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (pane) pane.classList.add('hidden');
|
|
|
|
|
+ if (btn) btn.className = 'px-4 py-2 text-xs font-bold border-b-2 border-transparent text-slate-400 hover:text-slate-200 transition';
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function addOutputNetworkRow(val = '') {
|
|
|
|
|
+ const container = document.getElementById('modal-bgp-output-networks-container');
|
|
|
|
|
+ if (!container) return;
|
|
|
|
|
+ const row = document.createElement('div');
|
|
|
|
|
+ row.className = 'flex items-center gap-2 output-net-row';
|
|
|
|
|
+ row.innerHTML = `
|
|
|
|
|
+ <input type="text" value="${escapeHtml(val)}" placeholder="e.g. 10.2.51.0/24 or BGP-AWMN" class="flex-1 bg-slate-900 border border-slate-700 rounded-lg px-3 py-1.5 text-white font-mono text-xs focus:outline-none focus:border-cyan-500">
|
|
|
|
|
+ <button type="button" onclick="this.closest('.output-net-row').remove()" class="w-7 h-7 flex items-center justify-center bg-slate-800 hover:bg-rose-950 text-slate-400 hover:text-rose-400 border border-slate-700 rounded-lg text-base font-bold transition" title="Remove network">-</button>
|
|
|
|
|
+ `;
|
|
|
|
|
+ container.appendChild(row);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function parseBgpTime(val) {
|
|
|
|
|
+ if (!val) return 0;
|
|
|
|
|
+ val = String(val).trim();
|
|
|
|
|
+ if (val.includes(':')) {
|
|
|
|
|
+ const parts = val.split(':').map(x => parseInt(x, 10) || 0);
|
|
|
|
|
+ if (parts.length === 3) return parts[0] * 3600 + parts[1] * 60 + parts[2];
|
|
|
|
|
+ if (parts.length === 2) return parts[0] * 60 + parts[1];
|
|
|
|
|
+ }
|
|
|
|
|
+ return parseInt(val, 10) || 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function formatBgpTime(secs) {
|
|
|
|
|
+ if (!secs || secs <= 0) return '00:00:00';
|
|
|
|
|
+ const h = Math.floor(secs / 3600);
|
|
|
|
|
+ const m = Math.floor((secs % 3600) / 60);
|
|
|
|
|
+ const s = secs % 60;
|
|
|
|
|
+ return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function populateBgpRoutingTables() {
|
|
|
|
|
+ const sel = document.getElementById('modal-bgp-peer-routing-table');
|
|
|
|
|
+ if (!sel) return;
|
|
|
|
|
+ const cur = sel.value || 'main';
|
|
|
|
|
+ sel.innerHTML = '<option value="main">main</option>';
|
|
|
|
|
+ (state.routingTables || []).forEach(t => {
|
|
|
|
|
+ if (t.name !== 'main') {
|
|
|
|
|
+ const opt = document.createElement('option');
|
|
|
|
|
+ opt.value = t.name;
|
|
|
|
|
+ opt.innerText = t.name;
|
|
|
|
|
+ sel.appendChild(opt);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ sel.value = cur;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
function openAddBgpPeerModal() {
|
|
function openAddBgpPeerModal() {
|
|
|
document.getElementById('bgp-peer-form').reset();
|
|
document.getElementById('bgp-peer-form').reset();
|
|
|
document.getElementById('modal-bgp-peer-id').value = '';
|
|
document.getElementById('modal-bgp-peer-id').value = '';
|
|
|
- document.getElementById('bgp-peer-modal-title').innerText = 'Add BGP Peer Connection';
|
|
|
|
|
- document.getElementById('modal-bgp-peer-nexthop-self').checked = true;
|
|
|
|
|
- const localAsEl = document.getElementById('modal-bgp-peer-local-as');
|
|
|
|
|
- if (localAsEl) localAsEl.value = '';
|
|
|
|
|
- const inFilterEl = document.getElementById('modal-bgp-peer-in-filter');
|
|
|
|
|
- if (inFilterEl) inFilterEl.value = '';
|
|
|
|
|
- const outFilterEl = document.getElementById('modal-bgp-peer-out-filter');
|
|
|
|
|
- if (outFilterEl) outFilterEl.value = '';
|
|
|
|
|
|
|
+ document.getElementById('bgp-peer-modal-title').innerText = 'New...';
|
|
|
|
|
+
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-enabled').checked = true;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-afi-ip').checked = true;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-afi-ipv6').checked = false;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-connect').checked = true;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-listen').checked = true;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-holdtime').value = '00:03:00';
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-keepalive').value = '00:01:00';
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-nexthop-choice').value = 'force-self';
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-redist-conn').checked = false;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-redist-static').checked = true;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-redist-ospf').checked = false;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-redist-bgp').checked = false;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-default-orig').checked = false;
|
|
|
|
|
+
|
|
|
|
|
+ populateBgpRoutingTables();
|
|
|
|
|
+
|
|
|
|
|
+ const container = document.getElementById('modal-bgp-output-networks-container');
|
|
|
|
|
+ if (container) {
|
|
|
|
|
+ container.innerHTML = '';
|
|
|
|
|
+ addOutputNetworkRow('');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const removeBtn = document.getElementById('modal-btn-remove-peer');
|
|
|
|
|
+ if (removeBtn) removeBtn.classList.add('hidden');
|
|
|
|
|
+
|
|
|
|
|
+ switchBgpPeerModalTab('general');
|
|
|
document.getElementById('bgp-peer-modal').classList.remove('hidden');
|
|
document.getElementById('bgp-peer-modal').classList.remove('hidden');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function openEditBgpPeerModal(id) {
|
|
function openEditBgpPeerModal(id) {
|
|
|
const p = (state.bgpPeers || []).find(item => item.id === id);
|
|
const p = (state.bgpPeers || []).find(item => item.id === id);
|
|
|
if (!p) return;
|
|
if (!p) return;
|
|
|
|
|
+
|
|
|
|
|
+ populateBgpRoutingTables();
|
|
|
|
|
+
|
|
|
document.getElementById('modal-bgp-peer-id').value = p.id;
|
|
document.getElementById('modal-bgp-peer-id').value = p.id;
|
|
|
|
|
+ document.getElementById('bgp-peer-modal-title').innerText = p.name || p.id;
|
|
|
|
|
+
|
|
|
|
|
+ // General Tab
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-enabled').checked = p.enabled !== false && !p.disabled;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-comment').value = p.comment || '';
|
|
|
document.getElementById('modal-bgp-peer-name').value = p.name || '';
|
|
document.getElementById('modal-bgp-peer-name').value = p.name || '';
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-local-as').value = p.local_as || '';
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-router-id').value = p.router_id || '';
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-afi-ip').checked = true;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-afi-ipv6').checked = p.afi === 'ipv6';
|
|
|
document.getElementById('modal-bgp-peer-remote-addr').value = p.remote_address || '';
|
|
document.getElementById('modal-bgp-peer-remote-addr').value = p.remote_address || '';
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-remote-port').value = p.remote_port || '';
|
|
|
document.getElementById('modal-bgp-peer-remote-as').value = p.remote_as || '';
|
|
document.getElementById('modal-bgp-peer-remote-as').value = p.remote_as || '';
|
|
|
- const localAsEl = document.getElementById('modal-bgp-peer-local-as');
|
|
|
|
|
- if (localAsEl) localAsEl.value = p.local_as || '';
|
|
|
|
|
document.getElementById('modal-bgp-peer-local-addr').value = p.local_address || '';
|
|
document.getElementById('modal-bgp-peer-local-addr').value = p.local_address || '';
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-local-port').value = p.local_port || '';
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-local-role').value = p.local_role || 'ebgp';
|
|
|
document.getElementById('modal-bgp-peer-password').value = p.password || '';
|
|
document.getElementById('modal-bgp-peer-password').value = p.password || '';
|
|
|
document.getElementById('modal-bgp-peer-multihop').checked = !!p.multihop;
|
|
document.getElementById('modal-bgp-peer-multihop').checked = !!p.multihop;
|
|
|
- document.getElementById('modal-bgp-peer-nexthop-self').checked = !!p.nexthop_self;
|
|
|
|
|
- document.getElementById('modal-bgp-peer-passive').checked = !!p.passive;
|
|
|
|
|
- document.getElementById('modal-bgp-peer-disabled').checked = !!p.disabled;
|
|
|
|
|
- document.getElementById('modal-bgp-peer-comment').value = p.comment || '';
|
|
|
|
|
- const inFilterEl = document.getElementById('modal-bgp-peer-in-filter');
|
|
|
|
|
- if (inFilterEl) inFilterEl.value = p.in_filter || '';
|
|
|
|
|
- const outFilterEl = document.getElementById('modal-bgp-peer-out-filter');
|
|
|
|
|
- if (outFilterEl) outFilterEl.value = p.out_filter || '';
|
|
|
|
|
- document.getElementById('bgp-peer-modal-title').innerText = 'Edit BGP Peer Connection';
|
|
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-connect').checked = p.connect !== false;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-listen').checked = p.listen !== false;
|
|
|
|
|
+
|
|
|
|
|
+ // Extra Tab
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-holdtime').value = p.hold_time ? formatBgpTime(p.hold_time) : '00:03:00';
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-keepalive').value = p.keepalive_time ? formatBgpTime(p.keepalive_time) : '00:01:00';
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-routing-table').value = p.routing_table || 'main';
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-redist-conn').checked = !!p.redist_connected;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-redist-static').checked = p.redist_static !== false;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-redist-ospf').checked = !!p.redist_ospf;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-redist-bgp').checked = !!p.redist_bgp;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-default-orig').checked = !!p.default_originate;
|
|
|
|
|
+
|
|
|
|
|
+ // Attributes Tab
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-nexthop-choice').value = p.nexthop_choice || (p.nexthop_self ? 'force-self' : 'default');
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-default-prepend').value = p.default_prepend || 0;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-allow-as-in').value = p.allow_as_in || 0;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-remove-priv-as').checked = !!p.remove_private_as;
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-as-override').checked = !!p.as_override;
|
|
|
|
|
+
|
|
|
|
|
+ // Filter Tab
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-in-filter').value = p.in_filter || '';
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-out-filter').value = p.out_filter || '';
|
|
|
|
|
+
|
|
|
|
|
+ // Output Networks
|
|
|
|
|
+ const container = document.getElementById('modal-bgp-output-networks-container');
|
|
|
|
|
+ if (container) {
|
|
|
|
|
+ container.innerHTML = '';
|
|
|
|
|
+ if (p.output_networks && p.output_networks.length > 0) {
|
|
|
|
|
+ p.output_networks.forEach(net => addOutputNetworkRow(net));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ addOutputNetworkRow('');
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const removeBtn = document.getElementById('modal-btn-remove-peer');
|
|
|
|
|
+ if (removeBtn) removeBtn.classList.remove('hidden');
|
|
|
|
|
+
|
|
|
|
|
+ switchBgpPeerModalTab('general');
|
|
|
document.getElementById('bgp-peer-modal').classList.remove('hidden');
|
|
document.getElementById('bgp-peer-modal').classList.remove('hidden');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+function copyCurrentBgpPeer() {
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-id').value = '';
|
|
|
|
|
+ const nameEl = document.getElementById('modal-bgp-peer-name');
|
|
|
|
|
+ if (nameEl) nameEl.value = (nameEl.value || 'peer') + '-copy';
|
|
|
|
|
+ document.getElementById('bgp-peer-modal-title').innerText = 'New...';
|
|
|
|
|
+ const removeBtn = document.getElementById('modal-btn-remove-peer');
|
|
|
|
|
+ if (removeBtn) removeBtn.classList.add('hidden');
|
|
|
|
|
+ showToast('Cloned', 'BGP connection copied to new draft', 'info');
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function removeCurrentBgpPeer() {
|
|
|
|
|
+ const id = document.getElementById('modal-bgp-peer-id')?.value;
|
|
|
|
|
+ if (!id) return;
|
|
|
|
|
+ deleteBgpPeer(id);
|
|
|
|
|
+ closeBgpPeerModal();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
function closeBgpPeerModal() {
|
|
function closeBgpPeerModal() {
|
|
|
document.getElementById('bgp-peer-modal').classList.add('hidden');
|
|
document.getElementById('bgp-peer-modal').classList.add('hidden');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-async function submitBgpPeer(e) {
|
|
|
|
|
- e.preventDefault();
|
|
|
|
|
- const payload = {
|
|
|
|
|
|
|
+function getBgpPeerFormData() {
|
|
|
|
|
+ const netInputs = document.querySelectorAll('#modal-bgp-output-networks-container .output-net-row input');
|
|
|
|
|
+ const outputNetworks = [];
|
|
|
|
|
+ netInputs.forEach(inp => {
|
|
|
|
|
+ const v = inp.value.trim();
|
|
|
|
|
+ if (v) outputNetworks.push(v);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ const enabled = document.getElementById('modal-bgp-peer-enabled').checked;
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
id: document.getElementById('modal-bgp-peer-id').value,
|
|
id: document.getElementById('modal-bgp-peer-id').value,
|
|
|
name: document.getElementById('modal-bgp-peer-name').value.trim(),
|
|
name: document.getElementById('modal-bgp-peer-name').value.trim(),
|
|
|
- remote_address: document.getElementById('modal-bgp-peer-remote-addr').value.trim(),
|
|
|
|
|
- remote_as: parseInt(document.getElementById('modal-bgp-peer-remote-as').value, 10),
|
|
|
|
|
|
|
+ enabled: enabled,
|
|
|
|
|
+ disabled: !enabled,
|
|
|
|
|
+ comment: document.getElementById('modal-bgp-peer-comment').value.trim(),
|
|
|
local_as: parseInt(document.getElementById('modal-bgp-peer-local-as')?.value, 10) || 0,
|
|
local_as: parseInt(document.getElementById('modal-bgp-peer-local-as')?.value, 10) || 0,
|
|
|
|
|
+ router_id: document.getElementById('modal-bgp-peer-router-id').value.trim(),
|
|
|
|
|
+ afi: document.getElementById('modal-bgp-peer-afi-ipv6').checked ? 'ipv6' : 'ip',
|
|
|
|
|
+ remote_address: document.getElementById('modal-bgp-peer-remote-addr').value.trim(),
|
|
|
|
|
+ remote_port: parseInt(document.getElementById('modal-bgp-peer-remote-port').value, 10) || 0,
|
|
|
|
|
+ remote_as: parseInt(document.getElementById('modal-bgp-peer-remote-as').value, 10) || 0,
|
|
|
local_address: document.getElementById('modal-bgp-peer-local-addr').value.trim(),
|
|
local_address: document.getElementById('modal-bgp-peer-local-addr').value.trim(),
|
|
|
|
|
+ local_port: parseInt(document.getElementById('modal-bgp-peer-local-port').value, 10) || 0,
|
|
|
|
|
+ local_role: document.getElementById('modal-bgp-peer-local-role').value,
|
|
|
password: document.getElementById('modal-bgp-peer-password').value,
|
|
password: document.getElementById('modal-bgp-peer-password').value,
|
|
|
multihop: document.getElementById('modal-bgp-peer-multihop').checked,
|
|
multihop: document.getElementById('modal-bgp-peer-multihop').checked,
|
|
|
- nexthop_self: document.getElementById('modal-bgp-peer-nexthop-self').checked,
|
|
|
|
|
- passive: document.getElementById('modal-bgp-peer-passive').checked,
|
|
|
|
|
- disabled: document.getElementById('modal-bgp-peer-disabled').checked,
|
|
|
|
|
|
|
+ connect: document.getElementById('modal-bgp-peer-connect').checked,
|
|
|
|
|
+ listen: document.getElementById('modal-bgp-peer-listen').checked,
|
|
|
|
|
+ hold_time: parseBgpTime(document.getElementById('modal-bgp-peer-holdtime').value),
|
|
|
|
|
+ keepalive_time: parseBgpTime(document.getElementById('modal-bgp-peer-keepalive').value),
|
|
|
|
|
+ routing_table: document.getElementById('modal-bgp-peer-routing-table').value,
|
|
|
|
|
+ redist_connected: document.getElementById('modal-bgp-peer-redist-conn').checked,
|
|
|
|
|
+ redist_static: document.getElementById('modal-bgp-peer-redist-static').checked,
|
|
|
|
|
+ redist_ospf: document.getElementById('modal-bgp-peer-redist-ospf').checked,
|
|
|
|
|
+ redist_bgp: document.getElementById('modal-bgp-peer-redist-bgp').checked,
|
|
|
|
|
+ default_originate: document.getElementById('modal-bgp-peer-default-orig').checked,
|
|
|
|
|
+ nexthop_choice: document.getElementById('modal-bgp-peer-nexthop-choice').value,
|
|
|
|
|
+ nexthop_self: document.getElementById('modal-bgp-peer-nexthop-choice').value === 'force-self',
|
|
|
|
|
+ default_prepend: parseInt(document.getElementById('modal-bgp-peer-default-prepend').value, 10) || 0,
|
|
|
|
|
+ allow_as_in: parseInt(document.getElementById('modal-bgp-peer-allow-as-in').value, 10) || 0,
|
|
|
|
|
+ remove_private_as: document.getElementById('modal-bgp-peer-remove-priv-as').checked,
|
|
|
|
|
+ as_override: document.getElementById('modal-bgp-peer-as-override').checked,
|
|
|
in_filter: (document.getElementById('modal-bgp-peer-in-filter')?.value || '').trim(),
|
|
in_filter: (document.getElementById('modal-bgp-peer-in-filter')?.value || '').trim(),
|
|
|
out_filter: (document.getElementById('modal-bgp-peer-out-filter')?.value || '').trim(),
|
|
out_filter: (document.getElementById('modal-bgp-peer-out-filter')?.value || '').trim(),
|
|
|
- comment: document.getElementById('modal-bgp-peer-comment').value.trim()
|
|
|
|
|
|
|
+ output_networks: outputNetworks
|
|
|
};
|
|
};
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function submitBgpPeer(e) {
|
|
|
|
|
+ if (e) e.preventDefault();
|
|
|
|
|
+ const payload = getBgpPeerFormData();
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
const res = await fetch(`${API_BASE}/routing/bgp/peers`, {
|
|
const res = await fetch(`${API_BASE}/routing/bgp/peers`, {
|
|
@@ -7398,7 +7575,7 @@ async function submitBgpPeer(e) {
|
|
|
});
|
|
});
|
|
|
if (res.ok) {
|
|
if (res.ok) {
|
|
|
closeBgpPeerModal();
|
|
closeBgpPeerModal();
|
|
|
- showToast('Success', 'BGP Peer saved', 'success');
|
|
|
|
|
|
|
+ showToast('Success', 'BGP Connection saved', 'success');
|
|
|
loadDynamicRouting();
|
|
loadDynamicRouting();
|
|
|
} else {
|
|
} else {
|
|
|
const err = await res.json();
|
|
const err = await res.json();
|
|
@@ -7409,6 +7586,34 @@ async function submitBgpPeer(e) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+async function applyBgpPeerModal(e) {
|
|
|
|
|
+ if (e) e.preventDefault();
|
|
|
|
|
+ const payload = getBgpPeerFormData();
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await fetch(`${API_BASE}/routing/bgp/peers`, {
|
|
|
|
|
+ method: 'POST',
|
|
|
|
|
+ headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
+ body: JSON.stringify(payload)
|
|
|
|
|
+ });
|
|
|
|
|
+ if (res.ok) {
|
|
|
|
|
+ const data = await res.json();
|
|
|
|
|
+ if (data.peer && data.peer.id) {
|
|
|
|
|
+ document.getElementById('modal-bgp-peer-id').value = data.peer.id;
|
|
|
|
|
+ document.getElementById('bgp-peer-modal-title').innerText = data.peer.name || data.peer.id;
|
|
|
|
|
+ document.getElementById('modal-btn-remove-peer')?.classList.remove('hidden');
|
|
|
|
|
+ }
|
|
|
|
|
+ showToast('Applied', 'BGP Connection applied', 'success');
|
|
|
|
|
+ loadDynamicRouting();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ const err = await res.json();
|
|
|
|
|
+ showToast('Error', err.error || 'Failed to apply peer', 'error');
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ showToast('Error', err.message, 'error');
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
async function deleteBgpPeer(id) {
|
|
async function deleteBgpPeer(id) {
|
|
|
if (!confirm('Are you sure you want to delete this BGP peer connection?')) return;
|
|
if (!confirm('Are you sure you want to delete this BGP peer connection?')) return;
|
|
|
try {
|
|
try {
|