feat(hamlog): confirmation defaults and grid columns; drop a settings paragraph
Preferences → Confirmations gains a HAMLOG.online row, sent and received, with the same defaults every other service has: a new QSO can start at N so the backlog is meaningful from the first contact. The defaults reach it through a new setExtraDefault — fill() writes through a pointer to a string field and these two live in the extras map, which no pointer reaches. The QSO grid gains four HAMLOG columns (status and date, both directions), hidden by default: a column per service shown to everyone is how a grid becomes unreadable. And the paragraph explaining what "Sent" means is gone from that page.
This commit is contained in:
@@ -344,6 +344,8 @@ const (
|
||||
keyQSLDefaultHRDLogStatus = "qsl.hrdlog_status"
|
||||
keyQSLDefaultQRZComStatus = "qsl.qrzcom_status"
|
||||
keyQSLDefaultQRZComCfm = "qsl.qrzcom_confirmed"
|
||||
keyQSLDefaultHamlogStatus = "qsl.hamlog_status"
|
||||
keyQSLDefaultHamlogCfm = "qsl.hamlog_confirmed"
|
||||
|
||||
// External services (logbook upload). QRZ.com first; Clublog / LoTW
|
||||
// will add their own keys under the same extsvc.* prefix.
|
||||
@@ -420,6 +422,12 @@ type QSLDefaults struct {
|
||||
HRDLogStatus string `json:"hrdlog_status"`
|
||||
QRZComStatus string `json:"qrzcom_status"`
|
||||
QRZComCfm string `json:"qrzcom_confirmed"` // QRZ.com download/confirmed status
|
||||
// HAMLOG.online lives in the ADIF extras rather than a column — the standard
|
||||
// names a field for hamlog.EU and none for hamlog.ONLINE — but a default is
|
||||
// a default: an operator who uploads everything wants new contacts to start
|
||||
// at "N" here exactly as they do for Club Log.
|
||||
HamlogStatus string `json:"hamlog_status"`
|
||||
HamlogCfm string `json:"hamlog_confirmed"`
|
||||
}
|
||||
|
||||
// CATSettings is the user-tweakable rig-control configuration. Stored as
|
||||
@@ -10521,6 +10529,7 @@ func (a *App) GetQSLDefaults() (QSLDefaults, error) {
|
||||
keyQSLDefaultEQSLSent, keyQSLDefaultEQSLRcvd,
|
||||
keyQSLDefaultClublogStatus, keyQSLDefaultHRDLogStatus,
|
||||
keyQSLDefaultQRZComStatus, keyQSLDefaultQRZComCfm,
|
||||
keyQSLDefaultHamlogStatus, keyQSLDefaultHamlogCfm,
|
||||
)
|
||||
if err != nil {
|
||||
return out, err
|
||||
@@ -10535,6 +10544,8 @@ func (a *App) GetQSLDefaults() (QSLDefaults, error) {
|
||||
out.HRDLogStatus = m[keyQSLDefaultHRDLogStatus]
|
||||
out.QRZComStatus = m[keyQSLDefaultQRZComStatus]
|
||||
out.QRZComCfm = m[keyQSLDefaultQRZComCfm]
|
||||
out.HamlogStatus = m[keyQSLDefaultHamlogStatus]
|
||||
out.HamlogCfm = m[keyQSLDefaultHamlogCfm]
|
||||
return out, nil
|
||||
}
|
||||
|
||||
@@ -10556,6 +10567,8 @@ func (a *App) SaveQSLDefaults(d QSLDefaults) error {
|
||||
keyQSLDefaultHRDLogStatus: strings.ToUpper(strings.TrimSpace(d.HRDLogStatus)),
|
||||
keyQSLDefaultQRZComStatus: strings.ToUpper(strings.TrimSpace(d.QRZComStatus)),
|
||||
keyQSLDefaultQRZComCfm: strings.ToUpper(strings.TrimSpace(d.QRZComCfm)),
|
||||
keyQSLDefaultHamlogStatus: strings.ToUpper(strings.TrimSpace(d.HamlogStatus)),
|
||||
keyQSLDefaultHamlogCfm: strings.ToUpper(strings.TrimSpace(d.HamlogCfm)),
|
||||
} {
|
||||
if err := a.settings.Set(a.ctx, scope+k, v); err != nil {
|
||||
return err
|
||||
@@ -10606,6 +10619,27 @@ func applyQSLDefaultsTo(q *qso.QSO, d QSLDefaults) {
|
||||
fill(&q.HRDLogUploadStatus, d.HRDLogStatus)
|
||||
fill(&q.QRZComUploadStatus, d.QRZComStatus)
|
||||
fill(&q.QRZComDownloadStatus, d.QRZComCfm)
|
||||
// The extras, which fill() cannot reach: it writes through a pointer to a
|
||||
// string field, and these two are map entries. Only set when the QSO does not
|
||||
// already carry them, which is the same rule fill() applies.
|
||||
setExtraDefault(q, hamlogSentKey, d.HamlogStatus)
|
||||
setExtraDefault(q, award.HamlogQSLKey, d.HamlogCfm)
|
||||
}
|
||||
|
||||
// setExtraDefault writes a default into an ADIF extras key, leaving an existing
|
||||
// value alone. A blank default means "say nothing", not "write an empty string":
|
||||
// an empty extra would be carried into every export.
|
||||
func setExtraDefault(q *qso.QSO, key, def string) {
|
||||
def = strings.ToUpper(strings.TrimSpace(def))
|
||||
if def == "" {
|
||||
return
|
||||
}
|
||||
if q.Extras == nil {
|
||||
q.Extras = map[string]string{}
|
||||
}
|
||||
if strings.TrimSpace(q.Extras[key]) == "" {
|
||||
q.Extras[key] = def
|
||||
}
|
||||
}
|
||||
|
||||
// ── External services (logbook upload) ─────────────────────────────────
|
||||
|
||||
+6
-2
@@ -10,7 +10,9 @@
|
||||
"The row colours in Appearance can be scoped to HAMLOG.online as well, alongside paper, LoTW, eQSL and QRZ.com.",
|
||||
"HAMLOG.online appears in the QSL Manager too: pick it to see every QSO never sent there and upload the backlog in one go. A contact already sent carries the date it went, so a second sweep does not send it twice.",
|
||||
"Right-clicking QSOs offers HAMLOG.online among the upload targets, and the toast names each service properly instead of echoing its internal id.",
|
||||
"Bulk edit can set HAMLOG.online sent and received, each with its status and its date — the same four fields every other service has there. A log uploaded to their site by hand had no way to be marked as sent, so OpsLog kept offering to upload every contact again."
|
||||
"Bulk edit can set HAMLOG.online sent and received, each with its status and its date — the same four fields every other service has there. A log uploaded to their site by hand had no way to be marked as sent, so OpsLog kept offering to upload every contact again.",
|
||||
"HAMLOG.online joins the Confirmations defaults and the QSO grid columns — sent and received, each with its status and date, hidden by default like the other extras-backed columns.",
|
||||
"Removed the explanatory paragraph from the Confirmations page."
|
||||
],
|
||||
"fr": [
|
||||
"Yaesu : une ligne ANT dans le panneau du poste sélectionne la prise d'antenne, et le choix est mémorisé pour la bande sur laquelle il a été fait — on change de bande, l'antenne suit. Aucune page à configurer : choisir l'antenne une fois sur une bande le dit très bien. Les postes à une seule prise n'affichent jamais la ligne.",
|
||||
@@ -20,7 +22,9 @@
|
||||
"Les couleurs de lignes dans Apparence peuvent aussi être limitées à HAMLOG.online, aux côtés du papier, de LoTW, d'eQSL et de QRZ.com.",
|
||||
"HAMLOG.online figure aussi dans le gestionnaire QSL : on le choisit pour voir tous les QSO jamais envoyés là-bas et expédier l'arriéré d'un coup. Un contact déjà envoyé porte la date de son départ, donc un second passage ne le renvoie pas.",
|
||||
"Le clic droit sur des QSO propose HAMLOG.online parmi les destinations d'envoi, et la notification nomme correctement chaque service au lieu d'afficher son identifiant interne.",
|
||||
"L'édition en masse peut renseigner HAMLOG.online envoyé et reçu, chacun avec son statut et sa date — les mêmes quatre champs que les autres services. Un journal téléversé à la main sur leur site n'avait aucun moyen d'être marqué comme envoyé, et OpsLog proposait donc de renvoyer tous les contacts."
|
||||
"L'édition en masse peut renseigner HAMLOG.online envoyé et reçu, chacun avec son statut et sa date — les mêmes quatre champs que les autres services. Un journal téléversé à la main sur leur site n'avait aucun moyen d'être marqué comme envoyé, et OpsLog proposait donc de renvoyer tous les contacts.",
|
||||
"HAMLOG.online rejoint les valeurs par défaut des Confirmations et les colonnes de la grille des QSO — envoyé et reçu, chacun avec son statut et sa date, masquées par défaut comme les autres colonnes issues des extras.",
|
||||
"Suppression du paragraphe explicatif de la page Confirmations."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -207,6 +207,14 @@ export const makeColCatalog = (t: TFn, myGrid?: string): ColEntry[] => [
|
||||
{ group: 'QSL', label: t('rqg.c.opslog_qsl_card_sent'), colId: 'opslog_qsl_card_sent', headerName: t('rqg.c.opslog_qsl_card_sent'), width: 100, cellClass: qslStatusCellClass, valueGetter: (p) => { const e = (p.data as any)?.extras ?? {}; return (e['APP_OPSLOG_QSL_SENT'] || e['APP_OPSLOG_QSL_CARD_SENT']) ? 'Y' : 'N'; }, defaultVisible: true },
|
||||
// App-specific: operator marked a QSL as RECEIVED for this QSO (drives PSE/TNX).
|
||||
{ group: 'QSL', label: t('rqg.c.opslog_qsl_card_rcvd'), colId: 'opslog_qsl_card_rcvd', headerName: t('rqg.c.opslog_qsl_card_rcvd'), width: 100, cellClass: qslStatusCellClass, valueGetter: (p) => { const e = (p.data as any)?.extras ?? {}; return e['APP_OPSLOG_QSL_RCVD'] ? 'Y' : 'N'; }, defaultVisible: false },
|
||||
// HAMLOG.online. No promoted column — the ADIF standard names a field for
|
||||
// hamlog.EU and none for hamlog.ONLINE — so these read the extras, exactly
|
||||
// like the OpsLog card columns above. Hidden by default: a column per
|
||||
// service, shown to everyone, is how a grid becomes unreadable.
|
||||
{ group: 'QSL', label: t('rqg.c.hamlog_sent'), colId: 'hamlog_sent', headerName: t('rqg.h.hamlog_sent'), width: 100, cellClass: qslStatusCellClass, valueGetter: (p) => { const e = (p.data as any)?.extras ?? {}; return e['APP_OPSLOG_HAMLOG_SENT'] || 'N'; }, defaultVisible: false },
|
||||
{ group: 'QSL', label: t('rqg.c.hamlog_sent_date'), colId: 'hamlog_sent_date', headerName: t('rqg.h.hamlog_sent_date'), width: 110, valueGetter: (p) => fmtDateOnly((p.data as any)?.extras?.['APP_OPSLOG_HAMLOG_SENT_DATE']), defaultVisible: false },
|
||||
{ group: 'QSL', label: t('rqg.c.hamlog_rcvd'), colId: 'hamlog_rcvd', headerName: t('rqg.h.hamlog_rcvd'), width: 100, cellClass: qslStatusCellClass, valueGetter: (p) => { const e = (p.data as any)?.extras ?? {}; return e['APP_OPSLOG_HAMLOG_QSL'] || 'N'; }, defaultVisible: false },
|
||||
{ group: 'QSL', label: t('rqg.c.hamlog_rcvd_date'), colId: 'hamlog_rcvd_date', headerName: t('rqg.h.hamlog_rcvd_date'), width: 110, valueGetter: (p) => fmtDateOnly((p.data as any)?.extras?.['APP_OPSLOG_HAMLOG_QSL_DATE']), defaultVisible: false },
|
||||
// App-specific: when the QSO's audio recording was e-mailed to the station.
|
||||
{ group: 'QSL', label: t('rqg.c.opslog_recording_sent'), colId: 'opslog_recording_sent', headerName: t('rqg.h.opslog_recording_sent'), width: 100, cellClass: qslStatusCellClass, valueGetter: (p) => { const e = (p.data as any)?.extras ?? {}; return e['APP_OPSLOG_RECORDING_SENT'] ? 'Y' : 'N'; }, defaultVisible: false },
|
||||
|
||||
|
||||
@@ -1708,6 +1708,7 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
|
||||
eqsl_sent: string; eqsl_rcvd: string;
|
||||
clublog_status: string; hrdlog_status: string; qrzcom_status: string;
|
||||
qrzcom_confirmed: string;
|
||||
hamlog_status: string; hamlog_confirmed: string;
|
||||
};
|
||||
const [qslDefaults, setQslDefaults] = useState<QSLDefaults>({
|
||||
qsl_sent: '', qsl_rcvd: '',
|
||||
@@ -1715,6 +1716,7 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
|
||||
eqsl_sent: '', eqsl_rcvd: '',
|
||||
clublog_status: '', hrdlog_status: '', qrzcom_status: '',
|
||||
qrzcom_confirmed: '',
|
||||
hamlog_status: '', hamlog_confirmed: '',
|
||||
});
|
||||
|
||||
// External services (logbook upload). One block per service; only QRZ is
|
||||
@@ -5206,9 +5208,6 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
|
||||
</div>
|
||||
|
||||
<div className="border-t border-border/60 pt-3 space-y-3">
|
||||
<div className="text-[11px] text-muted-foreground">
|
||||
{t('conf.note')}
|
||||
</div>
|
||||
{/* Clublog */}
|
||||
<div className="grid grid-cols-[150px_1fr_1fr] gap-3 items-end">
|
||||
<Label className="text-sm font-medium pb-1.5">Clublog</Label>
|
||||
@@ -5239,6 +5238,18 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
|
||||
{renderSelect('qrzcom_confirmed', FULL_OPTIONS)}
|
||||
</div>
|
||||
</div>
|
||||
{/* HAMLOG.online */}
|
||||
<div className="grid grid-cols-[150px_1fr_1fr] gap-3 items-end">
|
||||
<Label className="text-sm font-medium pb-1.5">HAMLOG.online</Label>
|
||||
<div>
|
||||
<Label className="text-[10px] text-muted-foreground uppercase tracking-wider mb-1 block">{t('conf.sent')}</Label>
|
||||
{renderSelect('hamlog_status', FULL_OPTIONS)}
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-[10px] text-muted-foreground uppercase tracking-wider mb-1 block">{t('conf.rcvd')}</Label>
|
||||
{renderSelect('hamlog_confirmed', FULL_OPTIONS)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -3032,6 +3032,8 @@ export namespace main {
|
||||
hrdlog_status: string;
|
||||
qrzcom_status: string;
|
||||
qrzcom_confirmed: string;
|
||||
hamlog_status: string;
|
||||
hamlog_confirmed: string;
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new QSLDefaults(source);
|
||||
@@ -3049,6 +3051,8 @@ export namespace main {
|
||||
this.hrdlog_status = source["hrdlog_status"];
|
||||
this.qrzcom_status = source["qrzcom_status"];
|
||||
this.qrzcom_confirmed = source["qrzcom_confirmed"];
|
||||
this.hamlog_status = source["hamlog_status"];
|
||||
this.hamlog_confirmed = source["hamlog_confirmed"];
|
||||
}
|
||||
}
|
||||
export class QSLEmailTemplates {
|
||||
|
||||
Reference in New Issue
Block a user