feat(hamqth): upload the whole log in one file

The per-QSO API is the only correct way to send a SELECTION, and at the
pace it must be driven a 14k backlog costs the better part of an hour.
HamQTH's other endpoint takes a whole log as one file — and REPLACES
what is on the site with it: its documentation says plainly that partial
uploads do not exist. So it is offered as its own deliberate act behind
a confirmation, never as the batch path behind 'send these', where it
would delete every QSO the operator had not selected.

Scoped to the callsign this profile uploads as, so a database holding
two operators' contacts cannot push one into the other's log; tar.gz
above 12 MB because the ceiling is 20 and a six-figure log passes it as
text; and every QSO not already stamped is marked sent afterwards, in
bulk, so the backlog list agrees with reality.
This commit is contained in:
2026-08-31 20:07:46 +02:00
parent bcd7e409ba
commit 386a8ad531
7 changed files with 283 additions and 6 deletions
+18 -2
View File
@@ -8,7 +8,7 @@ import {
Select, SelectTrigger, SelectValue, SelectContent, SelectItem,
} from '@/components/ui/select';
import { cn } from '@/lib/utils';
import { GetLoTWQSLDetail, SetLoTWQSLDetail, GetLoTWDownloadAllCalls, SetLoTWDownloadAllCalls, OpenExternalURL, FindQSOsForUpload, UploadQSOsManual, DownloadConfirmations, CancelConfirmations, ImportHamlogConfirmations, ExportHamlogUnmatched, OpenADIFFile, SaveADIFFile, SyncPOTAHunterLog, ListQSO, BulkUpdateQSL, UploadCallsign, GetSlotStats } from '../../wailsjs/go/main/App';
import { GetLoTWQSLDetail, SetLoTWQSLDetail, GetLoTWDownloadAllCalls, SetLoTWDownloadAllCalls, OpenExternalURL, FindQSOsForUpload, UploadFullLogHamQTH, UploadQSOsManual, DownloadConfirmations, CancelConfirmations, ImportHamlogConfirmations, ExportHamlogUnmatched, OpenADIFFile, SaveADIFFile, SyncPOTAHunterLog, ListQSO, BulkUpdateQSL, UploadCallsign, GetSlotStats } from '../../wailsjs/go/main/App';
import { Input } from '@/components/ui/input';
import { RecentQSOsGrid } from '@/components/RecentQSOsGrid';
import { EventsOn } from '../../wailsjs/runtime/runtime';
@@ -723,7 +723,23 @@ export function QSLManagerPanel({ onEditQSO, actions, paperRequest }: {
{service !== 'pota' && service !== 'paper' && (
<div className="flex items-center justify-between gap-2 px-3 py-2 border-t border-border bg-muted/20 shrink-0">
<div className="flex items-center gap-2 flex-wrap">
{service === 'hamlog' ? (
{service === 'hamqth' ? (
// HamQTH's file endpoint REPLACES the remote log — its own
// documentation is explicit that partial uploads do not exist. So
// it is offered as its own deliberate act, never as the batch path
// behind "send these": that would delete everything not selected.
<Button variant="outline" size="sm" disabled={busy}
title={t('qslm.hqFullTitle')}
onClick={async () => {
if (!window.confirm(t('qslm.hqFullConfirm'))) return;
setBusy(true);
setLogLines([]);
try { await UploadFullLogHamQTH(); }
catch (e: any) { setBusy(false); setLogLines((l) => [...l, String(e?.message ?? e)]); }
}}>
<UploadCloud className="size-3.5" /> {t('qslm.hqFull')}
</Button>
) : service === 'hamlog' ? (
<>
<Button variant="outline" size="sm" onClick={importHamlogCfm} disabled={busy}
title={t('qslm.hamlogImportTitle')}>
File diff suppressed because one or more lines are too long
+2
View File
@@ -1397,6 +1397,8 @@ export function UpdateQSOsFromQRZ(arg1:Array<number>):Promise<number>;
export function UploadCallsign(arg1:string):Promise<string>;
export function UploadFullLogHamQTH():Promise<void>;
export function UploadQSOsManual(arg1:string,arg2:Array<number>):Promise<void>;
export function WatchlistAdd(arg1:string,arg2:boolean):Promise<void>;
+4
View File
@@ -2730,6 +2730,10 @@ export function UploadCallsign(arg1) {
return window['go']['main']['App']['UploadCallsign'](arg1);
}
export function UploadFullLogHamQTH() {
return window['go']['main']['App']['UploadFullLogHamQTH']();
}
export function UploadQSOsManual(arg1, arg2) {
return window['go']['main']['App']['UploadQSOsManual'](arg1, arg2);
}