|
@@ -10244,7 +10244,11 @@ function renderOspfInstances() {
|
|
|
tbody.innerHTML = list.map((inst, idx) => {
|
|
tbody.innerHTML = list.map((inst, idx) => {
|
|
|
const isSel = inst.id === selId;
|
|
const isSel = inst.id === selId;
|
|
|
const selClass = isSel ? 'bg-[#1b2f48] text-white border-l-2 border-sky-400' : 'hover:bg-[#1a2636] text-slate-300';
|
|
const selClass = isSel ? 'bg-[#1b2f48] text-white border-l-2 border-sky-400' : 'hover:bg-[#1a2636] text-slate-300';
|
|
|
- const flagD = inst.disabled ? '<span class="text-rose-400 font-bold" title="Disabled">X</span>' : '';
|
|
|
|
|
|
|
+ const flagD = inst.disabled
|
|
|
|
|
+ ? '<span class="text-rose-400 font-bold" title="Disabled (X)">X</span>'
|
|
|
|
|
+ : (inst.running
|
|
|
|
|
+ ? '<span class="text-emerald-400 font-bold" title="Running (R)">R</span>'
|
|
|
|
|
+ : '<span class="text-amber-400 font-bold" title="Inactive (I)">I</span>');
|
|
|
|
|
|
|
|
const redist = [];
|
|
const redist = [];
|
|
|
if (inst.redistribute_connected) redist.push('conn');
|
|
if (inst.redistribute_connected) redist.push('conn');
|
|
@@ -10263,7 +10267,7 @@ function renderOspfInstances() {
|
|
|
return `
|
|
return `
|
|
|
<tr class="${selClass} cursor-pointer transition select-none" onclick="selectOspfRow('instances', '${inst.id}')" ondblclick="openEditOspfInstanceModal('${inst.id}')">
|
|
<tr class="${selClass} cursor-pointer transition select-none" onclick="selectOspfRow('instances', '${inst.id}')" ondblclick="openEditOspfInstanceModal('${inst.id}')">
|
|
|
<td class="py-1.5 px-3 w-8 text-center text-slate-500">${idx}</td>
|
|
<td class="py-1.5 px-3 w-8 text-center text-slate-500">${idx}</td>
|
|
|
- <td class="py-1.5 px-3 w-12 text-center text-sky-400">${flagD || '🔀'}</td>
|
|
|
|
|
|
|
+ <td class="py-1.5 px-3 w-12 text-center">${flagD}</td>
|
|
|
<td class="py-1.5 px-3 text-slate-400 italic">${escapeHtml(inst.comment || '')}</td>
|
|
<td class="py-1.5 px-3 text-slate-400 italic">${escapeHtml(inst.comment || '')}</td>
|
|
|
<td class="py-1.5 px-3 font-semibold text-white flex items-center gap-1.5">
|
|
<td class="py-1.5 px-3 font-semibold text-white flex items-center gap-1.5">
|
|
|
<span class="text-sky-400">↳</span> <span>${escapeHtml(inst.name || 'Default')}</span>
|
|
<span class="text-sky-400">↳</span> <span>${escapeHtml(inst.name || 'Default')}</span>
|
|
@@ -10642,10 +10646,22 @@ function populateBgpRoutingTables() {
|
|
|
sel.value = cur;
|
|
sel.value = cur;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+function populateBgpLocalAddrDatalist() {
|
|
|
|
|
+ const dlBgp = document.getElementById('bgp-peer-local-addr-datalist');
|
|
|
|
|
+ if (!dlBgp) return;
|
|
|
|
|
+ const addrs = [];
|
|
|
|
|
+ (state.interfaces || []).forEach(iface => {
|
|
|
|
|
+ if (iface.ip) addrs.push(iface.ip.split('/')[0]);
|
|
|
|
|
+ (iface.addresses || []).forEach(a => addrs.push(a.split('/')[0]));
|
|
|
|
|
+ });
|
|
|
|
|
+ dlBgp.innerHTML = Array.from(new Set(addrs.filter(Boolean))).map(ip => `<option value="${escapeHtml(ip)}">`).join('');
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
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 = 'New BGP Connection...';
|
|
document.getElementById('bgp-peer-modal-title').innerText = 'New BGP Connection...';
|
|
|
|
|
+ populateBgpLocalAddrDatalist();
|
|
|
|
|
|
|
|
// General Tab
|
|
// General Tab
|
|
|
document.getElementById('modal-bgp-peer-enabled').checked = true;
|
|
document.getElementById('modal-bgp-peer-enabled').checked = true;
|
|
@@ -10715,6 +10731,7 @@ function openEditBgpPeerModal(id) {
|
|
|
if (!p) return;
|
|
if (!p) return;
|
|
|
|
|
|
|
|
populateFilterChainsDatalist();
|
|
populateFilterChainsDatalist();
|
|
|
|
|
+ populateBgpLocalAddrDatalist();
|
|
|
|
|
|
|
|
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;
|
|
document.getElementById('bgp-peer-modal-title').innerText = p.name || p.id;
|
|
@@ -11479,6 +11496,11 @@ function openOspfTemplateModal(id = null) {
|
|
|
populateTemplateAreaDropdowns();
|
|
populateTemplateAreaDropdowns();
|
|
|
switchOspfTemplateTab('general');
|
|
switchOspfTemplateTab('general');
|
|
|
|
|
|
|
|
|
|
+ const dl = document.getElementById('ospf-tmpl-iface-datalist');
|
|
|
|
|
+ if (dl) {
|
|
|
|
|
+ dl.innerHTML = '<option value="*"><option value="all">' + (state.interfaces || []).map(i => `<option value="${escapeHtml(i.name)}">`).join('');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
const tmpl = (state.ospfTemplates || []).find(t => t.id === id) || {
|
|
const tmpl = (state.ospfTemplates || []).find(t => t.id === id) || {
|
|
|
id: '',
|
|
id: '',
|
|
|
interfaces: '',
|
|
interfaces: '',
|
|
@@ -19654,7 +19676,11 @@ function renderRipInstances() {
|
|
|
tbody.innerHTML = list.map((inst, idx) => {
|
|
tbody.innerHTML = list.map((inst, idx) => {
|
|
|
const isSel = inst.id === selId;
|
|
const isSel = inst.id === selId;
|
|
|
const selClass = isSel ? 'bg-[#1b2f48] text-white border-l-2 border-rose-400' : 'hover:bg-[#1a2636] text-slate-300';
|
|
const selClass = isSel ? 'bg-[#1b2f48] text-white border-l-2 border-rose-400' : 'hover:bg-[#1a2636] text-slate-300';
|
|
|
- const flagD = inst.disabled ? '<span class="text-rose-400 font-bold" title="Disabled">X</span>' : '<span class="text-emerald-400">R</span>';
|
|
|
|
|
|
|
+ const flagD = inst.disabled
|
|
|
|
|
+ ? '<span class="text-rose-400 font-bold" title="Disabled (X)">X</span>'
|
|
|
|
|
+ : (inst.running
|
|
|
|
|
+ ? '<span class="text-emerald-400 font-bold" title="Running (R)">R</span>'
|
|
|
|
|
+ : '<span class="text-amber-400 font-bold" title="Inactive (I)">I</span>');
|
|
|
const redist = [];
|
|
const redist = [];
|
|
|
if (inst.redistribute_connected) redist.push('conn');
|
|
if (inst.redistribute_connected) redist.push('conn');
|
|
|
if (inst.redistribute_static) redist.push('static');
|
|
if (inst.redistribute_static) redist.push('static');
|
|
@@ -19847,8 +19873,19 @@ async function removeSelectedRipInstance() {
|
|
|
function openRipInterfaceModal() {
|
|
function openRipInterfaceModal() {
|
|
|
document.getElementById('rip-interface-modal-title').innerText = 'New RIP Interface';
|
|
document.getElementById('rip-interface-modal-title').innerText = 'New RIP Interface';
|
|
|
document.getElementById('modal-rip-iface-id').value = '';
|
|
document.getElementById('modal-rip-iface-id').value = '';
|
|
|
- document.getElementById('modal-rip-iface-pattern').value = '';
|
|
|
|
|
- document.getElementById('modal-rip-iface-instance').value = 'rip1';
|
|
|
|
|
|
|
+
|
|
|
|
|
+ const dl = document.getElementById('rip-iface-datalist');
|
|
|
|
|
+ if (dl) {
|
|
|
|
|
+ dl.innerHTML = '<option value="*">' + (state.interfaces || []).map(i => `<option value="${escapeHtml(i.name)}">`).join('');
|
|
|
|
|
+ }
|
|
|
|
|
+ const instSel = document.getElementById('modal-rip-iface-instance');
|
|
|
|
|
+ if (instSel && instSel.tagName === 'SELECT') {
|
|
|
|
|
+ instSel.innerHTML = (state.ripInstances || []).map(i => `<option value="${escapeHtml(i.name)}">${escapeHtml(i.name)}</option>`).join('');
|
|
|
|
|
+ if (instSel.innerHTML === '') instSel.innerHTML = '<option value="default">default</option>';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ document.getElementById('modal-rip-iface-pattern').value = '*';
|
|
|
|
|
+ if (instSel) instSel.value = (state.ripInstances && state.ripInstances.length > 0) ? state.ripInstances[0].name : 'default';
|
|
|
document.getElementById('modal-rip-iface-mode').value = 'multicast';
|
|
document.getElementById('modal-rip-iface-mode').value = 'multicast';
|
|
|
document.getElementById('modal-rip-iface-metric').value = '1';
|
|
document.getElementById('modal-rip-iface-metric').value = '1';
|
|
|
document.getElementById('modal-rip-iface-comment').value = '';
|
|
document.getElementById('modal-rip-iface-comment').value = '';
|
|
@@ -19863,8 +19900,21 @@ function openEditRipInterfaceModal(id) {
|
|
|
if (!iface) return;
|
|
if (!iface) return;
|
|
|
document.getElementById('rip-interface-modal-title').innerText = `Edit RIP Interface: ${iface.interface}`;
|
|
document.getElementById('rip-interface-modal-title').innerText = `Edit RIP Interface: ${iface.interface}`;
|
|
|
document.getElementById('modal-rip-iface-id').value = iface.id;
|
|
document.getElementById('modal-rip-iface-id').value = iface.id;
|
|
|
- document.getElementById('modal-rip-iface-pattern').value = iface.interface || '';
|
|
|
|
|
- document.getElementById('modal-rip-iface-instance').value = iface.instance || '';
|
|
|
|
|
|
|
+
|
|
|
|
|
+ const dl = document.getElementById('rip-iface-datalist');
|
|
|
|
|
+ if (dl) {
|
|
|
|
|
+ dl.innerHTML = '<option value="*">' + (state.interfaces || []).map(i => `<option value="${escapeHtml(i.name)}">`).join('');
|
|
|
|
|
+ }
|
|
|
|
|
+ const instSel = document.getElementById('modal-rip-iface-instance');
|
|
|
|
|
+ if (instSel && instSel.tagName === 'SELECT') {
|
|
|
|
|
+ instSel.innerHTML = (state.ripInstances || []).map(i => `<option value="${escapeHtml(i.name)}">${escapeHtml(i.name)}</option>`).join('');
|
|
|
|
|
+ if (instSel.innerHTML === '') instSel.innerHTML = '<option value="default">default</option>';
|
|
|
|
|
+ instSel.value = iface.instance || 'default';
|
|
|
|
|
+ } else if (instSel) {
|
|
|
|
|
+ instSel.value = iface.instance || '';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ document.getElementById('modal-rip-iface-pattern').value = iface.interface || '*';
|
|
|
document.getElementById('modal-rip-iface-mode').value = iface.mode || 'multicast';
|
|
document.getElementById('modal-rip-iface-mode').value = iface.mode || 'multicast';
|
|
|
document.getElementById('modal-rip-iface-metric').value = iface.metric || 1;
|
|
document.getElementById('modal-rip-iface-metric').value = iface.metric || 1;
|
|
|
document.getElementById('modal-rip-iface-comment').value = iface.comment || '';
|
|
document.getElementById('modal-rip-iface-comment').value = iface.comment || '';
|
|
@@ -20788,7 +20838,11 @@ function renderRAdvInstances() {
|
|
|
tbody.innerHTML = list.map((inst, idx) => {
|
|
tbody.innerHTML = list.map((inst, idx) => {
|
|
|
const isSel = inst.id === selId;
|
|
const isSel = inst.id === selId;
|
|
|
const selClass = isSel ? 'bg-[#1b2f48] text-white border-l-2 border-blue-400' : 'hover:bg-[#1a2636] text-slate-300';
|
|
const selClass = isSel ? 'bg-[#1b2f48] text-white border-l-2 border-blue-400' : 'hover:bg-[#1a2636] text-slate-300';
|
|
|
- const flagD = inst.disabled ? '<span class="text-rose-400 font-bold">X</span>' : '<span class="text-emerald-400">R</span>';
|
|
|
|
|
|
|
+ const flagD = inst.disabled
|
|
|
|
|
+ ? '<span class="text-rose-400 font-bold" title="Disabled (X)">X</span>'
|
|
|
|
|
+ : (inst.running
|
|
|
|
|
+ ? '<span class="text-emerald-400 font-bold" title="Running (R)">R</span>'
|
|
|
|
|
+ : '<span class="text-amber-400 font-bold" title="Inactive (I)">I</span>');
|
|
|
return `
|
|
return `
|
|
|
<tr class="${selClass} cursor-pointer transition select-none" onclick="selectRadvRow('instances', '${inst.id}')" ondblclick="openEditRAdvInstanceModal('${inst.id}')">
|
|
<tr class="${selClass} cursor-pointer transition select-none" onclick="selectRadvRow('instances', '${inst.id}')" ondblclick="openEditRAdvInstanceModal('${inst.id}')">
|
|
|
<td class="py-1.5 px-3 w-8 text-center text-slate-500">${idx}</td>
|
|
<td class="py-1.5 px-3 w-8 text-center text-slate-500">${idx}</td>
|
|
@@ -20908,8 +20962,21 @@ async function removeSelectedRadvInstance() {
|
|
|
function openRAdvInterfaceModal() {
|
|
function openRAdvInterfaceModal() {
|
|
|
document.getElementById('radv-interface-modal-title').innerText = 'New RAdv Interface';
|
|
document.getElementById('radv-interface-modal-title').innerText = 'New RAdv Interface';
|
|
|
document.getElementById('modal-radv-iface-id').value = '';
|
|
document.getElementById('modal-radv-iface-id').value = '';
|
|
|
- document.getElementById('modal-radv-iface-interface').value = '';
|
|
|
|
|
- document.getElementById('modal-radv-iface-instance').value = 'radv1';
|
|
|
|
|
|
|
+
|
|
|
|
|
+ const dl = document.getElementById('radv-iface-datalist');
|
|
|
|
|
+ if (dl) {
|
|
|
|
|
+ dl.innerHTML = '<option value="*">' + (state.interfaces || []).map(i => `<option value="${escapeHtml(i.name)}">`).join('');
|
|
|
|
|
+ }
|
|
|
|
|
+ const instSel = document.getElementById('modal-radv-iface-instance');
|
|
|
|
|
+ if (instSel && instSel.tagName === 'SELECT') {
|
|
|
|
|
+ instSel.innerHTML = (state.radvInstances || []).map(i => `<option value="${escapeHtml(i.name)}">${escapeHtml(i.name)}</option>`).join('');
|
|
|
|
|
+ if (instSel.innerHTML === '') instSel.innerHTML = '<option value="default">default</option>';
|
|
|
|
|
+ instSel.value = (state.radvInstances && state.radvInstances.length > 0) ? state.radvInstances[0].name : 'default';
|
|
|
|
|
+ } else if (instSel) {
|
|
|
|
|
+ instSel.value = 'default';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ document.getElementById('modal-radv-iface-interface').value = '*';
|
|
|
document.getElementById('modal-radv-iface-min-ra').value = '200';
|
|
document.getElementById('modal-radv-iface-min-ra').value = '200';
|
|
|
document.getElementById('modal-radv-iface-max-ra').value = '600';
|
|
document.getElementById('modal-radv-iface-max-ra').value = '600';
|
|
|
document.getElementById('modal-radv-iface-lifetime').value = '1800';
|
|
document.getElementById('modal-radv-iface-lifetime').value = '1800';
|
|
@@ -20926,8 +20993,21 @@ function openEditRAdvInterfaceModal(id) {
|
|
|
if (!iface) return;
|
|
if (!iface) return;
|
|
|
document.getElementById('radv-interface-modal-title').innerText = `Edit RAdv Interface: ${iface.interface}`;
|
|
document.getElementById('radv-interface-modal-title').innerText = `Edit RAdv Interface: ${iface.interface}`;
|
|
|
document.getElementById('modal-radv-iface-id').value = iface.id;
|
|
document.getElementById('modal-radv-iface-id').value = iface.id;
|
|
|
- document.getElementById('modal-radv-iface-interface').value = iface.interface || '';
|
|
|
|
|
- document.getElementById('modal-radv-iface-instance').value = iface.instance || '';
|
|
|
|
|
|
|
+
|
|
|
|
|
+ const dl = document.getElementById('radv-iface-datalist');
|
|
|
|
|
+ if (dl) {
|
|
|
|
|
+ dl.innerHTML = '<option value="*">' + (state.interfaces || []).map(i => `<option value="${escapeHtml(i.name)}">`).join('');
|
|
|
|
|
+ }
|
|
|
|
|
+ const instSel = document.getElementById('modal-radv-iface-instance');
|
|
|
|
|
+ if (instSel && instSel.tagName === 'SELECT') {
|
|
|
|
|
+ instSel.innerHTML = (state.radvInstances || []).map(i => `<option value="${escapeHtml(i.name)}">${escapeHtml(i.name)}</option>`).join('');
|
|
|
|
|
+ if (instSel.innerHTML === '') instSel.innerHTML = '<option value="default">default</option>';
|
|
|
|
|
+ instSel.value = iface.instance || 'default';
|
|
|
|
|
+ } else if (instSel) {
|
|
|
|
|
+ instSel.value = iface.instance || '';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ document.getElementById('modal-radv-iface-interface').value = iface.interface || '*';
|
|
|
document.getElementById('modal-radv-iface-min-ra').value = iface.min_ra_interval || 200;
|
|
document.getElementById('modal-radv-iface-min-ra').value = iface.min_ra_interval || 200;
|
|
|
document.getElementById('modal-radv-iface-max-ra').value = iface.max_ra_interval || 600;
|
|
document.getElementById('modal-radv-iface-max-ra').value = iface.max_ra_interval || 600;
|
|
|
document.getElementById('modal-radv-iface-lifetime').value = iface.default_lifetime || 1800;
|
|
document.getElementById('modal-radv-iface-lifetime').value = iface.default_lifetime || 1800;
|