chore(tui): polish demo + regenerate screenshots
Rework the VHS demo so the README screenshots actually entice a download. Demo data / tooling: - seed.yaml: real, reachable service URLs (detail now shows nextcloud.com, not example.com); Auth Portal -> non-resolving home.arpa host so it reads as a believable, reliably-DOWN monitor - backfill: transient outages for Nextcloud/Jellyfin/Immich aligned with their state changes (uptime % now matches); log timestamps derived from now so the Logs view reads chronologically; real SSL warning; three probe nodes across regions; seeded alert send health - demo.tape: shorter warm-up, added Nodes + theme captures, ordered so every shot stays inside the 60s node-freshness window (consistent probe count) - vhs/crop: new tool to trim the empty terminal border around each screenshot - setup.sh: build backfill up front for deterministic timing; UPTOP_DEMO=1 Supporting code: - persist alert send health (new alert_health table, load on startup, best-effort save on send) so health/last-sent survive restarts - latency Min/Avg/Max ignore failed checks (no more "Min 0ms") - correct "probe"/"probes" pluralization - stable status dot instead of an animated spinner under UPTOP_DEMO
This commit is contained in:
+24
-6
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -122,6 +123,10 @@ type Model struct {
|
||||
|
||||
filterMode bool
|
||||
filterText string
|
||||
|
||||
// demoMode renders a stable status dot instead of the animated pulse so
|
||||
// screenshots/recordings don't capture the spinner mid-frame. Set via UPTOP_DEMO=1.
|
||||
demoMode bool
|
||||
}
|
||||
|
||||
func InitialModel(isAdmin bool, s store.Store, eng *monitor.Engine) Model {
|
||||
@@ -155,6 +160,7 @@ func InitialModel(isAdmin bool, s store.Store, eng *monitor.Engine) Model {
|
||||
collapsed: collapsed,
|
||||
theme: theme,
|
||||
themeIndex: themeIdx,
|
||||
demoMode: os.Getenv("UPTOP_DEMO") == "1",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -754,11 +760,6 @@ func (m *Model) submitForm() {
|
||||
}
|
||||
|
||||
func (m Model) pulseIndicator() string {
|
||||
frame := m.tickCount % len(pulseFrames)
|
||||
brightness := int(m.pulsePos*155) + 100
|
||||
if brightness > 255 {
|
||||
brightness = 255
|
||||
}
|
||||
hasDown := false
|
||||
for _, s := range m.sites {
|
||||
if !s.Paused && !m.isMonitorInMaintenance(s.ID) && (s.Status == "DOWN" || s.Status == "SSL EXP") {
|
||||
@@ -766,6 +767,19 @@ func (m Model) pulseIndicator() string {
|
||||
break
|
||||
}
|
||||
}
|
||||
// Stills can't show animation: render a stable status dot in demo mode.
|
||||
if m.demoMode {
|
||||
c := m.theme.Success
|
||||
if hasDown {
|
||||
c = m.theme.Danger
|
||||
}
|
||||
return lipgloss.NewStyle().Foreground(c).Render("●")
|
||||
}
|
||||
frame := m.tickCount % len(pulseFrames)
|
||||
brightness := int(m.pulsePos*155) + 100
|
||||
if brightness > 255 {
|
||||
brightness = 255
|
||||
}
|
||||
var color string
|
||||
if hasDown {
|
||||
color = fmt.Sprintf("#%02x%02x%02x", brightness, brightness/4, brightness/4)
|
||||
@@ -953,7 +967,11 @@ func (m Model) viewDashboard() string {
|
||||
online++
|
||||
}
|
||||
}
|
||||
statusParts = append(statusParts, fmt.Sprintf("%d probes", online))
|
||||
probeLabel := "probes"
|
||||
if online == 1 {
|
||||
probeLabel = "probe"
|
||||
}
|
||||
statusParts = append(statusParts, fmt.Sprintf("%d %s", online, probeLabel))
|
||||
}
|
||||
statusLine := strings.Join(statusParts, subtleStyle.Render(" · "))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user