Retire the Dashboard tab; Processes is the front page
The app repeated itself. The module list, /api/prefs/dashboard, applyPrefs and the per-user dashboard blob are gone. Widgets stays and now says plainly that it is for dashboards outside Ham Lab. This also closes a bug: applyPrefs set the sampling rate from intervalMs inside the dashboard layout, and reset it to the default when that field was absent — so with per-user layouts, one account saving a dashboard could reset the sampling rate for the whole machine. The sampler now has one source. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1eb59fd08c
commit
9bf60deffc
+4
-58
@@ -102,18 +102,8 @@ func New(cfg *config.Config, sessions *auth.Sessions, mgr *term.Manager, col *me
|
||||
s.sensors.Add(newStatusSensors(s))
|
||||
s.alerts = newAlertEngine(s)
|
||||
// The saved dashboard layout carries the sampling interval; apply it on boot.
|
||||
var raw json.RawMessage
|
||||
var histSec int
|
||||
st.View(func(x *store.State) {
|
||||
raw, histSec = x.Dashboard, x.HistorySec
|
||||
if len(raw) == 0 {
|
||||
for _, u := range x.Users {
|
||||
raw = u.Dashboard
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
s.applyPrefs(raw)
|
||||
st.View(func(x *store.State) { histSec = x.HistorySec })
|
||||
if histSec > 0 {
|
||||
col.SetWindow(time.Duration(histSec) * time.Second)
|
||||
}
|
||||
@@ -289,8 +279,6 @@ func New(cfg *config.Config, sessions *auth.Sessions, mgr *term.Manager, col *me
|
||||
m.HandleFunc("PUT /api/prefs/sampler", s.auth(s.putSampler))
|
||||
m.HandleFunc("GET /api/prefs/history", s.auth(s.getHistoryWindow))
|
||||
m.HandleFunc("PUT /api/prefs/history", s.auth(s.putHistoryWindow))
|
||||
m.HandleFunc("GET /api/prefs/dashboard", s.auth(s.getDashPrefs))
|
||||
m.HandleFunc("PUT /api/prefs/dashboard", s.auth(s.putDashPrefs))
|
||||
m.HandleFunc("/api/", func(w http.ResponseWriter, _ *http.Request) { jsonErr(w, 404, "not found") })
|
||||
m.HandleFunc("/", s.static)
|
||||
s.mux = m
|
||||
@@ -930,15 +918,11 @@ func (s *Server) migrateUsers() {
|
||||
st.Sessions[tok] = ses
|
||||
}
|
||||
}
|
||||
if len(st.UI) > 0 || len(st.Dashboard) > 0 {
|
||||
u := st.UserState(first)
|
||||
if len(u.UI) == 0 {
|
||||
if len(st.UI) > 0 {
|
||||
if u := st.UserState(first); len(u.UI) == 0 {
|
||||
u.UI = st.UI
|
||||
}
|
||||
if len(u.Dashboard) == 0 {
|
||||
u.Dashboard = st.Dashboard
|
||||
}
|
||||
st.UI, st.Dashboard = nil, nil
|
||||
st.UI = nil
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -2282,44 +2266,6 @@ func (s *Server) pushHistoryWindow(seconds int) {
|
||||
}
|
||||
}
|
||||
|
||||
// ---- dashboard layout prefs (opaque JSON object, owned by the UI) ----
|
||||
|
||||
func (s *Server) getDashPrefs(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Cache-Control", "no-store")
|
||||
jsonOK(w, 200, s.userPrefs(r, func(u *store.UserState) json.RawMessage { return u.Dashboard }))
|
||||
}
|
||||
|
||||
func (s *Server) putDashPrefs(w http.ResponseWriter, r *http.Request) {
|
||||
b, err := io.ReadAll(io.LimitReader(r.Body, 64<<10))
|
||||
if err != nil || !json.Valid(b) || len(b) == 0 || b[0] != '{' {
|
||||
jsonErr(w, 400, "expected a JSON object")
|
||||
return
|
||||
}
|
||||
if user := actorOf(r).User; user != "" {
|
||||
if err := s.store.Update(func(st *store.State) { st.UserState(user).Dashboard = json.RawMessage(b) }); err != nil {
|
||||
jsonErr(w, 500, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
s.applyPrefs(b)
|
||||
w.WriteHeader(204)
|
||||
}
|
||||
|
||||
// applyPrefs picks the few layout fields the server acts on (just the interval).
|
||||
func (s *Server) applyPrefs(raw []byte) {
|
||||
var p struct {
|
||||
IntervalMs int `json:"intervalMs"`
|
||||
}
|
||||
if len(raw) == 0 || json.Unmarshal(raw, &p) != nil {
|
||||
return
|
||||
}
|
||||
if p.IntervalMs > 0 {
|
||||
s.metrics.SetInterval(time.Duration(p.IntervalMs) * time.Millisecond)
|
||||
} else {
|
||||
s.metrics.SetInterval(metrics.DefaultInterval)
|
||||
}
|
||||
}
|
||||
|
||||
// ---- terminals ----
|
||||
|
||||
func (s *Server) listTerminals(w http.ResponseWriter, _ *http.Request) {
|
||||
|
||||
@@ -41,17 +41,15 @@ func (s *Session) UnmarshalJSON(b []byte) error {
|
||||
// UserState is what follows an account rather than the machine: how the console looks
|
||||
// to that person and how their dashboard is laid out.
|
||||
type UserState struct {
|
||||
Dashboard json.RawMessage `json:"dashboard,omitempty"` // layout prefs, opaque to the server
|
||||
UI json.RawMessage `json:"ui,omitempty"` // theme, accents; opaque to the server
|
||||
UI json.RawMessage `json:"ui,omitempty"` // theme, accents; opaque to the server
|
||||
}
|
||||
|
||||
type State struct {
|
||||
Terminals []Terminal `json:"terminals"`
|
||||
Sessions map[string]Session `json:"sessions"` // token -> session
|
||||
Users map[string]*UserState `json:"users,omitempty"`
|
||||
// Dashboard and UI are the pre-users machine-wide prefs; on first boot with users they
|
||||
// move to the first account. Kept so an old state file still reads.
|
||||
Dashboard json.RawMessage `json:"dashboard,omitempty"`
|
||||
// UI is the pre-users machine-wide look; on first boot with users it moves to the first
|
||||
// account. Kept so an old state file still reads.
|
||||
UI json.RawMessage `json:"ui,omitempty"`
|
||||
Alerts json.RawMessage `json:"alerts,omitempty"` // rules, channels and recent events (internal/api/alerts.go)
|
||||
SamplerMs int `json:"sampler_ms,omitempty"` // how often this machine samples; the hub keeps every machine on the console's refresh rate
|
||||
|
||||
Reference in New Issue
Block a user