From d273d21f1aebe821db61b143d3aced17fb1a1660 Mon Sep 17 00:00:00 2001 From: Gregory Salaun Date: Mon, 10 Aug 2026 19:55:02 +0200 Subject: [PATCH] fix(cluster): muting a worked spot must not brighten it "No colour on worked" blanked the spot status as well as the worked-call flag, on the theory that a spot bringing no novelty should stop painting entirely. But the status is exactly what the cluster list reads to DIM a row. Blanking it made isDull() fall through its "unresolved, never dim" guard, so every quiet grey row came back at full brightness. The option meant to calm the list was the one making it shout. It also forced a `muted` flag to exist purely so tooltips could say that an empty status did not, this time, mean "entity not resolved". It now removes the blue already-worked mark and nothing else, which is all it ever needed to do: a worked entity already renders with no colour of its own and is already dimmed. The flag, its two tooltip strings and the special-cased band map styling all go with it. --- changelog.json | 6 ++-- frontend/src/components/BandMap.tsx | 29 +++++----------- frontend/src/lib/i18n.tsx | 4 +-- frontend/src/lib/spotDisplay.ts | 52 +++++++++-------------------- 4 files changed, 31 insertions(+), 60 deletions(-) diff --git a/changelog.json b/changelog.json index b307b62..c0a76aa 100644 --- a/changelog.json +++ b/changelog.json @@ -7,14 +7,16 @@ "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.", "Station information gains an IOTA field (ADIF MY_IOTA, e.g. EU-005), stamped on every QSO like the SOTA and POTA references beside it. The QSO table has carried the field since the first release and both ADIF import and export already handled it — only the station profile could not supply it, so an island activation meant typing the reference on every contact.", - "PowerGenius XL: fixed the amplifier link dropping and reconnecting every few seconds, and the stall while transmitting. The amp pushes status frames on the same socket it answers commands on, and it pushes them constantly once in OPERATE; OpsLog read one line per command and took whatever arrived first as its answer, so the stream slipped permanently one reply behind until a command timed out and the connection was dropped. Replies are now matched to the command that asked for them. Only ever visible over a remote link with the amplifier in OPERATE." + "PowerGenius XL: fixed the amplifier link dropping and reconnecting every few seconds, and the stall while transmitting. The amp pushes status frames on the same socket it answers commands on, and it pushes them constantly once in OPERATE; OpsLog read one line per command and took whatever arrived first as its answer, so the stream slipped permanently one reply behind until a command timed out and the connection was dropped. Replies are now matched to the command that asked for them. Only ever visible over a remote link with the amplifier in OPERATE.", + "No colour on worked stations now does only that: it removes the blue already-worked mark and leaves everything else alone. It used to blank the spot status as well, and the status is what dims a quiet row — so turning the option on made every grey row bright white, which is the opposite of what it is for." ], "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.", "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.", "Les informations station gagnent un champ IOTA (MY_IOTA en ADIF, par exemple EU-005), estampillé sur chaque QSO comme les références SOTA et POTA à côté. La table des QSO portait le champ depuis la première version et l import comme l export ADIF le géraient déjà — seul le profil station ne savait pas le fournir, donc une activation d île obligeait à retaper la référence à chaque contact.", - "PowerGenius XL : corrigé le lien avec l ampli qui tombait et se reconnectait toutes les quelques secondes, et le blocage en émission. L ampli pousse des trames d état sur la socket même où il répond aux commandes, et il en pousse en permanence dès qu il est en OPERATE ; OpsLog lisait une ligne par commande et prenait la première arrivée pour sa réponse, donc le flux glissait définitivement d une réponse de retard jusqu à expiration et fermeture du lien. Les réponses sont désormais appariées à la commande qui les a demandées. Visible uniquement en liaison distante avec l ampli en OPERATE." + "PowerGenius XL : corrigé le lien avec l ampli qui tombait et se reconnectait toutes les quelques secondes, et le blocage en émission. L ampli pousse des trames d état sur la socket même où il répond aux commandes, et il en pousse en permanence dès qu il est en OPERATE ; OpsLog lisait une ligne par commande et prenait la première arrivée pour sa réponse, donc le flux glissait définitivement d une réponse de retard jusqu à expiration et fermeture du lien. Les réponses sont désormais appariées à la commande qui les a demandées. Visible uniquement en liaison distante avec l ampli en OPERATE.", + "Aucune couleur sur les stations déjà contactées ne fait plus que ça : la marque bleue disparaît, le reste ne bouge pas. L option vidait aussi le statut du spot, or c est le statut qui estompe une ligne sans intérêt — l activer rendait donc toutes les lignes grises blanches et éclatantes, soit l inverse du but recherché." ] }, { diff --git a/frontend/src/components/BandMap.tsx b/frontend/src/components/BandMap.tsx index aee89ca..8f9e25c 100644 --- a/frontend/src/components/BandMap.tsx +++ b/frontend/src/components/BandMap.tsx @@ -38,9 +38,6 @@ type SpotStatusEntry = { new_county?: boolean; new_pota?: boolean; new_pfx?: boolean; - // muted: the status was emptied on purpose by the "no colour on worked - // stations" option, so an empty status here is a choice, not an unknown. - muted?: boolean; }; // The extra markers are ORTHOGONAL to the entity status: a spot can be a worked @@ -152,7 +149,7 @@ function LegendDot({ cls, colour, label }: { cls?: string; colour?: string; labe // Human-readable label for a spot status — used in the pill hover tooltip // so the operator can see WHY a spot is coloured the way it is. -function statusLabel(s: string, t: (k: string) => string, muted = false): string { +function statusLabel(s: string, t: (k: string) => string): string { switch (s) { case 'new': return t('bmp.statusNew'); case 'new-band': return t('bmp.statusNewBand'); @@ -160,11 +157,10 @@ function statusLabel(s: string, t: (k: string) => string, muted = false): string case 'new-slot': return t('bmp.statusNewSlot'); case 'new-call': return t('bmp.statusNewCall'); case 'worked': return t('bmp.statusWorked'); - // An empty status means the entity could not be resolved — EXCEPT when the - // "no colour on worked stations" option emptied it on purpose. Saying - // "entity not resolved" there was a flat contradiction of the country - // printed two words earlier in the same tooltip. - default: return muted ? t('bmp.statusMuted') : t('bmp.statusUnresolved'); + // An empty status means the entity could not be resolved. Nothing else + // empties it: the mute option leaves the status alone and takes only the + // already-worked-callsign mark. + default: return t('bmp.statusUnresolved'); } } @@ -177,14 +173,7 @@ const QUIET_STYLE = { dot: 'fill-border', }; -function statusStyle(s: string, muted = false): { pill: string; bar: string; line: string; dot: string } { - // A muted spot must land on QUIET, never on the default branch below. That - // default paints bg-primary/60 — the theme's burnt orange at 60 % over a dark - // card, i.e. brown — because it was written for the rare unresolved entity and - // orange is this app's "look here" colour. With the mute option on, most of - // the map is muted, so the whole band map turned brown and the quietest spots - // shouted the loudest. - if (muted) return QUIET_STYLE; +function statusStyle(s: string): { pill: string; bar: string; line: string; dot: string } { // pill = full pill background+text+border // bar = thick left accent inside the pill // line = SVG leader stroke (visible on hover) @@ -581,7 +570,7 @@ export function BandMap({ band, spots, spotStatus: spotStatusRaw, currentFreqHz, {placed.map((p, i) => { const k = spotStatusKey(p.spot.dx_call, p.spot.band ?? '', p.spot.comment ?? '', p.spot.freq_hz); const st = spotStatus[k]?.status ?? ''; - const style = statusStyle(st, spotStatus[k]?.muted); + const style = statusStyle(st); const labelMidY = p.labelY + PILL_H / 2; const bumped = Math.abs(p.freqY - labelMidY) > 0.5; return ( @@ -629,7 +618,7 @@ export function BandMap({ band, spots, spotStatus: spotStatusRaw, currentFreqHz, const k = spotStatusKey(p.spot.dx_call, p.spot.band ?? '', p.spot.comment ?? '', p.spot.freq_hz); const entry = spotStatus[k]; const st = entry?.status ?? ''; - const style = statusStyle(st, entry?.muted); + const style = statusStyle(st); const mode = inferSpotMode(p.spot.comment ?? '', p.spot.freq_hz); return (