feat(tui): add SLA reporting view
CI / test (pull_request) Successful in 2m37s
CI / lint (pull_request) Successful in 57s
CI / vulncheck (pull_request) Successful in 51s

Full-screen SLA report accessible via [s] from detail panel.
Computes uptime%, downtime, outage count, longest outage, MTTR,
and MTBF from state_changes table. Includes daily breakdown with
bar chart, switchable time periods (24h/7d/30d/90d), and
scrollable viewport. LATE/STALE treated as UP for SLA purposes.
This commit is contained in:
2026-06-04 13:19:30 -04:00
parent 50ee878097
commit 3480679176
14 changed files with 661 additions and 7 deletions
+17
View File
@@ -370,6 +370,23 @@ func (s *SQLStore) GetStateChanges(siteID int, limit int) ([]models.StateChange,
return changes, rows.Err()
}
func (s *SQLStore) GetStateChangesSince(siteID int, since time.Time) ([]models.StateChange, error) {
rows, err := s.db.Query(s.q("SELECT id, site_id, from_status, to_status, error_reason, changed_at FROM state_changes WHERE site_id = ? AND changed_at >= ? ORDER BY changed_at DESC"), siteID, since)
if err != nil {
return nil, err
}
defer rows.Close()
var changes []models.StateChange
for rows.Next() {
var sc models.StateChange
if err := rows.Scan(&sc.ID, &sc.SiteID, &sc.FromStatus, &sc.ToStatus, &sc.ErrorReason, &sc.ChangedAt); err != nil {
return changes, err
}
changes = append(changes, sc)
}
return changes, rows.Err()
}
func (s *SQLStore) SaveCheck(siteID int, latencyNs int64, isUp bool) error {
return s.SaveCheckFromNode(siteID, "", latencyNs, isUp)
}
+3
View File
@@ -1,6 +1,8 @@
package store
import (
"time"
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
)
@@ -41,6 +43,7 @@ type Store interface {
// State Changes
SaveStateChange(siteID int, fromStatus, toStatus, errorReason string) error
GetStateChanges(siteID int, limit int) ([]models.StateChange, error)
GetStateChangesSince(siteID int, since time.Time) ([]models.StateChange, error)
// Nodes
RegisterNode(node models.ProbeNode) error