diff --git a/docs/superpowers/plans/2026-05-14-tui-overhaul.md b/docs/superpowers/plans/2026-05-14-tui-overhaul.md new file mode 100644 index 0000000..cc43768 --- /dev/null +++ b/docs/superpowers/plans/2026-05-14-tui-overhaul.md @@ -0,0 +1,194 @@ +# TUI Overhaul Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Overhaul the GitOpsCTL TUI to a high-density, K9s-inspired dashboard with Vim-style navigation and a pure black dark theme. + +**Architecture:** Component-based refactor of `internal/tui`. Decompose the monolithic model view into specialized renderers for Header, Table, Detail, and Footer. Implement a state machine for view management and a command mode for aliases. + +**Tech Stack:** Go, Bubble Tea, Lipgloss, lipgloss.Table. + +--- + +### Task 1: Update Theme and Styles +**Files:** +- Modify: `/Volumes/Seagate/developer/personal/gitopsctl/internal/tui/styles.go` + +- [ ] **Step 1: Update palette to K9s-Dark (Pure Black)** +```go + bg = lipgloss.Color("#000000") + fg = lipgloss.Color("#FFFFFF") + subtle = lipgloss.Color("#333333") + accent = lipgloss.Color("#00FFFF") // Cyan + green = lipgloss.Color("#00FF00") + red = lipgloss.Color("#FF0000") + yellow = lipgloss.Color("#FFFF00") +``` + +- [ ] **Step 2: Update base styles** +```go + Base = lipgloss.NewStyle().Background(bg).Foreground(fg) + DetailLabel = lipgloss.NewStyle().Foreground(accent).Width(18) +``` + +- [ ] **Step 3: Commit** +```bash +git add internal/tui/styles.go +git commit -m "style: update TUI palette to K9s high-contrast dark" +``` + +### Task 2: Decompose TUI into Components (Header) +**Files:** +- Create: `/Volumes/Seagate/developer/personal/gitopsctl/internal/tui/header.go` + +- [ ] **Step 1: Implement Header component** +```go +package tui + +import ( + "fmt" + "strings" + "github.com/charmbracelet/lipgloss" +) + +func (m Model) renderHeader() string { + logo := HeaderStyle.Render("⎈ GitOpsCTL") + + // Calculate vitals + var synced, drifted, errors int + for _, a := range m.apps { + switch a.Status { + case "Synced": synced++ + case "OutOfSync", "Drifted": drifted++ + case "Error": errors++ + } + } + + vitals := []string{ + kvCyan("APPS", fmt.Sprintf("%d", len(m.apps))), + kvGreen("SYNCED", fmt.Sprintf("%d", synced)), + kvYellow("DRIFTED", fmt.Sprintf("%d", drifted)), + kvRed("ERRORS", fmt.Sprintf("%d", errors)), + kvCyan("CLUSTERS", fmt.Sprintf("%d", len(m.clusters))), + } + + return lipgloss.JoinHorizontal(lipgloss.Top, + logo, + " ", + strings.Join(vitals, " "), + ) +} + +func kvCyan(k, v string) string { return lipgloss.NewStyle().Foreground(accent).Render(k) + ": " + v } +func kvGreen(k, v string) string { return lipgloss.NewStyle().Foreground(accent).Render(k) + ": " + lipgloss.NewStyle().Foreground(green).Render(v) } +func kvYellow(k, v string) string { return lipgloss.NewStyle().Foreground(accent).Render(k) + ": " + lipgloss.NewStyle().Foreground(yellow).Render(v) } +func kvRed(k, v string) string { return lipgloss.NewStyle().Foreground(accent).Render(k) + ": " + lipgloss.NewStyle().Foreground(red).Render(v) } +``` + +- [ ] **Step 2: Commit** +```bash +git add internal/tui/header.go +git commit -m "feat: add TUI header component with vitals" +``` + +### Task 3: Implement Full-Width Table View +**Files:** +- Create: `/Volumes/Seagate/developer/personal/gitopsctl/internal/tui/table.go` +- Modify: `/Volumes/Seagate/developer/personal/gitopsctl/internal/tui/model.go` + +- [ ] **Step 1: Implement Table rendering using lipgloss.Table** +```go +package tui + +import ( + "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/table" +) + +func (m Model) renderTable(width, height int) string { + var rows [][]string + var headers []string + + if m.state == appsView { + headers = []string{"NAME", "STATUS", "HEALTH", "REPO", "LAST SYNC"} + for i, a := range m.filteredApps() { + row := []string{a.Name, a.Status, "Healthy", a.RepoURL, "2m ago"} // Simplified for now + rows = append(rows, row) + } + } else { + headers = []string{"NAME", "STATUS", "VERSION", "KUBECONFIG"} + for i, c := range m.filteredClusters() { + row := []string{c.Name, c.Status, "v1.28.0", c.KubeconfigPath} + rows = append(rows, row) + } + } + + t := table.New(). + Border(lipgloss.NormalBorder()). + BorderStyle(lipgloss.NewStyle().Foreground(subtle)). + Headers(headers...). + Rows(rows...). + Width(width) + + return t.Render() +} +``` + +- [ ] **Step 2: Commit** +```bash +git add internal/tui/table.go +git commit -m "feat: implement full-width table view" +``` + +### Task 4: Advanced Vim Navigation and Command Mode +**Files:** +- Modify: `/Volumes/Seagate/developer/personal/gitopsctl/internal/tui/model.go` + +- [ ] **Step 1: Add command mode state to Model struct** +```go +type Model struct { + // ... existing ... + commandText string + commandMode bool // active when ':' is pressed +} +``` + +- [ ] **Step 2: Update Update() to handle gg, G, and : commands** +```go +case "g": + // Check for double 'g' + // ... logic ... +case "G": + if m.state == appsView { m.appCursor = len(m.filteredApps()) - 1 } +case ":": + m.commandMode = true + m.commandText = "" +``` + +- [ ] **Step 3: Commit** +```bash +git add internal/tui/model.go +git commit -m "feat: add advanced Vim keys and command mode" +``` + +### Task 5: Finalize Footer and Activity View +**Files:** +- Create: `/Volumes/Seagate/developer/personal/gitopsctl/internal/tui/footer.go` + +- [ ] **Step 1: Implement Footer with Command Line** +```go +func (m Model) renderFooter() string { + if m.commandMode { + return lipgloss.NewStyle().Foreground(green).Render(": " + m.commandText + "█") + } + // Render keybindings + return HelpDesc.Render("? Help :a Apps :c Clusters / Filter d Delete") +} +``` + +- [ ] **Step 2: Integrate everything into View()** +- [ ] **Step 3: Commit** +```bash +git add internal/tui/ +git commit -m "feat: finalize TUI overhaul" +``` diff --git a/docs/superpowers/specs/2026-05-14-tui-enhancement-design.md b/docs/superpowers/specs/2026-05-14-tui-enhancement-design.md new file mode 100644 index 0000000..6fcb3c5 --- /dev/null +++ b/docs/superpowers/specs/2026-05-14-tui-enhancement-design.md @@ -0,0 +1,80 @@ +# Design Spec: K9s-Inspired TUI Enhancement for GitOpsCTL + +## 1. Overview +Enhance the GitOpsCTL Terminal User Interface (TUI) to provide a high-density, high-contrast, and keyboard-driven experience inspired by K9s. The goal is to move from a basic split-screen dashboard to a professional, full-width resource management tool with advanced Vim capabilities. + +## 2. UI Architecture +The TUI will be reorganized into a three-tier layout: + +### 2.1 Header (Vitals) +- **Background**: Pure Black (`#000000`). +- **Content**: + - Left: App Name and Version. + - Right: "Vitals" block with live counts: + - `APPS`: Total number of applications. + - `SYNCED`: Count of apps in 'Synced' state (Green). + - `DRIFTED`: Count of apps in 'Drifted' or 'OutOfSync' state (Yellow). + - `ERRORS`: Count of apps in 'Error' state (Red). + - `CLUSTERS`: Total number of registered clusters. +- **Style**: High-contrast labels (Cyan) and values (White/Colored). + +### 2.2 Main View (Resource Table) +- **Layout**: Full-width table using `lipgloss.Table`. +- **Modes**: + - **Applications View**: Columns: `NAME`, `STATUS`, `HEALTH`, `REPO`, `BRANCH`, `LAST SYNC`. + - **Clusters View**: Columns: `NAME`, `STATUS`, `VERSION`, `KUBECONFIG`, `LAST CHECKED`. + - **Activity View**: Full-width log stream. + - **Detail View**: Full-page drill-down for a specific app or cluster (triggered by `Enter`). + +### 2.3 Footer (Command & Shortcuts) +- **Command Line**: Prefix `:` with an active cursor. Used for view switching and commands. +- **Shortcuts Bar**: Quick reference for context-sensitive keys (e.g., `? Help`, `s Sync`, `d Delete`). + +## 3. Navigation & Interaction (Vim-Style) +- **Movement**: + - `j`/`k`: Move selection down/up. + - `gg`: Jump to top of the list. + - `G`: Jump to bottom of the list. + - `ctrl+u`/`ctrl+d`: Page up/down. +- **Views & Commands**: + - `:a`: Switch to Applications view. + - `:c`: Switch to Clusters view. + - `:l`: Switch to Activity view. + - `/`: Enter filter mode (live search). + - `Enter`: Open Detail View for the selected resource. + - `Esc`: Back to previous view or clear filter/command. +- **Actions**: + - `s`: Trigger 'Sync' for the selected application. + - `c`: Trigger 'Health Check' for the selected cluster. + - `d`: Trigger 'Unregister' with a `y/n` confirmation. + - `a`: Trigger 'Approve' for manual sync apps. + +## 4. Theme (K9s-Dark) +- **Palette**: + - `BG`: `#000000` (Pure Black) + - `FG`: `#FFFFFF` (White) + - `Label`: `#00FFFF` (Cyan) + - `Border`: `#333333` (Dark Grey) + - `Selection`: `#7C6AF7` (Violet background or bold border) + - `Success`: `#00FF00` (Green) + - `Error`: `#FF0000` (Red) + - `Warning`: `#FFFF00` (Yellow) + +## 5. Technical Implementation +- **Framework**: Bubble Tea with Lipgloss. +- **Components**: Decompose `internal/tui/model.go` logic into smaller functional units: + - `Header`: Renders the vitals. + - `Table`: Generic table component for resources. + - `Detail`: Detail page renderer. + - `Command`: Command line handler. +- **State Management**: + - Track `activeView` (apps, clusters, logs, detail). + - Track `commandMode` (idle, command, filter). + - Use a `cursor` index for each view to preserve position when switching. + +## 6. Success Criteria +- [ ] User can switch between apps and clusters using `:a` and `:c`. +- [ ] Vim keys (`gg`, `G`, `j`, `k`) work as expected in list views. +- [ ] The theme is pure black with high-contrast colored text. +- [ ] 'Enter' drills down into a full-page detail view. +- [ ] All existing actions (Sync, Unregister) are accessible via the new interface.