Fix IP filter to check AP's own IP from DOM

Previous implementation fetched connected client IPs via API (which was
returning empty data). The filter now checks the AP's own management IP
directly from the data already in the table — no network request, instant.

An AP is shown when its IP last octet is between 150 and 155 inclusive.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-27 15:51:43 +02:00
parent d693321ba1
commit b455b2fd15

View File

@@ -221,9 +221,13 @@
const visibleCount = document.getElementById('visible-count');
const allRows = [...document.querySelectorAll('#ap-table-body tr')];
let ipMatchingMacs = null; // null = inactive; Set<string> = active
let ipFilterActive = false;
function normMac(s) { return (s || '').toUpperCase().replace(/-/g, ':'); }
function isTargetIp(ip) {
if (!ip) return false;
const last = parseInt((ip.split('.')[3] || ''), 10);
return last >= 150 && last <= 155;
}
function applyFilters() {
const q = filterInput.value.toLowerCase().trim();
@@ -234,9 +238,9 @@
const nameMatch = !q || name.includes(q) || site.includes(q);
let ipMatch = true;
if (ipMatchingMacs !== null) {
if (ipFilterActive) {
const cb = row.querySelector('.ap-checkbox');
ipMatch = ipMatchingMacs.has(normMac(cb?.dataset.mac));
ipMatch = isTargetIp(cb?.dataset.ip || '');
}
const visible = nameMatch && ipMatch;
@@ -252,18 +256,9 @@
// ── 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');
let cachedApClients = null;
function isTargetIp(ip) {
if (!ip) return false;
const parts = ip.split('.');
if (parts.length !== 4) return false;
const last = parseInt(parts[3], 10);
return last >= 150 && last <= 155;
}
function setIpFilterActive(active) {
ipFilterActive = active;
if (active) {
btnIpFilter.classList.replace('bg-white', 'bg-blue-50');
btnIpFilter.classList.replace('hover:bg-gray-50', 'hover:bg-blue-100');
@@ -279,40 +274,9 @@
}
}
btnIpFilter?.addEventListener('click', async () => {
if (ipMatchingMacs !== null) {
// Clear filter
ipMatchingMacs = null;
setIpFilterActive(false);
btnIpFilter?.addEventListener('click', () => {
setIpFilterActive(!ipFilterActive);
applyFilters();
return;
}
btnIpFilter.disabled = true;
ipFilterLabel.textContent = 'Loading…';
ipFilterIcon.classList.add('animate-spin');
try {
if (!cachedApClients) {
const res = await fetch('/api/all-clients');
if (!res.ok) { const e = await res.json(); throw new Error(e.detail || 'Request failed'); }
cachedApClients = (await res.json()).ap_clients || {};
}
ipMatchingMacs = new Set();
for (const [apMac, clients] of Object.entries(cachedApClients)) {
if (clients.some(c => isTargetIp(c.ip))) ipMatchingMacs.add(apMac);
}
setIpFilterActive(true);
applyFilters();
} catch (e) {
showToast('Failed to load client data: ' + e.message, 'error');
ipFilterLabel.textContent = 'Filter .150.155';
} finally {
btnIpFilter.disabled = false;
ipFilterIcon.classList.remove('animate-spin');
}
});
// ── Refresh ────────────────────────────────────────────────────────────────