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.
153 lines
3.1 KiB
Go
153 lines
3.1 KiB
Go
package ui
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/charmbracelet/bubbles/key"
|
|
)
|
|
|
|
// HelpModel is the help overlay model.
|
|
type HelpModel struct {
|
|
visible bool
|
|
}
|
|
|
|
// NewHelp creates a new help model.
|
|
func NewHelp() HelpModel {
|
|
return HelpModel{
|
|
visible: false,
|
|
}
|
|
}
|
|
|
|
// Show displays the help overlay.
|
|
func (m *HelpModel) Show() {
|
|
m.visible = true
|
|
}
|
|
|
|
// Hide hides the help overlay.
|
|
func (m *HelpModel) Hide() {
|
|
m.visible = false
|
|
}
|
|
|
|
// Toggle toggles the help overlay visibility.
|
|
func (m *HelpModel) Toggle() {
|
|
m.visible = !m.visible
|
|
}
|
|
|
|
// IsVisible returns true if the help overlay is visible.
|
|
func (m HelpModel) IsVisible() bool {
|
|
return m.visible
|
|
}
|
|
|
|
// Render renders the help overlay.
|
|
func (m HelpModel) Render(keys KeyMap, styles Styles) string {
|
|
if !m.visible {
|
|
return ""
|
|
}
|
|
|
|
var b strings.Builder
|
|
|
|
// Title
|
|
title := styles.HeaderBar.Render("Keybindings - Press ? or esc to close")
|
|
b.WriteString(title)
|
|
b.WriteString("\n\n")
|
|
|
|
// Define keybinding groups
|
|
groups := []struct {
|
|
name string
|
|
binds []keyHelp
|
|
}{
|
|
{
|
|
name: "Global",
|
|
binds: []keyHelp{
|
|
{keys.Help, "Show/hide this help"},
|
|
{keys.Quit, "Quit the application"},
|
|
{keys.RefreshNow, "Refresh data now"},
|
|
},
|
|
},
|
|
{
|
|
name: "Filters",
|
|
binds: []keyHelp{
|
|
{keys.Search, "Search by title/details"},
|
|
{keys.Priority, "Cycle priority filter"},
|
|
{keys.Category, "Cycle category filter"},
|
|
},
|
|
},
|
|
{
|
|
name: "Navigation",
|
|
binds: []keyHelp{
|
|
{keys.FocusNext, "Toggle focus (table/details)"},
|
|
{keys.Sort, "Cycle sort order"},
|
|
{keys.JumpToTop, "Jump to top (g)"},
|
|
{keys.JumpToBottom, "Jump to bottom (G)"},
|
|
{keys.Down, "Move down (j)"},
|
|
{keys.Up, "Move up (k)"},
|
|
},
|
|
},
|
|
{
|
|
name: "Actions",
|
|
binds: []keyHelp{
|
|
{keys.AckToggle, "Acknowledge/unacknowledge issue"},
|
|
{keys.Export, "Export issues to JSON"},
|
|
},
|
|
},
|
|
}
|
|
|
|
// Render each group
|
|
for i, group := range groups {
|
|
if i > 0 {
|
|
b.WriteString("\n")
|
|
}
|
|
|
|
// Group header
|
|
groupTitle := styles.HeaderKey.Render(group.name + ":")
|
|
b.WriteString(groupTitle)
|
|
b.WriteString("\n")
|
|
|
|
// Keybindings in this group
|
|
for _, kb := range group.binds {
|
|
line := renderKeyHelp(kb, styles)
|
|
b.WriteString(line)
|
|
b.WriteString("\n")
|
|
}
|
|
}
|
|
|
|
// Render collector health icon legend
|
|
b.WriteString("\n")
|
|
legendTitle := styles.HeaderKey.Render("Legend:")
|
|
b.WriteString(legendTitle)
|
|
b.WriteString("\n")
|
|
legendText := styles.HeaderVal.Render(" Collector health: ✓ (OK), ⚠ (DEGRADED), ✗ (ERROR)")
|
|
b.WriteString(legendText)
|
|
b.WriteString("\n")
|
|
|
|
return b.String()
|
|
}
|
|
|
|
type keyHelp struct {
|
|
binding key.Binding
|
|
help string
|
|
}
|
|
|
|
func renderKeyHelp(kb keyHelp, styles Styles) string {
|
|
// Get key names from the binding
|
|
keys := kb.binding.Keys()
|
|
if len(keys) == 0 {
|
|
return ""
|
|
}
|
|
|
|
// Format key names
|
|
keyStr := strings.Join(keys, ", ")
|
|
keyStyled := styles.HeaderVal.Render(keyStr)
|
|
|
|
// Format help text
|
|
helpStyled := styles.HeaderVal.Render(kb.help)
|
|
|
|
// Combine with padding
|
|
padding := ""
|
|
if needed := 10 - len(keyStr); needed > 0 {
|
|
padding = strings.Repeat(" ", needed)
|
|
}
|
|
return fmt.Sprintf(" %s%s%s", keyStyled, padding, helpStyled)
|
|
}
|