diff --git a/app_dxped.go b/app_dxped.go index a975859..325fb8c 100644 --- a/app_dxped.go +++ b/app_dxped.go @@ -119,22 +119,16 @@ func (a *App) judgeDXpeditions(list []DXpedition) { } } -// DXNews is one DX-World post plus what its callsigns are worth here. -type DXNews struct { - dxped.News - // Status is ENTITY-LEVEL only, and deliberately so: a headline announces no - // bands or modes, and asking the slot question without them would answer - // "new band" for every entity ever worked — the one mistake that costs a - // QSO. So it says "new" (entity never worked) or "worked", nothing finer; - // the announcements pane, which HAS the bands and modes, is where the - // sharper verdicts belong. - Status string `json:"status_chase"` - Unconfirmed bool `json:"unconfirmed"` -} - // GetDXWorldNews returns the DX-World headlines, with the callsigns mined out -// of each one and judged against the log. -func (a *App) GetDXWorldNews() ([]DXNews, error) { +// of each one so the reader can watch them. +// +// Deliberately NOT judged against the log. A headline names no band, so the +// only verdict available is entity-level, and a pane of "NEW DXCC" and +// "worked" badges turned out to say nothing an operator could act on — the +// same two words on every row is noise wearing the clothes of information. +// The announcements pane, which knows the bands and modes, is where a chase +// verdict is worth drawing. +func (a *App) GetDXWorldNews() ([]dxped.News, error) { if a.dxped == nil { a.dxped = dxped.New() } @@ -145,53 +139,7 @@ func (a *App) GetDXWorldNews() ([]DXNews, error) { return nil, err } } - out := make([]DXNews, 0, len(news)) - for _, n := range news { - out = append(out, DXNews{News: n}) - } - a.judgeNews(out) - return out, nil -} - -// judgeNews fills the entity-level verdict for each headline. -// -// One query per callsign with NO band and NO mode: the only verdict that -// means anything in that state is "this entity has never been worked". Every -// finer answer the spot judge can give without a band is an artefact of the -// missing band, so it is flattened to "worked" rather than repeated. -func (a *App) judgeNews(list []DXNews) { - if a.qso == nil || len(list) == 0 { - return - } - var queries []SpotQuery - var owners []int - for i, n := range list { - for _, call := range n.Calls { - queries = append(queries, SpotQuery{Call: call}) - owners = append(owners, i) - } - } - if len(queries) == 0 { - return - } - res := a.ClusterSpotStatuses(queries) - for i, r := range res { - if i >= len(owners) { - break - } - row := owners[i] - st := "" - switch { - case r.Status == "new": - st = "new" - case r.Status != "": - st = "worked" - } - if chaseRank[st] > chaseRank[list[row].Status] { - list[row].Status = st - list[row].Unconfirmed = r.UnconfStatus - } - } + return news, nil } // RefreshDXpeditions drops both caches so the next read goes to the network. diff --git a/changelog.json b/changelog.json index efedb3f..1ad2307 100644 --- a/changelog.json +++ b/changelog.json @@ -14,8 +14,7 @@ "QSO editor, QSL Info: a HamQTH channel and its row in the status table — sent only, the received column showing a dash since the site publishes no confirmations.", "QSO editor, QSL Info: the confirmation channels are listed paper QSL and LoTW first — the two that carry an ARRL award — then alphabetically, in both the picker and the status table.", "Band map: a chevron in the footer folds the colour legend away and brings it back — four lines of a short screen, remembered between sessions.", - "Band map: ctrl+wheel no longer zooms it — that gesture is the window zoom everywhere else in OpsLog. The + and − buttons keep the zoom.", - "DXpeditions: the news headlines carry a chase badge too — NEW DXCC or worked. Entity-level only, since a headline names no band: the finer verdicts stay in the announcements pane, which knows the bands and modes." + "Band map: ctrl+wheel no longer zooms it — that gesture is the window zoom everywhere else in OpsLog. The + and − buttons keep the zoom." ], "fr": [ "Changer de base de réglages n’affiche plus « OpsLog is already running » : la relance automatique attend désormais que l’instance qui se ferme libère son verrou au lieu de la prendre de vitesse.", @@ -29,8 +28,7 @@ "Éditeur de QSO, onglet QSL : un canal HamQTH et sa ligne dans le tableau des statuts — envoi seulement, la colonne reçu affichant un tiret puisque le site ne publie aucune confirmation.", "Éditeur de QSO, onglet QSL : les canaux de confirmation sont classés QSL papier puis LoTW — les deux qui comptent pour un diplôme ARRL — puis par ordre alphabétique, dans le sélecteur comme dans le tableau.", "Band map : un chevron dans le pied de page replie la légende des couleurs et la fait revenir — quatre lignes gagnées sur un petit écran, mémorisé d’une session à l’autre.", - "Band map : ctrl+molette ne zoome plus la carte — ce geste est le zoom de la fenêtre partout ailleurs dans OpsLog. Les boutons + et − gardent le zoom.", - "DXpéditions : les actualités portent aussi un badge de chasse — NOUVEAU DXCC ou contacté. Au niveau entité seulement, une manchette ne nommant aucune bande : les verdicts plus fins restent dans le volet des annonces, qui connaît bandes et modes." + "Band map : ctrl+molette ne zoome plus la carte — ce geste est le zoom de la fenêtre partout ailleurs dans OpsLog. Les boutons + et − gardent le zoom." ] }, { diff --git a/frontend/src/components/DXpeditionsPanel.tsx b/frontend/src/components/DXpeditionsPanel.tsx index e86bca0..e461bd8 100644 --- a/frontend/src/components/DXpeditionsPanel.tsx +++ b/frontend/src/components/DXpeditionsPanel.tsx @@ -26,10 +26,6 @@ type DXped = { type News = { title: string; link: string; pub_date: string; excerpt: string; creator: string; image_url: string; tag: string; calls?: string[]; - // Entity-level only — a headline names no band, so the backend answers - // 'new' or 'worked' and nothing finer. - status_chase?: string; - unconfirmed?: boolean; }; // One badge per expedition, the strongest verdict winning — the same palette @@ -184,7 +180,6 @@ export function DXpeditionsPanel() { )} {news.map((n, i) => { const newsCalls = n.calls ?? []; - const newsBadge = CHASE_BADGE[n.status_chase ?? '']; const newsAllWatched = newsCalls.length > 0 && newsCalls.every((c) => watched.has(c.toUpperCase())); return (
@@ -198,15 +193,6 @@ export function DXpeditionsPanel() { {n.tag && ( {n.tag} )} - {newsBadge && ( - - {t(newsBadge.label)} - - )} diff --git a/frontend/wailsjs/go/main/App.d.ts b/frontend/wailsjs/go/main/App.d.ts index 3743b9f..e6513a2 100644 --- a/frontend/wailsjs/go/main/App.d.ts +++ b/frontend/wailsjs/go/main/App.d.ts @@ -12,6 +12,7 @@ import {award} from '../models'; import {awardref} from '../models'; import {bandopen} from '../models'; import {cluster} from '../models'; +import {dxped} from '../models'; import {extsvc} from '../models'; import {powergenius} from '../models'; import {pskr} from '../models'; @@ -476,7 +477,7 @@ export function GetDVKMessages():Promise>; export function GetDVKStatus():Promise; -export function GetDXWorldNews():Promise>; +export function GetDXWorldNews():Promise>; export function GetDXpeditions():Promise>; diff --git a/frontend/wailsjs/go/models.ts b/frontend/wailsjs/go/models.ts index 764eaed..d5023ae 100644 --- a/frontend/wailsjs/go/models.ts +++ b/frontend/wailsjs/go/models.ts @@ -1466,6 +1466,37 @@ export namespace contest { } +export namespace dxped { + + export class News { + title: string; + link: string; + pub_date: string; + excerpt: string; + creator: string; + image_url: string; + tag: string; + calls: string[]; + + static createFrom(source: any = {}) { + return new News(source); + } + + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.title = source["title"]; + this.link = source["link"]; + this.pub_date = source["pub_date"]; + this.excerpt = source["excerpt"]; + this.creator = source["creator"]; + this.image_url = source["image_url"]; + this.tag = source["tag"]; + this.calls = source["calls"]; + } + } + +} + export namespace extsvc { export class ServiceConfig { @@ -2674,36 +2705,6 @@ export namespace main { this.rec_slot = source["rec_slot"]; } } - export class DXNews { - title: string; - link: string; - pub_date: string; - excerpt: string; - creator: string; - image_url: string; - tag: string; - calls: string[]; - status_chase: string; - unconfirmed: boolean; - - static createFrom(source: any = {}) { - return new DXNews(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.title = source["title"]; - this.link = source["link"]; - this.pub_date = source["pub_date"]; - this.excerpt = source["excerpt"]; - this.creator = source["creator"]; - this.image_url = source["image_url"]; - this.tag = source["tag"]; - this.calls = source["calls"]; - this.status_chase = source["status_chase"]; - this.unconfirmed = source["unconfirmed"]; - } - } export class DXpedition { dxcc: string; callsign: string;