refactor(tui): extract shared table rendering, fix cursor bounds

- New table_helpers.go with renderTable() and shared styles
- Remove 4 duplicated style blocks (header/cell/selected/border)
  from tab_alerts.go and tab_users.go
- All 3 tab views now use renderTable() for offset/end calc,
  selected row highlighting, and table construction
- Sites tab keeps siteGroupStyle via StyleOverride callback
- Clamp cursor to list length at end of refreshData() to prevent
  index-out-of-bounds after concurrent list changes
- Fix off-by-one in tab click handler (i <= maxTabs → i < tabCount)
This commit is contained in:
2026-05-15 00:49:14 -04:00
parent d6f33a4d1f
commit 0e6dc774cb
5 changed files with 204 additions and 249 deletions
+17 -4
View File
@@ -346,11 +346,11 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
func (m *Model) handleClick(msg tea.MouseMsg) (tea.Model, tea.Cmd) {
maxTabs := 3
if !m.isAdmin {
maxTabs = 2
tabCount := 3
if m.isAdmin {
tabCount = 4
}
for i := 0; i <= maxTabs; i++ {
for i := 0; i < tabCount; i++ {
if m.zones.Get(fmt.Sprintf("tab-%d", i)).InBounds(msg) {
m.switchTab(i)
return m, nil
@@ -477,6 +477,19 @@ func (m *Model) refreshData() {
}
}
m.logViewport.SetContent(strings.Join(monitor.GetLogs(), "\n"))
listLen := len(m.sites)
if m.currentTab == 1 {
listLen = len(m.alerts)
} else if m.currentTab == 3 {
listLen = len(m.users)
}
if listLen > 0 && m.cursor >= listLen {
m.cursor = listLen - 1
}
if m.cursor < m.tableOffset {
m.tableOffset = m.cursor
}
}
func (m *Model) submitForm() {