diff --git a/internal/tui/tab_alerts.go b/internal/tui/tab_alerts.go index a8ba6a7..a9d6d2b 100644 --- a/internal/tui/tab_alerts.go +++ b/internal/tui/tab_alerts.go @@ -148,23 +148,17 @@ func (m Model) viewAlertsTab() string { return "\n No alert channels configured. Press [n] to add one." } - maxName := 0 - for _, a := range m.alerts { - if n := len([]rune(a.Name)); n > maxName { - maxName = n - } + var headers []string + var widths []int + if m.isWide() { + headers = []string{"#", "", "NAME", "TYPE", "CONFIG", "LAST SENT"} + widths = []int{4, 3, 18, 12, 40, 12} + } else { + headers = []string{"#", "", "NAME", "TYPE", "CONFIG", "SENT"} + widths = []int{4, 3, 14, 10, 24, 8} } - - cols := []colDef{ - {"#", "#", 4, 4, false}, - {"", "", 3, 3, false}, - {"NAME", "NAME", 10, 20, false}, - {"TYPE", "TYPE", 10, 12, false}, - {"CONFIG", "CONFIG", 15, 40, true}, - {"SENT", "LAST SENT", 8, 12, false}, - } - headers, widths := m.computeTableLayout(cols, 0) nameW := widths[2] + cfgW := widths[4] return m.renderTable( headers, @@ -179,10 +173,10 @@ func (m Model) viewAlertsTab() string { fmtAlertHealth(h), m.zones.Mark(fmt.Sprintf("alert-%d", i), limitStr(a.Name, nameW-2)), fmtAlertType(a.Type), - fmtAlertConfig(struct { + limitStr(fmtAlertConfig(struct { Type string Settings map[string]string - }{a.Type, a.Settings}), + }{a.Type, a.Settings}), cfgW-2), fmtAlertLastSent(h), }) } diff --git a/internal/tui/tab_maint.go b/internal/tui/tab_maint.go index 3eb216f..8bf5541 100644 --- a/internal/tui/tab_maint.go +++ b/internal/tui/tab_maint.go @@ -100,16 +100,15 @@ func (m Model) viewMaintTab() string { return "\n No maintenance windows or incidents. Press [n] to create one." } - cols := []colDef{ - {"#", "#", 4, 4, false}, - {"TITLE", "TITLE", 12, 24, false}, - {"TYPE", "TYPE", 13, 14, false}, - {"MON", "MONITORS", 14, 22, true}, - {"ST", "STATUS", 11, 12, false}, - {"START", "STARTED", 14, 16, false}, - {"ENDS", "ENDS", 14, 16, false}, + var headers []string + var widths []int + if m.isWide() { + headers = []string{"#", "TITLE", "TYPE", "MONITORS", "STATUS", "STARTED", "ENDS"} + widths = []int{4, 24, 14, 22, 12, 16, 16} + } else { + headers = []string{"#", "TITLE", "TYPE", "MON", "ST", "START", "ENDS"} + widths = []int{4, 14, 13, 14, 11, 14, 14} } - headers, widths := m.computeTableLayout(cols, 0) titleW := widths[1] monW := widths[3] timeW := widths[5] diff --git a/internal/tui/tab_nodes.go b/internal/tui/tab_nodes.go index 6946e6d..3ddb79d 100644 --- a/internal/tui/tab_nodes.go +++ b/internal/tui/tab_nodes.go @@ -10,14 +10,15 @@ func (m Model) viewNodesTab() string { return "\n No probe nodes connected." } - cols := []colDef{ - {"NAME", "NAME", 12, 24, true}, - {"REGION", "REGION", 8, 14, false}, - {"SEEN", "LAST SEEN", 8, 20, false}, - {"VER", "VERSION", 8, 12, false}, - {"STATUS", "STATUS", 8, 10, false}, + var headers []string + var widths []int + if m.isWide() { + headers = []string{"NAME", "REGION", "LAST SEEN", "VERSION", "STATUS"} + widths = []int{24, 14, 16, 12, 10} + } else { + headers = []string{"NAME", "REGION", "SEEN", "VER", "STATUS"} + widths = []int{16, 10, 10, 8, 8} } - headers, widths := m.computeTableLayout(cols, 0) nameW := widths[0] return m.renderTable( diff --git a/internal/tui/tab_sites.go b/internal/tui/tab_sites.go index fecba98..20befa5 100644 --- a/internal/tui/tab_sites.go +++ b/internal/tui/tab_sites.go @@ -341,31 +341,29 @@ type tableLayout struct { } func (m Model) computeLayout() tableLayout { - cols := []colDef{ - {"#", "#", 4, 4, false}, - {"", "", 0, 0, false}, // NAME (special) - {"TYPE", "TYPE", 8, 10, false}, - {"STATUS", "STATUS", 8, 10, false}, - {"LAT", "LATENCY", 7, 10, false}, - {"UP%", "UPTIME", 8, 8, false}, - {"", "", 0, 0, false}, // HISTORY (special) - {"SSL", "SSL", 5, 5, false}, - {"RT", "RETRIES", 5, 9, false}, + wide := m.isWide() + + var fixed int + var headers []string + var widths []int + + if wide { + // # NAME TYPE STATUS LATENCY UPTIME HISTORY SSL RETRIES + headers = []string{"#", "NAME", "TYPE", "STATUS", "LATENCY", "UPTIME", "HISTORY", "SSL", "RETRIES"} + widths = []int{4, 0, 10, 10, 10, 8, 0, 7, 9} + fixed = 4 + 10 + 10 + 10 + 8 + 7 + 9 + } else { + // # NAME TYPE STATUS LAT UP% HISTORY SSL RT + headers = []string{"#", "NAME", "TYPE", "STATUS", "LAT", "UP%", "HISTORY", "SSL", "RT"} + widths = []int{4, 0, 8, 8, 7, 7, 0, 5, 5} + fixed = 4 + 8 + 8 + 7 + 7 + 5 + 5 } - numCols := len(cols) - borderOverhead := 2 + (numCols - 1) // left + right border + column separators - usable := m.termWidth - chromePadH - 2 - borderOverhead - if usable < 80 { - usable = 80 - } - - fixedMin := 0 - for i, c := range cols { - if i == 1 || i == 6 { - continue - } - fixedMin += c.minWidth + numCols := len(headers) + borderOverhead := 2 + (numCols - 1) + avail := m.termWidth - chromePadH - 2 - borderOverhead - fixed + if avail < 20 { + avail = 20 } maxName := 0 @@ -374,68 +372,26 @@ func (m Model) computeLayout() tableLayout { maxName = n } } - maxName += 4 // icon + padding + error preview room + maxName += 4 - avail := usable - fixedMin nameW := avail / 2 if nameW > maxName { nameW = maxName } - sparkW := avail - nameW - 2 - if nameW < 13 { nameW = 13 } if nameW > 40 { nameW = 40 } + + sparkW := avail - nameW if sparkW < 10 { sparkW = 10 } - if sparkW > 60 { - sparkW = 60 - } - surplus := usable - fixedMin - nameW - sparkW - 2 - if surplus < 0 { - surplus = 0 - } - - headers := make([]string, len(cols)) - widths := make([]int, len(cols)) - for i, c := range cols { - if i == 1 { - headers[i] = "NAME" - widths[i] = nameW - continue - } - if i == 6 { - headers[i] = "HISTORY" - widths[i] = sparkW + 2 - continue - } - - w := c.minWidth - expand := c.maxWidth - c.minWidth - if surplus >= expand { - w = c.maxWidth - surplus -= expand - } else if surplus > 0 { - w += surplus - surplus = 0 - } - - if w >= len(c.full)+2 { - headers[i] = c.full - } else { - headers[i] = c.short - } - widths[i] = w - } - - if surplus > 0 { - widths[6] += surplus - } + widths[1] = nameW + widths[6] = sparkW return tableLayout{ nameW: nameW, diff --git a/internal/tui/tab_users.go b/internal/tui/tab_users.go index 10e4108..a02badd 100644 --- a/internal/tui/tab_users.go +++ b/internal/tui/tab_users.go @@ -32,13 +32,15 @@ func (m Model) viewUsersTab() string { return "\n No users configured. Press [n] to add one." } - cols := []colDef{ - {"#", "#", 4, 4, false}, - {"USER", "USERNAME", 10, 18, false}, - {"ROLE", "ROLE", 8, 10, false}, - {"KEY", "PUBLIC KEY", 20, 60, true}, + var headers []string + var widths []int + if m.isWide() { + headers = []string{"#", "USERNAME", "ROLE", "PUBLIC KEY"} + widths = []int{4, 18, 10, 50} + } else { + headers = []string{"#", "USER", "ROLE", "KEY"} + widths = []int{4, 14, 8, 30} } - headers, widths := m.computeTableLayout(cols, 0) userW := widths[1] return m.renderTable( diff --git a/internal/tui/table_helpers.go b/internal/tui/table_helpers.go index 371ecee..175ca30 100644 --- a/internal/tui/table_helpers.go +++ b/internal/tui/table_helpers.go @@ -15,77 +15,10 @@ var ( type StyleOverride func(row, col int) *lipgloss.Style -type colDef struct { - short string - full string - minWidth int - maxWidth int - flex bool -} +const wideBreakpoint = 120 -func (m Model) computeTableLayout(cols []colDef, maxContentWidth int) ([]string, []int) { - numCols := len(cols) - borderOverhead := 2 + (numCols - 1) - usable := m.termWidth - chromePadH - 2 - borderOverhead - if usable < 40 { - usable = 40 - } - - fixedMin := 0 - flexIdx := -1 - for i, c := range cols { - if c.flex { - flexIdx = i - continue - } - fixedMin += c.minWidth - } - - flexW := usable - fixedMin - if maxContentWidth > 0 && flexW > maxContentWidth { - flexW = maxContentWidth - } - if flexW < 8 { - flexW = 8 - } - - surplus := usable - fixedMin - flexW - if surplus < 0 { - surplus = 0 - } - - headers := make([]string, numCols) - widths := make([]int, numCols) - for i, c := range cols { - if c.flex { - headers[i] = c.full - widths[i] = flexW - continue - } - - w := c.minWidth - expand := c.maxWidth - c.minWidth - if surplus >= expand { - w = c.maxWidth - surplus -= expand - } else if surplus > 0 { - w += surplus - surplus = 0 - } - - if w >= len(c.full)+2 { - headers[i] = c.full - } else { - headers[i] = c.short - } - widths[i] = w - } - - if surplus > 0 && flexIdx >= 0 { - widths[flexIdx] += surplus - } - - return headers, widths +func (m Model) isWide() bool { + return m.termWidth >= wideBreakpoint } func (m Model) renderTable(headers []string, items int, buildRows func(start, end int) [][]string, colWidths []int, styleOverride StyleOverride) string {