Files
mats f5015581a4
Build and Publish / Metadata (push) Successful in 10s
Build and Publish / BuildAndDeployAmd64 (push) Successful in 2m0s
fix issues TUI display reliability
2026-09-24 11:11:29 +02:00

105 lines
2.2 KiB
Go

package main
import (
"context"
"time"
tea "github.com/charmbracelet/bubbletea"
)
// modelConfig is the static configuration the dashboard needs beyond the
// scanner.
type modelConfig struct {
Interval time.Duration
Title string
BaseURL string
}
// tickMsg drives the clock and the scan countdown.
type tickMsg time.Time
// snapshotMsg carries a finished scan back into the model.
type snapshotMsg snapshot
type model struct {
sc *scanner
cfg modelConfig
snap snapshot
// scanErr is kept separately so a failed refresh does not erase the last
// successful data from the display.
scanErr error
scanning bool
nextScanAt time.Time
width, height int
ready bool
}
func newModel(sc *scanner, cfg modelConfig) model {
return model{sc: sc, cfg: cfg, nextScanAt: time.Now()}
}
func (m model) Init() tea.Cmd {
return tea.Batch(tickClock(), m.scanCmd())
}
func tickClock() tea.Cmd {
return tea.Tick(time.Second, func(t time.Time) tea.Msg { return tickMsg(t) })
}
func (m *model) scanCmd() tea.Cmd {
sc := m.sc
return func() tea.Msg { return snapshotMsg(sc.Scan(context.Background(), time.Now())) }
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.width, m.height, m.ready = msg.Width, msg.Height, true
return m, nil
case tea.KeyMsg:
switch msg.String() {
case "q", "esc", "ctrl+c":
return m, tea.Quit
case "r":
if !m.scanning {
m.scanning = true
return m, m.scanCmd()
}
return m, nil
}
return m, nil
case tickMsg:
now := time.Time(msg)
cmd := tickClock()
if !m.scanning && !now.Before(m.nextScanAt) {
m.scanning = true
return m, tea.Batch(cmd, m.scanCmd())
}
return m, cmd
case snapshotMsg:
snap := snapshot(msg)
if snap.Err != nil {
m.scanErr = snap.Err
} else {
m.snap = snap
m.scanErr = nil
}
m.scanning = false
m.nextScanAt = time.Now().Add(m.cfg.Interval)
return m, nil
}
return m, nil
}
func (m model) View() string {
return renderSnapshot(m.snap, snapshotOptions{
Width: m.width, Height: m.height, Title: m.cfg.Title, BaseURL: m.cfg.BaseURL,
Scanning: m.scanning, NextScanAt: m.nextScanAt, Now: time.Now(), ScanError: m.scanErr,
})
}