package ui import ( "strings" "sshm/internal/config" "sshm/internal/history" "github.com/charmbracelet/bubbles/table" ) // calculateNameColumnWidth calculates the optimal width for the Name column // based on the longest hostname, with a minimum of 8 and maximum of 40 characters func calculateNameColumnWidth(hosts []config.SSHHost) int { maxLength := 8 // Minimum width to accommodate the "Name" header for _, host := range hosts { if len(host.Name) > maxLength { maxLength = len(host.Name) } } // Add some padding (2 characters) for better visual spacing maxLength += 2 // Limit the maximum width to avoid extremely large columns if maxLength > 40 { maxLength = 40 } return maxLength } // calculateTagsColumnWidth calculates the optimal width for the Tags column // based on the longest tag string, with a minimum of 8 and maximum of 40 characters func calculateTagsColumnWidth(hosts []config.SSHHost) int { maxLength := 8 // Minimum width to accommodate the "Tags" header for _, host := range hosts { // Format tags exactly as they appear in the table var tagsStr string if len(host.Tags) > 0 { // Add the # prefix to each tag and join them with spaces var formattedTags []string for _, tag := range host.Tags { formattedTags = append(formattedTags, "#"+tag) } tagsStr = strings.Join(formattedTags, " ") } if len(tagsStr) > maxLength { maxLength = len(tagsStr) } } // Add some padding (2 characters) for better visual spacing maxLength += 2 // Limit the maximum width to avoid extremely large columns if maxLength > 40 { maxLength = 40 } return maxLength } // calculateLastLoginColumnWidth calculates the optimal width for the Last Login column // based on the longest time format, with a minimum of 12 and maximum of 20 characters func calculateLastLoginColumnWidth(hosts []config.SSHHost, historyManager *history.HistoryManager) int { maxLength := 12 // Minimum width to accommodate the "Last Login" header if historyManager != nil { for _, host := range hosts { if lastConnect, exists := historyManager.GetLastConnectionTime(host.Name); exists { timeStr := formatTimeAgo(lastConnect) if len(timeStr) > maxLength { maxLength = len(timeStr) } } } } // Add some padding (2 characters) for better visual spacing maxLength += 2 // Limit the maximum width to avoid extremely large columns if maxLength > 20 { maxLength = 20 } return maxLength } // updateTableRows updates the table with filtered hosts func (m *Model) updateTableRows() { var rows []table.Row hostsToShow := m.filteredHosts if hostsToShow == nil { hostsToShow = m.hosts } for _, host := range hostsToShow { // Format tags for display var tagsStr string if len(host.Tags) > 0 { // Add the # prefix to each tag and join them with spaces var formattedTags []string for _, tag := range host.Tags { formattedTags = append(formattedTags, "#"+tag) } tagsStr = strings.Join(formattedTags, " ") } // Format last login information var lastLoginStr string if m.historyManager != nil { if lastConnect, exists := m.historyManager.GetLastConnectionTime(host.Name); exists { lastLoginStr = formatTimeAgo(lastConnect) } } rows = append(rows, table.Row{ host.Name, host.Hostname, host.User, host.Port, tagsStr, lastLoginStr, }) } 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 }