feat: New tool to remove duplicates in the log

This commit is contained in:
2026-07-05 10:58:49 +02:00
parent 2d742be7df
commit 45b9bcdea7
7 changed files with 300 additions and 2 deletions
+9
View File
@@ -70,6 +70,7 @@ import { cleanSpotter, inferSpotMode, spotModeCategory, spotStatusKey } from '@/
import { WorkedBeforeGrid } from '@/components/WorkedBeforeGrid';
import { NetControlPanel } from '@/components/NetControlPanel';
import { ContestPanel, CONTEST_DEFAULT, type ContestSession } from '@/components/ContestPanel';
import { DuplicatesModal } from '@/components/DuplicatesModal';
import { useI18n } from '@/lib/i18n';
import { AlertsModal } from '@/components/AlertsModal';
import { BulkEditModal } from '@/components/BulkEditModal';
@@ -907,6 +908,7 @@ export default function App() {
const [settingsSection, setSettingsSection] = useState<string | undefined>(undefined);
const [showDeleteAll, setShowDeleteAll] = useState(false);
const [showAbout, setShowAbout] = useState(false);
const [showDuplicates, setShowDuplicates] = useState(false);
const [updateInfo, setUpdateInfo] = useState<{ latest: string; url: string } | null>(null);
// Check GitHub for a newer release once at startup (unless disabled in
// General); surface a toast if one exists. Best effort — silent on failure.
@@ -2325,6 +2327,8 @@ export default function App() {
{ type: 'item', label: (netEnabled ? '✓ ' : '') + t('tools.net'), action: 'tools.net' },
{ type: 'item', label: t('tools.alerts'), action: 'tools.alerts' },
{ type: 'separator' },
{ type: 'item', label: t('tools.duplicates'), action: 'tools.duplicates', disabled: total === 0 },
{ type: 'separator' },
// Maintenance — bumped here while we only have one entry. Will move
// to a Tools → Maintenance submenu once Clublog + LoTW refresh land.
{ type: 'item', label: ctyRefreshing ? 'Refreshing cty.dat…' : 'Refresh cty.dat', action: 'tools.refreshCty', disabled: ctyRefreshing },
@@ -2354,6 +2358,7 @@ export default function App() {
case 'tools.cwdecoder': toggleCwDecoder(); break;
case 'tools.net': setNetEnabled((v) => { const nv = !v; if (nv) setActiveTab('net'); return nv; }); break;
case 'tools.alerts': setAlertsOpen(true); break;
case 'tools.duplicates': setShowDuplicates(true); break;
case 'tools.refreshCty': refreshCtyDat(); break;
case 'tools.downloadRefs': downloadRefs(); break;
case 'help.about': setShowAbout(true); break;
@@ -4251,6 +4256,10 @@ export default function App() {
<AlertsModal onClose={() => setAlertsOpen(false)} bands={bands} modes={modes} countries={countries} />
)}
{showDuplicates && (
<DuplicatesModal onClose={() => setShowDuplicates(false)} onDeleted={() => refresh()} />
)}
<AutoEQSL
onSent={(call) => showToast(`OpsLog QSL sent to ${call}`)}
onError={(msg) => showToast(msg)}