From 5d4320bc735c2461fda7865e6601f2158de044ec Mon Sep 17 00:00:00 2001 From: zvx Date: Thu, 21 May 2026 07:05:20 +0000 Subject: [PATCH] =?UTF-8?q?feat(L-c):=20operator=20/events=20table=20polis?= =?UTF-8?q?h=20=E2=80=94=20readable=20Time,=20Location,=20Subject,=20Adapt?= =?UTF-8?q?er=20columns;=20sortable;=20plain-language=20summaries?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- src/central/gui/routes.py | 37 ++- .../templates/_event_summaries/_default.html | 2 + .../gui/templates/_event_summaries/eonet.html | 2 + .../gui/templates/_event_summaries/firms.html | 2 + .../gui/templates/_event_summaries/gdacs.html | 2 + .../templates/_event_summaries/inciweb.html | 2 + .../gui/templates/_event_summaries/nwis.html | 2 + .../gui/templates/_event_summaries/nws.html | 2 + .../_event_summaries/swpc_alerts.html | 2 + .../_event_summaries/swpc_kindex.html | 2 + .../_event_summaries/swpc_protons.html | 2 + .../_event_summaries/usgs_quake.html | 2 + .../_event_summaries/wfigs_incidents.html | 2 + .../_event_summaries/wfigs_perimeters.html | 2 + src/central/gui/templates/_events_rows.html | 30 ++- src/central/gui/templates/events_list.html | 62 +++++ tests/test_events_feed_frontend.py | 243 ++++++++++++++++++ 17 files changed, 381 insertions(+), 17 deletions(-) create mode 100644 src/central/gui/templates/_event_summaries/_default.html create mode 100644 src/central/gui/templates/_event_summaries/eonet.html create mode 100644 src/central/gui/templates/_event_summaries/firms.html create mode 100644 src/central/gui/templates/_event_summaries/gdacs.html create mode 100644 src/central/gui/templates/_event_summaries/inciweb.html create mode 100644 src/central/gui/templates/_event_summaries/nwis.html create mode 100644 src/central/gui/templates/_event_summaries/nws.html create mode 100644 src/central/gui/templates/_event_summaries/swpc_alerts.html create mode 100644 src/central/gui/templates/_event_summaries/swpc_kindex.html create mode 100644 src/central/gui/templates/_event_summaries/swpc_protons.html create mode 100644 src/central/gui/templates/_event_summaries/usgs_quake.html create mode 100644 src/central/gui/templates/_event_summaries/wfigs_incidents.html create mode 100644 src/central/gui/templates/_event_summaries/wfigs_perimeters.html diff --git a/src/central/gui/routes.py b/src/central/gui/routes.py index 7673e21..a056496 100644 --- a/src/central/gui/routes.py +++ b/src/central/gui/routes.py @@ -4,7 +4,7 @@ import base64 import json import logging import re -from datetime import datetime +from datetime import datetime, timezone from typing import Any logger = logging.getLogger("central.gui.routes") @@ -2870,6 +2870,31 @@ def _geometry_summary(geometry: dict | None) -> str: return geom_type +def _format_event_time(iso: str | None) -> str: + """Format an ISO-8601 timestamp as 'MM-DD-YYYY HH:MM UTC' (24h, no seconds).""" + if not iso: + return "" + try: + dt = datetime.fromisoformat(iso).astimezone(timezone.utc) + except (ValueError, TypeError): + return iso + return dt.strftime("%m-%d-%Y %H:%M") + " UTC" + + +def _decorate_table_events(events: list[dict]) -> None: + """Add display-only fields used by the HTML events table (in place). + + These are for the table chrome only and are deliberately NOT added in + _fetch_events, so the /events.json payload is unchanged. adapter_display + is sourced from the registry (display_name), with the bare name as fallback. + """ + display = {cls.name: cls.display_name for cls in discover_adapters().values()} + for event in events: + event["geometry_summary"] = _geometry_summary(event.get("geometry")) + event["time_human"] = _format_event_time(event.get("time")) + event["adapter_display"] = display.get(event.get("adapter"), event.get("adapter")) + + @router.get("/events.json") async def events_json(request: Request): @@ -2958,9 +2983,8 @@ async def events_list(request: Request) -> HTMLResponse: events = result.events next_cursor = result.next_cursor - # Add geometry summary to each event - for event in events: - event["geometry_summary"] = _geometry_summary(event.get("geometry")) + # Add table-only display fields (time_human, adapter_display, geometry_summary) + _decorate_table_events(events) # Registry-derived adapter list for the filter