From e66e2495e18576b828a02809c28d5982d24c14be Mon Sep 17 00:00:00 2001 From: Jobin <43548644+kjvjobin@users.noreply.github.com> Date: Thu, 6 Nov 2025 21:39:11 +0530 Subject: [PATCH] Revert "fix(tui): Enter works after filtering" --- .github/workflows/auto-tag.yml | 100 --------------------------- CHANGELOG.md | 5 -- cmd/kubeutil.go | 4 +- cmd/root.go | 2 +- cmd/tui_picker.go | 121 ++++++++------------------------- 5 files changed, 32 insertions(+), 200 deletions(-) delete mode 100644 .github/workflows/auto-tag.yml delete mode 100644 CHANGELOG.md diff --git a/.github/workflows/auto-tag.yml b/.github/workflows/auto-tag.yml deleted file mode 100644 index f471101..0000000 --- a/.github/workflows/auto-tag.yml +++ /dev/null @@ -1,100 +0,0 @@ -name: Auto tag from PR labels - -on: - pull_request: - types: [closed] - branches: [main] - -permissions: - contents: write - -jobs: - tag: - if: github.event.pull_request.merged == true - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 # need full history & tags - - - name: Fetch tags - run: git fetch --tags --force - - - name: Determine bump from PR labels - id: bump - shell: bash - env: - PR_LABELS: ${{ toJson(github.event.pull_request.labels) }} - run: | - # Collect label names (lowercase) - labels=$(echo "$PR_LABELS" | jq -r '.[].name' | tr '[:upper:]' '[:lower:]') - echo "PR labels: $labels" - - level="patch" # default if none present - if echo "$labels" | grep -q '\bmajor\b'; then - level="major" - elif echo "$labels" | grep -q '\bminor\b'; then - level="minor" - elif echo "$labels" | grep -q '\bpatch\b'; then - level="patch" - fi - - echo "level=$level" >> "$GITHUB_OUTPUT" - echo "Selected bump: $level" - - - name: Compute next tag - id: next - shell: bash - env: - LEVEL: ${{ steps.bump.outputs.level }} - run: | - # Latest semver tag (vX.Y.Z). If none, seed at v0.1.0 - latest="$(git tag --list 'v*.*.*' | sort -V | tail -n1)" - if [[ -z "$latest" ]]; then - latest="v0.1.0" - echo "No previous tag; starting at $latest" - fi - ver="${latest#v}" - IFS='.' read -r MA MI PA <<<"$ver" - - case "$LEVEL" in - major) MA=$((MA+1)); MI=0; PA=0 ;; - minor) MI=$((MI+1)); PA=0 ;; - patch) PA=$((PA+1)) ;; - *) PA=$((PA+1)) ;; - esac - - next="v${MA}.${MI}.${PA}" - echo "latest=$latest" - echo "next=$next" - echo "next=$next" >> "$GITHUB_OUTPUT" - - - name: Tag and push - env: - NEXT: ${{ steps.next.outputs.next }} - run: | - if git rev-parse -q --verify "refs/tags/${NEXT}" >/dev/null; then - echo "Tag ${NEXT} already exists; nothing to do." - exit 0 - fi - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git tag -a "$NEXT" -m "chore(release): $NEXT" - git push origin "$NEXT" - - # Optional: comment back on the PR with the new version - - name: Comment with result - if: ${{ always() }} - uses: actions/github-script@v7 - with: - script: | - const next = core.getInput('next', { required: false }) || '${{ steps.next.outputs.next }}'; - const level = '${{ steps.bump.outputs.level }}'; - github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number, - body: `🔖 Released **${next}** (bump: \`${level}\`).` - }); - result-encoding: string diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index f1019c5..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -## v0.1.1 — TUI filter/select fix -- Fix: After filtering pods, pressing Enter now selects correctly. - - Enter applies filter; if one result, auto-selects; otherwise returns focus to table. - - Tab toggles focus; Esc cancels filter. -- Improves overall UX without changing keybindings for table navigation. diff --git a/cmd/kubeutil.go b/cmd/kubeutil.go index 3592961..d68f56a 100644 --- a/cmd/kubeutil.go +++ b/cmd/kubeutil.go @@ -2,10 +2,10 @@ package cmd import ( "fmt" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" "os" "path/filepath" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" ) func kubeconfigPath() string { diff --git a/cmd/root.go b/cmd/root.go index f313fd0..af05e1d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -27,7 +27,7 @@ var rootCmd = &cobra.Command{ `, RunE: func(cmd *cobra.Command, args []string) error { if flagVersion { - fmt.Println("kdebug v0.1.1") + fmt.Println("kdebug v0.1.0") return nil } return runInteractive() diff --git a/cmd/tui_picker.go b/cmd/tui_picker.go index 0c24b40..a472ed7 100644 --- a/cmd/tui_picker.go +++ b/cmd/tui_picker.go @@ -14,12 +14,9 @@ import ( "k8s.io/client-go/kubernetes" ) -type focusArea int - -const ( - focusTable focusArea = iota - focusFilter -) +type podRow struct { + ns, name, ready, status, restarts, age string +} type pickModel struct { allPods []corev1.Pod @@ -27,20 +24,19 @@ type pickModel struct { filter textinput.Model selected *corev1.Pod termWidth, termHt int - focus focusArea } func newPickModel(pods []corev1.Pod) pickModel { - m := pickModel{allPods: pods, focus: focusTable} + m := pickModel{allPods: pods} - // Filter input (ASCII prompt avoids width quirks) + // ASCII prompt avoids width quirks in some fonts ti := textinput.New() - ti.Placeholder = "Press / to filter… (Enter applies; Enter again selects; Esc cancels)" + ti.Placeholder = "Press / to filter… (Enter to select, Esc to cancel)" ti.Prompt = "> " ti.Blur() m.filter = ti - // Seed columns; will be resized on first WindowSizeMsg + // Seed; real sizing happens on first WindowSizeMsg cols := []table.Column{ {Title: "NAMESPACE", Width: 12}, {Title: "NAME", Width: 24}, @@ -57,12 +53,13 @@ func newPickModel(pods []corev1.Pod) pickModel { table.WithHeight(10), ) - // Compact styles (no vertical padding so rows are tight) + // ZERO padding/margins/borders so headers align perfectly st := table.Styles{ Header: lipgloss.NewStyle().Bold(true), Cell: lipgloss.NewStyle(), + // Selected row style—no extra padding Selected: lipgloss.NewStyle(). - Background(lipgloss.Color("57")). // purple + Background(lipgloss.Color("57")). // tweak if you like Foreground(lipgloss.Color("230")), } t.SetStyles(st) @@ -119,81 +116,46 @@ func (m pickModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.KeyMsg: switch k.String() { case "/": - m.focus = focusFilter m.filter.Focus() return m, nil - - case "tab": - // Toggle focus - if m.focus == focusFilter { - m.filter.Blur() - m.focus = focusTable - } else { - m.focus = focusFilter - m.filter.Focus() - } - return m, nil - case "esc": - // If filtering, blur (and keep current filtered rows) - if m.focus == focusFilter { + if m.filter.Focused() { m.filter.Blur() - m.focus = focusTable + m.filter.SetValue("") + m.applyFilter("") return m, nil } return m, tea.Quit - case "enter", "ctrl+j": - if m.focus == focusFilter { - // Apply filter first + if m.filter.Focused() { m.applyFilter(m.filter.Value()) - - // If exactly one row remains, auto-select it and quit - if len(m.table.Rows()) == 1 { - r := m.table.Rows()[0] - if pod, ok := m.findPod(r); ok { - m.selected = &pod - return m, tea.Quit - } - } - - // Otherwise blur filter and return focus to table; - // user can press Enter again to select the highlighted row. - m.filter.Blur() - m.focus = focusTable return m, nil } - - // Table-focused: select highlighted row if len(m.table.Rows()) == 0 { return m, nil } r := m.table.SelectedRow() - if pod, ok := m.findPod(r); ok { - m.selected = &pod + ns, name := r[0], r[1] + for i := range m.allPods { + if m.allPods[i].Namespace == ns && m.allPods[i].Name == name { + m.selected = &m.allPods[i] + break + } } return m, tea.Quit } } - // Default updates - var cmds []tea.Cmd - - // Update table always (so arrows work even when filter focused off) - var tcmd tea.Cmd - m.table, tcmd = m.table.Update(msg) - cmds = append(cmds, tcmd) + var cmd tea.Cmd + m.table, cmd = m.table.Update(msg) - // Update filter only when focused - if m.focus == focusFilter { + if m.filter.Focused() { var fcmd tea.Cmd m.filter, fcmd = m.filter.Update(msg) - // Live filtering: update rows as user types m.applyFilter(m.filter.Value()) - cmds = append(cmds, fcmd) + return m, tea.Batch(cmd, fcmd) } - - return m, tea.Batch(cmds...) + return m, cmd } func (m *pickModel) resize() { @@ -208,7 +170,7 @@ func (m *pickModel) resize() { m.table.SetHeight(tableHeight) m.table.SetWidth(m.termWidth) - // Column widths: fixed for most, NAME grows/shrinks + // Fixed columns; give remainder to NAME. wNS := 16 wReady := 5 wStatus := 18 @@ -220,7 +182,6 @@ func (m *pickModel) resize() { if wName < 10 { wName = 10 } - m.table.SetColumns([]table.Column{ {Title: "NAMESPACE", Width: wNS}, {Title: "NAME", Width: wName}, @@ -235,47 +196,23 @@ func (m *pickModel) applyFilter(q string) { q = strings.TrimSpace(strings.ToLower(q)) if q == "" { m.table.SetRows(rowsFromPods(m.allPods)) - // Keep cursor in-bounds - if len(m.table.Rows()) > 0 && m.table.Cursor() >= len(m.table.Rows()) { - m.table.SetCursor(len(m.table.Rows()) - 1) - } return } filtered := make([]corev1.Pod, 0, len(m.allPods)) for _, p := range m.allPods { s := strings.ToLower(strings.Join([]string{ - p.Namespace, - p.Name, - podStatus(&p), - fmt.Sprintf("%v", p.Labels), + p.Namespace, p.Name, podStatus(&p), fmt.Sprintf("%v", p.Labels), }, " ")) if strings.Contains(s, q) { filtered = append(filtered, p) } } m.table.SetRows(rowsFromPods(filtered)) - // Reset cursor to first result when the list changes - if len(m.table.Rows()) > 0 { - m.table.SetCursor(0) - } -} - -func (m pickModel) findPod(r table.Row) (corev1.Pod, bool) { - if len(r) < 2 { - return corev1.Pod{}, false - } - ns, name := r[0], r[1] - for i := range m.allPods { - if m.allPods[i].Namespace == ns && m.allPods[i].Name == name { - return m.allPods[i], true - } - } - return corev1.Pod{}, false } func (m pickModel) View() string { - title := lipgloss.NewStyle().Bold(true). - Render("Select a pod (↑/↓ or j/k move, / filter, Enter selects, Tab switch, Esc cancel)") + // No extra blank lines; keeps header tight to first row + title := lipgloss.NewStyle().Bold(true).Render("Select a pod (↑/↓ or j/k to move, / to filter, Enter to select, Esc to cancel)") return title + "\n" + m.table.View() + "\n" + m.filter.View() }