diff --git a/app.go b/app.go index cdf9af5..c47d578 100644 --- a/app.go +++ b/app.go @@ -2672,6 +2672,23 @@ func (a *App) AddQSO(q qso.QSO) (id int64, err error) { // and the audio was discarded (recordings silently stopped working). The // snapshot is an in-memory copy; the heavy file encode still runs async. a.saveQSORecording(&q) + // Drop the cluster worked-index snapshot BEFORE announcing, so the refresh + // the frontend fires on qso:logged rebuilds it and sees this QSO. + // + // Without this the spot colours never moved after a contact. Logging emitted + // the event, the frontend dutifully re-queried every visible spot two + // seconds later, and ClusterSpotStatuses answered out of a snapshot built + // before the QSO — the same "new band" as before, for ever. Reported on an + // E51 and again on a ZD7 that stayed yellow on the band map with the QSO + // plainly in the log. + // + // Deliberately NOT invalidateAwardStats(): that also drops the award + // matrices, which are expensive to rebuild on a large log, and a contest run + // would pay for it once per QSO. This index is a handful of DISTINCT scans + // and it is what the spot colours actually read. + a.clusterStatusMu.Lock() + a.clusterStatusIdx = nil + a.clusterStatusMu.Unlock() // Announce the log RIGHT AWAY so the grid/UI refresh at once and the entry // form clears immediately — the operator is not made to wait on the DB. wruntime.EventsEmit(a.ctx, "qso:logged", id) diff --git a/changelog.json b/changelog.json index 2ffcd26..09931cf 100644 --- a/changelog.json +++ b/changelog.json @@ -4,11 +4,13 @@ "date": "", "en": [ "DX cluster: an L badge next to a callsign marks a station that uploads to LoTW, with a matching LoTW users only filter, and a Spotter continent filter narrows the list by where the spot came FROM — a JA report on 20 m tells a European little about their own path. The filter panel has been tidied along one rule: a switch is a behaviour you turn on or off, chips pick any number from a set. Nothing appears in both shapes any more, the Lock buttons sit in the heading of the section they lock, every section can be cleared the same way, and the whole panel is finally translated.", - "DX cluster: the Spotter continent filter now actually matches. RBN skimmers report as VU2OY-# and cluster nodes as DL1ABC-2, and the suffix was passed straight to the prefix lookup, so every spot came back with no continent and the filter silently selected nothing." + "DX cluster: the Spotter continent filter now actually matches. RBN skimmers report as VU2OY-# and cluster nodes as DL1ABC-2, and the suffix was passed straight to the prefix lookup, so every spot came back with no continent and the filter silently selected nothing.", + "A spot now stops being NEW the moment you log it. Logging announced the QSO but never dropped the cluster worked-index snapshot, so the refresh that follows re-read the answer computed BEFORE the contact — a station stayed yellow on the band map and in the cluster with the QSO plainly in the log, until something else happened to rebuild the index." ], "fr": [ "Cluster DX : un badge L à côté de l indicatif signale une station qui utilise LoTW, avec le filtre Utilisateurs LoTW seulement qui va avec, et un filtre Continent du spotter restreint selon l origine du spot — un report JA sur 20 m dit peu de chose à un Européen sur son propre chemin. Le panneau de filtres a été remis d aplomb selon une seule règle : un interrupteur est un comportement qu on active ou non, les pastilles choisissent dans un ensemble. Plus rien n existe sous les deux formes, les boutons de verrouillage sont dans le titre de la section qu ils verrouillent, chaque section s efface de la même façon, et le panneau est enfin traduit.", - "Cluster DX : le filtre Continent du spotter fonctionne enfin. Les skimmers RBN s annoncent en VU2OY-# et les nœuds cluster en DL1ABC-2, et ce suffixe partait tel quel dans la recherche de préfixe — tous les spots revenaient sans continent et le filtre ne sélectionnait rien." + "Cluster DX : le filtre Continent du spotter fonctionne enfin. Les skimmers RBN s annoncent en VU2OY-# et les nœuds cluster en DL1ABC-2, et ce suffixe partait tel quel dans la recherche de préfixe — tous les spots revenaient sans continent et le filtre ne sélectionnait rien.", + "Un spot cesse enfin d être NOUVEAU dès que tu l enregistres. La journalisation annonçait le QSO mais ne vidait jamais l instantané de l index des contacts, donc le rafraîchissement qui suit relisait la réponse calculée AVANT le contact — une station restait jaune sur le bandmap et dans le cluster alors que le QSO était bien au log, jusqu à ce qu autre chose reconstruise l index." ] }, { diff --git a/internal/qso/qso.go b/internal/qso/qso.go index 58ded0e..ae53347 100644 --- a/internal/qso/qso.go +++ b/internal/qso/qso.go @@ -3017,8 +3017,10 @@ func IsFilterableExtra(field string) bool { _, ok := filterableExtras[field]; // forever, once per subsquare. func (r *Repo) WorkedGridKeys(ctx context.Context, normMode func(string) string) (map[string]struct{}, error) { rows, err := r.db.QueryContext(ctx, - `SELECT DISTINCT COALESCE(gridsquare,''), COALESCE(mode,'') FROM qso - WHERE gridsquare IS NOT NULL AND gridsquare != ''`) + // The column is "grid", not "gridsquare" — that is the ADIF field name, and + // gridsquare_ext is a different (six-plus character) column entirely. + `SELECT DISTINCT COALESCE(grid,''), COALESCE(mode,'') FROM qso + WHERE grid IS NOT NULL AND grid != ''`) if err != nil { return nil, err }