Skip to content

Commit 179c3ed

Browse files
seanb4tclaude
andcommitted
fix(tui): skip preview pane in tab cycle when no email is selected
Tab previously cycled through all three panes (Mailbox → EmailList → Preview) even when the preview was empty, requiring two Tab presses to reach mailboxes from the email list. Now the preview pane is excluded from the cycle until an email is actually selected. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 4b2cbfb commit 179c3ed

10 files changed

Lines changed: 38 additions & 20 deletions

internal/tui/integration_selectmailbox_test.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ func TestIntegration_SelectMailbox_JK(t *testing.T) {
2222
return bytes.Contains(bts, []byte("Inbox"))
2323
}, teatest.WithDuration(5*time.Second))
2424

25-
// Focus cycles: PaneEmailList → PanePreview → PaneMailbox (2 tabs).
26-
tm.Send(tea.KeyMsg{Type: tea.KeyTab})
25+
// Focus cycles: PaneEmailList → PaneMailbox (1 tab, preview skipped when no email selected).
2726
tm.Send(tea.KeyMsg{Type: tea.KeyTab})
2827

2928
// Move cursor down twice: Inbox → Drafts → Sent.
@@ -67,8 +66,7 @@ func TestIntegration_SelectMailbox_Arrows(t *testing.T) {
6766
return bytes.Contains(bts, []byte("Inbox"))
6867
}, teatest.WithDuration(5*time.Second))
6968

70-
// Focus cycles: PaneEmailList → PanePreview → PaneMailbox (2 tabs).
71-
tm.Send(tea.KeyMsg{Type: tea.KeyTab})
69+
// Focus cycles: PaneEmailList → PaneMailbox (1 tab, preview skipped when no email selected).
7270
tm.Send(tea.KeyMsg{Type: tea.KeyTab})
7371

7472
// Move cursor down twice with arrow keys: Inbox → Drafts → Sent.

internal/tui/layout.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@ type paneLayout struct {
3434

3535
// paneManager tracks focus, sidebar visibility, and split ratio.
3636
type paneManager struct {
37-
focus PaneID
38-
sidebar bool
39-
splitPct int // percentage of main area for email list (30-80)
37+
focus PaneID
38+
sidebar bool
39+
hasPreview bool // true when an email is selected and preview pane has content
40+
splitPct int // percentage of main area for email list (30-80)
4041
}
4142

4243
func newPaneManager() paneManager {
@@ -59,10 +60,15 @@ func (pm *paneManager) cycleFocus() {
5960
}
6061

6162
func (pm *paneManager) visiblePanes() []PaneID {
63+
var panes []PaneID
6264
if pm.sidebar {
63-
return []PaneID{PaneMailbox, PaneEmailList, PanePreview}
65+
panes = append(panes, PaneMailbox)
6466
}
65-
return []PaneID{PaneEmailList, PanePreview}
67+
panes = append(panes, PaneEmailList)
68+
if pm.hasPreview {
69+
panes = append(panes, PanePreview)
70+
}
71+
return panes
6672
}
6773

6874
func (pm *paneManager) toggleSidebar() {

internal/tui/layout_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ func TestNewPaneManager(t *testing.T) {
2222

2323
func TestPaneManager_CycleFocus(t *testing.T) {
2424
pm := newPaneManager()
25+
pm.hasPreview = true
2526
pm.focus = PaneMailbox
2627

2728
pm.cycleFocus()
@@ -34,9 +35,21 @@ func TestPaneManager_CycleFocus(t *testing.T) {
3435
assert.Equal(t, PaneMailbox, pm.focus)
3536
}
3637

38+
func TestPaneManager_CycleFocus_SkipsPreviewWhenEmpty(t *testing.T) {
39+
pm := newPaneManager()
40+
pm.focus = PaneMailbox
41+
42+
pm.cycleFocus()
43+
assert.Equal(t, PaneEmailList, pm.focus)
44+
45+
pm.cycleFocus()
46+
assert.Equal(t, PaneMailbox, pm.focus, "should wrap back to mailbox, skipping empty preview")
47+
}
48+
3749
func TestPaneManager_CycleFocus_SkipsSidebarWhenHidden(t *testing.T) {
3850
pm := newPaneManager()
3951
pm.sidebar = false
52+
pm.hasPreview = true
4053
pm.focus = PaneEmailList
4154

4255
pm.cycleFocus()

internal/tui/testdata/TestIntegration_DashboardLoad.golden

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
│ 5 items ││ 5 items │
66
│ ││ │
77
││ Inbox (3) │││ * — Weekly Team Standup Notes │
8-
││ 25 emails │││ 7h ago Here are the notes from today's standup. Backend team completed the API migrati… │
8+
││ 25 emails │││ 8h ago Here are the notes from today's standup. Backend team completed the API migrati… │
99
│ ││ │
1010
│ Drafts ││ ! — Project Deadline Update │
11-
│ 2 emails ││ 8h ago The deadline for Phase 2 has been moved to March 15th. Please update your proje…
11+
│ 2 emails ││ 10h ago The deadline for Phase 2 has been moved to March 15th. Please update your proje… │
1212
│ ││ │
1313
│ Sent ││ — Invoice #2847 Attached │
1414
│ 150 emails ││ 1d ago Please find attached the invoice for services rendered in January 2026. Payment… │

internal/tui/testdata/TestIntegration_NarrowTerminal.golden

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
│ 5 items │
66
│ │
77
││ * — Weekly Team Standup Notes │
8-
││ 7h ago Here are the notes from today's standup. Backen…│
8+
││ 8h ago Here are the notes from today's standup. Backen…│
99
│ ••••• │
1010
│ │
1111
│ ↑/k up • ↓/j down • / filter • q quit • ? more │

internal/tui/testdata/TestIntegration_ReadEmail.golden

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
│ 5 items ││ 5 items │
66
│ ││ │
77
││ Inbox (3) │││ * — Weekly Team Standup Notes │
8-
││ 25 emails │││ 7h ago Here are the notes from today's standup. Backend team completed the API migrati… │
8+
││ 25 emails │││ 8h ago Here are the notes from today's standup. Backend team completed the API migrati… │
99
│ ││ │
1010
│ Drafts ││ ! — Project Deadline Update │
11-
│ 2 emails ││ 8h ago The deadline for Phase 2 has been moved to March 15th. Please update your proje…
11+
│ 2 emails ││ 10h ago The deadline for Phase 2 has been moved to March 15th. Please update your proje… │
1212
│ ││ │
1313
│ Sent ││ — Invoice #2847 Attached │
1414
│ 150 emails ││ 1d ago Please find attached the invoice for services rendered in January 2026. Payment… │

internal/tui/testdata/TestIntegration_SelectMailbox_Arrows.golden

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
│ 5 items ││ 5 items │
66
│ ││ │
77
│ Inbox (3) │││ * — Weekly Team Standup Notes │
8-
│ 25 emails │││ 7h ago Here are the notes from today's standup. Backend team completed the API migrati… │
8+
│ 25 emails │││ 8h ago Here are the notes from today's standup. Backend team completed the API migrati… │
99
│ ││ │
1010
│ Drafts ││ ! — Project Deadline Update │
11-
│ 2 emails ││ 8h ago The deadline for Phase 2 has been moved to March 15th. Please update your proje…
11+
│ 2 emails ││ 10h ago The deadline for Phase 2 has been moved to March 15th. Please update your proje… │
1212
│ ││ │
1313
││ Sent ││ — Invoice #2847 Attached │
1414
││ 150 emails ││ 1d ago Please find attached the invoice for services rendered in January 2026. Payment… │

internal/tui/testdata/TestIntegration_SelectMailbox_JK.golden

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
│ 5 items ││ 5 items │
66
│ ││ │
77
│ Inbox (3) │││ * — Weekly Team Standup Notes │
8-
│ 25 emails │││ 7h ago Here are the notes from today's standup. Backend team completed the API migrati… │
8+
│ 25 emails │││ 8h ago Here are the notes from today's standup. Backend team completed the API migrati… │
99
│ ││ │
1010
│ Drafts ││ ! — Project Deadline Update │
11-
│ 2 emails ││ 8h ago The deadline for Phase 2 has been moved to March 15th. Please update your proje…
11+
│ 2 emails ││ 10h ago The deadline for Phase 2 has been moved to March 15th. Please update your proje… │
1212
│ ││ │
1313
││ Sent ││ — Invoice #2847 Attached │
1414
││ 150 emails ││ 1d ago Please find attached the invoice for services rendered in January 2026. Payment… │

internal/tui/testdata/TestIntegration_ToggleSidebar.golden

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
│ 5 items │
66
│ │
77
││ * — Weekly Team Standup Notes │
8-
││ 7h ago Here are the notes from today's standup. Backend team completed the API migrati… │
8+
││ 8h ago Here are the notes from today's standup. Backend team completed the API migrati… │
99
│ │
1010
│ ! — Project Deadline Update │
11-
8h ago The deadline for Phase 2 has been moved to March 15th. Please update your proje…
11+
10h ago The deadline for Phase 2 has been moved to March 15th. Please update your proje… │
1212
│ │
1313
│ — Invoice #2847 Attached │
1414
│ 1d ago Please find attached the invoice for services rendered in January 2026. Payment… │

internal/tui/tui.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ func (m Model) handleLayoutKeys(msg tea.KeyMsg) (tea.Model, tea.Cmd, bool) { //n
318318
}
319319
switch msg.String() {
320320
case "tab":
321+
m.panes.hasPreview = m.emailReader != nil
321322
m.panes.cycleFocus()
322323
return m, nil, true
323324
case "enter":

0 commit comments

Comments
 (0)