Fix IP filter to check connected client IPs
Fetches clients for every AP in parallel using the existing /api/ap-clients endpoint, then keeps only APs where at least one client has an IP with last octet 150–155. Shows a loading spinner while fetching. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -222,6 +222,7 @@
|
||||
const allRows = [...document.querySelectorAll('#ap-table-body tr')];
|
||||
|
||||
let ipFilterActive = false;
|
||||
let ipMatchedMacs = new Set(); // AP MACs that have a client with a .150–.155 IP
|
||||
|
||||
function isTargetIp(ip) {
|
||||
if (!ip) return false;
|
||||
@@ -229,6 +230,8 @@
|
||||
return last >= 150 && last <= 155;
|
||||
}
|
||||
|
||||
function normMac(s) { return (s || '').toUpperCase().replace(/-/g, ':'); }
|
||||
|
||||
function applyFilters() {
|
||||
const q = filterInput.value.toLowerCase().trim();
|
||||
let shown = 0;
|
||||
@@ -240,7 +243,7 @@
|
||||
let ipMatch = true;
|
||||
if (ipFilterActive) {
|
||||
const cb = row.querySelector('.ap-checkbox');
|
||||
ipMatch = isTargetIp(cb?.dataset.ip || '');
|
||||
ipMatch = ipMatchedMacs.has(normMac(cb?.dataset.mac));
|
||||
}
|
||||
|
||||
const visible = nameMatch && ipMatch;
|
||||
@@ -256,6 +259,7 @@
|
||||
// ── IP range filter button ─────────────────────────────────────────────────
|
||||
const btnIpFilter = document.getElementById('btn-ip-filter');
|
||||
const ipFilterLabel = document.getElementById('ip-filter-label');
|
||||
const ipFilterIcon = document.getElementById('ip-filter-icon');
|
||||
|
||||
function setIpFilterActive(active) {
|
||||
ipFilterActive = active;
|
||||
@@ -274,9 +278,48 @@
|
||||
}
|
||||
}
|
||||
|
||||
btnIpFilter?.addEventListener('click', () => {
|
||||
setIpFilterActive(!ipFilterActive);
|
||||
btnIpFilter?.addEventListener('click', async () => {
|
||||
if (ipFilterActive) {
|
||||
ipMatchedMacs.clear();
|
||||
setIpFilterActive(false);
|
||||
applyFilters();
|
||||
return;
|
||||
}
|
||||
|
||||
btnIpFilter.disabled = true;
|
||||
ipFilterLabel.textContent = 'Loading…';
|
||||
ipFilterIcon.classList.add('animate-spin');
|
||||
|
||||
try {
|
||||
// Collect each AP's mac + site_key from the DOM checkboxes
|
||||
const apList = [];
|
||||
allRows.forEach(row => {
|
||||
const cb = row.querySelector('.ap-checkbox');
|
||||
if (cb?.dataset.mac && cb?.dataset.siteKey) {
|
||||
apList.push({ mac: cb.dataset.mac, siteKey: cb.dataset.siteKey });
|
||||
}
|
||||
});
|
||||
|
||||
// Fetch clients for every AP in parallel (reuses the same endpoint as the popup)
|
||||
const hits = await Promise.all(apList.map(async ({ mac, siteKey }) => {
|
||||
try {
|
||||
const res = await fetch(`/api/ap-clients?mac=${encodeURIComponent(mac)}&site_key=${encodeURIComponent(siteKey)}`);
|
||||
if (!res.ok) return null;
|
||||
const { clients } = await res.json();
|
||||
return (clients || []).some(c => isTargetIp(c.ip)) ? normMac(mac) : null;
|
||||
} catch { return null; }
|
||||
}));
|
||||
|
||||
ipMatchedMacs = new Set(hits.filter(Boolean));
|
||||
setIpFilterActive(true);
|
||||
applyFilters();
|
||||
} catch (e) {
|
||||
showToast('Failed to load client data', 'error');
|
||||
ipFilterLabel.textContent = 'Filter .150–.155';
|
||||
} finally {
|
||||
btnIpFilter.disabled = false;
|
||||
ipFilterIcon.classList.remove('animate-spin');
|
||||
}
|
||||
});
|
||||
|
||||
// ── Refresh ────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user