mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-08-29 06:18:20 +00:00
feat(packets): clear-filters button (#964)
Add a "✕ Clear" button in the packets filter bar that appears when any filter is active. Clicking it resets all filters (hash, node, observer, type, channel, wireshark expression, region, My Nodes), clears localStorage filter entries, resets all DOM inputs/multi-selects, updates the URL hash to plain #/packets, and triggers a table re-render. The button visibility is managed by updatePacketsUrl() which runs after every filter change, so it automatically appears/disappears as filters are toggled. Closes #964
This commit is contained in:
@@ -59,6 +59,12 @@
|
||||
|
||||
function updatePacketsUrl() {
|
||||
history.replaceState(null, '', '#/packets' + buildPacketsQuery(savedTimeWindowMin, RegionFilter.getRegionParam()));
|
||||
// Update clear-filters button visibility
|
||||
var cb = document.getElementById('clearFiltersBtn');
|
||||
if (cb) {
|
||||
var active = !!(filters.hash || filters.node || filters.observer || filters.channel || filters.type || filters._filterExpr || filters.myNodes) || !!RegionFilter.getRegionParam();
|
||||
cb.style.display = active ? '' : 'none';
|
||||
}
|
||||
}
|
||||
|
||||
let filtersBuilt = false;
|
||||
@@ -785,6 +791,7 @@
|
||||
</div>
|
||||
<div class="filter-bar" id="pktFilters">
|
||||
<button class="btn filter-toggle-btn" id="filterToggleBtn">Filters ▾</button>
|
||||
<button class="btn btn-clear-filters" id="clearFiltersBtn" title="Clear all filters" style="display:none;font-size:12px;padding:2px 8px;color:var(--text-muted);border:1px solid var(--border);border-radius:4px;background:transparent;cursor:pointer">✕ Clear</button>
|
||||
<div class="filter-group">
|
||||
<input type="text" placeholder="Packet hash…" id="fHash" aria-label="Filter by packet hash" title="Filter packets by hex hash prefix">
|
||||
<div class="node-filter-wrap" style="position:relative">
|
||||
@@ -1065,6 +1072,57 @@
|
||||
this.textContent = bar.classList.contains('filters-expanded') ? 'Filters ▴' : 'Filters ▾';
|
||||
});
|
||||
|
||||
// --- Clear filters button ---
|
||||
const clearBtn = document.getElementById('clearFiltersBtn');
|
||||
if (clearBtn) clearBtn.addEventListener('click', function() {
|
||||
// Reset filters object
|
||||
filters.hash = undefined;
|
||||
filters.node = undefined;
|
||||
filters.nodeName = undefined;
|
||||
filters.observer = undefined;
|
||||
filters.channel = undefined;
|
||||
filters.type = undefined;
|
||||
filters._filterExpr = undefined;
|
||||
filters._packetFilter = null;
|
||||
filters.myNodes = false;
|
||||
_observerFilterSet = null;
|
||||
|
||||
// Clear localStorage filter entries
|
||||
localStorage.removeItem('meshcore-observer-filter');
|
||||
localStorage.removeItem('meshcore-type-filter');
|
||||
|
||||
// Reset DOM inputs
|
||||
document.getElementById('fHash').value = '';
|
||||
document.getElementById('fNode').value = '';
|
||||
var pfInput = document.getElementById('packetFilterInput');
|
||||
if (pfInput) { pfInput.value = ''; pfInput.classList.remove('filter-active', 'filter-error'); }
|
||||
var pfError = document.getElementById('packetFilterError');
|
||||
if (pfError) pfError.style.display = 'none';
|
||||
var pfCount = document.getElementById('packetFilterCount');
|
||||
if (pfCount) pfCount.style.display = 'none';
|
||||
document.getElementById('fChannel').value = '';
|
||||
document.getElementById('fMyNodes').classList.remove('active');
|
||||
|
||||
// Reset observer multi-select
|
||||
var obMenu = document.getElementById('observerMenu');
|
||||
if (obMenu) obMenu.querySelectorAll('input[type=checkbox]').forEach(function(cb) { cb.checked = false; });
|
||||
document.getElementById('observerTrigger').textContent = 'All Observers ▾';
|
||||
|
||||
// Reset type multi-select
|
||||
var typeMenu = document.getElementById('typeMenu');
|
||||
if (typeMenu) typeMenu.querySelectorAll('input[type=checkbox]').forEach(function(cb) { cb.checked = false; });
|
||||
document.getElementById('typeTrigger').textContent = 'All Types ▾';
|
||||
|
||||
// Reset region filter
|
||||
RegionFilter.setSelected([]);
|
||||
|
||||
// Update URL and reload
|
||||
updatePacketsUrl();
|
||||
loadPackets();
|
||||
});
|
||||
// Show clear button if page loaded with active filters (e.g. from URL params)
|
||||
updatePacketsUrl();
|
||||
|
||||
// Filter event listeners
|
||||
document.getElementById('fHash').value = filters.hash || '';
|
||||
document.getElementById('fHash').addEventListener('input', debounce((e) => { filters.hash = e.target.value || undefined; updatePacketsUrl(); loadPackets(); }, 300));
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/* test-clear-filters.js — unit test for clear-filters button (#964) */
|
||||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
console.log('--- test-clear-filters.js ---');
|
||||
|
||||
const src = fs.readFileSync(path.join(__dirname, 'public', 'packets.js'), 'utf-8');
|
||||
|
||||
// Test 1: button HTML present
|
||||
assert(src.includes('clearFiltersBtn'), 'clearFiltersBtn ID should exist');
|
||||
assert(src.includes('✕ Clear'), 'Clear button label should exist');
|
||||
|
||||
// Test 2: clear handler resets all filter keys
|
||||
for (const k of ['hash', 'node', 'observer', 'channel', 'type', '_filterExpr']) {
|
||||
assert(src.includes(`filters.${k} = undefined`), `should reset filters.${k}`);
|
||||
}
|
||||
assert(src.includes('filters._packetFilter = null'), 'should reset _packetFilter');
|
||||
assert(src.includes('filters.myNodes = false'), 'should reset myNodes');
|
||||
|
||||
// Test 3: clears localStorage
|
||||
assert(src.includes("localStorage.removeItem('meshcore-observer-filter')"), 'clear observer localStorage');
|
||||
assert(src.includes("localStorage.removeItem('meshcore-type-filter')"), 'clear type localStorage');
|
||||
|
||||
// Test 4: resets RegionFilter
|
||||
assert(src.includes('RegionFilter.setSelected([])'), 'reset RegionFilter');
|
||||
|
||||
// Test 5: visibility toggle in updatePacketsUrl
|
||||
assert(src.includes("cb.style.display = active ?"), 'toggle clear btn visibility');
|
||||
|
||||
// Test 6: resets DOM inputs
|
||||
assert(src.includes("getElementById('fHash').value = ''"), 'clear hash input');
|
||||
assert(src.includes("getElementById('fNode').value = ''"), 'clear node input');
|
||||
assert(src.includes("getElementById('fChannel').value = ''"), 'clear channel select');
|
||||
|
||||
// Test 7: resets multi-select checkboxes
|
||||
assert(src.includes('observerMenu'), 'clear observer checkboxes');
|
||||
assert(src.includes('typeMenu'), 'clear type checkboxes');
|
||||
|
||||
console.log('All 7 tests passed ✅');
|
||||
Reference in New Issue
Block a user