From cdd91ab7e6d75f0d231e02c19d5fd58efff0ff35 Mon Sep 17 00:00:00 2001 From: rouggy Date: Tue, 8 Sep 2026 00:10:06 +0200 Subject: [PATCH] fix(ui): one section name, a chosen digital row, no MQTT chip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three things reported together. Preferences said the section name twice: a small line above every panel repeated the heading right underneath it — "GENERAL" over "General" — while the sidebar next to them already shows which section is open, highlighted. Two lines and a highlight for one fact; the small line goes. The band matrix opens on the digital row the operator chooses. Its digital row has always rotated — DIGI, then each digital mode in their own list — but it always STARTED on DIGI, so somebody who only works FT8 clicked through to their own mode on every callsign. Settings ▸ General now says where the rotation starts, and the dropdown offers exactly the modes the matrix rotates through (the phone-mode rule is now shared rather than copied, so the two cannot drift). DIGI stays the default: it is the right answer for anyone working several digital modes. And the MQTT chip is gone from the status bar. That is the name of a message protocol, not of anything an operator has — a chip in the status bar has to say what it is about, and this one told nobody anything. What it carried is shown in the Chase New panel, which is the place that uses it; its poller went with it. --- changelog.json | 10 ++++-- frontend/src/App.tsx | 38 +++++------------------ frontend/src/components/BandSlotGrid.tsx | 16 +++++++++- frontend/src/components/SettingsModal.tsx | 38 ++++++++++++++++++++--- frontend/src/lib/i18n.tsx | 4 +-- frontend/src/lib/uiPref.ts | 1 + 6 files changed, 67 insertions(+), 40 deletions(-) diff --git a/changelog.json b/changelog.json index ea77de3..99de2b2 100644 --- a/changelog.json +++ b/changelog.json @@ -10,7 +10,10 @@ "The cluster editor offers a list of known nodes. Setting up a telnet cluster is the step operators get stuck on: the address and the port are two pieces of information nobody has to hand, and a typo in either looks exactly like a node that is down. Pick one and the fields fill in — F4BPO, DXFun, F5LEN, F5MZN, KM3T, SOTA, POTA, and the two Reverse Beacon feeds, which are one network on two ports where 7000 carries CW and RTTY and 7001 carries FT8 and FT4. Everything stays editable, and a node typed in by hand works exactly the same. More will be added.", "Preferences no longer lag behind the keyboard. Two causes. Typing a cluster macro re-rendered the whole dialog on every keystroke and wrote a row into the database per character — the twenty-four boxes now stand on their own and the database write waits for the typing to stop. And every dialog sat on a blurred backdrop: a filter over the whole window, recomputed under every repaint, with an application behind it that never stops moving — CAT polling, spots arriving, meters sweeping. The dialogs you type in for minutes at a time now dim the background instead of blurring it.", "Station Control shows what commands the station, not only what it switches. The radio is there now — frequency, mode, band, and the split pair when there is one — with the CW keyer beside it (speed up and down, and Stop, because a message going to the wrong callsign has to end now) and the voice keyer with its recorded messages as buttons, so a CQ goes out without leaving the tab. The two keyers appear only when there is something behind them: a port configured, or a message actually recorded. All three move and reorder with the other cards.", - "One padlock on the entry form instead of five. Logging a contact from paper — a contest sheet, a friend's report, a QSO worked on another radio — means the frequency, the band, the mode, the date and both times all have to stop following the rig and the clock at once. That was five clicks in five different places, each of which had to be found first. The padlock beside Start UTC now holds all of them, and releases all of them." + "One padlock on the entry form instead of five. Logging a contact from paper — a contest sheet, a friend's report, a QSO worked on another radio — means the frequency, the band, the mode, the date and both times all have to stop following the rig and the clock at once. That was five clicks in five different places, each of which had to be found first. The padlock beside Start UTC now holds all of them, and releases all of them.", + "Preferences no longer says the section name twice — the small line above each panel repeated the heading right under it, and the sidebar beside it already shows which section is open.", + "The band matrix can open on the digital mode you actually work. An operator who only ever does FT8 was shown DIGI every time and had to click through to their own mode on every callsign; Settings → General now chooses which digital row the matrix starts on. The row still rotates when you click it, and DIGI — all of them together — stays the default.", + "The MQTT chip is gone from the status bar. That is the name of a message protocol, not of anything an operator has. The state it carried — the openings feed up or down, and how many reports have arrived — is in the Chase New panel, which is the place that uses it." ], "fr": [ "[NOUVEAU] Satellites. Un nouvel onglet (Outils → Satellites) permet de travailler les satellites amateurs de bout en bout. Une carte avec l'empreinte de chacun et la trace au sol du satellite sélectionné ; une vue du ciel comme la dessine n'importe quel tracker, centre à la verticale et bord à l'horizon, avec le passage entier et la position du satellite dessus ; un compte à rebours jusqu'à l'AOS — ou jusqu'au LOS une fois levé — avec lever, culmination et coucher, leurs directions à la boussole, distance, altitude et empreinte ; et un tableau des passages de tout ce que vous suivez.\n\n« Suivre » met la radio sur le satellite et l'y maintient, chaque seconde : un IC-9700 ou IC-9100 dans son propre mode satellite, un FlexRadio sur deux slices (A la descente, B la montée, créées si elles manquent, full duplex activé) — et n'importe quel autre poste sur la descente seule, ce qu'il annonce clairement plutôt que de faire le travail à moitié. Accordez le récepteur où vous voulez : le suivi lit le VFO, y voit la station que vous avez choisie, et déplace l'émetteur en conséquence. Un rotor az/él suit aussi, piloté directement en EasyComm II ou confié à PstRotator si vous le faites déjà tourner ; un rotor 450° est utilisé comme tel, et un passage qui traverse le nord continue au lieu de se dérouler.\n\nLes QSO faits pendant le suivi sont enregistrés avec les fréquences NOMINALES, SAT_NAME, SAT_MODE et PROP_MODE=SAT — les chiffres du transpondeur, sur lesquels les deux stations peuvent s'accorder, plutôt que l'endroit où une radio se trouvait.\n\nLes éléments orbitaux viennent de Celestrak, avec un miroir derrière, et sont conservés sur disque : l'onglet est rempli dès son ouverture, même sans internet. Les éléments d'un satellite qu'aucun flux ne diffuse encore peuvent être collés à la main et survivent à chaque mise à jour. Vingt-cinq satellites sont livrés avec un plan de fréquences — les FM et les linéaires, GreenCube, QO-100 bande étroite et large — dans un fichier que vous pouvez corriger vous-même quand un transpondeur change de mode. Toute la configuration est dans Réglages → Satellites, y compris le choix des satellites suivis, sélectionnés comme on choisit ses diplômes.", @@ -20,7 +23,10 @@ "L'éditeur de cluster propose une liste de nœuds connus. La configuration d'un cluster telnet est l'étape où l'on se bloque : l'adresse et le port sont deux informations que personne n'a sous la main, et une faute de frappe dans l'une ou l'autre ressemble exactement à un nœud en panne. On en choisit un et les champs se remplissent — F4BPO, DXFun, F5LEN, F5MZN, KM3T, SOTA, POTA, et les deux flux Reverse Beacon, qui sont un même réseau sur deux ports où 7000 porte la CW et le RTTY et 7001 le FT8 et le FT4. Tout reste modifiable, et un nœud saisi à la main fonctionne exactement pareil. D'autres seront ajoutés.", "Les Préférences ne traînent plus derrière le clavier. Deux causes. Saisir une macro de cluster redessinait tout le dialogue à chaque frappe et écrivait une ligne en base par caractère — les vingt-quatre champs sont désormais indépendants et l'écriture en base attend la fin de la saisie. Et chaque dialogue reposait sur un fond flouté : un filtre sur toute la fenêtre, recalculé sous chaque repaint, avec derrière lui une application qui ne s'arrête jamais de bouger — le CAT qui interroge, les spots qui arrivent, les vumètres qui balaient. Les dialogues dans lesquels on tape plusieurs minutes assombrissent désormais le fond au lieu de le flouter.", "Contrôle station montre ce qui commande la station, et plus seulement ce qui la commute. La radio y figure désormais — fréquence, mode, bande, et le couple split quand il y en a un — avec à côté le manipulateur CW (vitesse en plus ou en moins, et Stop, parce qu'un message parti vers le mauvais indicatif doit s'arrêter tout de suite) et le manipulateur vocal avec ses messages enregistrés en boutons, pour lancer un CQ sans quitter l'onglet. Les deux manipulateurs n'apparaissent que s'il y a quelque chose derrière : un port configuré, ou un message réellement enregistré. Les trois se déplacent et se réordonnent avec les autres cartes.", - "Un seul cadenas dans la saisie au lieu de cinq. Enregistrer un contact depuis une feuille — un carnet de concours, le report d'un ami, un QSO fait sur une autre radio — suppose que la fréquence, la bande, le mode, la date et les deux heures cessent tous en même temps de suivre le poste et l'horloge. C'étaient cinq clics à cinq endroits différents, qu'il fallait d'abord trouver. Le cadenas à côté de Début UTC les fige maintenant tous, et les libère tous." + "Un seul cadenas dans la saisie au lieu de cinq. Enregistrer un contact depuis une feuille — un carnet de concours, le report d'un ami, un QSO fait sur une autre radio — suppose que la fréquence, la bande, le mode, la date et les deux heures cessent tous en même temps de suivre le poste et l'horloge. C'étaient cinq clics à cinq endroits différents, qu'il fallait d'abord trouver. Le cadenas à côté de Début UTC les fige maintenant tous, et les libère tous.", + "Les Préférences ne disent plus deux fois le nom de la section — la petite ligne au-dessus de chaque panneau répétait le titre juste en dessous, et la barre latérale montre déjà laquelle est ouverte.", + "La matrice peut s'ouvrir sur le mode numérique que vous travaillez vraiment. Celui qui ne fait que du FT8 voyait DIGI à chaque fois et devait cliquer jusqu'à son mode pour chaque indicatif ; Réglages → Général choisit désormais la ligne numérique sur laquelle la matrice démarre. La ligne continue de tourner au clic, et DIGI — tous ensemble — reste le défaut.", + "La pastille MQTT disparaît de la barre d'état. C'est le nom d'un protocole de messages, pas de quelque chose que possède un opérateur. Ce qu'elle indiquait — le flux d'ouvertures actif ou non, et le nombre de reports arrivés — est dans le panneau Chasse au nouveau, à l'endroit qui s'en sert." ] }, { diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index fcdc940..ec792d0 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -52,7 +52,7 @@ import { ReportLiveActivity, LiveLastQSOAgeSec, GetAmpStatuses, AmpOperate, GetFlexState, FlexAmpOperate, - GetPSKReporterStatus, GetLiveOpenings, GetChaseNew, + GetLiveOpenings, GetChaseNew, QSLViaRepairStatus, RepairQSLVia, DismissQSLViaRepair, GetAutoCallStatus, SetAutoCall, SetAutoCallOnly, TakeAutoCallTarget, HaltAutoCall, WatchlistEntries, } from '../wailsjs/go/main/App'; @@ -2359,16 +2359,6 @@ export default function App() { return () => window.clearInterval(t); }, []); - // PSK Reporter feed, for the status-bar chip. Polled slowly: the chip only - // says up or down, and the count behind it is a tooltip. - const [pskr, setPskr] = useState(null); - useEffect(() => { - const load = () => { GetPSKReporterStatus().then(setPskr).catch(() => {}); }; - load(); - const t = window.setInterval(load, 10000); - return () => window.clearInterval(t); - }, []); - // "ON AIR" status-bar badge: mirrors the multi-op live status this operator // publishes — online (blinking) when a QSO was logged in the last 5 min, else // offline. Publishing is always on for a shared MySQL logbook (no user toggle: @@ -9136,26 +9126,12 @@ export default function App() { ); })} - {/* PSK Reporter, next to the hardware chips because it is the same - kind of fact: a link that is either up or it is not. Shown ONLY - when the opening watch is on — a permanently grey chip for a - feature nobody enabled is clutter, and the bar is 28 px. - - The decode count is in the tooltip rather than the chip: it moves - several times a second on an open band, and a number flickering in - the corner of the eye is not information, it is a distraction. */} - {pskr?.running && ( - - )} + {/* The PSK Reporter chip used to sit here, labelled MQTT. That is + the name of a message protocol, not of anything an operator has: + a chip in the status bar has to say what it is about, and this + one told nobody anything. The state it carried — the openings + feed up or down, and how many reports have arrived — is shown in + the Chase New panel, which is the place that uses it. */} {/* ON AIR badge: "did I log a QSO in the last 5 min" — meaningful on ANY logbook backend (only the live_status PUBLISHING is MySQL-specific), so it is always shown. Gating it on MySQL made it vanish for diff --git a/frontend/src/components/BandSlotGrid.tsx b/frontend/src/components/BandSlotGrid.tsx index 42124e4..0c88175 100644 --- a/frontend/src/components/BandSlotGrid.tsx +++ b/frontend/src/components/BandSlotGrid.tsx @@ -60,7 +60,11 @@ const DEFAULT_BANDS: { tag: string; label: string }[] = [ ]; const CLASSES = ['PH', 'CW', 'DIG'] as const; -const PHONE_MODES = new Set(['SSB','USB','LSB','AM','FM','DIGITALVOICE','PHONE']); +export const PHONE_MODES = new Set(['SSB','USB','LSB','AM','FM','DIGITALVOICE','PHONE']); + +// Which digital row the matrix opens on. Empty = DIG, the group of them all. +// Set in Settings ▸ General; see the rotation below. +export const MATRIX_DIGI_KEY = 'opslog.matrixDigiMode'; function classMatchesMode(cls: string, mode: string): boolean { const u = (mode || '').toUpperCase(); if (cls === 'PH') return PHONE_MODES.has(u); @@ -143,7 +147,17 @@ export function BandSlotGrid({ wb, busy, currentBand, currentMode, bands, modes, .filter((m) => m !== '' && m !== 'CW' && !PHONE_MODES.has(m)), [modes], ); + // Where the rotation STARTS. An operator who only ever works FT8 was shown + // "DIG" every time and had to click to the mode they actually use, on every + // callsign — so the row they want is the one it opens on. Empty (the default) + // keeps DIG, which is right for anyone working several digital modes. const [digIdx, setDigIdx] = useState(0); // 0 = the DIG group itself + useEffect(() => { + const want = (localStorage.getItem(MATRIX_DIGI_KEY) || '').toUpperCase().trim(); + if (!want) { setDigIdx(0); return; } + const i = digModes.indexOf(want); + setDigIdx(i >= 0 ? i + 1 : 0); + }, [digModes]); // A shorter mode list (the operator edited it) must not strand the rotation // on a row that no longer exists. const digPos = digModes.length ? digIdx % (digModes.length + 1) : 0; diff --git a/frontend/src/components/SettingsModal.tsx b/frontend/src/components/SettingsModal.tsx index bef2556..acfe91b 100644 --- a/frontend/src/components/SettingsModal.tsx +++ b/frontend/src/components/SettingsModal.tsx @@ -95,6 +95,7 @@ import { AppearancePanel } from '@/components/AppearancePanel'; import { UDPIntegrationsPanel } from '@/components/UDPIntegrationsPanel'; import { loadClusterMacros, saveClusterMacros, type ClusterMacro } from '@/lib/clusterMacros'; import { CLUSTER_PRESETS } from '@/lib/clusterPresets'; +import { MATRIX_DIGI_KEY, PHONE_MODES as MATRIX_PHONE_MODES } from '@/components/BandSlotGrid'; type LookupSettings = LookupSettingsForm; type StationSettings = StationSettingsForm; @@ -2007,6 +2008,17 @@ function SettingsModalImpl({ onClose, onSaved, initialSection, onMainPaneChanged const [startEqEnd, setStartEqEnd] = useState(() => localStorage.getItem('opslog.startEqualsEnd') === '1'); const [lookupOnBlur, setLookupOnBlur] = useState(() => localStorage.getItem('opslog.lookupOnBlur') === '1'); const [groupDigital, setGroupDigital] = useState(() => localStorage.getItem('opslog.groupDigitalSlots') === '1'); + // The digital row the band matrix opens on: '' = DIG, the group of them all. + const [matrixDigi, setMatrixDigi] = useState(() => localStorage.getItem(MATRIX_DIGI_KEY) || ''); + // The operator's own digital modes, which is what the matrix rotates through + // — the same rule it uses: everything in their mode list that is neither CW + // nor a phone mode. + const digitalModeNames = useMemo( + () => (lists.modes ?? []) + .map((m: any) => String(m?.name ?? '').toUpperCase().trim()) + .filter((m) => m && m !== 'CW' && !MATRIX_PHONE_MODES.has(m)), + [lists.modes], + ); const [milesUnit, setMilesUnit] = useState(() => localStorage.getItem('opslog.distanceMiles') === '1'); const [region, setRegion] = useState(() => iaruRegion()); const [clusterWorkedSameSlot, setClusterWorkedSameSlot] = useState(() => localStorage.getItem('opslog.clusterWorkedSameSlot') === '1'); @@ -2812,7 +2824,6 @@ function SettingsModalImpl({ onClose, onSaved, initialSection, onMainPaneChanged } } - const breadcrumb = useMemo(() => { const k = SECTION_KEY[selected]; return k ? t(k) : (SECTION_LABELS[selected] ?? selected); }, [selected, t]); // === Section content renderers === @@ -8106,6 +8117,24 @@ function SettingsModalImpl({ onClose, onSaved, initialSection, onMainPaneChanged { const v = !!c; setGroupDigital(v); writeUiPref('opslog.groupDigitalSlots', v ? '1' : '0'); }} /> {t('gen.groupDigital')} + {/* Which digital row the band matrix opens on. An operator who works + only FT8 was shown DIG every time and had to click through to the + mode they actually use, on every callsign. The row still rotates + — this only says where it starts. */} +
+ {t('gen.matrixDigi')} + +