Settings: one window for how far back every graph reaches, 1 minute to 24 hours
Each machine keeps 300 points per curve whatever the window, so memory doesn't follow it; a wider window means wider points, each the average of its bucket rather than one instant out of it. The hub passes the setting to every machine it manages. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
885b050d02
commit
04dd98e2cd
+28
-2
@@ -4,7 +4,7 @@ import { api, Me } from './api'
|
||||
import { savePrefs } from './accents'
|
||||
import { applyTheme, currentThemeId, THEMES } from './themes'
|
||||
import { Btn, Loading, askYes, toast, useEscape } from './ui'
|
||||
import { fmtMs, getRefreshMs, REFRESH_OPTIONS, setRefreshMs } from './prefs'
|
||||
import { fmtMs, fmtWindowSec, getHistorySec, getRefreshMs, HISTORY_OPTIONS, HISTORY_POINTS, REFRESH_OPTIONS, setHistorySec, setRefreshMs, strideMs } from './prefs'
|
||||
|
||||
const fmtUptime = (s: number) => { const d = Math.floor(s / 86400), h = Math.floor((s % 86400) / 3600), m = Math.floor((s % 3600) / 60); return d > 0 ? `${d}d ${h}h` : h > 0 ? `${h}h ${m}m` : `${m}m` }
|
||||
|
||||
@@ -33,6 +33,8 @@ function Preview({ vars }: { vars: Record<string, string> }) {
|
||||
export default function Settings({ me }: { me: Me }) {
|
||||
const [theme, setTheme] = useState(currentThemeId())
|
||||
const [refresh, setRefresh] = useState(getRefreshMs())
|
||||
const [history, setHistory] = useState(getHistorySec())
|
||||
const [histErr, setHistErr] = useState('')
|
||||
const [tokens, setTokens] = useState<{ name: string; created: string; scope?: string; sensors?: string[] }[] | null>(null)
|
||||
const [fresh, setFresh] = useState<{ name: string; token: string } | null>(null)
|
||||
const [making, setMaking] = useState(false)
|
||||
@@ -52,6 +54,14 @@ export default function Settings({ me }: { me: Me }) {
|
||||
setRefreshMs(ms); setRefresh(ms)
|
||||
await savePrefs()
|
||||
}
|
||||
// The window is the machine's own setting, not a look: the hub takes it and passes it on.
|
||||
useEffect(() => { api.historyWindow().then((h) => { setHistory(h.seconds); setHistorySec(h.seconds) }).catch(() => {}) }, [])
|
||||
const pickHistory = async (sec: number) => {
|
||||
const was = history
|
||||
setHistory(sec); setHistorySec(sec); setHistErr('')
|
||||
try { const h = await api.setHistoryWindow(sec); setHistory(h.seconds); setHistorySec(h.seconds) }
|
||||
catch (e) { setHistory(was); setHistorySec(was); setHistErr(e instanceof Error ? e.message : 'failed') }
|
||||
}
|
||||
|
||||
async function changePassword(e: FormEvent) {
|
||||
e.preventDefault()
|
||||
@@ -85,11 +95,27 @@ export default function Settings({ me }: { me: Me }) {
|
||||
{REFRESH_OPTIONS.map((ms) => <button key={ms} className={'chip' + (refresh === ms ? ' on' : '')} onClick={() => pickRefresh(ms)}>{fmtMs(ms)}</button>)}
|
||||
</div>
|
||||
<div className="muted small" style={{ marginTop: 8 }}>
|
||||
Every page polls at exactly this rate: dashboard, processes, disks, services, cron, updates, machines. The sampler on each machine follows it too, so charts keep 300 points and cover 300 × rate.
|
||||
Every page polls at exactly this rate: dashboard, processes, disks, services, cron, updates, machines. The sampler on each machine follows it too, so it is also the finest a graph can be — how far back the graphs reach is the next setting down.
|
||||
Fast rates cost CPU on the host, especially on the list pages, which run commands to refresh. Nothing is throttled behind your back.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div className="dash-bar"><h2 className="section">Graph history</h2><span className="spacer" /><span className="muted small">every graph, on every machine</span></div>
|
||||
<section className="card">
|
||||
<div className="chips">
|
||||
{HISTORY_OPTIONS.map((sec) => <button key={sec} className={'chip' + (history === sec ? ' on' : '')} onClick={() => pickHistory(sec)}>{fmtWindowSec(sec)}</button>)}
|
||||
</div>
|
||||
{histErr && <div className="error" style={{ marginTop: 8 }}>{histErr}</div>}
|
||||
<div className="muted small" style={{ marginTop: 8 }}>
|
||||
How far back every sparkline reaches — the dashboard, the processes page, the disks
|
||||
page and any sparkline widget. Each machine keeps {HISTORY_POINTS} points per curve whatever you
|
||||
pick, so a wider window is a coarser one: <b>{fmtWindowSec(history)}</b> puts a point every{' '}
|
||||
{fmtWindowSec(strideMs(history, refresh) / 1000)}, each the average of what happened
|
||||
in between rather than one instant out of it. Memory on the machine doesn't change.
|
||||
The history is kept in memory, so a machine that restarts starts its graphs again.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div className="dash-bar"><h2 className="section">Account · {me.host}</h2></div>
|
||||
<form className="card addform" onSubmit={changePassword}>
|
||||
<label>Current password <input type="password" value={cur} onChange={(e) => setCur(e.target.value)} autoComplete="current-password" required /></label>
|
||||
|
||||
Reference in New Issue
Block a user