notification

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 30, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package notification owns the notification feature: the scoped SQLite history store (with level migration and retention pruning) and the UI component — the popup, the history/detail overlays, the log-notification queue, and rendering. The UI half has no dependency on the root workbench package; the root shell supplies screen geometry, the store, and the connection scope through the component's methods and events.

Index

Constants

View Source
const Limit = 100

Limit bounds the number of live or loaded notifications retained by the UI.

Variables

View Source
var DismissTick = func(generation uint64, duration time.Duration) tea.Cmd {
	return tea.Tick(duration, func(time.Time) tea.Msg {
		return DismissMsg{Generation: generation}
	})
}

DismissTick builds the command that closes the popup after the given duration. It is a variable so tests can replace it with an immediate dismiss and avoid wall-clock waits.

Functions

func AttachLogProgram

func AttachLogProgram(program *tea.Program)

AttachLogProgram wires the running program into the log notification pipeline so entries logged by async commands surface as popups even when the UI is idle. Call once with the program returned by tea.NewProgram, before program.Run. Attaching nil detaches.

func DrainLogEntries

func DrainLogEntries() []log.Entry

DrainLogEntries returns and clears the queued log entries.

func EnqueueLogEntry

func EnqueueLogEntry(entry log.Entry)

EnqueueLogEntry is the log package notifier: it queues entries for the next Update drain and wakes the attached program so an entry from an async command surfaces even when the UI is idle. Safe for concurrent callers (async Bubble Tea commands). The wakeup is sent on its own goroutine: the program's message channel is unbuffered, so sending from inside an Update handler (where every current log call happens) would deadlock on the loop waiting for that same Update to return.

func NewHistory

func NewHistory(entries []Entry, selectedID int64, width, height int) *history

NewHistory builds the modal. selectedID selects the entry with that SQLite row ID, falling back to the newest entry when 0 or absent.

func SetNerdFont

func SetNerdFont(enabled bool)

SetNerdFont records the resolved nerd-font preference for log icons.

func StoredLogLevel

func StoredLogLevel(level log.Level) int

StoredLogLevel converts a log level to the persisted notification level.

Types

type DismissMsg

type DismissMsg struct {
	Generation uint64
}

DismissMsg closes the visible popup when its generation still matches the model's current one.

type Entry

type Entry struct {
	ID          int64
	CreatedAt   time.Time
	Title       string
	Description string
	Level       int
	// contains filtered or unexported fields
}

Entry is one captured status or log notification. ID is the SQLite row ID when the entry was persisted for a connection scope, 0 otherwise. Level is notificationLevelNone (0) for status messages, or log.Level + 1 for entries captured from the event log.

func LogEntry

func LogEntry(entry log.Entry) Entry

LogEntry builds the captured entry for one logged event, carrying the level's icon, title, and severity.

func StatusEntry

func StatusEntry(text string) Entry

StatusEntry builds the captured-status entry for one status transition. The entry always carries a real severity: routine query lifecycle transitions capture at Debug, every other status captures at Info, so history never stores the neutral level 0 again. (Rows persisted before leveled captures keep level 0 and render neutrally via logLevelOf.)

type LogWakeupMsg

type LogWakeupMsg struct{}

LogWakeupMsg wakes the idle program loop when a log entry arrives from an async command; the outer Update wrapper drains the queue into a popup.

type Model

type Model struct {
	Entries             []Entry
	Popup               *Entry
	Detail              *Entry
	History             *history
	Generation          uint64
	PopupSwallowRelease bool
	// contains filtered or unexported fields
}

Model is the notification feature component: the captured entries, the visible popup, the history/detail overlays, the popup click/release swallow state, and the dismiss generation counter. Root owns the persistence store, the connection scope, and screen geometry; the component owns every interaction and renders its own overlays.

func New

func New() Model

New builds an empty notification component.

func (*Model) ApplyPersisted added in v1.0.0

func (m *Model) ApplyPersisted(token uint64, id int64)

ApplyPersisted attaches a persisted row ID to entries that still carry the matching Show token. Stale completions are deliberately ignored.

func (Model) Consumes

func (m Model) Consumes(msg tea.Msg, layout uikit.Layout) bool

Consumes reports whether msg belongs to the notification overlays: the popup dismiss timer, the popup click and its trailing release, or an open history/detail modal (which swallows every input while open). Root routes the message into Update only when this returns true, so an idle notification state never intercepts messages meant for the panes.

func (Model) DetailOpen

func (m Model) DetailOpen() bool

DetailOpen reports whether the single-entry detail overlay is open.

func (Model) Draw

func (m Model) Draw(canvas uv.ScreenBuffer, layout uikit.Layout)

Draw renders the component's open overlays onto the canvas: the history modal, then the single-entry detail, then the popup last so it stays readable above everything. Root calls Draw from each overlay precedence slot and draws whatever is open.

func (Model) HistoryOpen

func (m Model) HistoryOpen() bool

HistoryOpen reports whether the history modal is open.

func (*Model) OpenHistory

func (m *Model) OpenHistory(selectedID int64, width, height int)

OpenHistory opens the history modal, selecting the entry with the given SQLite row ID (0 or absent falls back to the newest entry).

func (Model) PopupBounds

func (m Model) PopupBounds(layout uikit.Layout) (image.Rectangle, bool)

PopupBounds returns the screen rectangle of the visible popup. The popup is a bordered card anchored to the top-right corner.

func (Model) PopupOpen

func (m Model) PopupOpen() bool

PopupOpen reports whether the popup is visible.

func (*Model) Reset

func (m *Model) Reset()

Reset clears the captured entries and every overlay in place.

func (*Model) ResizeHistory

func (m *Model) ResizeHistory(width, height int)

ResizeHistory refits an open history modal to a new window size.

func (*Model) SetEntries

func (m *Model) SetEntries(entries []Entry)

SetEntries replaces the captured entry list (the scoped history load).

func (Model) Show

func (m Model) Show(entry Entry, persist bool, duration time.Duration) (Model, tea.Cmd, uint64)

Show surfaces one entry as the visible popup. Persistence itself is owned by the root app's asynchronous command; this component only records a token so the eventual row ID can be attached to the still-live entry.

func (Model) Update

func (m Model) Update(msg tea.Msg, layout uikit.Layout, keys uikit.KeyMatcher) (Model, uikit.Event, tea.Cmd)

Update handles the notification messages in the root's precedence order: the popup dismiss timer, the release trailing a popup click, the popup click itself (which opens the history or detail overlay), and the open overlays, which swallow every input while visible. Messages the component does not own pass through unchanged; root routes them only when Consumes reports them.

func (Model) View

func (m Model) View(layout uikit.Layout) string

View renders no pane content: notifications are pure overlays. The root draws them through Draw at its overlay precedence slots.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store is a scoped notification-history database. It owns the SQLite connection and applies the configured retention window when reading or appending entries.

func Open

func Open(path string, retentionDays int) (*Store, error)

Open opens (creating and migrating if needed) the notification database at path. retentionDays is the resolved history window applied on each prune.

func (*Store) Append

func (s *Store) Append(connectionID string, entry Entry, _ int) (int64, error)

Append persists one entry for a connection scope and returns the inserted row ID. It rejects an empty scope so an unscoped row is never written. limit matches the querylog.Store signature; notification history keeps every retained row, so the limit is not applied.

func (*Store) Close

func (s *Store) Close() error

Close releases the underlying database.

func (*Store) Load

func (s *Store) Load(connectionID string, limit int) ([]Entry, error)

Load returns the retained entries for one connection scope, newest first. An empty scope never reads unscoped rows and returns no entries.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL