perf(tui): precompute maintenance set, use cached sites #172

Merged
lerko merged 1 commits from perf/maint-map-group-queries into main 2026-07-02 00:12:28 +00:00
6 changed files with 103 additions and 10 deletions
+1
View File
@@ -123,6 +123,7 @@ func (m *Model) refreshLive() {
ordered = filterSites(ordered, m.filterText) ordered = filterSites(ordered, m.filterText)
} }
m.sites = ordered m.sites = ordered
m.buildMaintSet()
m.refreshLogContent() m.refreshLogContent()
if m.selectedID != 0 { if m.selectedID != 0 {
+2 -4
View File
@@ -156,9 +156,8 @@ func resolveSparklineIndex(x, sparkWidth, dataLen int) int {
} }
func (m Model) groupSparkline(groupID int, width int, bg lipgloss.TerminalColor) string { func (m Model) groupSparkline(groupID int, width int, bg lipgloss.TerminalColor) string {
allSites := m.engine.GetAllSites()
var childStatuses [][]bool var childStatuses [][]bool
for _, s := range allSites { for _, s := range m.sites {
if s.ParentID == groupID && !s.Paused && !m.isMonitorInMaintenance(s.ID) { if s.ParentID == groupID && !s.Paused && !m.isMonitorInMaintenance(s.ID) {
hist, _ := m.engine.GetHistory(s.ID) hist, _ := m.engine.GetHistory(s.ID)
if len(hist.Statuses) > 0 { if len(hist.Statuses) > 0 {
@@ -209,9 +208,8 @@ func (m Model) groupSparkline(groupID int, width int, bg lipgloss.TerminalColor)
} }
func (m Model) groupUptime(groupID int) string { func (m Model) groupUptime(groupID int) string {
allSites := m.engine.GetAllSites()
var allStatuses [][]bool var allStatuses [][]bool
for _, s := range allSites { for _, s := range m.sites {
if s.ParentID == groupID && !s.Paused && !m.isMonitorInMaintenance(s.ID) { if s.ParentID == groupID && !s.Paused && !m.isMonitorInMaintenance(s.ID) {
hist, _ := m.engine.GetHistory(s.ID) hist, _ := m.engine.GetHistory(s.ID)
if len(hist.Statuses) > 0 { if len(hist.Statuses) > 0 {
+15 -6
View File
@@ -21,27 +21,36 @@ type maintFormData struct {
} }
func (m Model) isMonitorInMaintenance(monitorID int) bool { func (m Model) isMonitorInMaintenance(monitorID int) bool {
return m.maintSet[monitorID]
}
func (m *Model) buildMaintSet() {
set := make(map[int]bool)
now := time.Now()
for _, mw := range m.maintenanceWindows { for _, mw := range m.maintenanceWindows {
if mw.Type != "maintenance" { if mw.Type != "maintenance" {
continue continue
} }
now := time.Now()
if mw.StartTime.After(now) { if mw.StartTime.After(now) {
continue continue
} }
if !mw.EndTime.IsZero() && mw.EndTime.Before(now) { if !mw.EndTime.IsZero() && mw.EndTime.Before(now) {
continue continue
} }
if mw.MonitorID == 0 || mw.MonitorID == monitorID { if mw.MonitorID == 0 {
return true for _, s := range m.sites {
set[s.ID] = true
}
break
} }
set[mw.MonitorID] = true
for _, s := range m.sites { for _, s := range m.sites {
if s.ID == monitorID && s.ParentID > 0 && mw.MonitorID == s.ParentID { if s.ParentID == mw.MonitorID {
return true set[s.ID] = true
} }
} }
} }
return false m.maintSet = set
} }
func (m *Model) initMaintHuhForm() tea.Cmd { func (m *Model) initMaintHuhForm() tea.Cmd {
+1
View File
@@ -207,6 +207,7 @@ type Model struct {
lastTabLoad time.Time // last dispatch of loadTabDataCmd (throttle) lastTabLoad time.Time // last dispatch of loadTabDataCmd (throttle)
tabSeq int // seq of the newest issued tab-data load tabSeq int // seq of the newest issued tab-data load
maintSet map[int]bool
bottomPanel bottomPanel bottomPanel bottomPanel
detailOpen bool detailOpen bool
maintCursor int maintCursor int
+1
View File
@@ -231,6 +231,7 @@ func (m *Model) handleTabData(msg tabDataMsg) (tea.Model, tea.Cmd) {
} }
m.nodes = msg.nodes m.nodes = msg.nodes
m.maintenanceWindows = msg.maint m.maintenanceWindows = msg.maint
m.buildMaintSet()
m.clampCursor() m.clampCursor()
return m, nil return m, nil
} }
+83
View File
@@ -389,3 +389,86 @@ func TestDetailRefreshCmd_OnlyWhileDetailOpen(t *testing.T) {
t.Error("refresh Cmd issued for an out-of-range cursor") t.Error("refresh Cmd issued for an out-of-range cursor")
} }
} }
func TestBuildMaintSet_GlobalWindow(t *testing.T) {
m := newTestModel(&tuiMockStore{})
m.sites = []models.Site{
{SiteConfig: models.SiteConfig{ID: 1, Name: "a"}},
{SiteConfig: models.SiteConfig{ID: 2, Name: "b"}},
}
m.maintenanceWindows = []models.MaintenanceWindow{
{ID: 1, MonitorID: 0, Type: "maintenance", StartTime: time.Now().Add(-time.Hour)},
}
m.buildMaintSet()
if !m.maintSet[1] || !m.maintSet[2] {
t.Error("global maint window should mark all monitors")
}
}
func TestBuildMaintSet_TargetedWindow(t *testing.T) {
m := newTestModel(&tuiMockStore{})
m.sites = []models.Site{
{SiteConfig: models.SiteConfig{ID: 1, Name: "a"}},
{SiteConfig: models.SiteConfig{ID: 2, Name: "b"}},
}
m.maintenanceWindows = []models.MaintenanceWindow{
{ID: 1, MonitorID: 1, Type: "maintenance", StartTime: time.Now().Add(-time.Hour)},
}
m.buildMaintSet()
if !m.maintSet[1] {
t.Error("targeted window should mark monitor 1")
}
if m.maintSet[2] {
t.Error("targeted window should NOT mark monitor 2")
}
}
func TestBuildMaintSet_GroupPropagates(t *testing.T) {
m := newTestModel(&tuiMockStore{})
m.sites = []models.Site{
{SiteConfig: models.SiteConfig{ID: 10, Name: "group", Type: "group"}},
{SiteConfig: models.SiteConfig{ID: 11, Name: "child1", ParentID: 10}},
{SiteConfig: models.SiteConfig{ID: 12, Name: "child2", ParentID: 10}},
{SiteConfig: models.SiteConfig{ID: 20, Name: "other"}},
}
m.maintenanceWindows = []models.MaintenanceWindow{
{ID: 1, MonitorID: 10, Type: "maintenance", StartTime: time.Now().Add(-time.Hour)},
}
m.buildMaintSet()
if !m.maintSet[10] || !m.maintSet[11] || !m.maintSet[12] {
t.Error("group maint window should mark group + children")
}
if m.maintSet[20] {
t.Error("unrelated monitor should NOT be marked")
}
}
func TestBuildMaintSet_ExpiredIgnored(t *testing.T) {
m := newTestModel(&tuiMockStore{})
m.sites = []models.Site{
{SiteConfig: models.SiteConfig{ID: 1, Name: "a"}},
}
m.maintenanceWindows = []models.MaintenanceWindow{
{ID: 1, MonitorID: 1, Type: "maintenance",
StartTime: time.Now().Add(-2 * time.Hour),
EndTime: time.Now().Add(-1 * time.Hour)},
}
m.buildMaintSet()
if m.maintSet[1] {
t.Error("expired maint window should not mark monitor")
}
}
func TestBuildMaintSet_IncidentIgnored(t *testing.T) {
m := newTestModel(&tuiMockStore{})
m.sites = []models.Site{
{SiteConfig: models.SiteConfig{ID: 1, Name: "a"}},
}
m.maintenanceWindows = []models.MaintenanceWindow{
{ID: 1, MonitorID: 0, Type: "incident", StartTime: time.Now().Add(-time.Hour)},
}
m.buildMaintSet()
if m.maintSet[1] {
t.Error("incident windows should not mark monitors as in maintenance")
}
}