feat(worked): fold portable callsigns into the worked-before history
Typing RK3DWA found nothing while RK3DWA/3 found 21 QSOs, so a station's history was only visible if you happened to type the exact form it had been logged under — and an operator who worked it as /0, /P or /MM saw none of it. The other RDA tools and Log4OM fold these together; this does too. The predicate strips the suffix from what was typed and matches "call = base OR call LIKE base/%", so it works from either end: the base call finds the portable QSOs and a portable call finds the plain ones. Deliberately not a bare prefix LIKE 'RK3DWA%', which would also match RK3DWAB — a different station. The '/' is what makes it the same operator. Settings -> General to turn it off. Default ON, hence the inverted storage: an existing install has no key, and reading that as OFF would leave everyone with the behaviour we were asked to change. Contest dupe checking is untouched — it runs through ContestDupe, a separate binding, and stays an exact match as a contest requires.
This commit is contained in:
@@ -27,6 +27,7 @@ import {
|
||||
AudioStartTX, AudioStopTX, AudioTXActive,
|
||||
ListClusterServers, SaveClusterServer, DeleteClusterServer,
|
||||
GetClusterAutoConnect, SetClusterAutoConnect, GetSelfSpotSettings, SaveSelfSpotSettings,
|
||||
GetWorkedCallVariants, SetWorkedCallVariants,
|
||||
ConnectClusterServer, DisconnectClusterServer,
|
||||
ConnectAllClusters, DisconnectAllClusters, GetClusterStatus,
|
||||
GetBackupSettings, SaveBackupSettings, RunBackupNow, PickBackupFolder,
|
||||
@@ -1524,6 +1525,8 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
|
||||
|
||||
const [clusterServers, setClusterServers] = useState<ClusterServer[]>([]);
|
||||
const [clusterAutoConnect, setClusterAutoConnectState] = useState(false);
|
||||
// Defaults to true so the checkbox matches the backend before the read lands.
|
||||
const [workedVariants, setWorkedVariants] = useState(true);
|
||||
// Self-spot. SELF_SPOT_MIN_MIN mirrors the backend floor — the input clamps on
|
||||
// blur, not per keystroke, or typing "10" would be rewritten to "5" the moment
|
||||
// the "1" landed and the field would fight the operator.
|
||||
@@ -1632,6 +1635,7 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
|
||||
try { setAudioCfg(await GetAudioSettings() as any); } catch {}
|
||||
try { setEmailCfg(await GetEmailSettings() as any); } catch {}
|
||||
try { setEqslCfg(await QSLGetEmailTemplates() as any); } catch {}
|
||||
try { setWorkedVariants(await GetWorkedCallVariants()); } catch {}
|
||||
reloadAudioDevices();
|
||||
reloadDvk();
|
||||
} catch (e: any) {
|
||||
@@ -5666,6 +5670,13 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
|
||||
<Checkbox checked={autofocusWB} onCheckedChange={(c) => { const v = !!c; setAutofocusWB(v); writeUiPref('opslog.autofocusWB', v ? '1' : '0'); }} />
|
||||
{t('gen.autofocusWB')}
|
||||
</label>
|
||||
{/* Backend setting, not a UI pref: the fold happens in the SQL. Saved
|
||||
instantly like the rest of this panel. */}
|
||||
<label className="flex items-center gap-2 text-sm cursor-pointer">
|
||||
<Checkbox checked={workedVariants}
|
||||
onCheckedChange={(c) => { const v = !!c; setWorkedVariants(v); SetWorkedCallVariants(v).catch((e: any) => setErr(String(e?.message ?? e))); }} />
|
||||
{t('gen.workedVariants')} <span className="text-xs text-muted-foreground">{t('gen.workedVariantsHint')}</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-2 text-sm cursor-pointer">
|
||||
<Checkbox checked={showBeamMap} onCheckedChange={(c) => { const v = !!c; setShowBeamMap(v); writeUiPref('opslog.showBeamOnMap', v ? '1' : '0'); }} />
|
||||
{t('gen.showBeam')}
|
||||
|
||||
Reference in New Issue
Block a user