feat(cluster): show the grid, and flag a new one
Finishes the half of this that was already computing on the backend and reaching nobody. A Grid column in the Geo group, NEW GRID as a badge in Status, a filled cell in the marker's own colour, and a filter chip. new_grid joins lib/spotMarkers rather than getting colours of its own, so the badge, the cell fill and the chip cannot drift apart - and the per-marker colour setting will drive it with the rest from one table. Magenta: the last hue in the categorical set not already spoken for, and one that does not read as a status, because a new square is never urgent the way a new entity is. The band map leaves it to the cluster, as it already leaves the prefix. The pill is 22 px tall and its accent strip stops being readable past three segments. A row carrying a new grid is no longer "dull", or the dimming would grey out the one thing worth looking at. The column is off by default, like the other Geo columns: it is only ever filled for stations this receiver decoded over the UDP link, so for an operator who does not run digital it would be a permanently empty column.
This commit is contained in:
+4
-2
@@ -8,7 +8,8 @@
|
||||
"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.",
|
||||
"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."
|
||||
"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.",
|
||||
"Grid squares in the cluster. Every CQ decoded over the WSJT-X UDP link carries the sender grid, and OpsLog now keeps it: a Grid column shows the square and NEW GRID flags one never worked, as a badge, a filled cell and a filter of its own. Whether a grid counts as new follows the group digital modes setting — with it on, a square worked on FT8 is no longer new on FT4; with it off the two are separate. Only stations your own receiver decodes have a grid: a cluster line carries the spotter grid at best, never the DX one. Turn the column on in Columns."
|
||||
],
|
||||
"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.",
|
||||
@@ -16,7 +17,8 @@
|
||||
"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.",
|
||||
"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é."
|
||||
"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é.",
|
||||
"Les carrés locator dans le cluster. Chaque CQ décodé sur le lien UDP WSJT-X porte le grid de l émetteur, et OpsLog le conserve désormais : une colonne Grid affiche le carré et NOUV GRID signale celui jamais contacté, en badge, en cellule remplie et avec son propre filtre. Ce qui compte comme nouveau suit le réglage de regroupement des modes digitaux — activé, un carré fait en FT8 n est plus neuf en FT4 ; désactivé, les deux sont distincts. Seules les stations décodées par ton propre récepteur ont un grid : une ligne de cluster porte le grid du spotter au mieux, jamais celui du DX. Colonne à activer dans Colonnes."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1487,7 +1487,7 @@ export default function App() {
|
||||
// is an OR across all of them, as it already was for a worked callsign.
|
||||
// 'new-call' is a DISPLAY status, produced by the slot-highlight option rather
|
||||
// than by the backend, so it is named here and not in SpotStatusKey.
|
||||
type SpotFilterKey = SpotStatusKey | 'new-pota' | 'new-county' | 'new-pfx' | 'new-call';
|
||||
type SpotFilterKey = SpotStatusKey | 'new-pota' | 'new-county' | 'new-pfx' | 'new-call' | 'new-grid';
|
||||
// Display options, shared with the band map through lib/spotDisplay. Kept in
|
||||
// localStorage (mirrored to settings by writeUiPref) so both panels and the
|
||||
// filter predicate read one source without prop-drilling through three levels.
|
||||
@@ -4713,7 +4713,8 @@ export default function App() {
|
||||
|| (!!e?.worked_call && clusterStatusFilter.has('worked'))
|
||||
|| (!!e?.new_pota && clusterStatusFilter.has('new-pota'))
|
||||
|| (!!e?.new_county && clusterStatusFilter.has('new-county'))
|
||||
|| (!!e?.new_pfx && clusterStatusFilter.has('new-pfx'));
|
||||
|| (!!e?.new_pfx && clusterStatusFilter.has('new-pfx'))
|
||||
|| (!!e?.new_grid && clusterStatusFilter.has('new-grid'));
|
||||
if (!matches) return false;
|
||||
}
|
||||
// LoTW only, and the spotter's continent. Both are properties of the
|
||||
@@ -4893,6 +4894,8 @@ export default function App() {
|
||||
{ k: 'new-pota' as SpotFilterKey, label: 'NEW POTA', cls: 'bg-success-muted text-success-muted-foreground border-success-border' },
|
||||
{ k: 'new-county' as SpotFilterKey, label: 'NEW COUNTY', cls: 'bg-success-muted text-success-muted-foreground border-success-border' },
|
||||
{ k: 'new-pfx' as SpotFilterKey, label: 'NEW PFX', cls: 'bg-caution-muted text-caution-muted-foreground border-caution-border' },
|
||||
// Only ever set for a station this receiver decoded over the UDP link.
|
||||
{ k: 'new-grid' as SpotFilterKey, label: 'NEW GRID', cls: 'bg-muted text-foreground border-border' },
|
||||
// Blue, like the already-worked call in the grid. Selecting it keeps
|
||||
// worked spots; the separate "Hide worked" checkbox drops them — they
|
||||
// are opposite controls, so don't use both at once.
|
||||
|
||||
@@ -48,12 +48,13 @@ type SpotStatusEntry = {
|
||||
//
|
||||
// Their colours come from lib/spotMarkers, shared with the cluster list: the
|
||||
// same fact must not be violet in one panel and green in the next.
|
||||
// The map shows three of the four. A new PREFIX is left to the cluster list: the
|
||||
// The map shows three of the five. A new PREFIX and a new GRID are left to the
|
||||
// cluster list, which has the width to name them: the
|
||||
// pill is 22 px tall, and a fourth segment turns the strip into a colour code
|
||||
// nobody can read at a glance. Add it here the day the strip earns more room.
|
||||
const BMP_MARKERS = SPOT_MARKERS.filter((m) => m.key !== 'new_pfx');
|
||||
const BMP_MARKERS = SPOT_MARKERS.filter((m) => m.key !== 'new_pfx' && m.key !== 'new_grid');
|
||||
const markersFor = (e: SpotStatusEntry | undefined) =>
|
||||
activeMarkers(e).filter((m) => m.key !== 'new_pfx');
|
||||
activeMarkers(e).filter((m) => m.key !== 'new_pfx' && m.key !== 'new_grid');
|
||||
|
||||
// The legend spells the markers out; the cluster list's badges are abbreviated
|
||||
// ("NEW CTY") because they sit in a narrow cell, and there is room here.
|
||||
|
||||
@@ -193,7 +193,7 @@ function statusColor(s: SpotStatusEntry | undefined): string | null {
|
||||
function isDull(s: SpotStatusEntry | undefined): boolean {
|
||||
if (!s || !s.status) return false;
|
||||
if (s.status === 'new' || s.status === 'new-band' || s.status === 'new-mode' || s.status === 'new-slot' || s.status === 'new-call') return false;
|
||||
return !(s.worked_call || s.new_pota || s.new_county || s.new_pfx);
|
||||
return !(s.worked_call || s.new_pota || s.new_county || s.new_pfx || s.new_grid);
|
||||
}
|
||||
|
||||
const makeColCatalog = (t: TFn): ColEntry[] => [
|
||||
@@ -266,6 +266,7 @@ const makeColCatalog = (t: TFn): ColEntry[] => [
|
||||
if (s?.new_county) parts.push(t('clg2.newCounty'));
|
||||
if (s?.new_pota) parts.push(t('clg2.newPota'));
|
||||
if (s?.new_pfx) parts.push(t('clg2.newPfx'));
|
||||
if (s?.new_grid) parts.push(t('clg2.newGrid'));
|
||||
return parts.join(' ');
|
||||
},
|
||||
cellRenderer: (p: any) => {
|
||||
@@ -286,6 +287,7 @@ const makeColCatalog = (t: TFn): ColEntry[] => [
|
||||
if (s?.new_county) parts.push({ text: t('clg2.newCounty'), color: markerColour('new_county') });
|
||||
if (s?.new_pota) parts.push({ text: t('clg2.newPota'), color: markerColour('new_pota') });
|
||||
if (s?.new_pfx) parts.push({ text: t('clg2.newPfx'), color: markerColour('new_pfx') });
|
||||
if (s?.new_grid) parts.push({ text: t('clg2.newGrid'), color: markerColour('new_grid') });
|
||||
if (parts.length === 0) return <span style={{ color: 'var(--muted-foreground)', fontSize: 10 }}>—</span>;
|
||||
return (
|
||||
<span style={{ whiteSpace: 'nowrap' }}>
|
||||
@@ -362,6 +364,18 @@ const makeColCatalog = (t: TFn): ColEntry[] => [
|
||||
: { color: 'var(--muted-foreground)' }) as any,
|
||||
tooltipValueGetter: (p: any) => (statusFor(p)?.new_pfx ? t('clg2.tipNewPfx') : undefined),
|
||||
},
|
||||
{
|
||||
group: 'Geo', label: t('clg2.c.grid'), colId: 'grid',
|
||||
headerName: t('clg2.c.grid'), width: 70, cellClass: 'font-mono',
|
||||
// Not on the spot: the square a station announced in a CQ that THIS receiver
|
||||
// decoded over the WSJT-X link, so it is filled for the digital watering
|
||||
// hole being monitored and empty everywhere else. A cluster line carries the
|
||||
// spotter's grid at best, never the DX's.
|
||||
valueGetter: (p: any) => statusFor(p)?.grid ?? '',
|
||||
cellStyle: (p: any) => (statusFor(p)?.new_grid ? fillStyle(markerColour('new_grid')) : null) as any,
|
||||
cellRenderer: (p: any) => cellText(p.value, null),
|
||||
tooltipValueGetter: (p: any) => (statusFor(p)?.new_grid ? t('clg2.tipNewGrid') : undefined),
|
||||
},
|
||||
{
|
||||
group: 'Geo', label: t('clg2.c.county'), colId: 'county',
|
||||
headerName: t('clg2.c.county'), width: 130, cellClass: 'font-mono',
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -31,6 +31,7 @@ type Entry = {
|
||||
new_county?: boolean;
|
||||
new_pota?: boolean;
|
||||
new_pfx?: boolean;
|
||||
new_grid?: boolean;
|
||||
} | undefined;
|
||||
|
||||
// applySpotDisplay rewrites a status entry per the options, so every consumer —
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
// statuses, blue is "callsign worked", green is POTA
|
||||
// worked blue — matches the WKD-CALL badge the cluster list has always used
|
||||
// prefix yellow — unchanged
|
||||
export type SpotMarkerKey = 'new_pota' | 'new_county' | 'new_pfx' | 'worked_call';
|
||||
// grid magenta — the last hue in the categorical set that is not already
|
||||
// spoken for here and does not read as a status; a grid is
|
||||
// never urgent the way a new entity is
|
||||
export type SpotMarkerKey = 'new_pota' | 'new_county' | 'new_pfx' | 'worked_call' | 'new_grid';
|
||||
|
||||
export type SpotMarker = {
|
||||
key: SpotMarkerKey;
|
||||
@@ -28,6 +31,7 @@ export const SPOT_MARKERS: SpotMarker[] = [
|
||||
{ key: 'new_pota', colour: 'var(--success)', labelKey: 'clg2.newPota' },
|
||||
{ key: 'new_county', colour: 'var(--chart-5)', labelKey: 'clg2.newCounty' },
|
||||
{ key: 'new_pfx', colour: 'var(--caution)', labelKey: 'clg2.newPfx' },
|
||||
{ key: 'new_grid', colour: 'var(--chart-7)', labelKey: 'clg2.newGrid' },
|
||||
{ key: 'worked_call', colour: 'var(--info)', labelKey: 'clg2.wkdCall' },
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user