swarm ui: a stored claude login closes the dialog and shows a toast
The login dialog stayed open with a success line after the code was accepted, though nothing is left to do in it. It now closes and a toast says the login is stored. The toast is a new swarm-ui primitive: a short note raised with showToast, rendered by a ToastHost at the app root, gone after a few seconds or on click.
This commit is contained in:
parent
892675628d
commit
73f875eab8
2 changed files with 211 additions and 15 deletions
|
|
@ -12,6 +12,7 @@ import {
|
|||
leavesLoginRunning,
|
||||
pastedCode,
|
||||
startOutlivedDialog,
|
||||
storedMessage,
|
||||
} from "../src/agent/claude-login/ClaudeLoginSteps.ts";
|
||||
|
||||
test("the routes name the agent, escaped", () => {
|
||||
|
|
@ -77,3 +78,7 @@ test("a pasted code is trimmed, and a blank one is nothing", () => {
|
|||
assert.equal(pastedCode(" abc-def \n"), "abc-def");
|
||||
assert.equal(pastedCode(" \n "), null);
|
||||
});
|
||||
|
||||
test("the stored toast names the agent", () => {
|
||||
assert.match(storedMessage("atlas"), /^Login stored\. atlas /);
|
||||
});
|
||||
|
|
|
|||
46
frontend/packages/swarm-ui/test/toasts.test.mjs
Normal file
46
frontend/packages/swarm-ui/test/toasts.test.mjs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// The toast list. Run by `npm test`, which Node runs with its built-in test
|
||||
// runner and type stripping, so the `.ts` module is imported as it is.
|
||||
import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
import {
|
||||
currentToasts,
|
||||
dismissToast,
|
||||
showToast,
|
||||
subscribeToasts,
|
||||
toastDuration,
|
||||
} from "../src/ui/toast/toasts.ts";
|
||||
|
||||
test("an error stays longer than the other tones", () => {
|
||||
assert.ok(toastDuration("error") > toastDuration("ok"));
|
||||
assert.equal(toastDuration("info"), toastDuration("ok"));
|
||||
});
|
||||
|
||||
test("a toast is listed with its tone and duration, oldest first", () => {
|
||||
const a = showToast("first", "ok");
|
||||
const b = showToast("second", "error", 100);
|
||||
const list = currentToasts().filter((t) => t.id === a || t.id === b);
|
||||
assert.deepEqual(
|
||||
list.map((t) => [t.message, t.tone, t.duration]),
|
||||
[
|
||||
["first", "ok", toastDuration("ok")],
|
||||
["second", "error", 100],
|
||||
],
|
||||
);
|
||||
dismissToast(a);
|
||||
dismissToast(b);
|
||||
});
|
||||
|
||||
test("dismissing removes one toast and tells the subscribers once", () => {
|
||||
const a = showToast("keep");
|
||||
const b = showToast("drop");
|
||||
let calls = 0;
|
||||
const stop = subscribeToasts(() => calls++);
|
||||
dismissToast(b);
|
||||
dismissToast(b);
|
||||
assert.equal(calls, 1);
|
||||
assert.ok(currentToasts().some((t) => t.id === a));
|
||||
assert.ok(!currentToasts().some((t) => t.id === b));
|
||||
stop();
|
||||
dismissToast(a);
|
||||
assert.equal(calls, 1);
|
||||
});
|
||||
Loading…
Reference in a new issue