Commit Graph
57 Commits
Author SHA1 Message Date
MrAlders0n fb376901f9 Drop empty observer telemetry frames and show airtime as duration 2026-07-15 21:44:11 -04:00
MrAlders0n 1b42e023d8 Restore files clobbered by the main merge 2026-07-14 23:30:50 -04:00
MrAlders0n cfe6a8f0ea Merge branch 'main' into dev
Signed-off-by: MrAlders0n <55921894+MrAlders0n@users.noreply.github.com>
2026-07-14 23:17:55 -04:00
MrAlders0n 43ebcd9638 Show loading feedback while packet history loads 2026-07-14 22:57:07 -04:00
MrAlders0n 2e2b845137 Filter packet history on the server when a single type, route or scope is selected 2026-07-14 22:31:50 -04:00
MrAlders0n 82a83fd33f Add Map deep-links for camera and settings with a copy-link button 2026-07-14 15:05:49 -04:00
MrAlders0n 58016bc773 Keep the packets list static while scrolled down instead of jumping on new packets 2026-07-13 18:51:56 -04:00
MrAlders0n 04f1757daa Add a .env option to skip the load splash 2026-07-13 11:50:57 -04:00
MrAlders0n 8344f3c8d2 Make VITE_ENABLED_THEMES an exclusive theme allowlist 2026-07-13 11:27:46 -04:00
MrAlders0n 8786ef3d0a Add .env options for hiding tabs, MeshMapper themes, app name and a GitHub link 2026-07-13 11:14:34 -04:00
MrAlders0n bda7147741 Add a copy link to node and observer detail panels
Deep-linked ?node/?observer selections now survive load: the region
reset watches the raw selection instead of the async-resolved regionKey,
so slug expansion no longer wipes a restored panel.
2026-07-12 17:12:08 -04:00
MrAlders0n dbb4dcac21 Add a copy button beside node and observer public keys 2026-07-12 07:57:52 -04:00
MrAlders0n c3979326aa Add a name search that spotlights matches and dims the rest of the mesh 2026-07-11 22:19:05 -04:00
MrAlders0n 6b0486f3f4 Gate the neighbour graph to a region and size labels by busyness 2026-07-11 22:11:16 -04:00
MrAlders0n 45669d7c26 Focus the neighbour graph into an ego view on click 2026-07-11 19:53:41 -04:00
MrAlders0n 25bd3ce30e Add a neighbour graph under the renamed Analytics tab 2026-07-11 18:56:58 -04:00
MrAlders0n 92806faaa4 map: colour a selected node's neighbour lines by obs count and freshness 2026-07-08 09:33:57 -04:00
MrAlders0n 5462c08662 map: dim other nodes to spotlight a selected node and its neighbours 2026-07-08 08:41:00 -04:00
MrAlders0n 26e83e0884 nodes: let the mobile detail panel minimize without deselecting 2026-07-07 23:50:21 -04:00
MrAlders0n 105e68ec04 map: rework live mode — packet dot, dashed trail, per-hop flash 2026-07-07 22:49:48 -04:00
MrAlders0n a0736545d8 map: shoot a comet along each packet's route in live mode 2026-07-06 08:13:03 -04:00
MrAlders0n b5e2e5dcac map: live mode dims nodes, flashes each packet's route 2026-07-06 08:00:33 -04:00
MrAlders0n e50501879a feat: discover renderers, neighbor map lines, live packet flow
- Discover packets decoded: DISCOVER_REQ/DISCOVER_RESP render real fields
  (type-filter roles, tag, node-to-node request SNR) instead of a raw dump.
- Neighbor lines on the map: On/Selected/Off control draws links between nodes
  and their known neighbors.
- Live packet flow: a play button animates packets hop-to-hop between repeaters
  in real time (off by default).
2026-07-05 22:08:54 -04:00
MrAlders0n 653768dcc8 Fix: github workflow + stats tab + add traces vs pings (#10)
* stats: node-types donut, multi-IATA filtering, preset split

 - node-types: new /stats/node-types endpoint + useNodeTypes; donutOption
   replaces the "Coming soon" card with a live donut
 - stats endpoints take iatas[] instead of a single iata, so multi-IATA
   regions filter instead of falling back to all (drops useStatsIata)
 - radio presets keep the node/observer split via stacked presetBarsOption
 - drop client-side telemetry ms-normalization (backend now emits epoch ms
   on both paths); charts pick delta-vs-raw counters off the response interval
 - MeshTab: range-driven charts lead, all-time charts follow; KPI window
   from overview.windowHours instead of a hardcoded 24h
 - ci: docker-publish builds a :dev image on dev-branch pushes

* feat: traces vs pings
feat: SNR for trace path in list
feat: known niehgbour count

* fix: github workflow, post images publically
2026-06-20 13:23:18 -04:00
MrAlders0n ad7b485913 feat: traces vs pings
feat: SNR for trace path in list
feat: known niehgbour count
2026-06-13 23:51:09 -04:00
MrAlders0n df9f4a07ad stats: node-types donut, multi-IATA filtering, preset split
- node-types: new /stats/node-types endpoint + useNodeTypes; donutOption
   replaces the "Coming soon" card with a live donut
 - stats endpoints take iatas[] instead of a single iata, so multi-IATA
   regions filter instead of falling back to all (drops useStatsIata)
 - radio presets keep the node/observer split via stacked presetBarsOption
 - drop client-side telemetry ms-normalization (backend now emits epoch ms
   on both paths); charts pick delta-vs-raw counters off the response interval
 - MeshTab: range-driven charts lead, all-time charts follow; KPI window
   from overview.windowHours instead of a hardcoded 24h
 - ci: docker-publish builds a :dev image on dev-branch pushes
2026-06-11 13:34:11 -04:00
MrAlders0n 9c93dac0f6 stats: bench the node-types donut until a real endpoint exists
The donut counted types among the top-10 nodes only, so the center
read '10 NODES' as if the region had ten nodes, and its center text
never sat quite right (ECharts titles anchor the main text, the
subtext hangs below). There's no /stats/node-types endpoint to feed it
properly yet (ticket filed), so the card shows 'Coming soon' and the
donut builder goes away rather than lingering as dead code.
2026-06-10 08:44:13 -04:00
MrAlders0n d1ff74cc1f stats: anchor the donut center text on the pie's exact center
textAlign/textVerticalAlign make left/top the anchor point, so the
value+label block centers on (35%, 50%) geometrically instead of the
hand-tuned top offset that drifted with card size.
2026-06-10 08:26:47 -04:00
MrAlders0n ad4e68f817 packets: highlight timer leak, analyzer close desync, dead code
- fresh-row highlights leaked under a steady stream (each new batch
  cancelled the previous batch's clear timer); per-batch timers in a
  small useFreshHashes hook now
- closing the analyzer drops ?hash and the row selection, so the same
  row reopens on the next click and a closed analyzer stays closed
  after reload/share
- sf=path / sf=payload from the URL fall back to hash search (only
  field matchesFilters implements; the UI options were already disabled)
- remove the summary preview line no backend path ever populates
- channel message rows key on packetHash (live WS messages carry no id)
2026-06-10 07:03:16 -04:00
MrAlders0n 39641b6339 ui: footer version from package.json plus a batch of interaction fixes
- footer read 'v0.1' forever; it's injected from package.json at build
  time now
- region picker shows 'Failed to load' instead of an eternal Loading
  when /iatas errors
- selecting text in a modal and releasing over the backdrop no longer
  closes it (close requires the press to start on the backdrop)
- Escape in a dropdown inside the mobile filter sheet closes just the
  dropdown, not the whole sheet
- Shift+Tab right after a modal opens wraps to the last control instead
  of escaping the focus trap
- formatCount rolls 999,999 over to 1M instead of printing 1000k
- TABS list moved to lib/constants so AppShell only exports components
2026-06-10 07:03:16 -04:00
MrAlders0n 7e2a4de78f channels: send the singular iata param the backend actually reads
/channels ignores the plural iatas param, so the sidebar was always
global no matter the region — and opening another region's channel
showed an empty panel because the messages endpoint IS region-filtered.
Single-IATA regions filter properly now; multi-IATA stays global until
the backend grows parseIATAs there (ticket).
2026-06-10 07:03:16 -04:00
MrAlders0n aec59225f0 observers: derive online/offline from lastStatusAt recency
The WS observerStatus event never says offline (the backend only
derives it at REST read time, 5-minute window) and the list never
refetches, so badges stayed green all session once an observer went
quiet. Status is now re-derived on a tick from lastStatusAt — the WS
patch keeps the timestamp fresh — using the same 5-minute rule as the
server.
2026-06-10 07:03:16 -04:00
MrAlders0n a78b735bb2 routes: keep paging when client-side region filtering starves the table
A multi-IATA region filters globally-paged rows client-side, and scroll
was the only trigger for the next page — an empty or too-short filtered
list could never fire it, so routes deeper in the cursor stream were
unreachable ('No routes' with routes that exist). Pull pages until the
region has a screenful or the cap calls it sparse.
2026-06-10 07:03:16 -04:00
MrAlders0n d5deb1e042 stats: node types back to a donut (3 categories), fix leaderboard labels
The donut suits node types after all — few slices, and the total reads
better in the ring than on three bars. The center text is a title block
with textAlign center now, which ECharts actually centers (the old
graphic text anchored its left edge at the ring's x and clipped);
TitleComponent registered in the tree-shaken setup. Payload types stays
a bar chart.

Leaderboard names (top nodes/observers, radio presets) are left-aligned
at the card edge and ellipsized instead of running off the grid's left
side.
2026-06-10 06:59:49 -04:00
MrAlders0n 12d5056e20 map: insert brand-new nodes from their nodeUpdate event
The WS patch only updated nodes already in the paged cache, and with
staleTime Infinity nothing ever refetched — a node that came up after
page load could never appear on the map. The event carries a full
summary, so unknown nodes are appended to the cache directly. The
Nodes table keeps patch-only behavior since its cache is filter-scoped.
2026-06-10 06:59:49 -04:00
MrAlders0n 39756bc0d1 nodes/map: trust the API's decimal-degree coordinates
microToDeg guessed microdegrees from integer values, but api/nodes.go
has always sent *float64 degrees — so a node sitting at an exact whole
degree got divided by 1e6 and rendered at the equator. Drop the shim
from the geojson builder, the nodes table and the detail panel, and fix
the ws.ts comment that repeated the wrong premise.

Also key neighbor rows by id+iata: the neighbors endpoint returns one
row per (neighbor, iata), so id alone collides for nodes heard in
several regions (live React duplicate-key error).
2026-06-10 06:59:49 -04:00
MrAlders0n 115f6a83cc stats: replace the type donuts with vertical bar charts
The payload-types donut was buckling: 10+ slivers, a scrollable legend
with truncated names, and a center total that clipped at narrower
widths. Bars label every category inline, show counts on top, and the
total moved into the card header. Node types gets the same treatment
for consistency.

Also fix charts starting on the fallback palette when a saved theme
loads: themeId is already the saved id before the CSS vars land, so
useChartColors now keys on a paletteRev that bumps on every applyTheme.
2026-06-10 06:46:13 -04:00
MrAlders0n 714b32fd22 fix back/forward tab navigation and the packet-list gap on tab return
The active tab was state seeded from ?tab once, so back/forward moved
the URL without moving the UI. The URL is the source of truth now, and
unknown ?tab values fall back to Packets instead of a blank pane.

Packets history also healed wrong: while the tab is unmounted its WS
handler is down, and staleTime Infinity meant the gap never closed.
Mounting now resets to a fresh first page. Same for lag notices, which
used to invalidate (and sequentially replay) up to 20 cached pages —
together with the ws reconnect notice this covers outage recovery too.
2026-06-10 06:39:12 -04:00
MrAlders0n f4093cf508 ws: fix subscription leak, stale sockets and half-open links
The big one: updateSubscription before the previous subscribe was acked
never unsubscribed it (the server keeps scopes additively), so a region
change right after connect left the old all-regions sub alive and the
live feed stayed a firehose. Subscribes now carry a tracked id and an
ack for a superseded subscribe is unsubscribed on arrival.

Also:
- doConnect/disconnect tear down the old socket and detach handlers, so
  a late close from a dead socket can't spawn a parallel reconnect loop
  (the StrictMode dev warning came from this)
- subscription ids are cleared per-connection instead of leaking a
  stale id onto the next socket
- pings now double as a liveness check: no pong for two intervals
  forces a reconnect instead of showing LIVE on a half-open link
- a server-sent close 1000 reconnects instead of going permanently dark
- after a reconnect the manager synthesizes a lag notice so live views
  refetch what they missed during the outage
2026-06-10 06:34:28 -04:00
MrAlders0n 7e07669f33 stats: fix live KPI counters never updating
useLiveOverview keyed its setQueryData on the whole RegionFilter object
while the overview query keys on the regionKey string, so every WS bump
silently missed the cache and the counters only moved on the 60s
refetch. Also drop pending counts when the region changes so old-region
increments don't bleed into the new KPIs.
2026-06-10 06:30:32 -04:00
MrAlders0n 08d50be490 Track devserver.sh and finish the tower -> beacon rename
scripts/ was caught by a stray .gitignore entry, so the npm start/stop
helpers pointed at a file fresh clones never got. Also sweep the last
tower-* references out of comments, compose and the map test fixture.
2026-06-09 23:16:04 -04:00
MrAlders0n be072bb42c feat(stats): add Mesh + Observer stats tab with ECharts
Integrate the stats feature onto main: live mesh KPIs, observations
time-series, payload/node-type donuts, top-nodes/observers leaderboards,
radio presets, scope stats, and per-observer telemetry (battery, airtime,
noise, queue, receive errors) with 1h/6h/24h bucketing.

- adapt to the multi-IATA region model (useRegion -> single iata for /stats/*)
- rename stats getScopes -> getStatsScopes (avoids /scopes name-list collision)
- donut legend kept right but scrollable + truncating so it never clips
- balanced mesh grid; observer empty-state for telemetry-less observers
- normalize telemetry t to ms (raw path emits seconds, bucketed emits ms)
- add echarts 5.5.1; lazy-load StatsOverview chunk
2026-06-09 22:02:27 -04:00
MrAlders0n ed9741ea63 feat: standardize trace view to be the same as packets view, etc 2026-06-09 20:37:57 -04:00
MrAlders0n 83c30ca236 Sync to features from server 2026-06-08 22:35:06 -04:00
MrAlders0n 84f235a3b4 Mobile support refactor and cleanup 2026-06-08 10:18:17 -04:00
MrAlders0n b8b1f5f27d Feat/scopes routes traces (#7)
* feat: replace getScopeStats with getScopes and update related tests
bug: lastSeen/sentAt was set to string instead of number by mistake

* feat: update timestamp handling and formatting across components

- WS messages carry epoch ms now instead of ISO strings
- new Timestamp component (relative/absolute), used in RouteTable and RouteDetailPanel
- IataChip and ScopeTag chips
- TraceDetailPanel and TraceList for trace drill-down
- tests updated for the timestamp change
2026-06-07 00:19:54 -04:00
MrAlders0n 8e2696b95a feat: loading pill for map and tables
- LoadingPill shows loading/error state in MapView, NodeTable and ObserverTable
- new useInfinitePages hook shares the pagination logic between them
- patchNodeSummary/patchObserverSummary now keep references stable
- tests for loading states, observer updates and infinite paging
2026-06-05 22:59:52 -04:00
MrAlders0n 81bdeec16b feat: implement paginated node fetching and add related tests 2026-06-05 20:23:17 -04:00
MrAlders0n eb50f310db feat: decrypted channel messages, scopes in ws 2026-06-05 17:22:37 -04:00
MrAlders0n 47c1813471 feat: added path resolution to traces 2026-06-05 09:24:21 -04:00