diff --git a/internal/ui/table.go b/internal/ui/table.go index f1c22bb..dd2ca7b 100644 --- a/internal/ui/table.go +++ b/internal/ui/table.go @@ -130,4 +130,119 @@ func (m *Model) updateTableRows() { } m.table.SetRows(rows) + + // Update table height and columns based on current terminal size + m.updateTableHeight() + m.updateTableColumns() +} + +// updateTableHeight dynamically adjusts table height based on terminal size +func (m *Model) updateTableHeight() { + if !m.ready { + return + } + + // Calculate dynamic table height based on terminal size + // Layout breakdown: + // - ASCII title: 5 lines (1 empty + 4 text lines) + // - Search bar: 1 line + // - Sort info: 1 line + // - Help text: 2 lines (multi-line text) + // - App margins/spacing: 2 lines + // Total reserved: 11 lines, mais réduisons à 7 pour forcer plus d'espace + reservedHeight := 7 // Réduction agressive pour tester + availableHeight := m.height - reservedHeight + hostCount := len(m.table.Rows()) + + // Minimum height should be at least 5 rows for usability + minTableHeight := 6 // 1 header + 5 data rows + maxTableHeight := availableHeight + if maxTableHeight < minTableHeight { + maxTableHeight = minTableHeight + } + + tableHeight := 1 // header + dataRowsNeeded := hostCount + maxDataRows := maxTableHeight - 1 // subtract 1 for header + + if dataRowsNeeded <= maxDataRows { + // We have enough space for all hosts + tableHeight += dataRowsNeeded + } else { + // We need to limit to available space + tableHeight += maxDataRows + } + + // FORCE: Ajoutons une ligne supplémentaire pour résoudre le problème + tableHeight += 1 + + // Update table height + m.table.SetHeight(tableHeight) +} + +// updateTableColumns dynamically adjusts table column widths based on terminal size +func (m *Model) updateTableColumns() { + if !m.ready { + return + } + + hostsToShow := m.filteredHosts + if hostsToShow == nil { + hostsToShow = m.hosts + } + + // Calculate base column widths + nameWidth := calculateNameColumnWidth(hostsToShow) + tagsWidth := calculateTagsColumnWidth(hostsToShow) + lastLoginWidth := calculateLastLoginColumnWidth(hostsToShow, m.historyManager) + + // Fixed column widths + hostnameWidth := 25 + userWidth := 12 + portWidth := 6 + + // Calculate total width needed for all columns + totalFixedWidth := hostnameWidth + userWidth + portWidth + totalVariableWidth := nameWidth + tagsWidth + lastLoginWidth + totalWidth := totalFixedWidth + totalVariableWidth + + // Available width (accounting for table borders and padding) + availableWidth := m.width - 4 // 4 chars for borders and padding + + // If the table is too wide, scale down the variable columns proportionally + if totalWidth > availableWidth { + excessWidth := totalWidth - availableWidth + variableColumnsWidth := totalVariableWidth + + if variableColumnsWidth > 0 { + // Reduce variable columns proportionally + nameReduction := (excessWidth * nameWidth) / variableColumnsWidth + tagsReduction := (excessWidth * tagsWidth) / variableColumnsWidth + lastLoginReduction := excessWidth - nameReduction - tagsReduction + + nameWidth = max(8, nameWidth-nameReduction) + tagsWidth = max(8, tagsWidth-tagsReduction) + lastLoginWidth = max(10, lastLoginWidth-lastLoginReduction) + } + } + + // Create new columns with updated widths + columns := []table.Column{ + {Title: "Name", Width: nameWidth}, + {Title: "Hostname", Width: hostnameWidth}, + {Title: "User", Width: userWidth}, + {Title: "Port", Width: portWidth}, + {Title: "Tags", Width: tagsWidth}, + {Title: "Last Login", Width: lastLoginWidth}, + } + + m.table.SetColumns(columns) +} + +// max returns the maximum of two integers +func max(a, b int) int { + if a > b { + return a + } + return b } diff --git a/internal/ui/tui.go b/internal/ui/tui.go index e998429..761d356 100644 --- a/internal/ui/tui.go +++ b/internal/ui/tui.go @@ -99,21 +99,12 @@ func NewModel(hosts []config.SSHHost, configFile string) Model { }) } - // Determine table height: 1 (header) + number of hosts (max 10) - hostCount := len(rows) - tableHeight := 1 // header - if hostCount < 10 { - tableHeight += hostCount - } else { - tableHeight += 10 - } - - // Create the table + // Create the table with initial height (will be updated on first WindowSizeMsg) t := table.New( table.WithColumns(columns), table.WithRows(rows), table.WithFocused(true), - table.WithHeight(tableHeight), + table.WithHeight(10), // Initial height, will be recalculated dynamically ) // Style the table @@ -135,6 +126,9 @@ func NewModel(hosts []config.SSHHost, configFile string) Model { // Initialize table styles based on initial focus state m.updateTableStyles() + // The table height will be properly set on the first WindowSizeMsg + // when m.ready becomes true and actual terminal dimensions are known + return m } diff --git a/internal/ui/update.go b/internal/ui/update.go index 5422dd0..eae25b6 100644 --- a/internal/ui/update.go +++ b/internal/ui/update.go @@ -31,6 +31,10 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.styles = NewStyles(m.width) m.ready = true + // Update table height and columns based on new window size + m.updateTableHeight() + m.updateTableColumns() + // Update sub-forms if they exist if m.addForm != nil { m.addForm.width = m.width diff --git a/internal/ui/view.go b/internal/ui/view.go index 19bec4a..46b6da6 100644 --- a/internal/ui/view.go +++ b/internal/ui/view.go @@ -39,7 +39,7 @@ func (m Model) renderListView() string { components = append(components, m.styles.Header.Render(asciiTitle)) // Add the search bar with the appropriate style based on focus - searchPrompt := "Search (/ to focus, Tab to switch): " + searchPrompt := "Search (/ to focus): " if m.searchMode { components = append(components, m.styles.SearchFocused.Render(searchPrompt+m.searchInput.View())) } else {