From a2958d458ee969c5f1b6ebd7c69c8b7c60c42ac8 Mon Sep 17 00:00:00 2001 From: rouggy Date: Tue, 21 Jul 2026 11:32:16 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20'stations=20on=20air'=20widget=20updates?= =?UTF-8?q?=20instantly=20after=20a=20QSO=20(UDP/FT8=20path=20now=20emits?= =?UTF-8?q?=20qso:logged;=20publishLiveStatus=20emits=20livestatus:updated?= =?UTF-8?q?=20so=20the=20widget=20re-reads=20exactly=20when=20the=20shared?= =?UTF-8?q?=20row=20changes)=20=E2=80=94=20was=20lagging=20~15-45s=20behin?= =?UTF-8?q?d=20the=20ON-AIR=20badge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.go | 7 +++++++ frontend/src/App.tsx | 8 ++++++-- livestatus.go | 14 ++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/app.go b/app.go index d3e0c93..54c727b 100644 --- a/app.go +++ b/app.go @@ -9636,6 +9636,13 @@ func (a *App) LogUDPLoggedADIF(adifText string) (int64, error) { q.ID = id a.noteLiveQSO() // multi-op: flip this operator back "online" a.materializeAwardRefs(q) + // Announce the log so UI widgets refresh AT ONCE (the Recent-QSOs grid, the + // ON-AIR badge and the "stations on air" widget). The manual log path always + // did this; the UDP/FT8 path did not, so a station running MSHV saw the top + // "on air" list lag ~15-45s behind the instant bottom badge. + if a.ctx != nil { + wruntime.EventsEmit(a.ctx, "qso:logged", id) + } a.saveQSORecording(&q) if a.extsvc != nil { a.extsvc.OnQSOLogged(id) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 5f1dd2d..cf3521c 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -452,9 +452,13 @@ export default function App() { const load = () => GetLiveStations().then((s) => setLiveStations((s ?? []) as LiveStation[])).catch(() => {}); load(); const id = window.setInterval(load, 5 * 1000); - // Small delay lets the async publishLiveStatus MySQL write land before we read. + // Refresh the instant the backend actually publishes a row change (a QSO put + // someone on air, or a 5-min silence took them off) — so this widget tracks the + // bottom ON-AIR badge instead of lagging behind its poll. Keep the qso:logged + // fallback too (a small delay lets the async publish land) for older paths. + const offStatus = EventsOn('livestatus:updated', load); const offLogged = EventsOn('qso:logged', () => { window.setTimeout(load, 1500); }); - return () => { window.clearInterval(id); offLogged?.(); }; + return () => { window.clearInterval(id); offStatus?.(); offLogged?.(); }; }, [liveStationsOn]); // Mode OpsLog shows when the rig reports generic DIG_U/DIG_L. OmniRig // can't tell us if it's FT8 vs FT4 vs RTTY, so the user picks the default diff --git a/livestatus.go b/livestatus.go index 292f81e..6024361 100644 --- a/livestatus.go +++ b/livestatus.go @@ -6,9 +6,21 @@ import ( "strings" "time" + wruntime "github.com/wailsapp/wails/v2/pkg/runtime" + "hamlog/internal/applog" ) +// emitLiveStatusChanged nudges the frontend to re-read GetLiveStations right when +// the shared table actually changes (a row appeared or was removed) — so the +// "stations on air" widget updates the instant a QSO is published, matching the +// bottom ON-AIR badge instead of waiting for its poll. +func (a *App) emitLiveStatusChanged() { + if a.ctx != nil { + wruntime.EventsEmit(a.ctx, "livestatus:updated", nil) + } +} + // Live operator status — for multi-operator events on a SHARED MySQL logbook // (e.g. a special-event call like TM74FR with several ops on different bands). // Each OpsLog instance heartbeats its current activity (operator call + station @@ -231,6 +243,7 @@ func (a *App) publishLiveStatus() { if _, err := a.logDb.ExecContext(a.ctx, "DELETE FROM live_status WHERE operator=?", op); err != nil { applog.Printf("livestatus: offline DELETE failed: %v", err) } + a.emitLiveStatusChanged() return } lastQSOArg := lastQSO.UTC() @@ -246,6 +259,7 @@ func (a *App) publishLiveStatus() { return } applog.Printf("livestatus: published op=%s station=%s %dHz %s %s ON AIR", op, station, freqHz, band, mode) + a.emitLiveStatusChanged() } // LiveStation is one operator's live status for the multi-op "who's on air" widget.