mirror of
https://github.com/zvx-echo6/central.git
synced 2026-06-10 20:04:43 +02:00
Hide tombstones from default events view + show-removed toggle (v0.9.11)
The /events feed was dominated by *.removed tombstone events (audit records for features dropped from upstream feeds), burying geometry-bearing events like fire perimeters (wfigs_perimeters: 54 real perimeters vs 1015 tombstones). The GUI now default-hides any event whose category ends in .removed, with a "Show removed" checkbox to restore them; URL state is preserved (HX-Push-Url) so a shared link shows what the sharer saw. events.json is unchanged (still returns tombstones) so API consumers are unaffected. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
92a1b3f2c6
commit
85d0e8f1cc
4 changed files with 116 additions and 2 deletions
|
|
@ -1227,3 +1227,38 @@ class TestEventsJsonSubject:
|
|||
def test_missing_source_fields_yields_none(self):
|
||||
"""An event lacking its adapter's source fields derives no subject."""
|
||||
assert _derive_subject(_subject_event("usgs_quake", {})) is None
|
||||
|
||||
|
||||
class TestShowRemovedToggle:
|
||||
"""v0.9.11 — tombstone visibility wiring. filter_state.show_removed drives
|
||||
the 'Show removed' checkbox in events_list.html; defaults to hidden."""
|
||||
|
||||
def _pool(self):
|
||||
conn = AsyncMock()
|
||||
conn.fetch.return_value = []
|
||||
conn.fetchrow.return_value = {
|
||||
"map_tile_url": "https://t/{z}/{x}/{y}.png", "map_attribution": "OSM"}
|
||||
pool = MagicMock()
|
||||
pool.acquire.return_value.__aenter__ = AsyncMock(return_value=conn)
|
||||
pool.acquire.return_value.__aexit__ = AsyncMock(return_value=None)
|
||||
return pool
|
||||
|
||||
async def _filter_state(self, query_params):
|
||||
req = MagicMock()
|
||||
req.state.operator = MagicMock(id=1, username="admin")
|
||||
req.state.csrf_token = "t"
|
||||
req.query_params = query_params
|
||||
templates = MagicMock()
|
||||
templates.TemplateResponse.return_value = MagicMock(status_code=200)
|
||||
with patch("central.gui.routes._get_templates", return_value=templates):
|
||||
with patch("central.gui.routes.get_pool", return_value=self._pool()):
|
||||
await events_list(req)
|
||||
return templates.TemplateResponse.call_args.kwargs["context"]["filter_state"]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_default_hides_removed(self):
|
||||
assert (await self._filter_state({}))["show_removed"] is False
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_show_removed_true_reflected(self):
|
||||
assert (await self._filter_state({"show_removed": "true"}))["show_removed"] is True
|
||||
|
|
|
|||
|
|
@ -251,3 +251,45 @@ async def test_select_includes_severity_column():
|
|||
parsed, _ = routes._parse_events_params({"time": "all"})
|
||||
cap = await _capture(parsed)
|
||||
assert "severity" in cap["query"]
|
||||
|
||||
|
||||
# --- show_removed / tombstone visibility (v0.9.11) --------------------------
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_gui_default_excludes_removed():
|
||||
"""GUI passes default_show_removed=False -> *.removed hidden by default."""
|
||||
parsed, _ = routes._parse_events_params(
|
||||
{"time": "all"}, default_time="last_24h", default_show_removed=False)
|
||||
assert parsed["show_removed"] is False
|
||||
cap = await _capture(parsed)
|
||||
assert "category NOT LIKE '%.removed'" in cap["query"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_show_removed_true_includes_all():
|
||||
"""?show_removed=true -> no tombstone exclusion in the query."""
|
||||
parsed, _ = routes._parse_events_params(
|
||||
{"time": "all", "show_removed": "true"}, default_show_removed=False)
|
||||
assert parsed["show_removed"] is True
|
||||
cap = await _capture(parsed)
|
||||
assert ".removed" not in cap["query"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_json_api_includes_removed_by_default():
|
||||
"""events.json calls the parser bare (default True) -> API output unchanged."""
|
||||
parsed, _ = routes._parse_events_params({"time": "all"})
|
||||
assert parsed["show_removed"] is True
|
||||
cap = await _capture(parsed)
|
||||
assert ".removed" not in cap["query"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_show_removed_composes_with_other_filters():
|
||||
"""The tombstone exclusion coexists with adapter/time filters."""
|
||||
parsed, _ = routes._parse_events_params(
|
||||
{"adapter": "wfigs_perimeters", "time": "all"}, default_show_removed=False)
|
||||
cap = await _capture(parsed)
|
||||
assert "adapter = ANY($" in cap["query"]
|
||||
assert "category NOT LIKE '%.removed'" in cap["query"]
|
||||
assert ["wfigs_perimeters"] in cap["params"]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue