diff options
Diffstat (limited to 'internal/tui/page')
| -rw-r--r-- | internal/tui/page/logs.go | 160 |
1 files changed, 143 insertions, 17 deletions
diff --git a/internal/tui/page/logs.go b/internal/tui/page/logs.go index c3de8684d..1495de8cf 100644 --- a/internal/tui/page/logs.go +++ b/internal/tui/page/logs.go @@ -17,10 +17,40 @@ type LogPage interface { layout.Sizeable layout.Bindings } + +// Custom keybindings for logs page +type logsKeyMap struct { + Left key.Binding + Right key.Binding + Tab key.Binding +} + +var logsKeys = logsKeyMap{ + Left: key.NewBinding( + key.WithKeys("left", "h"), + key.WithHelp("←/h", "left pane"), + ), + Right: key.NewBinding( + key.WithKeys("right", "l"), + key.WithHelp("→/l", "right pane"), + ), + Tab: key.NewBinding( + key.WithKeys("tab"), + key.WithHelp("tab", "switch panes"), + ), +} + type logsPage struct { width, height int table layout.Container details layout.Container + activePane int // 0 = table, 1 = details + keyMap logsKeyMap +} + +// Message to switch active pane +type switchPaneMsg struct { + pane int // 0 = table, 1 = details } func (p *logsPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { @@ -30,14 +60,54 @@ func (p *logsPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { p.width = msg.Width p.height = msg.Height return p, p.SetSize(msg.Width, msg.Height) + case switchPaneMsg: + p.activePane = msg.pane + if p.activePane == 0 { + p.table.Focus() + p.details.Blur() + } else { + p.table.Blur() + p.details.Focus() + } + return p, nil + case tea.KeyMsg: + // Handle navigation keys + switch { + case key.Matches(msg, p.keyMap.Left): + return p, func() tea.Msg { + return switchPaneMsg{pane: 0} + } + case key.Matches(msg, p.keyMap.Right): + return p, func() tea.Msg { + return switchPaneMsg{pane: 1} + } + case key.Matches(msg, p.keyMap.Tab): + return p, func() tea.Msg { + return switchPaneMsg{pane: (p.activePane + 1) % 2} + } + } } - table, cmd := p.table.Update(msg) - cmds = append(cmds, cmd) - p.table = table.(layout.Container) - details, cmd := p.details.Update(msg) - cmds = append(cmds, cmd) - p.details = details.(layout.Container) + // Update the active pane first to handle keyboard input + if p.activePane == 0 { + table, cmd := p.table.Update(msg) + cmds = append(cmds, cmd) + p.table = table.(layout.Container) + + // Update details pane without focus + details, cmd := p.details.Update(msg) + cmds = append(cmds, cmd) + p.details = details.(layout.Container) + } else { + details, cmd := p.details.Update(msg) + cmds = append(cmds, cmd) + p.details = details.(layout.Container) + + // Update table pane without focus + table, cmd := p.table.Update(msg) + cmds = append(cmds, cmd) + p.table = table.(layout.Container) + } return p, tea.Batch(cmds...) } @@ -48,14 +118,28 @@ func (p *logsPage) View() string { // Add padding to the right of the table view tableView := lipgloss.NewStyle().PaddingRight(3).Render(p.table.View()) + // Add border to the active pane + tableStyle := lipgloss.NewStyle() + detailsStyle := lipgloss.NewStyle() + + if p.activePane == 0 { + tableStyle = tableStyle.BorderForeground(t.Primary()) + } else { + detailsStyle = detailsStyle.BorderForeground(t.Primary()) + } + + tableView = tableStyle.Render(tableView) + detailsView := detailsStyle.Render(p.details.View()) + return styles.ForceReplaceBackgroundWithLipgloss( lipgloss.JoinVertical( lipgloss.Left, - styles.Bold().Render(" esc")+styles.Muted().Render(" to go back"), + styles.Bold().Render(" esc")+styles.Muted().Render(" to go back")+ + " "+styles.Bold().Render(" tab/←→/h/l")+styles.Muted().Render(" to switch panes"), "", lipgloss.JoinHorizontal(lipgloss.Top, tableView, - p.details.View(), + detailsView, ), "", ), @@ -64,7 +148,21 @@ func (p *logsPage) View() string { } func (p *logsPage) BindingKeys() []key.Binding { - return p.table.BindingKeys() + // Add our custom keybindings + bindings := []key.Binding{ + p.keyMap.Left, + p.keyMap.Right, + p.keyMap.Tab, + } + + // Add the active pane's keybindings + if p.activePane == 0 { + bindings = append(bindings, p.table.BindingKeys()...) + } else { + bindings = append(bindings, p.details.BindingKeys()...) + } + + return bindings } // GetSize implements LogPage. @@ -76,22 +174,50 @@ func (p *logsPage) GetSize() (int, int) { func (p *logsPage) SetSize(width int, height int) tea.Cmd { p.width = width p.height = height + + // Account for padding between panes (3 characters) + const padding = 3 + leftPaneWidth := (width - padding) / 2 + rightPaneWidth := width - leftPaneWidth - padding + return tea.Batch( - p.table.SetSize(width/2, height-3), - p.details.SetSize(width/2, height-3), + p.table.SetSize(leftPaneWidth, height-3), + p.details.SetSize(rightPaneWidth, height-3), ) } func (p *logsPage) Init() tea.Cmd { - return tea.Batch( - p.table.Init(), - p.details.Init(), - ) + // Start with table pane active + p.activePane = 0 + p.table.Focus() + p.details.Blur() + + // Force an initial selection to update the details pane + var cmds []tea.Cmd + cmds = append(cmds, p.table.Init()) + cmds = append(cmds, p.details.Init()) + + // Send a key down and then key up to select the first row + // This ensures the details pane is populated when returning to the logs page + cmds = append(cmds, func() tea.Msg { + return tea.KeyMsg{Type: tea.KeyDown} + }) + cmds = append(cmds, func() tea.Msg { + return tea.KeyMsg{Type: tea.KeyUp} + }) + + return tea.Batch(cmds...) } func NewLogsPage() LogPage { + // Create containers with borders to visually indicate active pane + tableContainer := layout.NewContainer(logs.NewLogsTable(), layout.WithBorderHorizontal()) + detailsContainer := layout.NewContainer(logs.NewLogsDetails(), layout.WithBorderHorizontal()) + return &logsPage{ - table: layout.NewContainer(logs.NewLogsTable()), - details: layout.NewContainer(logs.NewLogsDetails()), + table: tableContainer, + details: detailsContainer, + activePane: 0, // Start with table pane active + keyMap: logsKeys, } } |
