swarm-ui, hive dashboard, agent page: one profile menu with the signed-in user, avatar and authelia links
The swarm UI's user menu moves to @hive/shared and takes the whoami URL and authelia's URL as props; the swarm UI keeps a thin wrapper, and the hive dashboard and the per-agent page mount the same component. The dashboard's nginx vhost proxies /api/whoami to authelia (the agent page is served from the same vhost), and hive-c0re's state carries authelia_public_url, set from services.hyperhive.swarm.authelia.url. The agent page shows the menu only behind the gateway.
This commit is contained in:
parent
10b8422d93
commit
cd41e1d510
19 changed files with 417 additions and 154 deletions
67
frontend/packages/swarm-ui/test/user-identity.test.mjs
Normal file
67
frontend/packages/swarm-ui/test/user-identity.test.mjs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// What the profile menu shows of the signed-in user, shared by the swarm UI,
|
||||
// the hive dashboard and the per-agent page. Run by `npm test`.
|
||||
import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
import {
|
||||
accountLinks,
|
||||
initialOf,
|
||||
labelOf,
|
||||
parseWhoAmI,
|
||||
pickAccent,
|
||||
} from "../../shared/src/user-menu/identity.ts";
|
||||
|
||||
test("authelia's user info is read from its {status, data} envelope or bare", () => {
|
||||
const data = { display_name: "Mara", emails: ["mara@example.org"] };
|
||||
assert.deepEqual(parseWhoAmI({ status: "OK", data }), {
|
||||
displayName: "Mara",
|
||||
email: "mara@example.org",
|
||||
});
|
||||
assert.deepEqual(parseWhoAmI(data), {
|
||||
displayName: "Mara",
|
||||
email: "mara@example.org",
|
||||
});
|
||||
});
|
||||
|
||||
test("a shape that is not recognised gives no name instead of an error", () => {
|
||||
const none = { displayName: null, email: null };
|
||||
assert.deepEqual(parseWhoAmI(null), none);
|
||||
assert.deepEqual(parseWhoAmI("nope"), none);
|
||||
assert.deepEqual(
|
||||
parseWhoAmI({ data: { display_name: 3, emails: "x" } }),
|
||||
none,
|
||||
);
|
||||
assert.deepEqual(parseWhoAmI({ data: { emails: [7] } }), none);
|
||||
});
|
||||
|
||||
test("the label is the display name, else the e-mail, else none", () => {
|
||||
assert.equal(labelOf({ displayName: "Mara", email: "m@x" }), "Mara");
|
||||
assert.equal(labelOf({ displayName: "", email: "m@x" }), "m@x");
|
||||
assert.equal(labelOf({ displayName: null, email: null }), null);
|
||||
assert.equal(labelOf(null), null);
|
||||
});
|
||||
|
||||
test("the avatar letter is the label's first, capitalised, or a question mark", () => {
|
||||
assert.equal(initialOf(" mara"), "M");
|
||||
assert.equal(initialOf(null), "?");
|
||||
assert.equal(initialOf(""), "?");
|
||||
});
|
||||
|
||||
test("a name always gets the same colour, one of the theme's", () => {
|
||||
assert.equal(pickAccent("Mara"), pickAccent("Mara"));
|
||||
assert.match(pickAccent("Mara"), /^var\(--[a-z]+\)$/);
|
||||
const seen = new Set(
|
||||
["a", "b", "c", "d", "e", "f", "g", "h", "i"].map(pickAccent),
|
||||
);
|
||||
assert.ok(seen.size > 1, "different names do not all collapse to one colour");
|
||||
});
|
||||
|
||||
test("the account links sit under authelia's URL whether or not it ends in a slash", () => {
|
||||
const want = {
|
||||
settings: "https://auth.example.org/settings",
|
||||
logout: "https://auth.example.org/logout",
|
||||
};
|
||||
assert.deepEqual(accountLinks("https://auth.example.org/"), want);
|
||||
assert.deepEqual(accountLinks("https://auth.example.org"), want);
|
||||
assert.equal(accountLinks(null), null);
|
||||
assert.equal(accountLinks(""), null);
|
||||
});
|
||||
Loading…
Reference in a new issue