feat: flood-verdict banner, violet rain palette, per-station bands, chip contrast, Umami
Documentation / Build Sphinx Documentation (push) Successful in 27s
Documentation / Documentation Summary (push) Successful in 3s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Cleanup (push) Successful in 1s
Documentation / Validate Documentation (push) Failing after 11s
Documentation / Generate API Documentation (push) Successful in 11s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Test Suite (3.11) (push) Failing after 1m0s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Build Docker Image (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Staging (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Integration Test with Services (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Production (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Performance Test (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Code Quality (push) Successful in 30s

UI/UX review backlog round 2 plus analytics:
- at-a-glance verdict banner (role=status, aria-live) above the tiles:
  ok/watch/danger from P.1 level vs the official 3.70 m stage and the
  24 h forecast, with a not-an-official-warning disclaimer + ThaiWater
  link (also added to the forecast card)
- rainfall dots switch to a violet sequential ramp so they can never be
  confused with flow-status colors; legend gains 'Other markers' rows
  (grey no-data gauges, + bank-height sensors)
- history-chart flood bands now use each station's own /forecast
  thresholds (P.1 official fallback) instead of hardcoded 3.0/4.5
- chipStyle(): contrast-safe text on all code/risk/stage chips (dark ink
  on amber/ochre, darkened fills for white ink); risk/stage ramps drop
  the blue step for a monotonic green-ochre-amber-red escalation
- plain-language tooltips on the flow and capacity tiles
- Umami: client script tag plus opt-out server-side middleware posting
  api-request events (fire-and-forget, 3 s timeout, never blocks)
This commit is contained in:
2026-08-11 16:56:53 +07:00
parent 5848621c77
commit b89c7e1915
3 changed files with 161 additions and 24 deletions
+53
View File
@@ -267,6 +267,59 @@ async def background_scraping_task():
await asyncio.sleep(60) # Wait a minute before retrying
# Umami server-side API tracking (fire-and-forget; never blocks a response)
_UMAMI_TRACK_PREFIXES = (
"/api/",
"/measurements",
"/forecast",
"/stations",
"/sensors",
)
def _send_umami_event(path: str, method: str, status: int, host: str, user_agent: str):
try:
requests.post(
Config.UMAMI_API_URL,
json={
"type": "event",
"payload": {
"website": Config.UMAMI_WEBSITE_ID,
"url": path,
"hostname": host,
"name": "api-request",
"data": {"method": method, "status": status},
},
},
headers={"User-Agent": user_agent or "api-client"},
timeout=3,
)
except Exception:
pass # analytics must never affect API behavior
@app.middleware("http")
async def umami_api_tracking(request, call_next):
response = await call_next(request)
if (
Config.UMAMI_TRACK_API
and Config.UMAMI_WEBSITE_ID
and request.url.path.startswith(_UMAMI_TRACK_PREFIXES)
):
asyncio.get_event_loop().create_task(
asyncio.to_thread(
_send_umami_event,
request.url.path,
request.method,
response.status_code,
request.headers.get("host", "water.buildfor.life"),
request.headers.get("user-agent", ""),
)
)
return response
# API Routes