mirror of
https://github.com/nicolargo/glances.git
synced 2026-09-30 22:15:10 -04:00
The footer only carried the poll cadence as a read-only label. It now has
two ends:
- Left: "Glances v<release> · GitHub · API". The release comes from the
/status health probe, which now serves it as `glances_version` next to
the API version (v4 already serves the release from its own /status).
The /docs link appears only when `[outputs] api_doc` is on -- the same
key webserver_v5.build_app() reads to decide whether FastAPI mounts
Swagger UI at all, so the link can never point at a 404.
- Right: "Refresh: - Ns +". The two steppers walk a fixed ladder
(1, 2, 3, 5, 10, 15, 30, 60 s) so the whole range is seven clicks wide
instead of fifty-eight, clamping at both ends rather than wrapping. The
chosen cadence is remembered in localStorage and re-armed on the poll
timer immediately; `[global] refresh` stays the value a first visit
starts at.
Both ends are deliberately quiet: one size below the body text, muted,
dotted underlines instead of browser-blue links, and steppers with no
border or background. The cadence sits in a fixed-width box so stepping
2s -> 10s does not slide the "+" out from under the pointer.
The render probe's fake elements gained a `disabled` property on
<button>: Vue's shouldSetAsProp() tests `key in el`, and without it
`:disabled` fell back to setAttribute("disabled", "false") -- an
attribute whose mere presence disables a button in a real browser.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VeEhhw7pcPvZRguFPALgwh
79 lines
2.4 KiB
JavaScript
79 lines
2.4 KiB
JavaScript
import { test, beforeEach } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import {
|
|
REFRESH_STEPS,
|
|
stepRefresh,
|
|
loadRefresh,
|
|
saveRefresh,
|
|
} from "../../glances/outputs/static/js/v5/refresh.js";
|
|
|
|
function stubStorage(initial) {
|
|
const store = { ...initial };
|
|
globalThis.localStorage = {
|
|
getItem: (key) => (key in store ? store[key] : null),
|
|
setItem: (key, value) => {
|
|
store[key] = value;
|
|
},
|
|
};
|
|
return store;
|
|
}
|
|
|
|
beforeEach(() => {
|
|
delete globalThis.localStorage;
|
|
});
|
|
|
|
test("the ladder spans the whole 1..60 s range the footer advertises", () => {
|
|
assert.equal(REFRESH_STEPS[0], 1);
|
|
assert.equal(REFRESH_STEPS[REFRESH_STEPS.length - 1], 60);
|
|
const sorted = [...REFRESH_STEPS].sort((a, b) => a - b);
|
|
assert.deepEqual(REFRESH_STEPS, sorted, "stepRefresh scans the ladder in order");
|
|
});
|
|
|
|
test("stepping moves one rung in the asked direction", () => {
|
|
assert.equal(stepRefresh(2, 1), 3);
|
|
assert.equal(stepRefresh(2, -1), 1);
|
|
assert.equal(stepRefresh(15, 1), 30);
|
|
assert.equal(stepRefresh(15, -1), 10);
|
|
});
|
|
|
|
test("stepping clamps at both ends instead of wrapping", () => {
|
|
// A "+" that jumped back to 1 s would silently make the page poll 60x
|
|
// faster -- the opposite of what the click asked for.
|
|
assert.equal(stepRefresh(60, 1), 60);
|
|
assert.equal(stepRefresh(1, -1), 1);
|
|
});
|
|
|
|
test("stepping from an off-ladder cadence lands on the nearest rung", () => {
|
|
// `[global] refresh=4` is legal and is not a rung.
|
|
assert.equal(stepRefresh(4, 1), 5);
|
|
assert.equal(stepRefresh(4, -1), 3);
|
|
// A config value past the top of the ladder is pulled back onto it.
|
|
assert.equal(stepRefresh(120, -1), 60);
|
|
assert.equal(stepRefresh(120, 1), 60);
|
|
});
|
|
|
|
test("loadRefresh returns null when nothing was ever saved", () => {
|
|
stubStorage({});
|
|
assert.equal(loadRefresh(), null);
|
|
});
|
|
|
|
test("loadRefresh returns null rather than repairing an unusable value", () => {
|
|
stubStorage({ "glances.refresh": "not a number" });
|
|
assert.equal(loadRefresh(), null);
|
|
stubStorage({ "glances.refresh": "0" });
|
|
assert.equal(loadRefresh(), null);
|
|
});
|
|
|
|
test("a saved cadence survives the reload", () => {
|
|
stubStorage({});
|
|
saveRefresh(15);
|
|
assert.equal(loadRefresh(), 15);
|
|
});
|
|
|
|
test("no localStorage at all degrades to 'not remembered', never to a throw", () => {
|
|
// Private browsing, blocked site data, and the render probe's DOM stub all
|
|
// look like this.
|
|
assert.equal(loadRefresh(), null);
|
|
assert.doesNotThrow(() => saveRefresh(5));
|
|
});
|