diff --git a/meshview/templates/reach.html b/meshview/templates/reach.html new file mode 100644 index 0000000..09b4030 --- /dev/null +++ b/meshview/templates/reach.html @@ -0,0 +1,308 @@ +{% extends "base.html" %} + +{% block css %} +.reach-page { + max-width: 1200px; + margin: 0 auto; + padding: 0 16px; +} + +.reach-header { + margin-bottom: 16px; +} + +.reach-header h1 { + font-size: 1.6rem; + margin-bottom: 6px; +} + +.reach-panel { + border: 1px solid rgba(255, 255, 255, 0.18); + border-radius: 8px; + padding: 16px; + background: rgba(255, 255, 255, 0.04); +} + +.reach-node-id { + font-family: monospace; + font-size: 1.1rem; +} + +.reach-controls { + display: flex; + gap: 10px; + margin-top: 14px; +} + +.reach-search { + min-width: 0; + flex: 1; +} + +@media (max-width: 600px) { + .reach-controls { + flex-direction: column; + } +} + +.reach-summary { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); + gap: 12px; + margin-top: 16px; +} + +.reach-metric { + border: 1px solid rgba(255, 255, 255, 0.12); + border-radius: 8px; + padding: 12px; + background: rgba(0, 0, 0, 0.18); +} + +.reach-metric-value { + font-size: 1.5rem; + line-height: 1.2; +} + +.reach-table-wrap { + overflow-x: auto; + margin-top: 18px; +} + +.reach-table { + width: 100%; + min-width: 760px; +} + +.reach-table th, +.reach-table td { + vertical-align: top; +} + +.reach-muted { + color: rgba(255, 255, 255, 0.62); +} +{% endblock %} + +{% block body %} +
+
+

Reach Report

+

+ Review how often each gateway hears packets from a selected node. +

+
+ +
+
Selected Node ID
+
3530776522
+ +
+ + + +
+ +
+
+
Latest Packets
+
...
+
+
+
Unique Gateways
+
...
+
+
+ +
+ + + + + + + + + + + + + + +
GatewayHeard PacketsTotal PacketsReach
Loading packets...
+
+
+
+ + +{% endblock %} diff --git a/meshview/web.py b/meshview/web.py index e8f7f25..3772ab8 100644 --- a/meshview/web.py +++ b/meshview/web.py @@ -259,6 +259,12 @@ async def map(request): return web.Response(text=template.render(), content_type="text/html") +@routes.get("/reach") +async def reach(request): + template = env.get_template("reach.html") + return web.Response(text=template.render(), content_type="text/html") + + @routes.get("/nodelist") async def nodelist(request): template = env.get_template("nodelist.html")