feat: Station Control amp parity + all amps, Help→Send log to F4BPO, bulk-edit frequency, fix Cluster midnight sort
- Station Control: the amplifier panel is now the exact same card as the FlexRadio panel (extracted shared AmpCard: OPERATE/STANDBY, ON/OFF, power level, output-power bar, live FWD/ID/temp meters). Every configured amp gets its own card — no dropdown. - Help → "Send log to F4BPO" (only when SMTP is configured): e-mails opslog.log + previous session + crash log to the developer. New email.SendFiles for multi-attachment. - Bulk edit: new "Frequency (MHz)" field sets freq_hz AND recomputes band; out-of-band values rejected. Fixes a run logged on a stale/default freq after CAT dropped. - Cluster: Time column sorted lexically on the HHMMZ string, so spots after 0000Z sorted below 2359Z and looked frozen at the UTC rollover. Now sorts by real arrival time. - Also folds in the DVK auto-CQ/2-column layout and Station Control dashboard batch (changelog 0.20.10, EN+FR).
This commit is contained in:
+14
-2
@@ -41,6 +41,16 @@ func (c Config) opts() []mail.Option {
|
||||
|
||||
// Send delivers a plain-text email to `to`, optionally attaching a file.
|
||||
func Send(cfg Config, to, subject, body, attachPath string) error {
|
||||
var attach []string
|
||||
if attachPath != "" {
|
||||
attach = []string{attachPath}
|
||||
}
|
||||
return SendFiles(cfg, to, subject, body, attach)
|
||||
}
|
||||
|
||||
// SendFiles is like Send but attaches any number of files (missing paths are
|
||||
// skipped by the mail library at send time).
|
||||
func SendFiles(cfg Config, to, subject, body string, attachPaths []string) error {
|
||||
if cfg.Host == "" {
|
||||
return fmt.Errorf("SMTP server not configured")
|
||||
}
|
||||
@@ -65,8 +75,10 @@ func Send(cfg Config, to, subject, body, attachPath string) error {
|
||||
}
|
||||
m.Subject(subject)
|
||||
m.SetBodyString(mail.TypeTextPlain, body)
|
||||
if attachPath != "" {
|
||||
m.AttachFile(attachPath)
|
||||
for _, p := range attachPaths {
|
||||
if p != "" {
|
||||
m.AttachFile(p)
|
||||
}
|
||||
}
|
||||
client, err := mail.NewClient(cfg.Host, cfg.opts()...)
|
||||
if err != nil {
|
||||
|
||||
@@ -792,6 +792,31 @@ func (r *Repo) BulkSetField(ctx context.Context, ids []int64, column, value stri
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// BulkSetFrequency sets freq_hz AND band together on every listed QSO. Kept
|
||||
// separate from BulkSetField because frequency is numeric and must keep the band
|
||||
// consistent — the main use is fixing a batch that was logged on a stale/default
|
||||
// frequency after CAT dropped. freqHz "" is not allowed (caller validates).
|
||||
func (r *Repo) BulkSetFrequency(ctx context.Context, ids []int64, freqHz int64, band string) (int64, error) {
|
||||
if len(ids) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
ph := make([]string, len(ids))
|
||||
args := make([]any, 0, len(ids)+3)
|
||||
args = append(args, freqHz, band, db.NowISO())
|
||||
for i, id := range ids {
|
||||
ph[i] = "?"
|
||||
args = append(args, id)
|
||||
}
|
||||
res, err := r.db.ExecContext(ctx,
|
||||
`UPDATE qso SET freq_hz = ?, band = ?, updated_at = ? WHERE id IN (`+strings.Join(ph, ",")+`)`,
|
||||
args...)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("bulk set frequency: %w", err)
|
||||
}
|
||||
n, _ := res.RowsAffected()
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// SetExtra merges ONE key into a QSO's extras JSON without rewriting the rest of
|
||||
// the row. A slow caller that only wants to stamp its own app field (e-mailing a
|
||||
// QSL card, saving a recording) must not do a full-row Update: the row it read may
|
||||
|
||||
Reference in New Issue
Block a user