ui(pool): pick an account's users from its own Edit

Each account row in the Account pool card has a pencil: tick the users
whose sessions run on it (one moves off any other account, unticking sends
one back to the balancer). PUT /api/accounts/:name/users saves the set in one
transaction, audits each change and switches a Claude login into each added
user's home at once. The card-level switch button and pinned list are gone.
This commit is contained in:
2026-10-19 10:45:54 +07:00
parent 776ad6466f
commit c042adc51b
11 changed files with 305 additions and 232 deletions
@@ -201,6 +201,42 @@ describe("pinning a user to one account", () => {
assert.equal(pins.pinFor(miaId, "claude"), null);
});
it("sets exactly who runs on one account from its Edit", async () => {
const boss = await login("boss", BOSS_PASS);
const id = (name) => db.prepare("SELECT id FROM users WHERE username = ?").get(name).id;
claudePool.addAccount("team-y", `sk-ant-oat01-${"y".repeat(40)}`);
pins.setPin(id("ana"), "claude", "team-1");
const edit = (account, userIds, extra = {}) =>
call("PUT", `/api/accounts/${account}/users`, {
cookie: boss,
body: { tool: "claude", userIds, currentPassword: BOSS_PASS, ...extra },
});
const r = await edit("team-y", [id("mia"), id("ana")]);
assert.equal(r.status, 200);
assert.deepEqual(r.body.added.map((u) => [u.username, u.switched]).sort(), [
["ana", "next-session"],
["mia", "next-session"],
]);
assert.equal(pins.pinFor(id("ana"), "claude"), "team-y", "moved off team-1");
const again = await edit("team-y", [id("mia")]);
assert.deepEqual(again.body.added, []);
assert.deepEqual(
again.body.removed.map((u) => u.username),
["ana"]
);
assert.equal(pins.pinFor(id("ana"), "claude"), null);
assert.equal(pins.pinFor(id("mia"), "claude"), "team-y");
const audit = db.prepare("SELECT path FROM audit_log ORDER BY id DESC LIMIT 1").get();
assert.match(audit.path, /unpin ana from claude/);
assert.equal((await edit("team-y", [9999])).body.error.code, "ENOUSER");
assert.equal((await edit("team-y", "x")).body.error.code, "EBADUSER");
assert.equal((await edit("nope", [])).body.error.code, "ENOACCOUNT");
assert.equal((await edit("team-y", [], { currentPassword: "x" })).body.error.code, "EREAUTH");
assert.equal(pins.pinFor(id("mia"), "claude"), "team-y", "a refused edit changes nothing");
await edit("team-y", []);
claudePool.removeAccount("team-y");
});
it("is ignored in local mode and dropped with its user", async () => {
const miaId = db.prepare("SELECT id FROM users WHERE username = 'mia'").get().id;
pins.setPin(miaId, "claude", "team-1");