Skip to content

v2.7.2 Release Changes - #1171

Merged
tvancott42 merged 27 commits into
mainfrom
dev
Aug 23, 2026
Merged

v2.7.2 Release Changes#1171
tvancott42 merged 27 commits into
mainfrom
dev

Conversation

@tvancott42

Copy link
Copy Markdown
Collaborator

No description provided.

tvancott42 and others added 27 commits August 22, 2026 10:28
The tooltip was bound to the annotation's <text>, and an SVG text only hit-tests
against the strokes it paints, so the target was the outline of an 11px glyph.
Bind it to the background rect ApexCharts inserts before the text instead, and
keep the text transparent to pointers so it does not punch a hole in the middle.
ONT Stats marked before drawing its series, and a series redraw makes ApexCharts
rebuild the annotation nodes from config - so every tooltip was bound to nodes
that were replaced a moment later, and the marks stayed dead until a time range
change redrew them. Draw first, mark after, as SFP Stats and Device Stats do.

The same trap is reachable on every tab: the signature short-circuit skips the
redraw when the events have not changed, so a filter toggle that leaves the
event set alone would strand the tooltips the same way. The layer now re-tags
when it finds the nodes no longer bound.
SFP Stats and ONT Stats both refresh their PON charts asynchronously AFTER the
marks are drawn, and ApexCharts rebuilds the annotation nodes from config on that
update - so the marks came back looking identical with nothing bound to them.
Filtering to a PON-bearing module left every mark on those charts unhoverable
until a time range change redrew them.

The layer cannot be the last writer by arrangement, so it watches its charts and
re-tags when it finds the labels no longer bound. Verified against the real
library: the tooltips survive the PON refresh whichever order the tab draws in.
A deep link to a tab beyond the visible few left the strip parked at the start,
so on a phone the page read as if the first tab were open. The open tab is now
centered when it changes, clamped so the first and last sit flush with their end.
Only a change of tab moves the strip, so hand-scrolling it is never overridden.
The summary claimed the Nokia G-010S-P, which is GPON and runs its own vendor
image - 8311 is XGS-PON only, so that stick can never reach this provider. Names
the sticks that do run it, and PRX126 as the WAS-110's chipset rather than a
model of its own.
Autopilot announces a plan when it books it, and it books into the next
quiet hour at least NotifyHoursAhead away - which for a Sunday 3 AM window
picked on a Monday is nearly a week out. The one alert the site got was
long gone by the time it rebooted, and a manually scheduled plan was never
announced at all.

The executor's scheduled-plan branch now publishes rollout.starting_soon at
T-12h, keyed to the start so a postpone re-arms it, and suppressed when the
plan was booked within 8 hours ahead of that mark so a short-lead run is not
announced twice.

Also: lead times read as days and hours past a day ("in about 7 days and
23 hours"), not as 191 hours.
… to their pages

Dismiss implied the finding was written off; it is visibility-only and the
issue stays scored. The button tooltip now says so.

Also adds the settings-title-link icon to Monitoring, Adaptive SQM Monitor,
LAN Speed Test Settings, External Speed Test Servers, Security Audit, Alert
Channels and Threat Intelligence, and renames Speed Test Settings to LAN Speed
Test Settings (it only configures iperf3) with matching search terms.
Renaming the card to "LAN Speed Test Settings" cost it the index-0 scoring
bonus, dropping it to an exact tie with "External Speed Test Servers" for the
query "speed test" - which the alphabetical tie-break then handed to the WAN
server list. Ties now keep the order providers list their entries, which is
the order the cards appear on the tab.
…d module versions, and add status tables to every Monitoring tab (#1169)

Cellular modem monitoring: GL.iNet SoC modems, device and module versions, status tables (#1169)

GL.iNet's 5G routers carry the modem on the SoC, where gl_modem needs -B cpu
and a mandatory -U flag. We only emitted the USB form, so every poll returned
its usage text and surfaced as "the modem did not respond". Addressing is now
resolved per modem from GL's own cellular service and re-resolved when a cached
command line stops being accepted.

Also fixes the Quectel bandwidth field, which is an index into a table rather
than a figure in MHz: band n41 at 90 MHz reported 11 and was recorded as 11 MHz.
This affected every GL.iNet modem, not only the SoC ones.

Monitored devices now record what they are and what they run. SoftwareVersion
and HostVersion split by layer - the thing being monitored, and the device
containing it - and ModuleVendor/ModuleModel record the radio module itself.
Firmware is read on every poll and never cached, because Firmware Rollout
changes it from inside this app; which module is fitted is remembered once.
All four reach InfluxDB as fields.

Cable Modem, Cellular and Starlink Stats gain the status table SFP and ONT
already had, now one shared renderer that drops any column no device fills.
Every statistics table gains a Latest column - mean/min/max without "now" was
an incomplete set - plus a window total for error counters, and a tint on the
column opening each metric group.

Fixes a Client Performance regression where the CM/ONT level bar's global
.signal-gauge rule sized its dBm readout to 14px, and four places that judged
a poll by a shell chain's exit status, which belongs only to the last command.

GL.iNet paths are pinned to output captured from a real GL-E5800 but have not
run against one; no test site has that hardware.
One step, anchored on the Device Stats statistics table. The table is built
in JS, so the anchor is set via el.dataset.tour rather than markup.
Gated on the cellular predicate so it only reaches sites with an enabled
modem. Anchored on the Module row, whose tooltip is the thing to hover.
What these gateways report, and what the Dashboard card shows, is the SFP ONT
stick rather than the gateway holding it - the same split cellular modems now
record as ModuleVendor/ModuleModel and SoftwareVersion/HostVersion.
…stored

The card renders the stick's vendor and part number through SfpModelLabel, so
wiring ModuleVendor/ModuleModel is plumbing what we have rather than new
collection.
SFP-form ONTs are a module inside the gateway holding them, the same shape as a
Quectel module inside a GL router. The vendor and part number are already read
and rendered; what is missing is deciding which layer each provider reports and
normalizing the strings before they are stored.
The column was hide-mobile on both the header and the cell, so the link to what
an alert was about was gone entirely on a phone rather than scrolled off.
…1170)

* Bind the agent tunnel at startup instead of gating it on multi-site

The tunnel listener was bound only when multisite.enabled was already true at
process start, read with raw SQLite because Kestrel is configured before EF
exists. Enabling multi-site in the UI therefore wrote a flag nothing read again
until a restart, and nothing in Settings said so: agents enrolled, dialed 8043,
and got whatever the reverse proxy returns for a dead backend, usually a 502
that reads as a broken proxy route.

Bind whenever the bindings can be reproduced instead. The installs that lose the
tunnel are the ones that already lost it: ResolveHttpBindings returns null for a
server serving its own HTTPS, which cannot be re-bound alongside the listener.

AgentTunnelOptions.Enabled keeps its meaning; AgentTunnelRegistry already
documents it as "whether this server bound the agent tunnel listener", and the
one state that disappears is a multi-site install pre-restart, where Enabled was
false and a permanently tunnel-less agent showed Online off REST heartbeats.

The bail message moves after Build(), gated on multi-site actually being on, so
it reaches installs with agents rather than every single-site HTTPS install.

* Agent README: rewrite the multi-WAN section around Vantages

The section predated Vantages and still led with a separate agent instance per
WAN carrying a global probeSourceIp, which is now the fallback path. A Vantage
pairs the WAN with the agent that probes it, and an agent on the gateway reaches
every WAN by that WAN's own interface with no routing to build.

Source binding moved with it: the source is set per Vantage and pushed per
target, and ProbeRunner prefers it over agent.json's probeSourceIp, so that key
is documented as the default it now is. "Probe-only mode" went too, since
nothing makes such an agent probe-only any more.

* Agent README: rewrite the multi-WAN section again

The first pass read contrived past the opening. Rewritten from scratch against
the Vantages card's own copy so the README reinforces the UI rather than
competing with it, and with the separate-interface requirement for an
off-gateway agent restored from the section this replaced.

* Agent README: split the routing requirement out, add WAN Steering as the IP-based alternative

* Agent README: cut the multi-WAN section down

* Log the tunnel bind warning through Serilog, not stdout

A Windows service install discards stdout, so the warning could not reach the
non-container installs it is aimed at.

* ResolveHttpBindings: match Kestrel on 0.0.0.0 and reject an empty host

Both paths now run on every install, not just multi-site ones.

Kestrel binds a URL host of 0.0.0.0 as IPv4-only while * and + are dual-stack,
so folding it into * added an IPv6 listener nobody configured. An empty host in
http://:8042 fell through to ListenAnyIP, where URL-based config fails loudly.
#612 moved the all-interfaces branch from 0.0.0.0 to * to get IPv6 and left this
one on 127.0.0.1. Every proxy config we document dials localhost, which resolves
to ::1 first on the NAS, so each connection failed there before falling back.
Kestrel's localhost URL binds 127.0.0.1 and ::1, so the intent is unchanged.
…'s real answers

GL's cellular ubus reports the fuller build string
(QRM650VNA01ACR02A04G8G_OCPU_RGH_01.005.01.005) where AT+CGMR answers with a
short revision that reads like a model number (RG650VNA01ACR02A04G8G). It is
now read in the same SSH session as the AT batch rather than off the cached
endpoint, so it is never a stale version, and AT+CGMR remains the fallback for
firmware without that ubus service.

The CGMR fixtures assumed that command echoed the ubus string; a live GL-E5800
says otherwise, so they are corrected to what the hardware sent. Product parsing
is pinned to the real board model string, which had only a negative test.
The offer used to hide anything already stacked and anything hosting a stack, so
rearranging meant unstacking first. Stacking now detaches the card from wherever
it was, and any cards it was hosting return to the top level - a stack stays one
level deep, which is all the renderer draws.
Tapping either one opened the tooltip and bounced to the Cellular Stats tab,
since the whole card is the link. Both now stop the click.
A step whose one idea lives in two places had to pick one of them or spend a
second step on it. alsoSelectors adds spotlights beside the primary target: they
are best-effort, so a missing companion dims rather than failing the step, and
the card is placed clear of all of them. A step with one target is unchanged -
the union of one rect is that rect.

The v2.7.2 cellular step uses it for the module row and the device badge, whose
copy now says hover or press, since a phone has no hover and the tooltips became
tappable when they stopped bubbling into the card link.
@tvancott42
tvancott42 merged commit d59a19d into main Aug 23, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant