Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 194 additions & 0 deletions docs/superpowers/plans/2026-05-14-tui-overhaul.md
Original file line number Diff line number Diff line change
@@ -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"
```
80 changes: 80 additions & 0 deletions docs/superpowers/specs/2026-05-14-tui-enhancement-design.md
Original file line number Diff line number Diff line change
@@ -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.
Loading