diff --git a/internal/models/models.go b/internal/models/models.go
index f79c9c5..467fd33 100644
--- a/internal/models/models.go
+++ b/internal/models/models.go
@@ -24,6 +24,7 @@ type Site struct {
DNSResolveType string
DNSServer string
IgnoreTLS bool
+ Paused bool
FailureCount int
Status string
diff --git a/internal/monitor/monitor.go b/internal/monitor/monitor.go
index 791aac1..76a55bb 100644
--- a/internal/monitor/monitor.go
+++ b/internal/monitor/monitor.go
@@ -162,6 +162,7 @@ func UpdateSiteConfig(site models.Site) {
s.DNSResolveType = site.DNSResolveType
s.DNSServer = site.DNSServer
s.IgnoreTLS = site.IgnoreTLS
+ s.Paused = site.Paused
LiveState[site.ID] = s
}
}
@@ -173,10 +174,26 @@ func RemoveSite(id int) {
RemoveHistory(id)
}
+func ToggleSitePause(id int) bool {
+ Mutex.Lock()
+ defer Mutex.Unlock()
+ site, ok := LiveState[id]
+ if !ok {
+ return false
+ }
+ site.Paused = !site.Paused
+ LiveState[id] = site
+ if site.Paused {
+ AddLog(fmt.Sprintf("Monitor '%s' paused", site.Name))
+ } else {
+ AddLog(fmt.Sprintf("Monitor '%s' resumed", site.Name))
+ }
+ return site.Paused
+}
+
func monitorRoutine(id int) {
checkByID(id)
for {
- // If paused, just sleep loop to keep goroutine alive but idle
if !IsEngineActive() {
time.Sleep(5 * time.Second)
continue
@@ -189,6 +206,11 @@ func monitorRoutine(id int) {
return
}
+ if site.Paused {
+ time.Sleep(5 * time.Second)
+ continue
+ }
+
interval := site.Interval
if interval < 5 {
interval = 5
@@ -206,7 +228,7 @@ func checkByID(id int) {
Mutex.RLock()
site, exists := LiveState[id]
Mutex.RUnlock()
- if !exists {
+ if !exists || site.Paused {
return
}
switch site.Type {
diff --git a/internal/server/server.go b/internal/server/server.go
index 6e857b4..89460ed 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -148,7 +148,6 @@ func renderStatusPage(w http.ResponseWriter, title string) {
{{.Title}}
-
{{.Title}}
- {{range .Sites}}
-
-
-
{{.Name}}
-
{{.Type}} | {{if eq .Type "http"}}{{.URL}}{{else}}Heartbeat Monitor{{end}}
-
Last Check: {{.LastCheck.Format "15:04:05"}}
-
-
{{.Status}}
-
- {{end}}
+
+
+
Powered by Go-Upkeep
`
diff --git a/internal/store/postgres.go b/internal/store/postgres.go
index 34ce96b..ea7f58b 100644
--- a/internal/store/postgres.go
+++ b/internal/store/postgres.go
@@ -47,7 +47,8 @@ func (p *PostgresStore) Init() error {
accepted_codes TEXT DEFAULT '200-299',
dns_resolve_type TEXT DEFAULT '',
dns_server TEXT DEFAULT '',
- ignore_tls BOOLEAN DEFAULT FALSE
+ ignore_tls BOOLEAN DEFAULT FALSE,
+ paused BOOLEAN DEFAULT FALSE
);`,
`CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
@@ -73,6 +74,7 @@ func (p *PostgresStore) Init() error {
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS dns_resolve_type TEXT DEFAULT ''",
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS dns_server TEXT DEFAULT ''",
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS ignore_tls BOOLEAN DEFAULT FALSE",
+ "ALTER TABLE sites ADD COLUMN IF NOT EXISTS paused BOOLEAN DEFAULT FALSE",
}
for _, m := range migrations {
p.db.Exec(m)
@@ -83,7 +85,7 @@ func (p *PostgresStore) Init() error {
// ... [CRUD Methods are identical to Phase 4, keeping them concise here] ...
func (p *PostgresStore) GetSites() []models.Site {
- rows, err := p.db.Query("SELECT id, COALESCE(name, url), url, COALESCE(type, 'http'), COALESCE(token, ''), interval, alert_id, check_ssl, threshold, max_retries, COALESCE(hostname, ''), COALESCE(port, 0), COALESCE(timeout, 0), COALESCE(method, 'GET'), COALESCE(description, ''), COALESCE(parent_id, 0), COALESCE(accepted_codes, '200-299'), COALESCE(dns_resolve_type, ''), COALESCE(dns_server, ''), COALESCE(ignore_tls, FALSE) FROM sites")
+ rows, err := p.db.Query("SELECT id, COALESCE(name, url), url, COALESCE(type, 'http'), COALESCE(token, ''), interval, alert_id, check_ssl, threshold, max_retries, COALESCE(hostname, ''), COALESCE(port, 0), COALESCE(timeout, 0), COALESCE(method, 'GET'), COALESCE(description, ''), COALESCE(parent_id, 0), COALESCE(accepted_codes, '200-299'), COALESCE(dns_resolve_type, ''), COALESCE(dns_server, ''), COALESCE(ignore_tls, FALSE), COALESCE(paused, FALSE) FROM sites")
if err != nil {
return []models.Site{}
}
@@ -92,7 +94,7 @@ func (p *PostgresStore) GetSites() []models.Site {
for rows.Next() {
var s models.Site
rows.Scan(&s.ID, &s.Name, &s.URL, &s.Type, &s.Token, &s.Interval, &s.AlertID, &s.CheckSSL, &s.ExpiryThreshold, &s.MaxRetries,
- &s.Hostname, &s.Port, &s.Timeout, &s.Method, &s.Description, &s.ParentID, &s.AcceptedCodes, &s.DNSResolveType, &s.DNSServer, &s.IgnoreTLS)
+ &s.Hostname, &s.Port, &s.Timeout, &s.Method, &s.Description, &s.ParentID, &s.AcceptedCodes, &s.DNSResolveType, &s.DNSServer, &s.IgnoreTLS, &s.Paused)
sites = append(sites, s)
}
return sites
@@ -102,9 +104,9 @@ func (p *PostgresStore) AddSite(site models.Site) {
if site.Type == "push" {
token = generateToken()
}
- p.db.Exec("INSERT INTO sites (name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries, hostname, port, timeout, method, description, parent_id, accepted_codes, dns_resolve_type, dns_server, ignore_tls) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)",
+ p.db.Exec("INSERT INTO sites (name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries, hostname, port, timeout, method, description, parent_id, accepted_codes, dns_resolve_type, dns_server, ignore_tls, paused) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20)",
site.Name, site.URL, site.Type, token, site.Interval, site.AlertID, site.CheckSSL, site.ExpiryThreshold, site.MaxRetries,
- site.Hostname, site.Port, site.Timeout, site.Method, site.Description, site.ParentID, site.AcceptedCodes, site.DNSResolveType, site.DNSServer, site.IgnoreTLS)
+ site.Hostname, site.Port, site.Timeout, site.Method, site.Description, site.ParentID, site.AcceptedCodes, site.DNSResolveType, site.DNSServer, site.IgnoreTLS, site.Paused)
}
func (p *PostgresStore) UpdateSite(site models.Site) {
var existingToken string
@@ -112,9 +114,12 @@ func (p *PostgresStore) UpdateSite(site models.Site) {
if site.Type == "push" && existingToken == "" {
existingToken = generateToken()
}
- p.db.Exec("UPDATE sites SET name=$1, url=$2, type=$3, token=$4, interval=$5, alert_id=$6, check_ssl=$7, threshold=$8, max_retries=$9, hostname=$10, port=$11, timeout=$12, method=$13, description=$14, parent_id=$15, accepted_codes=$16, dns_resolve_type=$17, dns_server=$18, ignore_tls=$19 WHERE id=$20",
+ p.db.Exec("UPDATE sites SET name=$1, url=$2, type=$3, token=$4, interval=$5, alert_id=$6, check_ssl=$7, threshold=$8, max_retries=$9, hostname=$10, port=$11, timeout=$12, method=$13, description=$14, parent_id=$15, accepted_codes=$16, dns_resolve_type=$17, dns_server=$18, ignore_tls=$19, paused=$20 WHERE id=$21",
site.Name, site.URL, site.Type, existingToken, site.Interval, site.AlertID, site.CheckSSL, site.ExpiryThreshold, site.MaxRetries,
- site.Hostname, site.Port, site.Timeout, site.Method, site.Description, site.ParentID, site.AcceptedCodes, site.DNSResolveType, site.DNSServer, site.IgnoreTLS, site.ID)
+ site.Hostname, site.Port, site.Timeout, site.Method, site.Description, site.ParentID, site.AcceptedCodes, site.DNSResolveType, site.DNSServer, site.IgnoreTLS, site.Paused, site.ID)
+}
+func (p *PostgresStore) UpdateSitePaused(id int, paused bool) {
+ p.db.Exec("UPDATE sites SET paused=$1 WHERE id=$2", paused, id)
}
func (p *PostgresStore) DeleteSite(id int) { p.db.Exec("DELETE FROM sites WHERE id=$1", id) }
func (p *PostgresStore) GetAllAlerts() []models.AlertConfig {
@@ -207,9 +212,9 @@ func (p *PostgresStore) ImportData(data models.Backup) error {
tx.Exec("INSERT INTO alerts (id, name, type, settings) VALUES ($1, $2, $3, $4)", a.ID, a.Name, a.Type, string(jsonBytes))
}
for _, st := range data.Sites {
- tx.Exec("INSERT INTO sites (id, name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries, hostname, port, timeout, method, description, parent_id, accepted_codes, dns_resolve_type, dns_server, ignore_tls) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20)",
+ tx.Exec("INSERT INTO sites (id, name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries, hostname, port, timeout, method, description, parent_id, accepted_codes, dns_resolve_type, dns_server, ignore_tls, paused) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21)",
st.ID, st.Name, st.URL, st.Type, st.Token, st.Interval, st.AlertID, st.CheckSSL, st.ExpiryThreshold, st.MaxRetries,
- st.Hostname, st.Port, st.Timeout, st.Method, st.Description, st.ParentID, st.AcceptedCodes, st.DNSResolveType, st.DNSServer, st.IgnoreTLS)
+ st.Hostname, st.Port, st.Timeout, st.Method, st.Description, st.ParentID, st.AcceptedCodes, st.DNSResolveType, st.DNSServer, st.IgnoreTLS, st.Paused)
}
tx.Exec("SELECT setval('sites_id_seq', (SELECT MAX(id) FROM sites))")
diff --git a/internal/store/sqlite.go b/internal/store/sqlite.go
index d55a35e..a0331cd 100644
--- a/internal/store/sqlite.go
+++ b/internal/store/sqlite.go
@@ -49,7 +49,8 @@ func (s *SQLiteStore) Init() error {
accepted_codes TEXT DEFAULT '200-299',
dns_resolve_type TEXT DEFAULT '',
dns_server TEXT DEFAULT '',
- ignore_tls BOOLEAN DEFAULT 0
+ ignore_tls BOOLEAN DEFAULT 0,
+ paused BOOLEAN DEFAULT 0
);
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -73,6 +74,7 @@ func (s *SQLiteStore) Init() error {
"ALTER TABLE sites ADD COLUMN dns_resolve_type TEXT DEFAULT ''",
"ALTER TABLE sites ADD COLUMN dns_server TEXT DEFAULT ''",
"ALTER TABLE sites ADD COLUMN ignore_tls BOOLEAN DEFAULT 0",
+ "ALTER TABLE sites ADD COLUMN paused BOOLEAN DEFAULT 0",
}
for _, m := range migrations {
s.db.Exec(m)
@@ -90,7 +92,7 @@ func generateToken() string {
}
func (s *SQLiteStore) GetSites() []models.Site {
- rows, err := s.db.Query("SELECT id, COALESCE(name, url), url, COALESCE(type, 'http'), COALESCE(token, ''), interval, alert_id, check_ssl, threshold, max_retries, COALESCE(hostname, ''), COALESCE(port, 0), COALESCE(timeout, 0), COALESCE(method, 'GET'), COALESCE(description, ''), COALESCE(parent_id, 0), COALESCE(accepted_codes, '200-299'), COALESCE(dns_resolve_type, ''), COALESCE(dns_server, ''), COALESCE(ignore_tls, 0) FROM sites")
+ rows, err := s.db.Query("SELECT id, COALESCE(name, url), url, COALESCE(type, 'http'), COALESCE(token, ''), interval, alert_id, check_ssl, threshold, max_retries, COALESCE(hostname, ''), COALESCE(port, 0), COALESCE(timeout, 0), COALESCE(method, 'GET'), COALESCE(description, ''), COALESCE(parent_id, 0), COALESCE(accepted_codes, '200-299'), COALESCE(dns_resolve_type, ''), COALESCE(dns_server, ''), COALESCE(ignore_tls, 0), COALESCE(paused, 0) FROM sites")
if err != nil {
return []models.Site{}
}
@@ -98,7 +100,7 @@ func (s *SQLiteStore) GetSites() []models.Site {
var sites []models.Site
for rows.Next() {
var st models.Site
- rows.Scan(&st.ID, &st.Name, &st.URL, &st.Type, &st.Token, &st.Interval, &st.AlertID, &st.CheckSSL, &st.ExpiryThreshold, &st.MaxRetries, &st.Hostname, &st.Port, &st.Timeout, &st.Method, &st.Description, &st.ParentID, &st.AcceptedCodes, &st.DNSResolveType, &st.DNSServer, &st.IgnoreTLS)
+ rows.Scan(&st.ID, &st.Name, &st.URL, &st.Type, &st.Token, &st.Interval, &st.AlertID, &st.CheckSSL, &st.ExpiryThreshold, &st.MaxRetries, &st.Hostname, &st.Port, &st.Timeout, &st.Method, &st.Description, &st.ParentID, &st.AcceptedCodes, &st.DNSResolveType, &st.DNSServer, &st.IgnoreTLS, &st.Paused)
sites = append(sites, st)
}
return sites
@@ -108,9 +110,9 @@ func (s *SQLiteStore) AddSite(site models.Site) {
if site.Type == "push" {
token = generateToken()
}
- s.db.Exec("INSERT INTO sites (name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries, hostname, port, timeout, method, description, parent_id, accepted_codes, dns_resolve_type, dns_server, ignore_tls) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+ s.db.Exec("INSERT INTO sites (name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries, hostname, port, timeout, method, description, parent_id, accepted_codes, dns_resolve_type, dns_server, ignore_tls, paused) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
site.Name, site.URL, site.Type, token, site.Interval, site.AlertID, site.CheckSSL, site.ExpiryThreshold, site.MaxRetries,
- site.Hostname, site.Port, site.Timeout, site.Method, site.Description, site.ParentID, site.AcceptedCodes, site.DNSResolveType, site.DNSServer, site.IgnoreTLS)
+ site.Hostname, site.Port, site.Timeout, site.Method, site.Description, site.ParentID, site.AcceptedCodes, site.DNSResolveType, site.DNSServer, site.IgnoreTLS, site.Paused)
}
func (s *SQLiteStore) UpdateSite(site models.Site) {
var existingToken string
@@ -118,9 +120,12 @@ func (s *SQLiteStore) UpdateSite(site models.Site) {
if site.Type == "push" && existingToken == "" {
existingToken = generateToken()
}
- s.db.Exec("UPDATE sites SET name=?, url=?, type=?, token=?, interval=?, alert_id=?, check_ssl=?, threshold=?, max_retries=?, hostname=?, port=?, timeout=?, method=?, description=?, parent_id=?, accepted_codes=?, dns_resolve_type=?, dns_server=?, ignore_tls=? WHERE id=?",
+ s.db.Exec("UPDATE sites SET name=?, url=?, type=?, token=?, interval=?, alert_id=?, check_ssl=?, threshold=?, max_retries=?, hostname=?, port=?, timeout=?, method=?, description=?, parent_id=?, accepted_codes=?, dns_resolve_type=?, dns_server=?, ignore_tls=?, paused=? WHERE id=?",
site.Name, site.URL, site.Type, existingToken, site.Interval, site.AlertID, site.CheckSSL, site.ExpiryThreshold, site.MaxRetries,
- site.Hostname, site.Port, site.Timeout, site.Method, site.Description, site.ParentID, site.AcceptedCodes, site.DNSResolveType, site.DNSServer, site.IgnoreTLS, site.ID)
+ site.Hostname, site.Port, site.Timeout, site.Method, site.Description, site.ParentID, site.AcceptedCodes, site.DNSResolveType, site.DNSServer, site.IgnoreTLS, site.Paused, site.ID)
+}
+func (s *SQLiteStore) UpdateSitePaused(id int, paused bool) {
+ s.db.Exec("UPDATE sites SET paused=? WHERE id=?", paused, id)
}
func (s *SQLiteStore) DeleteSite(id int) {
s.db.Exec("DELETE FROM sites WHERE id=?", id)
@@ -232,9 +237,9 @@ func (s *SQLiteStore) ImportData(data models.Backup) error {
tx.Exec("INSERT INTO alerts (id, name, type, settings) VALUES (?, ?, ?, ?)", a.ID, a.Name, a.Type, string(jsonBytes))
}
for _, st := range data.Sites {
- tx.Exec("INSERT INTO sites (id, name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries, hostname, port, timeout, method, description, parent_id, accepted_codes, dns_resolve_type, dns_server, ignore_tls) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+ tx.Exec("INSERT INTO sites (id, name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries, hostname, port, timeout, method, description, parent_id, accepted_codes, dns_resolve_type, dns_server, ignore_tls, paused) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
st.ID, st.Name, st.URL, st.Type, st.Token, st.Interval, st.AlertID, st.CheckSSL, st.ExpiryThreshold, st.MaxRetries,
- st.Hostname, st.Port, st.Timeout, st.Method, st.Description, st.ParentID, st.AcceptedCodes, st.DNSResolveType, st.DNSServer, st.IgnoreTLS)
+ st.Hostname, st.Port, st.Timeout, st.Method, st.Description, st.ParentID, st.AcceptedCodes, st.DNSResolveType, st.DNSServer, st.IgnoreTLS, st.Paused)
}
return tx.Commit()
diff --git a/internal/store/store.go b/internal/store/store.go
index e9c05ac..85b47f6 100644
--- a/internal/store/store.go
+++ b/internal/store/store.go
@@ -11,6 +11,7 @@ type Store interface {
GetSites() []models.Site
AddSite(site models.Site)
UpdateSite(site models.Site)
+ UpdateSitePaused(id int, paused bool)
DeleteSite(id int)
// Alerts
diff --git a/internal/tui/tab_alerts.go b/internal/tui/tab_alerts.go
index c0ee2ec..4aa9c54 100644
--- a/internal/tui/tab_alerts.go
+++ b/internal/tui/tab_alerts.go
@@ -26,8 +26,6 @@ var (
alertBorderStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("#444"))
-
- alertColWidths = []int{4, 16, 10, 36}
)
type alertFormData struct {
@@ -120,27 +118,25 @@ func (m Model) viewAlertsTab() string {
})
}
+ tableWidth := m.termWidth - 6
+ if tableWidth < 40 {
+ tableWidth = 40
+ }
+
t := table.New().
Border(lipgloss.RoundedBorder()).
BorderStyle(alertBorderStyle).
+ Width(tableWidth).
Headers("ID", "NAME", "TYPE", "CONFIG").
Rows(rows...).
StyleFunc(func(row, col int) lipgloss.Style {
if row == table.HeaderRow {
- s := alertHeaderStyle
- if col < len(alertColWidths) {
- s = s.Width(alertColWidths[col])
- }
- return s
+ return alertHeaderStyle
}
- s := alertCellStyle
if row == selectedVisual {
- s = alertSelectedStyle
+ return alertSelectedStyle
}
- if col < len(alertColWidths) {
- s = s.Width(alertColWidths[col])
- }
- return s
+ return alertCellStyle
})
return "\n" + t.Render()
diff --git a/internal/tui/tab_sites.go b/internal/tui/tab_sites.go
index 2ac265b..8d7a6dc 100644
--- a/internal/tui/tab_sites.go
+++ b/internal/tui/tab_sites.go
@@ -34,8 +34,6 @@ var (
siteBorderStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("#444"))
-
- siteColWidths = []int{4, 14, 6, 8, 9, 8, 20, 10, 6}
)
type siteFormData struct {
@@ -195,7 +193,10 @@ func fmtRetries(site models.Site) string {
return s
}
-func fmtStatus(status string) string {
+func fmtStatus(status string, paused bool) string {
+ if paused {
+ return warnStyle.Render("PAUSED")
+ }
switch {
case status == "DOWN" || status == "SSL EXP":
return dangerStyle.Render(status)
@@ -236,7 +237,7 @@ func (m Model) viewSitesTab() string {
strconv.Itoa(site.ID),
m.zones.Mark(fmt.Sprintf("site-%d", i), limitStr(site.Name, 13)),
site.Type,
- fmtStatus(site.Status),
+ fmtStatus(site.Status, site.Paused),
fmtLatency(site.Latency),
fmtUptime(hist.TotalChecks, hist.UpChecks),
spark,
@@ -245,27 +246,25 @@ func (m Model) viewSitesTab() string {
})
}
+ tableWidth := m.termWidth - 6
+ if tableWidth < 40 {
+ tableWidth = 40
+ }
+
t := table.New().
Border(lipgloss.RoundedBorder()).
BorderStyle(siteBorderStyle).
+ Width(tableWidth).
Headers("ID", "NAME", "TYPE", "STATUS", "LATENCY", "UPTIME", "HISTORY", "SSL", "RETRY").
Rows(rows...).
StyleFunc(func(row, col int) lipgloss.Style {
if row == table.HeaderRow {
- s := siteHeaderStyle
- if col < len(siteColWidths) {
- s = s.Width(siteColWidths[col])
- }
- return s
+ return siteHeaderStyle
}
- s := siteCellStyle
if row == selectedVisual {
- s = siteSelectedStyle
+ return siteSelectedStyle
}
- if col < len(siteColWidths) {
- s = s.Width(siteColWidths[col])
- }
- return s
+ return siteCellStyle
})
return "\n" + t.Render()
diff --git a/internal/tui/tab_users.go b/internal/tui/tab_users.go
index 48fd9a3..14f9a93 100644
--- a/internal/tui/tab_users.go
+++ b/internal/tui/tab_users.go
@@ -26,8 +26,6 @@ var (
userBorderStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("#444"))
-
- userColWidths = []int{4, 16, 10, 44}
)
type userFormData struct {
@@ -73,27 +71,25 @@ func (m Model) viewUsersTab() string {
})
}
+ tableWidth := m.termWidth - 6
+ if tableWidth < 40 {
+ tableWidth = 40
+ }
+
t := table.New().
Border(lipgloss.RoundedBorder()).
BorderStyle(userBorderStyle).
+ Width(tableWidth).
Headers("ID", "USERNAME", "ROLE", "PUBLIC KEY").
Rows(rows...).
StyleFunc(func(row, col int) lipgloss.Style {
if row == table.HeaderRow {
- s := userHeaderStyle
- if col < len(userColWidths) {
- s = s.Width(userColWidths[col])
- }
- return s
+ return userHeaderStyle
}
- s := userCellStyle
if row == selectedVisual {
- s = userSelectedStyle
+ return userSelectedStyle
}
- if col < len(userColWidths) {
- s = s.Width(userColWidths[col])
- }
- return s
+ return userCellStyle
})
return "\n" + t.Render()
diff --git a/internal/tui/tui.go b/internal/tui/tui.go
index 7af994b..6f9c5ed 100644
--- a/internal/tui/tui.go
+++ b/internal/tui/tui.go
@@ -19,7 +19,7 @@ import (
)
var (
- subtleStyle = lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#D9DCCF", Dark: "#383838"})
+ subtleStyle = lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#9ca0b0", Dark: "#565f89"})
specialStyle = lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#43BF6D", Dark: "#73F59F"})
warnStyle = lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#F0E442", Dark: "#F0E442"})
dangerStyle = lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#F25D94", Dark: "#F25D94"})
@@ -48,6 +48,8 @@ type Model struct {
cursor int
tableOffset int
maxTableRows int
+ termWidth int
+ termHeight int
editID int
editToken string
@@ -126,6 +128,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
+ m.termWidth = msg.Width
+ m.termHeight = msg.Height
m.maxTableRows = msg.Height - 12
if m.maxTableRows < 1 {
m.maxTableRows = 1
@@ -255,6 +259,16 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.state = stateFormUser
return m, m.initUserHuhForm()
}
+ case "p":
+ if m.currentTab == 0 && len(m.sites) > 0 {
+ site := m.sites[m.cursor]
+ monitor.ToggleSitePause(site.ID)
+ site.Paused = !site.Paused
+ if store.Get() != nil {
+ store.Get().UpdateSitePaused(site.ID, site.Paused)
+ }
+ m.refreshData()
+ }
case "d", "backspace":
if m.currentTab == 1 && len(m.alerts) > 0 {
store.Get().DeleteAlert(m.alerts[m.cursor].ID)
@@ -476,11 +490,15 @@ func (m Model) viewDashboard() string {
}
}
- footer := subtleStyle.Render("\n[n] New [e/Enter] Edit [d] Delete [Tab/Click] Switch [Ctrl+L] Clear [q] Quit")
+ footer := subtleStyle.Render("\n[n] New [e/Enter] Edit [d] Delete [p] Pause [Tab/Click] Switch [Ctrl+L] Clear [q] Quit")
if m.currentTab == 3 {
footer = subtleStyle.Render("\n[n] Add User [d] Revoke [Tab/Click] Switch [Ctrl+L] Clear [q] Quit")
}
- return lipgloss.NewStyle().Padding(1, 2).Render(header + "\n" + content + "\n" + footer)
+ s := lipgloss.NewStyle().Padding(1, 2)
+ if m.termHeight > 0 {
+ s = s.MaxHeight(m.termHeight)
+ }
+ return s.Render(header + "\n" + content + "\n" + footer)
}
func limitStr(text string, max int) string {