fix(cluster): let the two display options compose, and stop claiming a station was worked

Three defects in the options added in the previous commit, all found on air.

Order. Mute returned early, so with both options on the mute swallowed exactly
the spots the slot option existed to surface: the mute test is entity-level, and
an unworked callsign inside a worked entity passes it. Slot promotion now runs
first, and protects itself for free since bringsNothingNew is false on new-slot.
The two were documented as composing - "mute what is done, light up what is
not" - and they did not.

Empty status. Muting emptied the status, but an empty status already meant
"entity not resolved" in the band map, so every muted spot claimed its entity
was unknown with the country printed two words earlier in the same tooltip. A
muted flag now records WHY it went empty; blanking still drives the colour, the
badges and the ranking.

Wording. The muted tooltip said "already worked" of a station never worked -
LZ8NG on a 421st Bulgarian. What is worked is the ENTITY on this band and mode,
so that is what it says now.

new-mode had no case in the band map's statusLabel and fell through to "entity
not resolved" too. Pre-existing, same one-line switch.
This commit is contained in:
2026-08-10 12:01:31 +02:00
parent a3815c24a1
commit 2cb1add3db
3 changed files with 43 additions and 15 deletions
+11 -3
View File
@@ -38,6 +38,9 @@ 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
@@ -149,13 +152,18 @@ 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): string {
function statusLabel(s: string, t: (k: string) => string, muted = false): string {
switch (s) {
case 'new': return t('bmp.statusNew');
case 'new-band': return t('bmp.statusNewBand');
case 'new-mode': return t('bmp.statusNewMode');
case 'new-slot': return t('bmp.statusNewSlot');
case 'worked': return t('bmp.statusWorked');
default: return t('bmp.statusUnresolved');
// 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');
}
}
@@ -617,7 +625,7 @@ export function BandMap({ band, spots, spotStatus: spotStatusRaw, currentFreqHz,
'hover:translate-x-0.5 hover:shadow',
style.pill,
)}
title={`${p.spot.dx_call}${entry?.country ? ' · ' + entry.country : ''} · ${p.spot.freq_khz.toFixed(1)} kHz · ${statusLabel(st, t)}${markersFor(entry).map((m) => ' · ' + t(BMP_MARKER_LABEL[m.key])).join('')}${p.spot.comment ? ' · ' + p.spot.comment : ''}${p.spot.spotter ? ' · de ' + p.spot.spotter : ''}`}
title={`${p.spot.dx_call}${entry?.country ? ' · ' + entry.country : ''} · ${p.spot.freq_khz.toFixed(1)} kHz · ${statusLabel(st, t, entry?.muted)}${markersFor(entry).map((m) => ' · ' + t(BMP_MARKER_LABEL[m.key])).join('')}${p.spot.comment ? ' · ' + p.spot.comment : ''}${p.spot.spotter ? ' · de ' + p.spot.spotter : ''}`}
>
{/* Left accent strip. With no extra marker it repeats the status
colour, exactly as before; otherwise it splits into one