swarm-ui: the refresh picker shows a spinner in place of its clock while its page is fetching
usePolled reports when a request is in flight (through a new onBusy of the poller) and holds it on for at least 0.4 seconds, so a quick answer still reads as a refresh. The picker swaps its clock for the spinner, in the same box so its width stays, and the spinner stands still where motion is off. Every page with a picker passes it; a page with several polled requests shows it while any of them runs. The Jobs page fetches through shared components and has none yet.
This commit is contained in:
parent
89bbeb9757
commit
47c447409b
2 changed files with 296 additions and 23 deletions
77
frontend/packages/swarm-ui/test/busy-hold.test.mjs
Normal file
77
frontend/packages/swarm-ui/test/busy-hold.test.mjs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// What the refresh spinner shows: on at once, off only after a minimum time.
|
||||
import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
import { createBusyHold } from "../src/ui/polled/busy-hold.ts";
|
||||
|
||||
// A clock and a timer the test moves by hand.
|
||||
function rig() {
|
||||
let t = 0;
|
||||
const timers = [];
|
||||
const shown = [];
|
||||
const hold = createBusyHold({
|
||||
show: (s) => shown.push(s),
|
||||
minMs: 400,
|
||||
now: () => t,
|
||||
after: (fn, ms) => {
|
||||
const timer = { fn, at: t + ms, live: true };
|
||||
timers.push(timer);
|
||||
return timer;
|
||||
},
|
||||
cancel: (timer) => {
|
||||
timer.live = false;
|
||||
},
|
||||
});
|
||||
const advance = (ms) => {
|
||||
t += ms;
|
||||
for (const timer of timers) {
|
||||
if (timer.live && timer.at <= t) {
|
||||
timer.live = false;
|
||||
timer.fn();
|
||||
}
|
||||
}
|
||||
};
|
||||
return { hold, shown, advance };
|
||||
}
|
||||
|
||||
test("it turns on at once and, for a quick answer, off only after the minimum", () => {
|
||||
const { hold, shown, advance } = rig();
|
||||
hold.busy(true);
|
||||
assert.deepEqual(shown, [true]);
|
||||
advance(50);
|
||||
hold.busy(false);
|
||||
assert.deepEqual(shown, [true]);
|
||||
advance(349);
|
||||
assert.deepEqual(shown, [true]);
|
||||
advance(1);
|
||||
assert.deepEqual(shown, [true, false]);
|
||||
});
|
||||
|
||||
test("a slow answer turns it off as soon as it arrives", () => {
|
||||
const { hold, shown, advance } = rig();
|
||||
hold.busy(true);
|
||||
advance(900);
|
||||
hold.busy(false);
|
||||
assert.deepEqual(shown, [true, false]);
|
||||
});
|
||||
|
||||
test("a new request while it is held keeps it on and cancels the pending off", () => {
|
||||
const { hold, shown, advance } = rig();
|
||||
hold.busy(true);
|
||||
advance(100);
|
||||
hold.busy(false);
|
||||
hold.busy(true);
|
||||
advance(1000);
|
||||
assert.deepEqual(shown, [true]);
|
||||
hold.busy(false);
|
||||
assert.deepEqual(shown, [true, false]);
|
||||
});
|
||||
|
||||
test("stop drops a pending off, and busy(false) with nothing shown does nothing", () => {
|
||||
const { hold, shown, advance } = rig();
|
||||
hold.busy(false);
|
||||
hold.busy(true);
|
||||
hold.busy(false);
|
||||
hold.stop();
|
||||
advance(1000);
|
||||
assert.deepEqual(shown, [true]);
|
||||
});
|
||||
|
|
@ -92,3 +92,25 @@ test("the answer of a dropped request that fails is not reported", async () => {
|
|||
await flush();
|
||||
assert.deepEqual(sink.seen.error, []);
|
||||
});
|
||||
|
||||
test("onBusy follows a request in flight, however it ends", async () => {
|
||||
const { calls, fetch } = manualFetch();
|
||||
const sink = collect();
|
||||
const busy = [];
|
||||
const poller = createPoller({ fetch, ...sink, onBusy: (b) => busy.push(b) });
|
||||
poller.tick();
|
||||
poller.tick();
|
||||
assert.deepEqual(busy, [true]);
|
||||
calls[0].resolve("one");
|
||||
await flush();
|
||||
assert.deepEqual(busy, [true, false]);
|
||||
poller.tick();
|
||||
calls[1].reject(new Error("boom"));
|
||||
await flush();
|
||||
assert.deepEqual(busy, [true, false, true, false]);
|
||||
poller.tick();
|
||||
poller.stop();
|
||||
assert.deepEqual(busy, [true, false, true, false, true, false]);
|
||||
poller.stop();
|
||||
assert.equal(busy.length, 6);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue