Add complete TUI application for monitoring Kubernetes clusters and host systems. Features include: Core features: - Collector framework with concurrent scheduling - Host collectors: disk, memory, load, network - Kubernetes collectors: pods, nodes, workloads, events with informers - Issue deduplication, state management, and resolve-after logic - Bubble Tea TUI with table view, details pane, and filtering - JSON export functionality UX improvements: - Help overlay with keybindings - Priority/category filters with visual indicators - Direct priority jump (0/1/2/3) - Bulk acknowledge (Shift+A) - Clipboard copy (y) - Theme toggle (T) - Age format toggle (d) - Wide title toggle (t) - Vi-style navigation (j/k) - Home/End jump (g/G) - Rollup drill-down in details Robustness: - Grace period for unreachable clusters - Rollups for high-volume issues - Flap suppression - RBAC error handling Files: All core application code with tests for host collectors, engine, store, model, and export packages.
123 lines
3.3 KiB
Go
123 lines
3.3 KiB
Go
package ui
|
|
|
|
import "github.com/charmbracelet/lipgloss"
|
|
|
|
// ThemeMode represents the UI theme mode.
|
|
type ThemeMode int
|
|
|
|
const (
|
|
ThemeAuto ThemeMode = iota
|
|
ThemeLight
|
|
ThemeDark
|
|
)
|
|
|
|
// Styles centralizes all lipgloss styling.
|
|
// Keep these simple: excessive styling can slow rendering at high row counts.
|
|
|
|
type Styles struct {
|
|
HeaderBar lipgloss.Style
|
|
HeaderKey lipgloss.Style
|
|
HeaderVal lipgloss.Style
|
|
FilterActive lipgloss.Style
|
|
|
|
TableHeader lipgloss.Style
|
|
TableCell lipgloss.Style
|
|
|
|
P0 lipgloss.Style
|
|
P1 lipgloss.Style
|
|
P2 lipgloss.Style
|
|
P3 lipgloss.Style
|
|
|
|
StateOpen lipgloss.Style
|
|
StateAck lipgloss.Style
|
|
StateRes lipgloss.Style
|
|
|
|
DetailsTitle lipgloss.Style
|
|
DetailsBody lipgloss.Style
|
|
Muted lipgloss.Style
|
|
Error lipgloss.Style
|
|
}
|
|
|
|
// LightTheme returns light theme styles.
|
|
func LightTheme() Styles {
|
|
base := lipgloss.NewStyle()
|
|
muted := base.Foreground(lipgloss.Color("8"))
|
|
|
|
return Styles{
|
|
HeaderBar: base.
|
|
Background(lipgloss.Color("236")).
|
|
Foreground(lipgloss.Color("252")).
|
|
Padding(0, 1),
|
|
HeaderKey: base.Foreground(lipgloss.Color("250")).Bold(true),
|
|
HeaderVal: base.Foreground(lipgloss.Color("254")),
|
|
FilterActive: base.Bold(true).Foreground(lipgloss.Color("46")),
|
|
|
|
TableHeader: base.Foreground(lipgloss.Color("252")).Bold(true),
|
|
TableCell: base.Foreground(lipgloss.Color("252")),
|
|
|
|
P0: base.Foreground(lipgloss.Color("9")).Bold(true),
|
|
P1: base.Foreground(lipgloss.Color("208")).Bold(true),
|
|
P2: base.Foreground(lipgloss.Color("11")),
|
|
P3: base.Foreground(lipgloss.Color("10")),
|
|
|
|
StateOpen: base.Foreground(lipgloss.Color("252")),
|
|
StateAck: base.Foreground(lipgloss.Color("14")),
|
|
StateRes: muted,
|
|
|
|
DetailsTitle: base.Bold(true).Foreground(lipgloss.Color("252")),
|
|
DetailsBody: base.Foreground(lipgloss.Color("252")),
|
|
Muted: muted,
|
|
Error: base.Foreground(lipgloss.Color("9")),
|
|
}
|
|
}
|
|
|
|
// DarkTheme returns dark theme styles with better contrast.
|
|
func DarkTheme() Styles {
|
|
base := lipgloss.NewStyle()
|
|
muted := base.Foreground(lipgloss.Color("245"))
|
|
|
|
return Styles{
|
|
HeaderBar: base.
|
|
Background(lipgloss.Color("238")).
|
|
Foreground(lipgloss.Color("231")).
|
|
Padding(0, 1),
|
|
HeaderKey: base.Foreground(lipgloss.Color("159")).Bold(true),
|
|
HeaderVal: base.Foreground(lipgloss.Color("231")),
|
|
FilterActive: base.Bold(true).Foreground(lipgloss.Color("84")),
|
|
|
|
TableHeader: base.Foreground(lipgloss.Color("231")).Bold(true),
|
|
TableCell: base.Foreground(lipgloss.Color("231")),
|
|
|
|
P0: base.Foreground(lipgloss.Color("203")).Bold(true),
|
|
P1: base.Foreground(lipgloss.Color("229")).Bold(true),
|
|
P2: base.Foreground(lipgloss.Color("48")),
|
|
P3: base.Foreground(lipgloss.Color("42")),
|
|
|
|
StateOpen: base.Foreground(lipgloss.Color("231")),
|
|
StateAck: base.Foreground(lipgloss.Color("48")),
|
|
StateRes: muted,
|
|
|
|
DetailsTitle: base.Bold(true).Foreground(lipgloss.Color("231")),
|
|
DetailsBody: base.Foreground(lipgloss.Color("231")),
|
|
Muted: muted,
|
|
Error: base.Foreground(lipgloss.Color("203")),
|
|
}
|
|
}
|
|
|
|
func defaultStyles() Styles {
|
|
// Default to light theme for backwards compatibility
|
|
return LightTheme()
|
|
}
|
|
|
|
func defaultStylesForMode(themeMode ThemeMode) Styles {
|
|
switch themeMode {
|
|
case ThemeLight:
|
|
return LightTheme()
|
|
case ThemeDark:
|
|
return DarkTheme()
|
|
default:
|
|
// Auto mode defaults to light theme
|
|
return LightTheme()
|
|
}
|
|
}
|