Commit Graph
7 Commits
Author SHA1 Message Date
sjgandClaude Opus 5 ae7df31d91 [fix](trx-frontend-http): replay what arrived before a lazy view loaded
CI / lint (pull_request) Successful in 2m23s
CI / test (pull_request) Successful in 8m36s
CI / frontend (pull_request) Failing after 1m23s
CI / reuse (pull_request) Successful in 5s
Opening the Map or Statistics page showed only what had been decoded since
the moment it was opened, and a reload — landing straight on the tab, so its
module loads at startup ahead of the history — was the only way to see the
rest.  Two things were being thrown away.

The decode log the Statistics page counts lives in the map module, which is
lazy.  Recording into a module that is not loaded yet is a no-op, and unlike
the map markers nothing replayed the log when it finally arrived, so every
decode heard before the first visit was simply never counted.  Hold those
records in the client and hand them over when the module attaches.

The map's own replay covered APRS, AIS and VDES, whose plugins implement
syncMap, but not the grid squares: the FTx family and WSPR plotted locators
as decodes arrived and had no replay at all, so everything they heard before
the map loaded was lost, and the unique-grid counter with it.  Both plot
through a helper now, which their syncMap replays oldest first.  A replayed
WSPR spot carries the frequency it was heard on rather than one worked out
against wherever the dial has moved to since.

Pinned in decode-flow, whose history fixture gains FT8 and WSPR spots: after
a first visit the statistics count every stored decode and every grid square,
which before this change were 0 and 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SyX26FCpMQxiBoC7r5K1A7
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-08-07 08:56:06 +02:00
sjgandClaude Opus 5 bf3bcc8a84 [fix](trx-frontend-http): show one rig at a time on the digital modes page
CI / lint (pull_request) Successful in 2m24s
CI / test (pull_request) Successful in 8m34s
CI / test (push) Successful in 7m47s
CI / frontend (pull_request) Successful in 4m28s
CI / reuse (pull_request) Successful in 5s
CI / lint (push) Successful in 2m21s
CI / frontend (push) Successful in 3m37s
CI / reuse (push) Successful in 6s
A client connected to several rigs decodes all of them at once, and the
decode stream carries every rig's traffic to every browser.  The decoder
panels listed all of it: a station a background rig copied on another band
appeared in the APRS list next to the selected rig's, the vessel counts and
the "latest seen" lines counted both, the status lines said "Receiving"
because some other rig was, and the CW pane interleaved two rigs into one
stream of text that read as neither.

The page is about the rig the operator selected — the one whose spectrum is
on screen and whose audio is playing — so each panel now shows what that rig
heard: rows, counts, latest-seen, status, the live picture a WEFAX or SSTV
frame is painting, and the CW pane.

Nothing is dropped on the way in.  The map is the whole station's view, has
its own rig filter, and would empty out if the plugins stopped feeding it, so
the histories still hold every rig and the map still plots them.  That also
means a switch loses nothing: the runtime gained a rerender hook, which the
rig switch calls, and switching back brings the other rig's traffic up again.
The CW pane is the exception — a running stream of text cannot be unpicked
after the fact — so it starts empty on the rig switched to.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SyX26FCpMQxiBoC7r5K1A7
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-08-07 08:11:13 +02:00
sjgandClaude Opus 5 0d4c657b97 [fix](trx-frontend-http): route feature bundles through the host contract
CI / lint (pull_request) Failing after 2s
CI / test (pull_request) Failing after 1s
CI / frontend (pull_request) Failing after 41s
CI / reuse (pull_request) Failing after 2s
CI / lint (push) Failing after 2s
CI / test (push) Failing after 2s
CI / frontend (push) Failing after 36s
CI / reuse (push) Failing after 1s
The bookmark fix addressed one instance of a defect the TypeScript
migration left across the feature entries.  app.js stopped being a
classic script, so its top-level declarations are no longer shared
globals, but the converted entries kept reading them as window
properties that nothing publishes.

Restore the broken behavior:

- ais, aprs, hf-aprs read serverLat, serverLon and haversineKm as
  undefined, so every positioned packet rendered an empty distance.
- ais, aprs, hf-aprs, cw, sat, vdes, wefax, wspr called an undefined
  postPath, so clear-history and decoder toggles threw.
- scheduler read authRole as undefined, so the lazy-load path never
  self-initialized and the Settings tab opened an inert scheduler.
- background-decode read authEnabled as undefined, so control gating
  fell back to role-only.
- vchan read fifteen application values and services as undefined:
  mode and bandwidth sync, the out-of-band hint, RX audio restart, and
  the frequency field all silently no-opped on a virtual channel.
- vchan wrapped window.refreshFreqDisplay, capturing an undefined
  original exactly as it did for setRigFrequency, so leaving a channel
  never restored the application's own frequency display.
- _audioChannelOverride was a const that nothing could assign, so RX
  audio always subscribed to the primary channel.
- ftx-family read fmtTime, a helper legacy ft8.js owned locally, so
  decode bar timestamps rendered empty.

Declare the contract once in plugins/host.ts and import it from the
feature entries, rather than restoring globals that
docs/frontend-architecture.md excludes.  trx.state gains jogUnit,
rxActive and audioChannelOverride, and makes lastModeName writable;
trx.core gains the tuning, RDS, WFM, jog and RX audio services the
entries need.  vchan interception moves to an interceptFreqDisplay
service method that refreshFreqDisplay calls, matching the frequency,
mode and bandwidth interception it already registers.

Reading registry-built elements through a strict lookup is the same
defect as in bookmarks: renderTimelineNeedle guards its result, but
schedulerEl throws, so the now-initializing scheduler crashed on the
timeline needle group that its own SVG creates.

Feature tests move onto a shared host fixture, and entries that now
import a common module are bundled through bundleEntry like the other
shared-module entries.  Covers scheduler self-initialization and the
distance path that the bare window reads broke.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdyUjuXejCEfiub675z6cz
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-08-02 11:20:17 +02:00
sjg 26be675242 build: enable frontend module code splitting 2026-08-01 14:40:59 +02:00
sjg 9fef0ebc7b refactor: route all decoders through plugin runtime 2026-08-01 13:06:38 +02:00
sjg d96624be4f refactor: convert WSPR plugin to TypeScript 2026-08-01 12:15:19 +02:00
sjg 888f793eb8 build: add frontend TypeScript toolchain 2026-08-01 11:52:47 +02:00