Fix multi-select filters (AND→OR) and add localStorage persistence

- Server: support comma-separated type filter values (OR logic)
- Server: add observer_id filtering to /api/packets endpoint
- Client: fix type and observer filters to use OR logic for multi-select
- Client: persist observer and type filter selections to localStorage
- Keys: meshcore-observer-filter, meshcore-type-filter
This commit is contained in:
you
2026-03-22 00:34:38 +00:00
parent 29d1493556
commit 59062946be
3 changed files with 14 additions and 4 deletions
+1 -1
View File
@@ -84,7 +84,7 @@
<script src="hop-resolver.js?v=1774126708"></script>
<script src="app.js?v=1774126708"></script>
<script src="home.js?v=1774042199"></script>
<script src="packets.js?v=1774138896"></script>
<script src="packets.js?v=1774139673"></script>
<script src="map.js?v=1774126708" onerror="console.error('Failed to load:', this.src)"></script>
<script src="channels.js?v=1774331200" onerror="console.error('Failed to load:', this.src)"></script>
<script src="nodes.js?v=1774126708" onerror="console.error('Failed to load:', this.src)"></script>
+11 -2
View File
@@ -13,6 +13,8 @@
let selectedId = null;
let groupByHash = true;
let filters = {};
{ const o = localStorage.getItem('meshcore-observer-filter'); if (o) filters.observer = o;
const t = localStorage.getItem('meshcore-type-filter'); if (t) filters.type = t; }
let wsHandler = null;
let observers = [];
let regionMap = {};
@@ -21,6 +23,7 @@
let totalCount = 0;
let expandedHashes = new Set();
let hopNameCache = {};
let showHexHashes = localStorage.getItem('meshcore-hex-hashes') === 'true';
let filtersBuilt = false;
const PANEL_WIDTH_KEY = 'meshcore-panel-width';
@@ -116,6 +119,9 @@
}
function renderHop(h) {
if (showHexHashes) {
return `<span class="hop">${escapeHtml(h)}</span>`;
}
const entry = hopNameCache[h];
const name = entry ? (typeof entry === 'string' ? entry : entry.name) : null;
const pubkey = entry?.pubkey || h;
@@ -242,8 +248,8 @@
// Check if new packets pass current filters
const filtered = newPkts.filter(p => {
if (filters.type !== undefined && filters.type !== '' && p.payload_type !== Number(filters.type)) return false;
if (filters.observer && p.observer_id !== filters.observer) return false;
if (filters.type) { const types = filters.type.split(',').map(Number); if (!types.includes(p.payload_type)) return false; }
if (filters.observer) { const obsSet = new Set(filters.observer.split(',')); if (!obsSet.has(p.observer_id)) return false; }
if (filters.hash && p.hash !== filters.hash) return false;
if (RegionFilter.getRegionParam()) {
const selectedRegions = RegionFilter.getRegionParam().split(',');
@@ -462,6 +468,7 @@
<button class="col-toggle-btn" id="colToggleBtn" title="Show/hide table columns">Columns ▾</button>
<div class="col-toggle-menu" id="colToggleMenu"></div>
</div>
<button class="btn btn-icon${showHexHashes ? ' active' : ''}" id="hexHashToggle" title="Show hex hashes in path column">Hex</button>
</div>
</div>
<table class="data-table" id="pktTable">
@@ -512,6 +519,7 @@
if (e.target.checked) selectedObservers.add(id); else selectedObservers.delete(id);
}
filters.observer = selectedObservers.size > 0 ? [...selectedObservers].join(',') : undefined;
if (filters.observer) localStorage.setItem('meshcore-observer-filter', filters.observer); else localStorage.removeItem('meshcore-observer-filter');
buildObserverMenu();
updateObsTrigger();
loadPackets();
@@ -553,6 +561,7 @@
if (e.target.checked) selectedTypes.add(id); else selectedTypes.delete(id);
}
filters.type = selectedTypes.size > 0 ? [...selectedTypes].join(',') : undefined;
if (filters.type) localStorage.setItem('meshcore-type-filter', filters.type); else localStorage.removeItem('meshcore-type-filter');
buildTypeMenu();
updateTypeTrigger();
loadPackets();
+2 -1
View File
@@ -921,7 +921,8 @@ app.get('/api/packets', (req, res) => {
}
let results = [...allPackets.values()].sort((a, b) => order === 'DESC' ? b.timestamp.localeCompare(a.timestamp) : a.timestamp.localeCompare(b.timestamp));
// Apply additional filters
if (type !== undefined) results = results.filter(p => String(p.payload_type) === String(type));
if (type !== undefined) { const types = String(type).split(','); results = results.filter(p => types.includes(String(p.payload_type))); }
if (observer) { const obsIds = observer.split(','); results = results.filter(p => obsIds.includes(p.observer_id)); }
if (region) results = results.filter(p => (p.observer_id || '').includes(region) || (p.decoded_json || '').includes(region));
if (since) results = results.filter(p => p.timestamp >= since);
if (until) results = results.filter(p => p.timestamp <= until);