From 0601098ab0bf8dec08c3683d7ba7d1570749d9db Mon Sep 17 00:00:00 2001 From: m5r Date: Sun, 16 Aug 2026 23:55:10 +0200 Subject: [PATCH] admin: drop the learned tag from the query tables --- admin/src/features/clients/clientNames.tsx | 6 +++++- admin/src/features/live/LiveLogPage.test.tsx | 11 ++++------- admin/src/features/queries/QueryLogPage.test.tsx | 11 ++++------- admin/src/ui/styles.ts | 6 ++++-- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/admin/src/features/clients/clientNames.tsx b/admin/src/features/clients/clientNames.tsx index 1bb83d5..9249dc7 100644 --- a/admin/src/features/clients/clientNames.tsx +++ b/admin/src/features/clients/clientNames.tsx @@ -3,6 +3,11 @@ * with the same precedence the Clients page applies: a hand-typed `name` wins, * the reverse-DNS `learned_name` stands in muted behind it, and an address with * neither — including one the loaded list has never seen — stays bare. + * + * The muted colour is the whole of the affordance here. The Clients page pairs + * it with an outlined "learned" tag, and keeps it: one mention per client is + * information. Repeating that tag down every row of a query table is noise, so + * the tables carry the name alone. */ import { useMemo } from "react"; @@ -43,7 +48,6 @@ export function ClientName({ ip, names }: { ip: string; names: ClientNames }) { return ( {client.learned_name} - learned ); } diff --git a/admin/src/features/live/LiveLogPage.test.tsx b/admin/src/features/live/LiveLogPage.test.tsx index d04761e..31e03b9 100644 --- a/admin/src/features/live/LiveLogPage.test.tsx +++ b/admin/src/features/live/LiveLogPage.test.tsx @@ -131,14 +131,11 @@ test("resolves each row's client to its display name, keeping the IP as the tool expect(named.getAttribute("title")).toBe("192.0.2.10"); expect(screen.queryByText("pi.lan")).toBeNull(); - // The cell holds the learned name followed by the tag, so the match is on - // the containing span rather than on a bare text node. - const learned = screen.getByText( - (content, element) => element?.tagName === "SPAN" && content.startsWith("laptop.lan"), - ); + // A learned name reads muted and nothing more here: the "learned" tag would + // repeat on every row of the table, so the Clients page carries it instead. + const learned = screen.getByText("laptop.lan"); expect(learned.getAttribute("title")).toBe("192.0.2.11"); - // The affordance is text, not colour, so a screen reader announces it too. - expect(within(learned).getByText("learned")).toBeTruthy(); + expect(within(learned.closest("tr")!).queryByText("learned")).toBeNull(); // A known client with neither name, and a client the loaded list has never // seen, both fall back to the bare address with no tooltip standing in. diff --git a/admin/src/features/queries/QueryLogPage.test.tsx b/admin/src/features/queries/QueryLogPage.test.tsx index 9f864e3..8cabf1d 100644 --- a/admin/src/features/queries/QueryLogPage.test.tsx +++ b/admin/src/features/queries/QueryLogPage.test.tsx @@ -137,14 +137,11 @@ test("resolves each row's client to its display name, keeping the IP as the tool expect(named.getAttribute("title")).toBe("192.0.2.10"); expect(screen.queryByText("pi.lan")).toBeNull(); - // The cell holds the learned name followed by the tag, so the match is on - // the containing span rather than on a bare text node. - const learned = screen.getByText( - (content, element) => element?.tagName === "SPAN" && content.startsWith("laptop.lan"), - ); + // A learned name reads muted and nothing more here: the "learned" tag would + // repeat on every row of the table, so the Clients page carries it instead. + const learned = screen.getByText("laptop.lan"); expect(learned.getAttribute("title")).toBe("192.0.2.11"); - // The affordance is text, not colour, so a screen reader announces it too. - expect(within(learned).getByText("learned")).toBeTruthy(); + expect(within(learned.closest("tr")!).queryByText("learned")).toBeNull(); // A known client with neither name, and a client the loaded list has never // seen, both fall back to the bare address with no tooltip standing in. diff --git a/admin/src/ui/styles.ts b/admin/src/ui/styles.ts index a569a2e..84a2409 100644 --- a/admin/src/ui/styles.ts +++ b/admin/src/ui/styles.ts @@ -169,8 +169,10 @@ export const styles = stylex.create({ }, /** * A learned name is runtime state, not something the operator typed, so it - * reads muted and carries an outlined "learned" tag. The tag is real text — - * a screen reader announces it — because colour alone is not an affordance. + * reads muted wherever it appears. The Clients page adds the outlined tag, + * where the client is named once; the query tables leave it off rather than + * repeat it on every row. The tag is real text — a screen reader announces + * it — because colour alone is not an affordance. */ learnedName: { color: colors.textMuted,