Documentation
¶
Overview ¶
Package panels contains the eight read-only panels rendered by the TUI. Each panel is a self-contained bubbletea sub-model that renders against the shared state owned by the root model.
Index ¶
- func Emit(r state.WriteRequest) tea.Cmd
- func EmitSystemDetail(name string) tea.Cmd
- func EmitTalkgroupDetail(id uint32) tea.Cmd
- func RefreshTheme()
- type ActivePanel
- func (p *ActivePanel) HandleMouse(msg tea.MouseMsg, localY int) tea.Cmd
- func (ActivePanel) Keys() []key.Binding
- func (ActivePanel) Title() string
- func (p *ActivePanel) Update(msg tea.Msg, s *state.SharedState) (Panel, tea.Cmd)
- func (p *ActivePanel) View(width, height int, focused bool, s *state.SharedState) string
- type DashboardPanel
- type DevicesPanel
- func (p *DevicesPanel) HandleMouse(msg tea.MouseMsg, localY int) tea.Cmd
- func (DevicesPanel) Keys() []key.Binding
- func (p *DevicesPanel) Reveal(key string)
- func (DevicesPanel) Title() string
- func (p *DevicesPanel) Update(msg tea.Msg, s *state.SharedState) (Panel, tea.Cmd)
- func (p *DevicesPanel) View(width, height int, focused bool, s *state.SharedState) string
- type EventsPanel
- type HistoryPanel
- func (p *HistoryPanel) HandleMouse(msg tea.MouseMsg, localY int) tea.Cmd
- func (HistoryPanel) Keys() []key.Binding
- func (p *HistoryPanel) ReloadRequested() bool
- func (HistoryPanel) Title() string
- func (p *HistoryPanel) Update(msg tea.Msg, s *state.SharedState) (Panel, tea.Cmd)
- func (p *HistoryPanel) View(width, height int, focused bool, s *state.SharedState) string
- type HistoryRefreshedMsg
- type HuntPanel
- type ImportCommitMsg
- type ImportDiscardMsg
- type ImportPanel
- type ImportPreviewArrivedMsg
- type ImportResultArrivedMsg
- type ImportUploadMsg
- type MetricsPanel
- func (p *MetricsPanel) HandleMouse(msg tea.MouseMsg, localY int) tea.Cmd
- func (MetricsPanel) Keys() []key.Binding
- func (MetricsPanel) Title() string
- func (p *MetricsPanel) Update(msg tea.Msg, s *state.SharedState) (Panel, tea.Cmd)
- func (p *MetricsPanel) View(width, height int, focused bool, s *state.SharedState) string
- type MouseAware
- type Panel
- type Revealer
- type ScannerPanel
- type SettingsErrorMsg
- type SettingsPanel
- type SystemDetailMsg
- type SystemsPanel
- func (p *SystemsPanel) Cursor() int
- func (p *SystemsPanel) HandleMouse(msg tea.MouseMsg, localY int) tea.Cmd
- func (SystemsPanel) Keys() []key.Binding
- func (p *SystemsPanel) Reveal(key string)
- func (SystemsPanel) Title() string
- func (p *SystemsPanel) Update(msg tea.Msg, s *state.SharedState) (Panel, tea.Cmd)
- func (p *SystemsPanel) View(width, height int, focused bool, s *state.SharedState) string
- type TalkgroupDetailMsg
- type TalkgroupsPanel
- func (p *TalkgroupsPanel) FilterValue() string
- func (p *TalkgroupsPanel) HandleMouse(msg tea.MouseMsg, localY int) tea.Cmd
- func (TalkgroupsPanel) Keys() []key.Binding
- func (p *TalkgroupsPanel) Reveal(key string)
- func (p *TalkgroupsPanel) RowCount() int
- func (p *TalkgroupsPanel) SetFilterValue(v string)
- func (TalkgroupsPanel) Title() string
- func (p *TalkgroupsPanel) Update(msg tea.Msg, s *state.SharedState) (Panel, tea.Cmd)
- func (p *TalkgroupsPanel) View(width, height int, focused bool, s *state.SharedState) string
- type ThemeChangedMsg
- type TonesPanel
- func (p *TonesPanel) HandleMouse(msg tea.MouseMsg, localY int) tea.Cmd
- func (TonesPanel) Keys() []key.Binding
- func (TonesPanel) Title() string
- func (p *TonesPanel) Update(msg tea.Msg, s *state.SharedState) (Panel, tea.Cmd)
- func (p *TonesPanel) View(width, height int, focused bool, s *state.SharedState) string
- type WriteActionMsg
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Emit ¶
func Emit(r state.WriteRequest) tea.Cmd
Emit returns a tea.Cmd that delivers the WriteActionMsg to the root model.
func EmitSystemDetail ¶
EmitSystemDetail returns a Cmd delivering a SystemDetailMsg.
func EmitTalkgroupDetail ¶
EmitTalkgroupDetail returns a Cmd delivering a TalkgroupDetailMsg.
func RefreshTheme ¶
func RefreshTheme()
RefreshTheme rebuilds the package-level styles from the active theme.Theme(). Safe to call any time; mutates module-level vars so don't call concurrently with a render.
Types ¶
type ActivePanel ¶
type ActivePanel struct {
// contains filtered or unexported fields
}
ActivePanel renders calls currently being followed.
func NewActive ¶
func NewActive() *ActivePanel
func (*ActivePanel) HandleMouse ¶
HandleMouse moves the cursor on a left-click and forwards wheel ticks. After picking a row the `e` keybind ends that call.
func (ActivePanel) Keys ¶
func (ActivePanel) Keys() []key.Binding
func (ActivePanel) Title ¶
func (ActivePanel) Title() string
func (*ActivePanel) Update ¶
func (p *ActivePanel) Update(msg tea.Msg, s *state.SharedState) (Panel, tea.Cmd)
func (*ActivePanel) View ¶
func (p *ActivePanel) View(width, height int, focused bool, s *state.SharedState) string
type DashboardPanel ¶
type DashboardPanel struct{}
DashboardPanel is the at-a-glance landing screen. It is a pure renderer over SharedState; it owns no local state.
func NewDashboard ¶
func NewDashboard() *DashboardPanel
NewDashboard returns the default landing panel.
func (DashboardPanel) Keys ¶
func (DashboardPanel) Keys() []key.Binding
func (DashboardPanel) Title ¶
func (DashboardPanel) Title() string
func (*DashboardPanel) Update ¶
func (p *DashboardPanel) Update(_ tea.Msg, _ *state.SharedState) (Panel, tea.Cmd)
func (*DashboardPanel) View ¶
func (p *DashboardPanel) View(width, height int, _ bool, s *state.SharedState) string
type DevicesPanel ¶
type DevicesPanel struct {
// contains filtered or unexported fields
}
DevicesPanel renders the SDR pool snapshot — every dongle the daemon has opened, with role / tuner / configured gain / PPM / bias-tee state.
func NewDevices ¶
func NewDevices() *DevicesPanel
func (*DevicesPanel) HandleMouse ¶
HandleMouse moves the cursor on a left-click and forwards wheel ticks.
func (DevicesPanel) Keys ¶
func (DevicesPanel) Keys() []key.Binding
func (*DevicesPanel) Reveal ¶
func (p *DevicesPanel) Reveal(key string)
Reveal positions the cursor on the row whose Serial matches key.
func (DevicesPanel) Title ¶
func (DevicesPanel) Title() string
func (*DevicesPanel) Update ¶
func (p *DevicesPanel) Update(msg tea.Msg, s *state.SharedState) (Panel, tea.Cmd)
func (*DevicesPanel) View ¶
func (p *DevicesPanel) View(width, height int, focused bool, s *state.SharedState) string
type EventsPanel ¶
type EventsPanel struct {
// contains filtered or unexported fields
}
EventsPanel renders the rolling SSE event log.
func NewEvents ¶
func NewEvents() *EventsPanel
func (EventsPanel) Keys ¶
func (EventsPanel) Keys() []key.Binding
func (EventsPanel) Title ¶
func (EventsPanel) Title() string
func (*EventsPanel) Update ¶
func (p *EventsPanel) Update(msg tea.Msg, s *state.SharedState) (Panel, tea.Cmd)
func (*EventsPanel) View ¶
func (p *EventsPanel) View(width, height int, focused bool, s *state.SharedState) string
type HistoryPanel ¶
type HistoryPanel struct {
// contains filtered or unexported fields
}
HistoryPanel renders ended calls from /api/v1/calls/history.
Loading is on-demand: the root model issues the initial fetch when this panel becomes active and again when the user presses `r`. The panel does not poll continuously — history is a stable list and the daemon already paginates it.
Refresh is asynchronous: when the SharedState hash for History changes, Update returns a tea.Cmd that builds the new []table.Row slice off the Update goroutine. The result arrives back as a HistoryRefreshedMsg and is committed only when its hash still matches the latest snapshot — newer results win.
func (*HistoryPanel) HandleMouse ¶
HandleMouse moves the cursor on a left-click and forwards wheel ticks. History is read-only — the cursor just controls which row is highlighted.
func (HistoryPanel) Keys ¶
func (HistoryPanel) Keys() []key.Binding
func (*HistoryPanel) ReloadRequested ¶
func (p *HistoryPanel) ReloadRequested() bool
ReloadRequested returns true when the user pressed `r` since the last call. The root model checks this each Update and issues the reload Cmd as needed.
func (HistoryPanel) Title ¶
func (HistoryPanel) Title() string
func (*HistoryPanel) Update ¶
func (p *HistoryPanel) Update(msg tea.Msg, s *state.SharedState) (Panel, tea.Cmd)
func (*HistoryPanel) View ¶
func (p *HistoryPanel) View(width, height int, focused bool, s *state.SharedState) string
type HistoryRefreshedMsg ¶
HistoryRefreshedMsg carries the result of an async refresh job. Exported so the root model can route it to the history panel.
type HuntPanel ¶ added in v0.3.5
type HuntPanel struct {
// contains filtered or unexported fields
}
HuntPanel renders the live system-discovery ("hunt") run — its state, sweep/ identify progress, and the discovered system summary — and lets the operator start a run (bands to sweep + an optional name) or stop the active one.
type ImportCommitMsg ¶ added in v0.1.5
ImportCommitMsg is emitted when the operator presses 'c' on the Preview view.
type ImportDiscardMsg ¶ added in v0.1.5
type ImportDiscardMsg struct {
ID string
}
ImportDiscardMsg is emitted when the operator presses 'd' on the Preview view.
type ImportPanel ¶ added in v0.1.5
type ImportPanel struct {
// contains filtered or unexported fields
}
ImportPanel is the live-import cockpit. Three views:
- Stage — operator adds local file paths via a textinput; pressing 'u' uploads them to the daemon and we transition to Preview.
- Preview — table of parsed systems returned by the daemon; 'c' commits, 'd' discards, esc returns to Stage.
- Result — list of systems_added / systems_replaced; esc returns to Stage.
func NewImport ¶ added in v0.1.5
func NewImport() *ImportPanel
NewImport returns a fresh import panel.
func (*ImportPanel) Keys ¶ added in v0.1.5
func (*ImportPanel) Keys() []key.Binding
func (*ImportPanel) Title ¶ added in v0.1.5
func (*ImportPanel) Title() string
func (*ImportPanel) Update ¶ added in v0.1.5
func (p *ImportPanel) Update(msg tea.Msg, shared *state.SharedState) (Panel, tea.Cmd)
func (*ImportPanel) View ¶ added in v0.1.5
func (p *ImportPanel) View(width, height int, focused bool, shared *state.SharedState) string
type ImportPreviewArrivedMsg ¶ added in v0.1.5
type ImportPreviewArrivedMsg struct {
Preview client.ImportPreview
Err error
}
ImportPreviewArrivedMsg is consumed by the panel when the root model has received the staging response.
type ImportResultArrivedMsg ¶ added in v0.1.5
type ImportResultArrivedMsg struct {
Result client.ImportResult
Err error
}
ImportResultArrivedMsg is consumed by the panel when a commit finishes.
type ImportUploadMsg ¶ added in v0.1.5
type ImportUploadMsg struct {
Paths []string
}
ImportUploadMsg is emitted when the operator has confirmed an upload via 'u'. The root model resolves it into an HTTP call.
type MetricsPanel ¶
type MetricsPanel struct {
// contains filtered or unexported fields
}
MetricsPanel surfaces a curated subset of /metrics. Showing every Prometheus series produced by the daemon would be noisy; this whitelist captures the headline counters operators usually care about.
func NewMetrics ¶
func NewMetrics() *MetricsPanel
func (*MetricsPanel) HandleMouse ¶
HandleMouse moves the cursor on a left-click and forwards wheel ticks. Metrics rows aren't actionable; the cursor is purely for keyboard navigation.
func (MetricsPanel) Keys ¶
func (MetricsPanel) Keys() []key.Binding
func (MetricsPanel) Title ¶
func (MetricsPanel) Title() string
func (*MetricsPanel) Update ¶
func (p *MetricsPanel) Update(msg tea.Msg, s *state.SharedState) (Panel, tea.Cmd)
func (*MetricsPanel) View ¶
func (p *MetricsPanel) View(width, height int, focused bool, s *state.SharedState) string
type MouseAware ¶
MouseAware is an optional interface for panels that want to react to mouse events inside their body. localY is the row offset relative to the panel's top-left (0 = panel border row); msg carries the full bubbletea mouse payload so the panel can distinguish a left-click on a data row (move cursor) from a scroll-wheel tick (advance one row) from a button release (no-op). Returning a tea.Cmd is permitted but most implementations will return nil.
type Panel ¶
type Panel interface {
Title() string
Keys() []key.Binding
Update(msg tea.Msg, shared *state.SharedState) (Panel, tea.Cmd)
View(width, height int, focused bool, shared *state.SharedState) string
}
Panel is the contract every visible panel implements. Update may return a replacement Panel — bubbletea's Elm-style "return next state" pattern. Panels never call the network; they read from shared state populated by the root model's polling Cmds.
type Revealer ¶
type Revealer interface {
Reveal(key string)
}
Revealer is an optional interface for panels that can pre-position their internal cursor on a specific row when the operator jumps in from the command palette. key is panel-defined: SystemsPanel takes a system name, TalkgroupsPanel a decimal ID, DevicesPanel a serial, ScannerPanel "sys:<name>" or "conv:<idx>".
type ScannerPanel ¶
type ScannerPanel struct {
// contains filtered or unexported fields
}
ScannerPanel is the police-scanner cockpit. Renders three sections:
- Systems (trunked) — per-system CC hunt state + last grant.
- Conventional — fixed-frequency analog channels + current dwell.
- TG scan summary — global scan_mode + scan-list size.
Operator mutations (hold / resume / retune / dwell / cycle scan mode) ride the existing WriteRequest machinery so the daemon's allow_mutations gate + the TUI's --write flag govern them.
func NewScanner ¶
func NewScanner() *ScannerPanel
NewScanner returns a new read+write scanner cockpit.
func (ScannerPanel) Keys ¶
func (ScannerPanel) Keys() []key.Binding
func (*ScannerPanel) Reveal ¶
func (p *ScannerPanel) Reveal(key string)
Reveal pre-positions the scanner's virtual cursor on a system or conventional channel. key forms:
"sys:<name>" — trunked system by name "conv:<index>" — conventional channel by zero-based index
The actual cursor index can't be computed until we see SharedState, so we stash the request and resolve it on the next Update tick.
func (ScannerPanel) Title ¶
func (ScannerPanel) Title() string
func (*ScannerPanel) Update ¶
func (p *ScannerPanel) Update(msg tea.Msg, s *state.SharedState) (Panel, tea.Cmd)
func (*ScannerPanel) View ¶
func (p *ScannerPanel) View(width, height int, focused bool, s *state.SharedState) string
type SettingsErrorMsg ¶ added in v0.1.5
SettingsErrorMsg is dispatched by the root model when a Settings PATCH comes back with an error (validation failure, 503, etc.). The panel re-opens the editor on the failing row and surfaces the message inline so the operator can correct without re-navigating.
type SettingsPanel ¶
type SettingsPanel struct {
// contains filtered or unexported fields
}
SettingsPanel is the tabbed inspector that surfaces every config knob, output, protocol surface, and runtime fact. Driven by SharedState.Runtime; one /api/v1/runtime poll feeds every tab so the operator sees a coherent snapshot.
func NewSettings ¶
func NewSettings() *SettingsPanel
func (SettingsPanel) Keys ¶
func (SettingsPanel) Keys() []key.Binding
func (SettingsPanel) Title ¶
func (SettingsPanel) Title() string
func (*SettingsPanel) Update ¶
func (p *SettingsPanel) Update(msg tea.Msg, s *state.SharedState) (Panel, tea.Cmd)
func (*SettingsPanel) View ¶
func (p *SettingsPanel) View(width, height int, focused bool, s *state.SharedState) string
type SystemDetailMsg ¶
type SystemDetailMsg struct{ Name string }
SystemDetailMsg is emitted by the Systems panel when the operator presses Enter on a row. The root model fetches the detail record via GET /api/v1/systems/{name} and renders a read-only modal.
type SystemsPanel ¶
type SystemsPanel struct {
// contains filtered or unexported fields
}
SystemsPanel renders the configured trunking systems.
func NewSystems ¶
func NewSystems() *SystemsPanel
func (*SystemsPanel) Cursor ¶
func (p *SystemsPanel) Cursor() int
Cursor exposes the current table cursor index for tests.
func (*SystemsPanel) HandleMouse ¶
HandleMouse moves the cursor on a left-click and forwards wheel ticks. Chrome clicks are ignored.
func (SystemsPanel) Keys ¶
func (SystemsPanel) Keys() []key.Binding
func (*SystemsPanel) Reveal ¶
func (p *SystemsPanel) Reveal(key string)
Reveal positions the cursor on the row whose Name matches the given key. No-op when the row is absent; the operator still ends up on the panel.
func (SystemsPanel) Title ¶
func (SystemsPanel) Title() string
func (*SystemsPanel) Update ¶
func (p *SystemsPanel) Update(msg tea.Msg, s *state.SharedState) (Panel, tea.Cmd)
func (*SystemsPanel) View ¶
func (p *SystemsPanel) View(width, height int, focused bool, s *state.SharedState) string
type TalkgroupDetailMsg ¶
type TalkgroupDetailMsg struct{ ID uint32 }
TalkgroupDetailMsg is emitted by the Talkgroups panel when the operator presses Enter on a row.
type TalkgroupsPanel ¶
type TalkgroupsPanel struct {
// contains filtered or unexported fields
}
TalkgroupsPanel renders all configured talkgroups with a substring filter and sort cycle.
func NewTalkgroups ¶
func NewTalkgroups() *TalkgroupsPanel
func (*TalkgroupsPanel) FilterValue ¶
func (p *TalkgroupsPanel) FilterValue() string
FilterValue exposes the current filter for testing.
func (*TalkgroupsPanel) HandleMouse ¶
HandleMouse moves the cursor on a left-click and forwards wheel ticks. The first body line is reserved for the filter input + sort summary, so chromeRows == 1.
func (TalkgroupsPanel) Keys ¶
func (TalkgroupsPanel) Keys() []key.Binding
func (*TalkgroupsPanel) Reveal ¶
func (p *TalkgroupsPanel) Reveal(key string)
Reveal positions the cursor on the row whose ID (decimal string in the first column) matches key. Used by the command palette to land the operator on the talkgroup they searched for.
func (*TalkgroupsPanel) RowCount ¶
func (p *TalkgroupsPanel) RowCount() int
RowCount returns the number of rows currently in the table.
func (*TalkgroupsPanel) SetFilterValue ¶
func (p *TalkgroupsPanel) SetFilterValue(v string)
SetFilterValue sets the filter from a test harness without keystroke simulation.
func (TalkgroupsPanel) Title ¶
func (TalkgroupsPanel) Title() string
func (*TalkgroupsPanel) Update ¶
func (p *TalkgroupsPanel) Update(msg tea.Msg, s *state.SharedState) (Panel, tea.Cmd)
func (*TalkgroupsPanel) View ¶
func (p *TalkgroupsPanel) View(width, height int, focused bool, s *state.SharedState) string
type ThemeChangedMsg ¶
type ThemeChangedMsg struct{}
ThemeChangedMsg is broadcast by the root model after a palette swap. Panels that cache lipgloss styles (chiefly the bubbles/table-backed ones, which call SetStyles in their constructor) handle it by re-applying tableStyles() so the new palette takes effect on the next render. Read-only panels that fetch theme.Theme() on every View() can ignore it.
type TonesPanel ¶
type TonesPanel struct {
// contains filtered or unexported fields
}
TonesPanel renders the tone-alert ring buffer.
func NewTones ¶
func NewTones() *TonesPanel
func (*TonesPanel) HandleMouse ¶
HandleMouse moves the cursor on a left-click and forwards wheel ticks. After picking a row the `R` keybind resets that device's tone-detector.
func (TonesPanel) Keys ¶
func (TonesPanel) Keys() []key.Binding
func (TonesPanel) Title ¶
func (TonesPanel) Title() string
func (*TonesPanel) Update ¶
func (p *TonesPanel) Update(msg tea.Msg, s *state.SharedState) (Panel, tea.Cmd)
func (*TonesPanel) View ¶
func (p *TonesPanel) View(width, height int, focused bool, s *state.SharedState) string
type WriteActionMsg ¶
type WriteActionMsg struct{ Request state.WriteRequest }
WriteActionMsg is what panels emit to ask the root model to run a mutation. The root catches this exact type, so panels stay decoupled from the root's modal mechanics and HTTP client.
Exported so tests in other packages can assert on it; intended to be opaque to consumers.