fix: bulk edit refused the fields it offered (#3)

My mistake yesterday: the new confirmation columns went into uploadStatusCols —
the QSL Manager's FILTER whitelist — instead of bulkEditableCols. The dialog
listed QRZ.com received status and the ten dates, and the repository refused
them at Apply, after the operator had selected 54 QSOs.

Moved to the right map. And two fields have been broken this way since long
before: State and County were offered under "Contacted station" (whose IOTA /
POTA / SOTA / SIG siblings are all allowed) but were missing from the whitelist,
so choosing one always failed. Added — they are exactly what an import loses and
what a whole run shares.

The real fix is the test. Two lists in two languages had to agree by hand and
nothing checked it, so the failure only ever surfaced as an error message at the
last click. The new tests read the ACTUAL field ids out of BulkEditModal.tsx and
FilterBuilder.tsx and assert the repository accepts every one — a field added to
the UI alone now fails the build instead of the operator.
This commit is contained in:
2026-07-28 09:45:22 +02:00
parent d49126d45c
commit 843dccf0c4
9 changed files with 197 additions and 37 deletions
+23 -3
View File
@@ -29,6 +29,14 @@ const (
type OmniRig struct {
RigNum int // 1 (Rig1) or 2 (Rig2)
// ForceVFO overrides which VFO to read: "" trusts the rig file, "A"/"B" do
// not. OmniRig's VFO report is only as good as the .ini behind it, and a
// wrong one is invisible: an IC-7610 file was seen declaring VFO B while the
// operator worked on the main VFO, so OpsLog wrote to A (SetSimplexMode acts
// on the main VFO) and read B — the frequency "never followed the knob",
// while it was following the other one all along.
ForceVFO string
omnirig *ole.IDispatch
rig *ole.IDispatch
lastSig string // last logged Split/VFO signature — only log on change
@@ -62,11 +70,17 @@ type OmniRig struct {
}
// NewOmniRig creates a non-connected backend. Call Connect before use.
func NewOmniRig(rigNum int) *OmniRig {
// NewOmniRig builds the backend. forceVFO is "" to follow whatever the rig file
// reports, or "A"/"B" to override it — see the ForceVFO field.
func NewOmniRig(rigNum int, forceVFO string) *OmniRig {
if rigNum < 1 || rigNum > 2 {
rigNum = 1
}
return &OmniRig{RigNum: rigNum}
v := strings.ToUpper(strings.TrimSpace(forceVFO))
if v != "A" && v != "B" {
v = ""
}
return &OmniRig{RigNum: rigNum, ForceVFO: v}
}
func (o *OmniRig) Name() string { return "omnirig" }
@@ -306,7 +320,13 @@ func (o *OmniRig) ReadState() (RigState, error) {
}
splitRecentOn := o.splitFlaky && !o.lastSplitOnAt.IsZero() && now.Sub(o.lastSplitOnAt) < 6*time.Second
s.FreqHz, s.RxFreqHz, s.Split = resolveOmniRigVFOs(o.rigType, freqMain, freqA, freqB, s.Vfo, splitRaw, splitRecentOn)
// A forced VFO replaces whatever the rig file reported, BEFORE anything is
// derived from it. Nothing downstream then has to know about the override.
vfo := s.Vfo
if o.ForceVFO != "" {
vfo = o.ForceVFO
}
s.FreqHz, s.RxFreqHz, s.Split = resolveOmniRigVFOs(o.rigType, freqMain, freqA, freqB, vfo, splitRaw, splitRecentOn)
// Diagnostic logged ONLY when Split or VFO changes (not on a timer), so normal
// operation stays quiet but toggling split or SUB VFO on the radio is