Two-tier bookmark system: general bookmarks shared across all rigs plus
rig-specific bookmarks with scope picker in the Bookmarks tab. Scheduler
storage split into per-rig files with migration from legacy single file.
Decode history tagged with rig_id and filterable via ?remote= on
/decode/history endpoint. Decode SSE reconnects on rig switch to refresh
filtered history.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
When the user changes frequency, applyLocalTunedFrequency sets lastFreqHz
optimistically. But the SSE state stream could push back the old server
frequency before set_freq completes, causing the marker to snap back then
forward. Add a sequence-guarded _freqOptimisticHz that suppresses stale
SSE frequency updates while a set_freq is in flight.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Call drawSignalOverlay() synchronously on frequency and bandwidth changes instead of deferring entirely to requestAnimationFrame. Also make bookmark apply fire-and-forget so the click handler returns immediately after optimistic UI updates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Replace single-connection relay with per-rig audio manager that spawns independent TCP connections for each rig. Each rig gets its own broadcast channel, stream info, and vchan command routing. Selected rig mirrors to global channels for backward compat. Also fix bookmark apply to update spectrum marker instantly and fire all requests in parallel.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Add checkbox column to bookmark table with select-all support and a
Delete Selected button for batch removal. New POST /bookmarks/batch_delete
API endpoint accepts an array of IDs and removes them in one request.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
bmReadDecoders, bmWriteDecoders, and bmApply were all missing FT4,
so the decoder checkbox was never saved and tuning a bookmark never
toggled the FT4 decoder state.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Add client-side command plumbing, HTTP endpoint handling, and frontend interception so bandwidth changes are applied per active virtual channel and survive reconnects.
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
When on a non-primary (virtual) channel, redirect freq and mode changes
to the channel metadata API instead of the server:
- vchan.js: add vchanIsOnVirtual(), vchanSetChannelFreq/Mode(); expose
window.vchanInterceptMode() hook; wrap window.setRigFrequency so all
callers (jog, freq input, bookmarks, spectrum click) are automatically
redirected without modification
- app.js: check vchanInterceptMode() in applyModeFromPicker() before
posting /set_mode
- bookmarks.js: check vchanInterceptMode() for mode in bmApply();
setRigFrequency() redirect is automatic via the vchan.js wrapper;
bandwidth and decoder toggles still apply regardless of channel
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
- Add "Enable HF APRS" toggle button to the HF APRS tab (same style as
FT8/WSPR); button is disabled during TX like other decoder toggles
- app.js: sync button text/colour from SSE state updates
- hf-aprs.js: connect button click to /toggle_hf_aprs_decode
- bookmarks.js: add "HF APRS" checkbox to Add/Edit Bookmark decoder
section; bmReadDecoders/bmWriteDecoders handle "hf-aprs" key; bmApply
toggles the decoder to match bookmark preference on recall
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
- Move bookmark frequency markers from drawSpectrum() to drawSignalOverlay()
so dashed lines span both the waterfall and waveform canvases
- Assign distinct palette colors to named categories; uncategorised uses
--accent-yellow resolved from the live theme at runtime
- Compute WCAG-compliant foreground color (dark/light) per category so label
text is always legible against the solid background
- Add text search input to the Bookmarks toolbar; filters by name, category,
and comment client-side without re-fetching from the server
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
let-declared bmList is not a window property, so window.bmList in
app.js always returned undefined. Change to var so it lands on window;
read it via typeof guard in app.js to stay safe if bookmarks.js is absent.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Draw bookmark frequency markers on the spectrum canvas: amber vertical
line + ribbon shape (rectangle with V-notch) at each bookmark in view.
Below the freq axis, show a #spectrum-bookmark-axis row of clickable
amber ribbon labels (clip-path bookmark shape); clicking tunes the rig.
Labels auto-appear / collapse as bookmarks scroll in and out of view.
Server: reject POST/PUT with 409 Conflict when another bookmark already
exists at the requested freq_hz (BookmarkStore::freq_taken helper).
Client: bmFetch() triggers a spectrum redraw so markers appear
immediately on load without requiring a tab visit first.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Replace the free-text decoder input with FT8/WSPR checkboxes so users
cannot enter arbitrary decoder strings. Hide the "+ Add Bookmark" button
by default and show it only when the authenticated role is `control`
(or auth is disabled), matching the server-side write-endpoint guard.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
Add a "Bookmarks" tab between Main and Plugins in the tab bar.
HTML: tab panel with toolbar (category filter + Add Bookmark button),
an inline add/edit form (hidden by default, prefills freq/mode/BW from
the current rig state), and a sortable table showing all columns with
Tune / Edit / Del action buttons.
CSS: responsive bm-* classes following existing card/button theming,
works in both dark and light modes and all palette variants.
bookmarks.js: fetches bookmarks on tab activation, renders table with
event delegation, handles create/update/delete via REST, and applies a
bookmark by calling set_freq → set_mode → set_bandwidth, plus toggles
FT8/WSPR decoders when the stored mode is DIG.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>