mirror of
https://github.com/lukaszraczylo/kportal.git
synced 2026-10-12 04:35:10 +00:00
refactor(ui): migrate to bubbletea v2 and lipgloss v2
Switch imports to charm.land/bubbletea/v2 and charm.land/lipgloss/v2. View now returns tea.View with AltScreen set, key handling uses KeyPressMsg, and colour fields use image/color.
This commit is contained in:
@@ -3,8 +3,8 @@ module github.com/lukaszraczylo/kportal
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
github.com/charmbracelet/bubbletea v1.3.10
|
||||
github.com/charmbracelet/lipgloss v1.1.0
|
||||
charm.land/bubbletea/v2 v2.0.10
|
||||
charm.land/lipgloss/v2 v2.0.6
|
||||
github.com/fsnotify/fsnotify v1.10.1
|
||||
github.com/go-logr/logr v1.4.4
|
||||
github.com/grandcat/zeroconf v1.0.0
|
||||
@@ -18,17 +18,17 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
|
||||
github.com/charmbracelet/colorprofile v0.4.3 // indirect
|
||||
github.com/charmbracelet/ultraviolet v0.0.0-20260811164956-006e29f97886 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.11.8 // indirect
|
||||
github.com/charmbracelet/x/cellbuf v0.0.15 // indirect
|
||||
github.com/charmbracelet/x/term v0.2.2 // indirect
|
||||
github.com/charmbracelet/x/termios v0.1.1 // indirect
|
||||
github.com/charmbracelet/x/windows v0.2.2 // indirect
|
||||
github.com/clipperhouse/displaywidth v0.11.0 // indirect
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.4 // indirect
|
||||
github.com/go-openapi/jsonpointer v1.0.2 // indirect
|
||||
github.com/go-openapi/jsonreference v1.0.3 // indirect
|
||||
@@ -49,16 +49,12 @@ require (
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.4.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.24 // indirect
|
||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.30 // indirect
|
||||
github.com/miekg/dns v1.1.73 // indirect
|
||||
github.com/moby/spdystream v0.5.1 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||
github.com/muesli/termenv v0.16.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/spf13/pflag v1.0.10 // indirect
|
||||
@@ -68,6 +64,7 @@ require (
|
||||
go.yaml.in/yaml/v3 v3.0.5 // indirect
|
||||
golang.org/x/net v0.59.0 // indirect
|
||||
golang.org/x/oauth2 v0.37.0 // indirect
|
||||
golang.org/x/sync v0.23.0 // indirect
|
||||
golang.org/x/sys v0.48.0 // indirect
|
||||
golang.org/x/term v0.46.0 // indirect
|
||||
golang.org/x/text v0.42.0 // indirect
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
charm.land/bubbletea/v2 v2.0.10 h1:oolvo20VBpI0PfqE7iFjkZ1bx0WpmXGfnKz5Yldjq5o=
|
||||
charm.land/bubbletea/v2 v2.0.10/go.mod h1:QOatcnhOjYIfxzUSTz6raF7Ex4R/rIuHa3SnBdCCpMc=
|
||||
charm.land/lipgloss/v2 v2.0.6 h1:EaGKeuA8FvF+v2BT5VmZd2LoYLaMZJXA5n34th8nCIQ=
|
||||
charm.land/lipgloss/v2 v2.0.6/go.mod h1:ipDDJNSGa1hlwDtSfW1s2/xR8Vdhbut4PXh2zEKZd0Q=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
|
||||
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
|
||||
github.com/aymanbagabas/go-udiff v0.4.1 h1:OEIrQ8maEeDBXQDoGCbbTTXYJMYRCRO1fnodZ12Gv5o=
|
||||
github.com/aymanbagabas/go-udiff v0.4.1/go.mod h1:0L9PGwj20lrtmEMeyw4WKJ/TMyDtvAoK9bf2u/mNo3w=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
|
||||
github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
|
||||
github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q=
|
||||
github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q=
|
||||
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
|
||||
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
|
||||
github.com/charmbracelet/ultraviolet v0.0.0-20260811164956-006e29f97886 h1:rdnVWKgJpTVXKuKuJyxDJ+NFJdUaUqGvyGy61OcvlbA=
|
||||
github.com/charmbracelet/ultraviolet v0.0.0-20260811164956-006e29f97886/go.mod h1:nAw0d9PhFp1qdzi2xhQU5YOu5sVpDIHWlaW2Uz/bCro=
|
||||
github.com/charmbracelet/x/ansi v0.11.8 h1:JMFwp0CgDC2+jcOB162HH5k7I3FVbgFSMMYg7dSPBQQ=
|
||||
github.com/charmbracelet/x/ansi v0.11.8/go.mod h1:ZNN+3mXny/516oTQPLMPIBeSINvNJJQ8uQXDgbeJxY0=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.15 h1:ur3pZy0o6z/R7EylET877CBxaiE1Sp1GMxoFPAIztPI=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.15/go.mod h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a h1:G99klV19u0QnhiizODirwVksQB91TJKV/UaTnACcG30=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I=
|
||||
github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
|
||||
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
|
||||
github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY=
|
||||
github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo=
|
||||
github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2/jYn2GuM=
|
||||
github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k=
|
||||
github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8=
|
||||
github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
|
||||
@@ -30,8 +32,6 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
|
||||
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
||||
github.com/fxamacker/cbor/v2 v2.9.4 h1:xwjVlxEMR3S605oUlgBjKLTTeGFciYPGYCtF/35LKGo=
|
||||
@@ -93,10 +93,6 @@ github.com/lucasb-eyer/go-colorful v1.4.1 h1:1EO+WB73+EH8EVbzlrG3KLAfEypQWVHIBql
|
||||
github.com/lucasb-eyer/go-colorful v1.4.1/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/lukaszraczylo/oss-telemetry v0.2.5 h1:W6Qgwp7IY4yBRO361MmnEAmM59motdQpbAFAx8v6fJM=
|
||||
github.com/lukaszraczylo/oss-telemetry v0.2.5/go.mod h1:+Cn78qZo8rc3T9eZt0v3oICYRdd75wORtSidc8lNjDQ=
|
||||
github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI=
|
||||
github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A=
|
||||
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
||||
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||
github.com/mattn/go-runewidth v0.0.30 h1:+KUuiDA4fF0R1p5FeueHefjDm+GIM+kWfFnDjybOPgk=
|
||||
github.com/mattn/go-runewidth v0.0.30/go.mod h1:3qAiGCV4Koz/yuveO58qUefmUTRm8r0IGEXZ9jeHp/8=
|
||||
github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
@@ -110,12 +106,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
|
||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
||||
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
|
||||
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
@@ -160,7 +152,6 @@ golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
|
||||
golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
|
||||
golang.org/x/term v0.46.0 h1:3+OXuTbaKDgwk8jTi3aSLHRlmWqHEUDUtxnbFigO4YE=
|
||||
|
||||
+22
-15
@@ -21,13 +21,14 @@ package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
"log"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/charmbracelet/lipgloss/table"
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"charm.land/lipgloss/v2"
|
||||
"charm.land/lipgloss/v2/table"
|
||||
"github.com/lukaszraczylo/kportal/internal/config"
|
||||
"github.com/lukaszraczylo/kportal/internal/k8s"
|
||||
)
|
||||
@@ -173,7 +174,7 @@ func (ui *BubbleTeaUI) SetUpdateAvailable(version, url string) {
|
||||
// Start starts the bubbletea application
|
||||
func (ui *BubbleTeaUI) Start() error {
|
||||
m := model{ui: ui}
|
||||
ui.program = tea.NewProgram(m, tea.WithAltScreen())
|
||||
ui.program = tea.NewProgram(m)
|
||||
_, err := ui.program.Run()
|
||||
return err
|
||||
}
|
||||
@@ -325,7 +326,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
m.termHeight = msg.Height
|
||||
return m, nil
|
||||
|
||||
case tea.KeyMsg:
|
||||
case tea.KeyPressMsg:
|
||||
// Route based on current view mode
|
||||
switch viewMode {
|
||||
case ViewModeMain:
|
||||
@@ -390,7 +391,13 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m model) View() string {
|
||||
func (m model) View() tea.View {
|
||||
v := tea.NewView(m.view())
|
||||
v.AltScreen = true
|
||||
return v
|
||||
}
|
||||
|
||||
func (m model) view() string {
|
||||
m.ui.mu.RLock()
|
||||
viewMode := m.ui.viewMode
|
||||
deleteConfirming := m.ui.deleteConfirming
|
||||
@@ -438,13 +445,13 @@ func (m model) View() string {
|
||||
|
||||
// mainViewColors holds the color palette for the main view
|
||||
type mainViewColors struct {
|
||||
header lipgloss.Color
|
||||
active lipgloss.Color
|
||||
warning lipgloss.Color
|
||||
errorColor lipgloss.Color
|
||||
muted lipgloss.Color
|
||||
selectedBg lipgloss.Color
|
||||
selectedFg lipgloss.Color
|
||||
header color.Color
|
||||
active color.Color
|
||||
warning color.Color
|
||||
errorColor color.Color
|
||||
muted color.Color
|
||||
selectedBg color.Color
|
||||
selectedFg color.Color
|
||||
}
|
||||
|
||||
// defaultMainViewColors returns the default color palette
|
||||
@@ -526,7 +533,7 @@ func (m model) getTermDimensions() (width, height int) {
|
||||
}
|
||||
|
||||
// renderTitle renders the title bar with version and optional update notification
|
||||
func (m model) renderTitle(headerColor lipgloss.Color) string {
|
||||
func (m model) renderTitle(headerColor color.Color) string {
|
||||
var b strings.Builder
|
||||
|
||||
titleStyle := lipgloss.NewStyle().
|
||||
@@ -552,7 +559,7 @@ func (m model) renderTitle(headerColor lipgloss.Color) string {
|
||||
|
||||
// renderEmptyMessage renders the message shown when no forwards are configured.
|
||||
// It includes an actionable hint so a first-time user knows how to proceed.
|
||||
func (m model) renderEmptyMessage(mutedColor lipgloss.Color) string {
|
||||
func (m model) renderEmptyMessage(mutedColor color.Color) string {
|
||||
mutedStyle := lipgloss.NewStyle().Foreground(mutedColor)
|
||||
hintStyle := lipgloss.NewStyle().Foreground(highlightColor)
|
||||
return mutedStyle.Render("No forwards configured") + "\n\n" +
|
||||
|
||||
+27
-23
@@ -9,7 +9,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"github.com/lukaszraczylo/kportal/internal/config"
|
||||
)
|
||||
|
||||
@@ -323,13 +323,13 @@ func (m *GenerateModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
m.step = GenerateStepDone
|
||||
return m, tea.Quit
|
||||
|
||||
case tea.KeyMsg:
|
||||
case tea.KeyPressMsg:
|
||||
return m.handleKey(msg)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m *GenerateModel) handleKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
func (m *GenerateModel) handleKey(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
|
||||
if m.loading {
|
||||
// Allow only ctrl+c / esc while loading
|
||||
switch msg.String() {
|
||||
@@ -354,12 +354,12 @@ func (m *GenerateModel) handleKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
|
||||
// ---------- Namespace step ----------
|
||||
|
||||
func (m *GenerateModel) handleNamespaceKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
func (m *GenerateModel) handleNamespaceKey(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
|
||||
if m.nsFiltering {
|
||||
switch msg.Type {
|
||||
case tea.KeyEnter, tea.KeyEsc:
|
||||
switch msg.Code {
|
||||
case tea.KeyEnter, tea.KeyEscape:
|
||||
m.nsFiltering = false
|
||||
if msg.Type == tea.KeyEsc {
|
||||
if msg.Code == tea.KeyEscape {
|
||||
m.nsFilter = ""
|
||||
m.recomputeNamespaceFilter()
|
||||
}
|
||||
@@ -370,12 +370,11 @@ func (m *GenerateModel) handleNamespaceKey(msg tea.KeyMsg) (tea.Model, tea.Cmd)
|
||||
m.recomputeNamespaceFilter()
|
||||
}
|
||||
return m, nil
|
||||
case tea.KeyRunes, tea.KeySpace:
|
||||
m.nsFilter += string(msg.Runes)
|
||||
default:
|
||||
m.nsFilter += msg.Text
|
||||
m.recomputeNamespaceFilter()
|
||||
return m, nil
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
switch msg.String() {
|
||||
@@ -391,7 +390,7 @@ func (m *GenerateModel) handleNamespaceKey(msg tea.KeyMsg) (tea.Model, tea.Cmd)
|
||||
m.moveCursor(&m.nsCursor, &m.nsScroll, len(m.nsFilteredView), -10)
|
||||
case "pgdown":
|
||||
m.moveCursor(&m.nsCursor, &m.nsScroll, len(m.nsFilteredView), 10)
|
||||
case " ":
|
||||
case "space":
|
||||
if len(m.nsFilteredView) > 0 {
|
||||
ns := m.nsFilteredView[m.nsCursor]
|
||||
m.nsSelected[ns] = !m.nsSelected[ns]
|
||||
@@ -475,12 +474,12 @@ func (m *GenerateModel) buildServiceOrder() {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *GenerateModel) handleServiceKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
func (m *GenerateModel) handleServiceKey(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
|
||||
if m.svcFiltering {
|
||||
switch msg.Type {
|
||||
case tea.KeyEnter, tea.KeyEsc:
|
||||
switch msg.Code {
|
||||
case tea.KeyEnter, tea.KeyEscape:
|
||||
m.svcFiltering = false
|
||||
if msg.Type == tea.KeyEsc {
|
||||
if msg.Code == tea.KeyEscape {
|
||||
m.svcFilter = ""
|
||||
m.recomputeServiceFilter()
|
||||
}
|
||||
@@ -491,12 +490,11 @@ func (m *GenerateModel) handleServiceKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
m.recomputeServiceFilter()
|
||||
}
|
||||
return m, nil
|
||||
case tea.KeyRunes, tea.KeySpace:
|
||||
m.svcFilter += string(msg.Runes)
|
||||
default:
|
||||
m.svcFilter += msg.Text
|
||||
m.recomputeServiceFilter()
|
||||
return m, nil
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
switch msg.String() {
|
||||
@@ -515,7 +513,7 @@ func (m *GenerateModel) handleServiceKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
m.moveCursor(&m.svcCursor, &m.svcScroll, len(m.svcFilteredView), -10)
|
||||
case "pgdown":
|
||||
m.moveCursor(&m.svcCursor, &m.svcScroll, len(m.svcFilteredView), 10)
|
||||
case " ":
|
||||
case "space":
|
||||
if len(m.svcFilteredView) > 0 {
|
||||
c := m.svcFilteredView[m.svcCursor]
|
||||
if !m.svcLocked[c.Key()] && c.Protocol == "TCP" {
|
||||
@@ -593,7 +591,7 @@ func (m *GenerateModel) selectedCandidates() []ServiceCandidate {
|
||||
|
||||
// ---------- Port assignment step ----------
|
||||
|
||||
func (m *GenerateModel) handlePortKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
func (m *GenerateModel) handlePortKey(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
|
||||
switch msg.String() {
|
||||
case "ctrl+c":
|
||||
m.step = GenerateStepCancelled
|
||||
@@ -627,7 +625,7 @@ func (m *GenerateModel) handlePortKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
// Digit-only input
|
||||
for _, r := range msg.Runes {
|
||||
for _, r := range msg.Text {
|
||||
if r >= '0' && r <= '9' && len(m.startingPortStr) < 5 {
|
||||
m.startingPortStr += string(r)
|
||||
m.portError = ""
|
||||
@@ -716,7 +714,13 @@ func (m *GenerateModel) countSkippedNonTCP() int {
|
||||
// ---------- View ----------
|
||||
|
||||
// View implements tea.Model.
|
||||
func (m *GenerateModel) View() string {
|
||||
func (m *GenerateModel) View() tea.View {
|
||||
v := tea.NewView(m.view())
|
||||
v.AltScreen = true
|
||||
return v
|
||||
}
|
||||
|
||||
func (m *GenerateModel) view() string {
|
||||
var b strings.Builder
|
||||
b.WriteString(wizardHeaderStyle.Render(fmt.Sprintf("kportal generate · context: %s", m.contextName)))
|
||||
b.WriteString("\n")
|
||||
@@ -975,7 +979,7 @@ func RunGenerate(
|
||||
existingForwards []config.Forward,
|
||||
) (GenerateResult, error) {
|
||||
m := NewGenerateModel(discovery, mutator, contextName, configPath, dryRun, existingForwards)
|
||||
prog := tea.NewProgram(m, tea.WithAltScreen())
|
||||
prog := tea.NewProgram(m)
|
||||
finalModel, err := prog.Run()
|
||||
if err != nil {
|
||||
return GenerateResult{}, err
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"github.com/lukaszraczylo/kportal/internal/config"
|
||||
"github.com/lukaszraczylo/kportal/internal/k8s"
|
||||
)
|
||||
@@ -72,22 +72,22 @@ func (f *fakeDiscovery) ListServices(_ context.Context, _, ns string) ([]k8s.Ser
|
||||
return f.servicesByNS[ns], nil
|
||||
}
|
||||
|
||||
// keyOf builds a tea.KeyMsg the same way bubbletea does for typed runes.
|
||||
func keyOf(s string) tea.KeyMsg {
|
||||
// keyOf builds a tea.KeyPressMsg the same way bubbletea does for typed runes.
|
||||
func keyOf(s string) tea.KeyPressMsg {
|
||||
switch s {
|
||||
case "enter":
|
||||
return tea.KeyMsg{Type: tea.KeyEnter}
|
||||
return tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
case "esc":
|
||||
return tea.KeyMsg{Type: tea.KeyEsc}
|
||||
return tea.KeyPressMsg{Code: tea.KeyEscape}
|
||||
case "space":
|
||||
return tea.KeyMsg{Type: tea.KeySpace, Runes: []rune(" ")}
|
||||
return tea.KeyPressMsg{Code: tea.KeySpace, Text: " "}
|
||||
case "backspace":
|
||||
return tea.KeyMsg{Type: tea.KeyBackspace}
|
||||
return tea.KeyPressMsg{Code: tea.KeyBackspace}
|
||||
}
|
||||
if len(s) == 1 {
|
||||
return tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune(s)}
|
||||
return tea.KeyPressMsg{Text: s}
|
||||
}
|
||||
return tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune(s)}
|
||||
return tea.KeyPressMsg{Text: s}
|
||||
}
|
||||
|
||||
// drainModel applies a sequence of messages and returns the final model.
|
||||
@@ -169,7 +169,7 @@ func TestGenerateModel_NamespaceFilter(t *testing.T) {
|
||||
t.Fatalf("expected [beta], got %v", gm.nsFilteredView)
|
||||
}
|
||||
// Exit filter
|
||||
gm = drainModel(t, gm, tea.KeyMsg{Type: tea.KeyEnter}).(*GenerateModel)
|
||||
gm = drainModel(t, gm, tea.KeyPressMsg{Code: tea.KeyEnter}).(*GenerateModel)
|
||||
if gm.nsFiltering {
|
||||
t.Fatal("expected filtering to be off after enter")
|
||||
}
|
||||
@@ -496,7 +496,7 @@ func TestGenerateModel_PortStepView(t *testing.T) {
|
||||
m.step = GenerateStepPortAssign
|
||||
m.svcOrder = []ServiceCandidate{{Namespace: "ns", Service: "svc", Port: 80, Protocol: "TCP"}}
|
||||
m.svcSelected[m.svcOrder[0].Key()] = true
|
||||
view := m.View()
|
||||
view := m.View().Content
|
||||
if !contains(view, "Step 3 / 3") {
|
||||
t.Fatalf("expected step header in view, got: %s", view)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"github.com/lukaszraczylo/kportal/internal/config"
|
||||
"github.com/lukaszraczylo/kportal/internal/k8s"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -44,10 +44,10 @@ func TestHandleMainViewKeys_Quit(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.key, func(t *testing.T) {
|
||||
m := newTestModel()
|
||||
_, cmd := m.handleMainViewKeys(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune(tt.key)})
|
||||
_, cmd := m.handleMainViewKeys(tea.KeyPressMsg{Text: tt.key})
|
||||
|
||||
if tt.key == "ctrl+c" {
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyCtrlC}
|
||||
keyMsg := tea.KeyPressMsg{Code: 'c', Mod: tea.ModCtrl}
|
||||
_, cmd = m.handleMainViewKeys(keyMsg)
|
||||
}
|
||||
|
||||
@@ -76,14 +76,14 @@ func TestHandleMainViewKeys_Navigation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
key string
|
||||
keyType tea.KeyType
|
||||
code rune
|
||||
initialIndex int
|
||||
expectedIndex int
|
||||
}{
|
||||
{"down arrow", "down", tea.KeyDown, 0, 1},
|
||||
{"j key", "j", tea.KeyRunes, 0, 1},
|
||||
{"j key", "j", 0, 0, 1},
|
||||
{"up arrow", "up", tea.KeyUp, 2, 1},
|
||||
{"k key", "k", tea.KeyRunes, 2, 1},
|
||||
{"k key", "k", 0, 2, 1},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -92,11 +92,11 @@ func TestHandleMainViewKeys_Navigation(t *testing.T) {
|
||||
m.ui.selectedIndex = tt.initialIndex
|
||||
m.ui.mu.Unlock()
|
||||
|
||||
var keyMsg tea.KeyMsg
|
||||
if tt.keyType == tea.KeyRunes {
|
||||
keyMsg = tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune(tt.key)}
|
||||
var keyMsg tea.KeyPressMsg
|
||||
if tt.code == 0 {
|
||||
keyMsg = tea.KeyPressMsg{Text: tt.key}
|
||||
} else {
|
||||
keyMsg = tea.KeyMsg{Type: tt.keyType}
|
||||
keyMsg = tea.KeyPressMsg{Code: tt.code}
|
||||
}
|
||||
|
||||
m.handleMainViewKeys(keyMsg)
|
||||
@@ -123,7 +123,7 @@ func TestHandleMainViewKeys_Toggle(t *testing.T) {
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
// Toggle with space
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeySpace}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeySpace, Text: " "}
|
||||
m.handleMainViewKeys(keyMsg)
|
||||
|
||||
// Check disabled state changed
|
||||
@@ -151,7 +151,7 @@ func TestHandleMainViewKeys_NewWizard(t *testing.T) {
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
// Without dependencies, 'n' should do nothing
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("n")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "n"}
|
||||
m.handleMainViewKeys(keyMsg)
|
||||
|
||||
m.ui.mu.RLock()
|
||||
@@ -180,7 +180,7 @@ func TestHandleMainViewKeys_DeleteConfirmation(t *testing.T) {
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
// Press 'd' to show delete confirmation
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("d")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "d"}
|
||||
m.handleMainViewKeys(keyMsg)
|
||||
|
||||
m.ui.mu.RLock()
|
||||
@@ -204,7 +204,7 @@ func TestHandleMainViewKeys_DeleteConfirmation_PreventsDuplicate(t *testing.T) {
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
// Press 'd' for first forward
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("d")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "d"}
|
||||
m.handleMainViewKeys(keyMsg)
|
||||
|
||||
// Change selection
|
||||
@@ -234,7 +234,7 @@ func TestHandleDeleteConfirmation_Cancel(t *testing.T) {
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
// Press Esc
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEsc}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEscape}
|
||||
m.handleDeleteConfirmation(keyMsg)
|
||||
|
||||
m.ui.mu.RLock()
|
||||
@@ -257,7 +257,7 @@ func TestHandleDeleteConfirmation_NavigateAndConfirm(t *testing.T) {
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
// Navigate left to "Yes"
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyLeft}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyLeft}
|
||||
m.handleDeleteConfirmation(keyMsg)
|
||||
|
||||
m.ui.mu.RLock()
|
||||
@@ -265,7 +265,7 @@ func TestHandleDeleteConfirmation_NavigateAndConfirm(t *testing.T) {
|
||||
m.ui.mu.RUnlock()
|
||||
|
||||
// Navigate right back to "No"
|
||||
keyMsg = tea.KeyMsg{Type: tea.KeyRight}
|
||||
keyMsg = tea.KeyPressMsg{Code: tea.KeyRight}
|
||||
m.handleDeleteConfirmation(keyMsg)
|
||||
|
||||
m.ui.mu.RLock()
|
||||
@@ -288,7 +288,7 @@ func TestHandleDeleteConfirmation_ConfirmYes(t *testing.T) {
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
// Press Enter on "Yes"
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
_, cmd := m.handleDeleteConfirmation(keyMsg)
|
||||
|
||||
// Should return a command to remove the forward
|
||||
@@ -314,7 +314,7 @@ func TestHandleDeleteConfirmation_QuickYKey(t *testing.T) {
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
// Press 'y' - should confirm regardless of cursor position
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("y")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "y"}
|
||||
_, cmd := m.handleDeleteConfirmation(keyMsg)
|
||||
|
||||
assert.NotNil(t, cmd)
|
||||
@@ -336,7 +336,7 @@ func TestHandleDeleteConfirmation_QuickNKey(t *testing.T) {
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
// Press 'n' - should cancel regardless of cursor position
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("n")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "n"}
|
||||
m.handleDeleteConfirmation(keyMsg)
|
||||
|
||||
m.ui.mu.RLock()
|
||||
@@ -358,7 +358,7 @@ func TestHandleBenchmarkKeys_Cancel(t *testing.T) {
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
// Press Esc
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEsc}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEscape}
|
||||
m.handleBenchmarkKeys(keyMsg)
|
||||
|
||||
assert.True(t, cancelled, "Cancel function should be called")
|
||||
@@ -385,7 +385,7 @@ func TestHandleBenchmarkKeys_Navigation(t *testing.T) {
|
||||
m.ui.mu.RUnlock()
|
||||
|
||||
// Move down
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyDown}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyDown}
|
||||
m.handleBenchmarkKeys(keyMsg)
|
||||
|
||||
m.ui.mu.RLock()
|
||||
@@ -400,7 +400,7 @@ func TestHandleBenchmarkKeys_Navigation(t *testing.T) {
|
||||
m.ui.mu.RUnlock()
|
||||
|
||||
// Move up
|
||||
keyMsg = tea.KeyMsg{Type: tea.KeyUp}
|
||||
keyMsg = tea.KeyPressMsg{Code: tea.KeyUp}
|
||||
m.handleBenchmarkKeys(keyMsg)
|
||||
|
||||
m.ui.mu.RLock()
|
||||
@@ -422,7 +422,7 @@ func TestHandleHTTPLogKeys_Close(t *testing.T) {
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
// Press Esc
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEsc}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEscape}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
|
||||
m.ui.mu.RLock()
|
||||
@@ -451,7 +451,7 @@ func TestHandleHTTPLogKeys_FilterCycle(t *testing.T) {
|
||||
m.ui.mu.RUnlock()
|
||||
|
||||
// Press 'f' to cycle - should skip Text mode and go to Non200
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("f")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "f"}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
|
||||
m.ui.mu.RLock()
|
||||
@@ -484,7 +484,7 @@ func TestHandleHTTPLogKeys_TextFilter(t *testing.T) {
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
// Press '/'
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("/")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "/"}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
|
||||
m.ui.mu.RLock()
|
||||
@@ -505,7 +505,7 @@ func TestHandleHTTPLogKeys_ClearFilters(t *testing.T) {
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
// Press 'c'
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("c")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "c"}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
|
||||
m.ui.mu.RLock()
|
||||
@@ -869,7 +869,7 @@ func TestModel_Update_ViewModeRouting(t *testing.T) {
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
// Send a key message - should not panic
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEsc}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEscape}
|
||||
_, _ = m.Update(keyMsg)
|
||||
})
|
||||
}
|
||||
@@ -925,7 +925,7 @@ func TestHandleRemoveWizardKeys_EscInConfirmingCancels(t *testing.T) {
|
||||
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEsc}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEscape}
|
||||
_, cmd := m.handleRemoveWizardKeys(keyMsg)
|
||||
|
||||
// No removal command must be dispatched.
|
||||
@@ -962,7 +962,7 @@ func TestHandleRemoveWizardKeys_EscNotConfirmingExits(t *testing.T) {
|
||||
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEsc}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEscape}
|
||||
_, cmd := m.handleRemoveWizardKeys(keyMsg)
|
||||
|
||||
// Should return tea.ClearScreen command on full exit.
|
||||
@@ -992,7 +992,7 @@ func TestHandleRemoveWizardKeys_EnterOnYesStillConfirms(t *testing.T) {
|
||||
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
_, cmd := m.handleRemoveWizardKeys(keyMsg)
|
||||
|
||||
assert.NotNil(t, cmd, "Enter on Yes must still dispatch removeForwardsCmd")
|
||||
@@ -1017,7 +1017,7 @@ func TestHandleAddWizardKeys_HToggleHTTPLog(t *testing.T) {
|
||||
|
||||
require.False(t, m.ui.addWizard.httpLog, "httpLog should default to false")
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("h")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "h"}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
assert.True(t, m.ui.addWizard.httpLog, "first 'h' should enable httpLog")
|
||||
|
||||
@@ -1042,7 +1042,7 @@ func TestHandleAddWizardKeys_HOnAliasFocusIsTextInput(t *testing.T) {
|
||||
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("h")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "h"}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
assert.False(t, m.ui.addWizard.httpLog, "httpLog must NOT toggle when alias has focus")
|
||||
@@ -1067,7 +1067,7 @@ func TestEditPrefill_PreservesHTTPLog(t *testing.T) {
|
||||
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("e")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "e"}
|
||||
m.handleMainViewKeys(keyMsg)
|
||||
|
||||
require.NotNil(t, m.ui.addWizard, "wizard should be active after 'e'")
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"github.com/lukaszraczylo/kportal/internal/benchmark"
|
||||
"github.com/lukaszraczylo/kportal/internal/config"
|
||||
"github.com/lukaszraczylo/kportal/internal/k8s"
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"github.com/lukaszraczylo/kportal/internal/config"
|
||||
"github.com/lukaszraczylo/kportal/internal/k8s"
|
||||
)
|
||||
@@ -31,7 +31,7 @@ func isFilterableStep(step AddWizardStep) bool {
|
||||
}
|
||||
|
||||
// handleMainViewKeys handles keyboard input in the main view
|
||||
func (m model) handleMainViewKeys(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
func (m model) handleMainViewKeys(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
|
||||
// If delete confirmation is showing, handle it separately
|
||||
if m.ui.deleteConfirming {
|
||||
return m.handleDeleteConfirmation(msg)
|
||||
@@ -53,7 +53,7 @@ func (m model) handleMainViewKeys(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
case "pgdown", "ctrl+d":
|
||||
m.ui.moveSelection(10)
|
||||
|
||||
case " ", "enter":
|
||||
case "space", "enter":
|
||||
m.ui.toggleSelected()
|
||||
|
||||
case "n": // Enter add wizard
|
||||
@@ -294,7 +294,7 @@ func (m model) handleMainViewKeys(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
// handleDeleteConfirmation handles keyboard input for delete confirmation dialog
|
||||
func (m model) handleDeleteConfirmation(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
func (m model) handleDeleteConfirmation(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
|
||||
m.ui.mu.Lock()
|
||||
|
||||
switch msg.String() {
|
||||
@@ -336,7 +336,7 @@ func (m model) handleDeleteConfirmation(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
// handleAddWizardKeys handles keyboard input in the add wizard
|
||||
func (m model) handleAddWizardKeys(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
func (m model) handleAddWizardKeys(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
|
||||
m.ui.mu.Lock()
|
||||
defer m.ui.mu.Unlock()
|
||||
|
||||
@@ -781,7 +781,7 @@ func (m model) handleAddWizardEnter() (tea.Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
// handleRemoveWizardKeys handles keyboard input in the remove wizard
|
||||
func (m model) handleRemoveWizardKeys(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
func (m model) handleRemoveWizardKeys(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
|
||||
m.ui.mu.Lock()
|
||||
defer m.ui.mu.Unlock()
|
||||
|
||||
@@ -822,7 +822,7 @@ func (m model) handleRemoveWizardKeys(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
case "pgdown", "ctrl+d":
|
||||
wizard.moveCursor(10)
|
||||
|
||||
case " ":
|
||||
case "space":
|
||||
if !wizard.confirming {
|
||||
wizard.toggleSelection()
|
||||
}
|
||||
@@ -1051,7 +1051,7 @@ func (m model) handleForwardsRemoved(msg ForwardsRemovedMsg) (tea.Model, tea.Cmd
|
||||
}
|
||||
|
||||
// handleBenchmarkKeys handles keyboard input in the benchmark view
|
||||
func (m model) handleBenchmarkKeys(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
func (m model) handleBenchmarkKeys(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
|
||||
m.ui.mu.Lock()
|
||||
defer m.ui.mu.Unlock()
|
||||
|
||||
@@ -1192,7 +1192,7 @@ func (m model) applyBenchmarkTextInput() {
|
||||
}
|
||||
|
||||
// handleHTTPLogKeys handles keyboard input in the HTTP log view
|
||||
func (m model) handleHTTPLogKeys(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
func (m model) handleHTTPLogKeys(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
|
||||
m.ui.mu.Lock()
|
||||
defer m.ui.mu.Unlock()
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"github.com/lukaszraczylo/kportal/internal/config"
|
||||
"github.com/lukaszraczylo/kportal/internal/k8s"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -44,7 +44,7 @@ func TestHandleMainViewKeys_PageUpDown(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyPgUp}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyPgUp}
|
||||
m.handleMainViewKeys(keyMsg)
|
||||
ui.mu.RLock()
|
||||
assert.Equal(t, 0, ui.selectedIndex)
|
||||
@@ -54,7 +54,7 @@ func TestHandleMainViewKeys_PageUpDown(t *testing.T) {
|
||||
ui.mu.Lock()
|
||||
ui.selectedIndex = 0
|
||||
ui.mu.Unlock()
|
||||
keyMsg = tea.KeyMsg{Type: tea.KeyPgDown}
|
||||
keyMsg = tea.KeyPressMsg{Code: tea.KeyPgDown}
|
||||
m.handleMainViewKeys(keyMsg)
|
||||
ui.mu.RLock()
|
||||
assert.Equal(t, 10, ui.selectedIndex)
|
||||
@@ -76,7 +76,7 @@ func TestHandleMainViewKeys_NewWizard_WithDiscovery(t *testing.T) {
|
||||
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("n")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "n"}
|
||||
_, cmd := m.handleMainViewKeys(keyMsg)
|
||||
|
||||
ui.mu.RLock()
|
||||
@@ -99,7 +99,7 @@ func TestHandleMainViewKeys_NewWizard_AlreadyActive(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("n")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "n"}
|
||||
m.handleMainViewKeys(keyMsg)
|
||||
|
||||
// Should still be the same wizard (not replaced).
|
||||
@@ -116,7 +116,7 @@ func TestHandleMainViewKeys_HttpLog_NoSubscriber(t *testing.T) {
|
||||
ui.AddForward("id-1", fwd)
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("l")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "l"}
|
||||
m.handleMainViewKeys(keyMsg)
|
||||
|
||||
ui.mu.RLock()
|
||||
@@ -133,7 +133,7 @@ func TestHandleMainViewKeys_HttpLog_WithSubscriber(t *testing.T) {
|
||||
ui.AddForward("id-1", fwd)
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("l")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "l"}
|
||||
m.handleMainViewKeys(keyMsg)
|
||||
|
||||
// Subscription should be established.
|
||||
@@ -151,7 +151,7 @@ func TestHandleMainViewKeys_Benchmark(t *testing.T) {
|
||||
ui.AddForward("id-1", fwd)
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("b")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "b"}
|
||||
m.handleMainViewKeys(keyMsg)
|
||||
|
||||
ui.mu.RLock()
|
||||
@@ -170,7 +170,7 @@ func TestHandleMainViewKeys_Benchmark_BlocksWhenActive(t *testing.T) {
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
prevState := ui.benchmarkState
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("b")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "b"}
|
||||
m.handleMainViewKeys(keyMsg)
|
||||
|
||||
// Should not have replaced the benchmark state.
|
||||
@@ -184,7 +184,7 @@ func TestHandleMainViewKeys_Benchmark_BlocksWhenActive(t *testing.T) {
|
||||
func TestHandleAddWizardKeys_CtrlC(t *testing.T) {
|
||||
m := newModelWithWizard(StepSelectContext)
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyCtrlC}
|
||||
keyMsg := tea.KeyPressMsg{Code: 'c', Mod: tea.ModCtrl}
|
||||
_, cmd := m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
assert.NotNil(t, cmd) // tea.ClearScreen
|
||||
@@ -197,7 +197,7 @@ func TestHandleAddWizardKeys_CtrlC(t *testing.T) {
|
||||
func TestHandleAddWizardKeys_Esc_FirstStep_Cancels(t *testing.T) {
|
||||
m := newModelWithWizard(StepSelectContext)
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEsc}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEscape}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
m.ui.mu.RLock()
|
||||
@@ -209,7 +209,7 @@ func TestHandleAddWizardKeys_Esc_FirstStep_Cancels(t *testing.T) {
|
||||
func TestHandleAddWizardKeys_Esc_MiddleStep_GoesBack(t *testing.T) {
|
||||
m := newModelWithWizard(StepSelectNamespace)
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEsc}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEscape}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
m.ui.mu.RLock()
|
||||
@@ -221,7 +221,7 @@ func TestHandleAddWizardKeys_Esc_ClearsSearchFilter_InsteadOfBack(t *testing.T)
|
||||
m := newModelWithWizard(StepSelectContext)
|
||||
m.ui.addWizard.searchFilter = "my"
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEsc}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEscape}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
m.ui.mu.RLock()
|
||||
@@ -235,7 +235,7 @@ func TestHandleAddWizardKeys_Esc_EditMode_AlwaysCancels(t *testing.T) {
|
||||
m := newModelWithWizard(StepEnterRemotePort)
|
||||
m.ui.addWizard.isEditing = true
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEsc}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEscape}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
m.ui.mu.RLock()
|
||||
@@ -250,11 +250,11 @@ func TestHandleAddWizardKeys_Navigation(t *testing.T) {
|
||||
m := newModelWithWizard(StepSelectContext)
|
||||
m.ui.addWizard.contexts = []string{"ctx-a", "ctx-b", "ctx-c"}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyDown}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyDown}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
assert.Equal(t, 1, m.ui.addWizard.cursor)
|
||||
|
||||
keyMsg = tea.KeyMsg{Type: tea.KeyUp}
|
||||
keyMsg = tea.KeyPressMsg{Code: tea.KeyUp}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
assert.Equal(t, 0, m.ui.addWizard.cursor)
|
||||
}
|
||||
@@ -268,11 +268,11 @@ func TestHandleAddWizardKeys_PageNavigation(t *testing.T) {
|
||||
m.ui.addWizard.contexts = contexts
|
||||
m.ui.addWizard.cursor = 15
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyPgUp}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyPgUp}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
assert.Equal(t, 5, m.ui.addWizard.cursor)
|
||||
|
||||
keyMsg = tea.KeyMsg{Type: tea.KeyPgDown}
|
||||
keyMsg = tea.KeyPressMsg{Code: tea.KeyPgDown}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
assert.Equal(t, 15, m.ui.addWizard.cursor)
|
||||
}
|
||||
@@ -283,7 +283,7 @@ func TestHandleAddWizardKeys_ConfirmationStep_UpFocusAlias(t *testing.T) {
|
||||
m := newModelWithWizard(StepConfirmation)
|
||||
m.ui.addWizard.confirmationFocus = FocusButtons
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyUp}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyUp}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
assert.Equal(t, FocusAlias, m.ui.addWizard.confirmationFocus)
|
||||
}
|
||||
@@ -292,7 +292,7 @@ func TestHandleAddWizardKeys_ConfirmationStep_DownFocusButtons(t *testing.T) {
|
||||
m := newModelWithWizard(StepConfirmation)
|
||||
m.ui.addWizard.confirmationFocus = FocusAlias
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyDown}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyDown}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
assert.Equal(t, FocusButtons, m.ui.addWizard.confirmationFocus)
|
||||
}
|
||||
@@ -301,7 +301,7 @@ func TestHandleAddWizardKeys_Tab_TogglesFocus(t *testing.T) {
|
||||
m := newModelWithWizard(StepConfirmation)
|
||||
m.ui.addWizard.confirmationFocus = FocusAlias
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyTab}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyTab}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
assert.Equal(t, FocusButtons, m.ui.addWizard.confirmationFocus)
|
||||
|
||||
@@ -316,7 +316,7 @@ func TestHandleAddWizardKeys_Backspace_TextMode(t *testing.T) {
|
||||
m.ui.addWizard.inputMode = InputModeText
|
||||
m.ui.addWizard.textInput = "808"
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyBackspace}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyBackspace}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
assert.Equal(t, "80", m.ui.addWizard.textInput)
|
||||
}
|
||||
@@ -325,7 +325,7 @@ func TestHandleAddWizardKeys_Backspace_SearchFilter(t *testing.T) {
|
||||
m := newModelWithWizard(StepSelectContext)
|
||||
m.ui.addWizard.searchFilter = "my"
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyBackspace}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyBackspace}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
assert.Equal(t, "m", m.ui.addWizard.searchFilter)
|
||||
}
|
||||
@@ -334,7 +334,7 @@ func TestHandleAddWizardKeys_Backspace_EmptyFilter_NoOp(t *testing.T) {
|
||||
m := newModelWithWizard(StepSelectContext)
|
||||
m.ui.addWizard.searchFilter = ""
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyBackspace}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyBackspace}
|
||||
// Must not panic.
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
}
|
||||
@@ -345,7 +345,7 @@ func TestHandleAddWizardKeys_TypeCharAddsToSearchFilter(t *testing.T) {
|
||||
m := newModelWithWizard(StepSelectContext)
|
||||
// Context step is filterable in list mode.
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("p")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "p"}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
assert.Equal(t, "p", m.ui.addWizard.searchFilter)
|
||||
}
|
||||
@@ -356,7 +356,7 @@ func TestHandleAddWizardKeys_TypeCharInTextMode(t *testing.T) {
|
||||
m := newModelWithWizard(StepEnterRemotePort)
|
||||
m.ui.addWizard.inputMode = InputModeText
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("8")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "8"}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
assert.Equal(t, "8", m.ui.addWizard.textInput)
|
||||
}
|
||||
@@ -377,7 +377,7 @@ func TestHandleAddWizardEnter_SelectContext(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
_, cmd := m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
ui.mu.RLock()
|
||||
@@ -393,7 +393,7 @@ func TestHandleAddWizardEnter_SelectContext_Loading_NoOp(t *testing.T) {
|
||||
m := newModelWithWizard(StepSelectContext)
|
||||
m.ui.addWizard.loading = true
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
_, cmd := m.handleAddWizardKeys(keyMsg)
|
||||
assert.Nil(t, cmd)
|
||||
}
|
||||
@@ -405,7 +405,7 @@ func TestHandleAddWizardEnter_SelectNamespace(t *testing.T) {
|
||||
m.ui.addWizard.namespaces = []string{"default", "kube-system"}
|
||||
m.ui.addWizard.cursor = 1 // kube-system
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, StepSelectResourceType, m.ui.addWizard.step)
|
||||
@@ -428,7 +428,7 @@ func TestHandleAddWizardEnter_SelectResourceType_Service(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
_, cmd := m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
ui.mu.RLock()
|
||||
@@ -454,7 +454,7 @@ func TestHandleAddWizardEnter_SelectResourceType_PodPrefix(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
_, cmd := m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
ui.mu.RLock()
|
||||
@@ -477,7 +477,7 @@ func TestHandleAddWizardEnter_EnterResource_PodPrefix(t *testing.T) {
|
||||
Containers: []k8s.ContainerInfo{{Name: "main", Ports: []k8s.PortInfo{{Port: 8080}}}},
|
||||
}}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, StepEnterRemotePort, m.ui.addWizard.step)
|
||||
@@ -490,7 +490,7 @@ func TestHandleAddWizardEnter_EnterResource_PodPrefix_EmptyInput_NoOp(t *testing
|
||||
m.ui.addWizard.inputMode = InputModeText
|
||||
m.ui.addWizard.textInput = ""
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, StepEnterResource, m.ui.addWizard.step) // should not advance
|
||||
@@ -505,7 +505,7 @@ func TestHandleAddWizardEnter_EnterResource_PodSelector(t *testing.T) {
|
||||
m.ui.addWizard.textInput = "app=my"
|
||||
m.ui.addWizard.matchingPods = []k8s.PodInfo{{Name: "my-pod"}}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, StepEnterRemotePort, m.ui.addWizard.step)
|
||||
@@ -518,7 +518,7 @@ func TestHandleAddWizardEnter_EnterResource_PodSelector_NoMatchingPods_NoOp(t *t
|
||||
m.ui.addWizard.textInput = "app=my"
|
||||
m.ui.addWizard.matchingPods = nil
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, StepEnterResource, m.ui.addWizard.step)
|
||||
@@ -535,7 +535,7 @@ func TestHandleAddWizardEnter_EnterResource_Service(t *testing.T) {
|
||||
}
|
||||
m.ui.addWizard.cursor = 0
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, StepEnterRemotePort, m.ui.addWizard.step)
|
||||
@@ -549,7 +549,7 @@ func TestHandleAddWizardEnter_RemotePort_TextMode_ValidPort(t *testing.T) {
|
||||
m.ui.addWizard.inputMode = InputModeText
|
||||
m.ui.addWizard.textInput = "8080"
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, StepEnterLocalPort, m.ui.addWizard.step)
|
||||
@@ -561,7 +561,7 @@ func TestHandleAddWizardEnter_RemotePort_TextMode_InvalidPort(t *testing.T) {
|
||||
m.ui.addWizard.inputMode = InputModeText
|
||||
m.ui.addWizard.textInput = "invalid"
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, StepEnterRemotePort, m.ui.addWizard.step)
|
||||
@@ -577,7 +577,7 @@ func TestHandleAddWizardEnter_RemotePort_ListMode_SelectPort(t *testing.T) {
|
||||
}
|
||||
m.ui.addWizard.cursor = 1 // 8080 → TargetPort 9090
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, StepEnterLocalPort, m.ui.addWizard.step)
|
||||
@@ -590,7 +590,7 @@ func TestHandleAddWizardEnter_RemotePort_ListMode_ManualEntry(t *testing.T) {
|
||||
m.ui.addWizard.detectedPorts = []k8s.PortInfo{{Port: 80}}
|
||||
m.ui.addWizard.cursor = 1 // "Manual entry" option
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, InputModeText, m.ui.addWizard.inputMode)
|
||||
@@ -612,7 +612,7 @@ func TestHandleAddWizardEnter_LocalPort_ValidPort(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
_, cmd := m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
// loading set, cmd generated.
|
||||
@@ -627,7 +627,7 @@ func TestHandleAddWizardEnter_LocalPort_InvalidPort(t *testing.T) {
|
||||
m := newModelWithWizard(StepEnterLocalPort)
|
||||
m.ui.addWizard.textInput = "0" // invalid (must be > 0)
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
assert.NotNil(t, m.ui.addWizard.error)
|
||||
@@ -639,7 +639,7 @@ func TestHandleAddWizardEnter_Confirmation_FocusAlias_MoveToButtons(t *testing.T
|
||||
m := newModelWithWizard(StepConfirmation)
|
||||
m.ui.addWizard.confirmationFocus = FocusAlias
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, FocusButtons, m.ui.addWizard.confirmationFocus)
|
||||
@@ -650,7 +650,7 @@ func TestHandleAddWizardEnter_Confirmation_CancelButton(t *testing.T) {
|
||||
m.ui.addWizard.confirmationFocus = FocusButtons
|
||||
m.ui.addWizard.cursor = 1 // Cancel
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
_, cmd := m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
assert.NotNil(t, cmd) // tea.ClearScreen
|
||||
@@ -667,7 +667,7 @@ func TestHandleAddWizardEnter_Confirmation_PortNotAvailable_Error(t *testing.T)
|
||||
m.ui.addWizard.portAvailable = false
|
||||
m.ui.addWizard.localPort = 8080
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
assert.NotNil(t, m.ui.addWizard.error)
|
||||
@@ -697,7 +697,7 @@ func TestHandleAddWizardEnter_Confirmation_Save_NewForward(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
_, cmd := m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
require.NotNil(t, cmd)
|
||||
@@ -731,7 +731,7 @@ func TestHandleAddWizardEnter_Confirmation_Save_NewForward_WithHTTPLog(t *testin
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
_, cmd := m.handleAddWizardKeys(keyMsg)
|
||||
require.NotNil(t, cmd)
|
||||
msg := cmd()
|
||||
@@ -767,7 +767,7 @@ func TestHandleAddWizardEnter_Confirmation_Update_EditMode(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
_, cmd := m.handleAddWizardKeys(keyMsg)
|
||||
require.NotNil(t, cmd)
|
||||
msg := cmd()
|
||||
@@ -790,7 +790,7 @@ func TestHandleAddWizardEnter_Success_AddAnother(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
_, cmd := m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
// A cmd (loadContextsCmd) must be returned.
|
||||
@@ -801,7 +801,7 @@ func TestHandleAddWizardEnter_Success_ReturnToMain(t *testing.T) {
|
||||
m := newModelWithWizard(StepSuccess)
|
||||
m.ui.addWizard.cursor = 1 // "Return to main"
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
_, cmd := m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
assert.NotNil(t, cmd)
|
||||
@@ -828,7 +828,7 @@ func TestHandleAddWizardKeys_SelectorValidation_OnChar(t *testing.T) {
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
// Typing a char in PodSelector step should return a validation cmd.
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("-")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "-"}
|
||||
_, cmd := m.handleAddWizardKeys(keyMsg)
|
||||
|
||||
// A cmd is returned (validateSelectorCmd); we don't invoke it as it needs a real cluster.
|
||||
@@ -849,7 +849,7 @@ func TestHandleRemoveWizardKeys_SpaceToggle(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeySpace}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeySpace, Text: " "}
|
||||
m.handleRemoveWizardKeys(keyMsg)
|
||||
|
||||
ui.mu.RLock()
|
||||
@@ -874,7 +874,7 @@ func TestHandleRemoveWizardKeys_SelectAll(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("a")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "a"}
|
||||
m.handleRemoveWizardKeys(keyMsg)
|
||||
|
||||
ui.mu.RLock()
|
||||
@@ -895,7 +895,7 @@ func TestHandleRemoveWizardKeys_SelectNone(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("n")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "n"}
|
||||
m.handleRemoveWizardKeys(keyMsg)
|
||||
|
||||
ui.mu.RLock()
|
||||
@@ -915,7 +915,7 @@ func TestHandleRemoveWizardKeys_CtrlC_ExitsAlways(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyCtrlC}
|
||||
keyMsg := tea.KeyPressMsg{Code: 'c', Mod: tea.ModCtrl}
|
||||
m.handleRemoveWizardKeys(keyMsg)
|
||||
|
||||
ui.mu.RLock()
|
||||
@@ -935,7 +935,7 @@ func TestHandleRemoveWizardKeys_Enter_NothingSelected_NoOp(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
_, cmd := m.handleRemoveWizardKeys(keyMsg)
|
||||
|
||||
assert.Nil(t, cmd)
|
||||
@@ -955,7 +955,7 @@ func TestHandleRemoveWizardKeys_Enter_ShowConfirmation(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
m.handleRemoveWizardKeys(keyMsg)
|
||||
|
||||
ui.mu.RLock()
|
||||
@@ -976,7 +976,7 @@ func TestHandleRemoveWizardKeys_Enter_ConfirmNo(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
_, cmd := m.handleRemoveWizardKeys(keyMsg)
|
||||
|
||||
assert.Nil(t, cmd)
|
||||
@@ -997,13 +997,13 @@ func TestHandleRemoveWizardKeys_Navigation_InSelection(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyDown}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyDown}
|
||||
m.handleRemoveWizardKeys(keyMsg)
|
||||
ui.mu.RLock()
|
||||
assert.Equal(t, 1, ui.removeWizard.cursor)
|
||||
ui.mu.RUnlock()
|
||||
|
||||
keyMsg = tea.KeyMsg{Type: tea.KeyUp}
|
||||
keyMsg = tea.KeyPressMsg{Code: tea.KeyUp}
|
||||
m.handleRemoveWizardKeys(keyMsg)
|
||||
ui.mu.RLock()
|
||||
assert.Equal(t, 0, ui.removeWizard.cursor)
|
||||
@@ -1017,7 +1017,7 @@ func TestHandleBenchmarkKeys_Tab(t *testing.T) {
|
||||
m.ui.benchmarkState.step = BenchmarkStepConfig
|
||||
m.ui.benchmarkState.cursor = 0
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyTab}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyTab}
|
||||
m.handleBenchmarkKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, 1, m.ui.benchmarkState.cursor)
|
||||
@@ -1028,7 +1028,7 @@ func TestHandleBenchmarkKeys_Tab_Wraps(t *testing.T) {
|
||||
m.ui.benchmarkState.step = BenchmarkStepConfig
|
||||
m.ui.benchmarkState.cursor = 3
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyTab}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyTab}
|
||||
m.handleBenchmarkKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, 0, m.ui.benchmarkState.cursor)
|
||||
@@ -1040,7 +1040,7 @@ func TestHandleBenchmarkKeys_Backspace(t *testing.T) {
|
||||
m.ui.benchmarkState.cursor = 0
|
||||
m.ui.benchmarkState.textInput = "/api"
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyBackspace}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyBackspace}
|
||||
m.handleBenchmarkKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, "/ap", m.ui.benchmarkState.textInput)
|
||||
@@ -1053,7 +1053,7 @@ func TestHandleBenchmarkKeys_TypeChar_UpdatesField(t *testing.T) {
|
||||
m.ui.benchmarkState.cursor = 1 // Method field
|
||||
m.ui.benchmarkState.textInput = "GE"
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("T")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "T"}
|
||||
m.handleBenchmarkKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, "GET", m.ui.benchmarkState.method)
|
||||
@@ -1063,7 +1063,7 @@ func TestHandleBenchmarkKeys_Enter_ResultsStep_ReturnsToMain(t *testing.T) {
|
||||
m := newModelWithBenchmark()
|
||||
m.ui.benchmarkState.step = BenchmarkStepResults
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
_, cmd := m.handleBenchmarkKeys(keyMsg)
|
||||
|
||||
assert.NotNil(t, cmd) // tea.ClearScreen
|
||||
@@ -1077,7 +1077,7 @@ func TestHandleBenchmarkKeys_Enter_ConfigStep_StartsRunning(t *testing.T) {
|
||||
m := newModelWithBenchmark()
|
||||
m.ui.benchmarkState.step = BenchmarkStepConfig
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
_, cmd := m.handleBenchmarkKeys(keyMsg)
|
||||
|
||||
require.NotNil(t, cmd)
|
||||
@@ -1157,7 +1157,7 @@ func TestHandleHTTPLogKeys_Detail_Esc(t *testing.T) {
|
||||
m.ui.httpLogState.showingDetail = true
|
||||
m.ui.httpLogState.entries = []HTTPLogEntry{{Method: "GET", Path: "/test"}}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEsc}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEscape}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
|
||||
assert.False(t, m.ui.httpLogState.showingDetail)
|
||||
@@ -1169,11 +1169,11 @@ func TestHandleHTTPLogKeys_Detail_UpDown(t *testing.T) {
|
||||
m.ui.httpLogState.detailScroll = 5
|
||||
m.ui.httpLogState.entries = []HTTPLogEntry{{Method: "GET"}}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyUp}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyUp}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
assert.Equal(t, 4, m.ui.httpLogState.detailScroll)
|
||||
|
||||
keyMsg = tea.KeyMsg{Type: tea.KeyDown}
|
||||
keyMsg = tea.KeyPressMsg{Code: tea.KeyDown}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
assert.Equal(t, 5, m.ui.httpLogState.detailScroll)
|
||||
}
|
||||
@@ -1184,11 +1184,11 @@ func TestHandleHTTPLogKeys_Detail_PgUpDown(t *testing.T) {
|
||||
m.ui.httpLogState.detailScroll = 25
|
||||
m.ui.httpLogState.entries = []HTTPLogEntry{{Method: "GET"}}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyPgUp}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyPgUp}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
assert.Equal(t, 5, m.ui.httpLogState.detailScroll)
|
||||
|
||||
keyMsg = tea.KeyMsg{Type: tea.KeyPgDown}
|
||||
keyMsg = tea.KeyPressMsg{Code: tea.KeyPgDown}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
assert.Equal(t, 25, m.ui.httpLogState.detailScroll)
|
||||
}
|
||||
@@ -1199,7 +1199,7 @@ func TestHandleHTTPLogKeys_Detail_GoToTop(t *testing.T) {
|
||||
m.ui.httpLogState.detailScroll = 99
|
||||
m.ui.httpLogState.entries = []HTTPLogEntry{{Method: "GET"}}
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("g")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "g"}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, 0, m.ui.httpLogState.detailScroll)
|
||||
@@ -1213,7 +1213,7 @@ func TestHandleHTTPLogKeys_Enter_ShowDetail(t *testing.T) {
|
||||
m.ui.httpLogState.entries = []HTTPLogEntry{{Method: "GET", Path: "/test", StatusCode: 200}}
|
||||
m.ui.httpLogState.cursor = 0
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
|
||||
assert.True(t, m.ui.httpLogState.showingDetail)
|
||||
@@ -1227,11 +1227,11 @@ func TestHandleHTTPLogKeys_Navigate_UpDown(t *testing.T) {
|
||||
}
|
||||
m.ui.httpLogState.cursor = 1
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyUp}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyUp}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
assert.Equal(t, 0, m.ui.httpLogState.cursor)
|
||||
|
||||
keyMsg = tea.KeyMsg{Type: tea.KeyDown}
|
||||
keyMsg = tea.KeyPressMsg{Code: tea.KeyDown}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
assert.Equal(t, 1, m.ui.httpLogState.cursor)
|
||||
}
|
||||
@@ -1243,7 +1243,7 @@ func TestHandleHTTPLogKeys_Down_AtBottom_EnablesAutoScroll(t *testing.T) {
|
||||
m.ui.httpLogState.cursor = 0
|
||||
m.ui.httpLogState.autoScroll = false
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyDown}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyDown}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
|
||||
assert.True(t, m.ui.httpLogState.autoScroll)
|
||||
@@ -1257,7 +1257,7 @@ func TestHandleHTTPLogKeys_GoToTop_G(t *testing.T) {
|
||||
}
|
||||
m.ui.httpLogState.cursor = 2
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("g")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "g"}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, 0, m.ui.httpLogState.cursor)
|
||||
@@ -1272,7 +1272,7 @@ func TestHandleHTTPLogKeys_GoToBottom_CapitalG(t *testing.T) {
|
||||
}
|
||||
m.ui.httpLogState.cursor = 0
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("G")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "G"}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, 2, m.ui.httpLogState.cursor)
|
||||
@@ -1283,7 +1283,7 @@ func TestHandleHTTPLogKeys_ToggleAutoScroll(t *testing.T) {
|
||||
m := newModelWithHTTPLog()
|
||||
m.ui.httpLogState.autoScroll = false
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("a")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "a"}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
assert.True(t, m.ui.httpLogState.autoScroll)
|
||||
|
||||
@@ -1301,12 +1301,12 @@ func TestHandleHTTPLogKeys_PgUpDown_List(t *testing.T) {
|
||||
m.ui.httpLogState.entries = entries
|
||||
m.ui.httpLogState.cursor = 25
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyPgUp}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyPgUp}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
assert.Equal(t, 5, m.ui.httpLogState.cursor)
|
||||
assert.False(t, m.ui.httpLogState.autoScroll)
|
||||
|
||||
keyMsg = tea.KeyMsg{Type: tea.KeyPgDown}
|
||||
keyMsg = tea.KeyPressMsg{Code: tea.KeyPgDown}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
// PgDown +20 from 5 = 25; index 25 is in range (30 items, indices 0-29).
|
||||
assert.Equal(t, 25, m.ui.httpLogState.cursor)
|
||||
@@ -1319,7 +1319,7 @@ func TestHandleHTTPLogKeys_FilterActive_Typing(t *testing.T) {
|
||||
m.ui.httpLogState.filterActive = true
|
||||
m.ui.httpLogState.filterText = "te"
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("s")}
|
||||
keyMsg := tea.KeyPressMsg{Text: "s"}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, "tes", m.ui.httpLogState.filterText)
|
||||
@@ -1330,7 +1330,7 @@ func TestHandleHTTPLogKeys_FilterActive_Backspace(t *testing.T) {
|
||||
m.ui.httpLogState.filterActive = true
|
||||
m.ui.httpLogState.filterText = "tes"
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyBackspace}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyBackspace}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
|
||||
assert.Equal(t, "te", m.ui.httpLogState.filterText)
|
||||
@@ -1341,7 +1341,7 @@ func TestHandleHTTPLogKeys_FilterActive_EscClearsFilter(t *testing.T) {
|
||||
m.ui.httpLogState.filterActive = true
|
||||
m.ui.httpLogState.filterText = "test"
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEsc}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEscape}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
|
||||
assert.False(t, m.ui.httpLogState.filterActive)
|
||||
@@ -1353,7 +1353,7 @@ func TestHandleHTTPLogKeys_FilterActive_EnterConfirms(t *testing.T) {
|
||||
m.ui.httpLogState.filterActive = true
|
||||
m.ui.httpLogState.filterText = "api"
|
||||
|
||||
keyMsg := tea.KeyMsg{Type: tea.KeyEnter}
|
||||
keyMsg := tea.KeyPressMsg{Code: tea.KeyEnter}
|
||||
m.handleHTTPLogKeys(keyMsg)
|
||||
|
||||
assert.False(t, m.ui.httpLogState.filterActive)
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
func typeKeys(t *testing.T, m model, text string) {
|
||||
t.Helper()
|
||||
for _, r := range text {
|
||||
m.handleAddWizardKeys(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{r}})
|
||||
m.handleAddWizardKeys(tea.KeyPressMsg{Text: string(r)})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ func TestManualNamespace_BackFromLaterStepRestoresTextInput(t *testing.T) {
|
||||
m := newModelWithWizard(StepSelectResourceType)
|
||||
m.ui.addWizard.namespaceManual = true
|
||||
|
||||
m.handleAddWizardKeys(tea.KeyMsg{Type: tea.KeyEsc})
|
||||
m.handleAddWizardKeys(tea.KeyPressMsg{Code: tea.KeyEscape})
|
||||
|
||||
w := m.ui.addWizard
|
||||
assert.Equal(t, StepSelectNamespace, w.step)
|
||||
@@ -98,7 +98,7 @@ func TestKeysJK_StillNavigateInListMode(t *testing.T) {
|
||||
m := newModelWithWizard(StepSelectResourceType)
|
||||
m.ui.addWizard.inputMode = InputModeList
|
||||
|
||||
m.handleAddWizardKeys(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'j'}})
|
||||
m.handleAddWizardKeys(tea.KeyPressMsg{Text: string('j')})
|
||||
|
||||
assert.Equal(t, 1, m.ui.addWizard.cursor)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"charm.land/lipgloss/v2"
|
||||
)
|
||||
|
||||
// Color palette for wizards
|
||||
|
||||
@@ -987,7 +987,7 @@ func TestRenderDeleteConfirmation_NoSelected(t *testing.T) {
|
||||
|
||||
func TestModelView_MainViewDefault(t *testing.T) {
|
||||
m := newTestModel()
|
||||
result := m.View()
|
||||
result := m.View().Content
|
||||
assert.NotEmpty(t, result)
|
||||
}
|
||||
|
||||
@@ -1001,7 +1001,7 @@ func TestModelView_DeleteConfirmationOverlay(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
result := m.View()
|
||||
result := m.View().Content
|
||||
assert.Contains(t, result, "Delete Port Forward")
|
||||
}
|
||||
|
||||
@@ -1013,7 +1013,7 @@ func TestModelView_AddWizardOverlay(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
result := m.View()
|
||||
result := m.View().Content
|
||||
assert.NotEmpty(t, result)
|
||||
}
|
||||
|
||||
@@ -1028,7 +1028,7 @@ func TestModelView_RemoveWizardOverlay(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
result := m.View()
|
||||
result := m.View().Content
|
||||
assert.Contains(t, result, "alpha")
|
||||
}
|
||||
|
||||
@@ -1040,7 +1040,7 @@ func TestModelView_BenchmarkOverlay(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
result := m.View()
|
||||
result := m.View().Content
|
||||
assert.NotEmpty(t, result)
|
||||
}
|
||||
|
||||
@@ -1052,7 +1052,7 @@ func TestModelView_HTTPLogFullScreen(t *testing.T) {
|
||||
ui.mu.Unlock()
|
||||
m := model{ui: ui, termWidth: 120, termHeight: 40}
|
||||
|
||||
result := m.View()
|
||||
result := m.View().Content
|
||||
assert.Contains(t, result, "HTTP Traffic Log")
|
||||
}
|
||||
|
||||
@@ -1061,7 +1061,7 @@ func TestModelView_ZeroTermSize(t *testing.T) {
|
||||
m.termWidth = 0
|
||||
m.termHeight = 0
|
||||
// Must not panic even with zero term dims.
|
||||
result := m.View()
|
||||
result := m.View().Content
|
||||
assert.NotEmpty(t, result)
|
||||
}
|
||||
|
||||
@@ -1406,8 +1406,8 @@ func TestGetStatusIconAndText(t *testing.T) {
|
||||
|
||||
func TestDefaultMainViewColors(t *testing.T) {
|
||||
colors := defaultMainViewColors()
|
||||
assert.NotEmpty(t, string(colors.header))
|
||||
assert.NotEmpty(t, string(colors.active))
|
||||
assert.NotNil(t, colors.header)
|
||||
assert.NotNil(t, colors.active)
|
||||
}
|
||||
|
||||
func TestMainViewKeyBindings(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user