Watch
0
0
Fork
You've already forked hyperhive
0

swarm ui: the login button's wording is a tested function

The label that switches between log in and log in again moves next to the
stored login's other wording, so it has a test.
This commit is contained in:
iris 2026-11-15 15:52:42 +01:00 • committed by mara
commit 78e063e78c
3 changed files with 18 additions and 1 deletions

View file

@ -24,6 +24,13 @@ export function storedAtMs(login: StoredLogin): number | null {
return Number.isNaN(ms) ? null : ms; return Number.isNaN(ms) ? null : ms;
} }
// The settings row's login button: `log in` when the swarm holds no login for
// the agent, `log in again` when it holds one, so a forced relogin reads as
// what it is.
export function loginButtonLabel(login: StoredLogin): string {
return login.stored_at === null ? "log in" : "log in again";
}
// What the delete's confirmation says: it removes the swarm's copy, and the // What the delete's confirmation says: it removes the swarm's copy, and the
// agent reads the store every 5 minutes and logs out when the copy is gone. // agent reads the store every 5 minutes and logs out when the copy is gone.
export function deleteMessage(agent: string): string { export function deleteMessage(agent: string): string {

View file

@ -17,6 +17,7 @@ import { showToast } from "../../ui/toast/toasts.js";
import { import {
deleteMessage, deleteMessage,
deleteStoredLoginPath, deleteStoredLoginPath,
loginButtonLabel,
storedAtMs, storedAtMs,
storedLoginPath, storedLoginPath,
type StoredLogin, type StoredLogin,
@ -81,7 +82,7 @@ export function AgentClaudeLogin({ agent }: { agent: string }) {
const loginBadge = ( const loginBadge = (
<Badge <Badge
variant="quiet" variant="quiet"
value={login.stored_at === null ? "log in" : "log in again"} value={loginButtonLabel(login)}
title={`log ${agent} in to claude from here`} title={`log ${agent} in to claude from here`}
onClick={() => setLoggingIn(true)} onClick={() => setLoggingIn(true)}
/> />

View file

@ -6,6 +6,7 @@ import { test } from "node:test";
import { import {
deleteMessage, deleteMessage,
deleteStoredLoginPath, deleteStoredLoginPath,
loginButtonLabel,
storedAtMs, storedAtMs,
storedLoginPath, storedLoginPath,
} from "../src/agent/claude-login/StoredLogin.ts"; } from "../src/agent/claude-login/StoredLogin.ts";
@ -32,3 +33,11 @@ test("the delete's confirmation names the agent", () => {
assert.match(deleteMessage("atlas"), /stored claude login for atlas/); assert.match(deleteMessage("atlas"), /stored claude login for atlas/);
assert.match(deleteMessage("atlas"), /logged out within 5 minutes/); assert.match(deleteMessage("atlas"), /logged out within 5 minutes/);
}); });
test("the login button says log in until a login is stored, then log in again", () => {
assert.equal(loginButtonLabel({ stored_at: null }), "log in");
assert.equal(
loginButtonLabel({ stored_at: "2026-11-10T12:00:00Z" }),
"log in again",
);
});