fix(packets): re-fetch when the observer filter changes (#2241) (#2242)

Fixes #2241.

## Problem

In grouped mode, ticking an observer on `#/packets` updated the URL and
the trigger label but left the table unchanged until a reload. Since
#1821 `applyObserverFilter` leaves grouped rows to the server's EXISTS
filter, while the observer menu's change handler still only called
`renderTableRows()`, which re-renders the rows already loaded without a
new `/api/packets` request.

## Change

- `public/packets.js`: the observer menu change handler calls
`loadPackets()` instead of `renderTableRows()`, so the request carries
the new `observer=` set.
- `tests/unit/test-observer-menu-interactions.js`: two tests asserting
the handler re-fetches, for ticking one observer and for "All
Observers". Both failed before the change.

## Verification

- `sh test-all.sh`: all suites pass (locally
`test-preflight-xss-gate.js` needs a real `python3` on PATH and
`PYTHONUTF8=1`, unrelated to this change).
- Browser, local server on the freshened e2e fixture: 55 rows; one
observer ticked gives 2 rows, all from that observer; back to "All
Observers" gives 53 rows. No reload in between.
- Reproduced the original bug on an operator's v3.14.0 instance before
the change.

## Not done

- Playwright E2E suite not run locally.
- Perf: one `/api/packets` request per checkbox toggle, the same request
a reload or the node filter already makes. No per-item calls.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
efitenandClaude Opus 5.5 authored and GitHub committed 2026-10-17 21:07:27 +02:00
1 parent 8b5ca5735c
commit a910a3e480
2 files changed
+23 -3

No files matched your search

+2 -1
View File
@@ -2026,7 +2026,8 @@
buildObserverMenu();
updateObsTrigger();
updatePacketsUrl();
renderTableRows();
// Grouped rows are filtered by the server only (#1821), so re-fetch.
loadPackets();
});
// --- Type multi-select ---
+21 -2
View File
@@ -63,12 +63,13 @@ function stubEl(overrides) {
const updateObsTrigger = () => calls.push('updateObsTrigger');
const updatePacketsUrl = () => calls.push('updatePacketsUrl');
const renderTableRows = () => calls.push('renderTableRows');
const loadPackets = () => calls.push('loadPackets');
const fn = new Function(
'e', 'selectedObservers', 'filters', 'localStorage',
'buildObserverMenu', 'updateObsTrigger', 'updatePacketsUrl', 'renderTableRows',
'buildObserverMenu', 'updateObsTrigger', 'updatePacketsUrl', 'renderTableRows', 'loadPackets',
body
);
fn(target, selectedObservers, filters, localStorage, buildObserverMenu, updateObsTrigger, updatePacketsUrl, renderTableRows);
fn(target, selectedObservers, filters, localStorage, buildObserverMenu, updateObsTrigger, updatePacketsUrl, renderTableRows, loadPackets);
}
test('change event with no data-obs-id (bubbled from search input) is a no-op', () => {
@@ -88,6 +89,24 @@ function stubEl(overrides) {
assert(calls.includes('buildObserverMenu'), 'buildObserverMenu should run for a real toggle');
assert(calls.includes('updatePacketsUrl'), 'updatePacketsUrl should run for a real toggle');
});
// Grouped mode leaves the observer filter to the server (#1821), so a
// re-render of the already loaded rows changes nothing until a reload.
test('toggling an observer re-fetches packets from the server', () => {
const calls = [];
const filters = {};
run({ target: { dataset: { obsId: '7' }, checked: true } }, { calls, selectedObservers: new Set(), filters });
assert.strictEqual(filters.observer, '7');
assert(calls.includes('loadPackets'), 'loadPackets must run so the server applies the observer filter');
});
test('selecting All Observers re-fetches packets from the server', () => {
const calls = [];
const filters = { observer: '7' };
run({ target: { dataset: { obsId: '__all__' }, checked: true } }, { calls, selectedObservers: new Set(['7']), filters });
assert.strictEqual(filters.observer, undefined);
assert(calls.includes('loadPackets'), 'loadPackets must run so the unfiltered set is fetched');
});
}
// --- 2. Clear Filters must reset and re-apply the observer search box ---