2 Commits
Author SHA1 Message Date
mokhtar 3ed9a57822 changelog: 0.0.5 releases today
Gates / test (push) Successful in 1m44s
Gates / frontend (push) Successful in 1m2s
Gates / test-aarch64 (push) Successful in 5m55s
Gates / package (push) Successful in 28s
Gates / container (push) Successful in 16s
CI / gates (push) Successful in 20m25s
Release / guard (push) Successful in 18s
Gates / frontend (push) Successful in 1m5s
Gates / test-aarch64 (push) Successful in 6m33s
Gates / test (push) Successful in 1m31s
Gates / package (push) Successful in 3m41s
Gates / container (push) Successful in 9s
Release / gates (push) Successful in 19m27s
Release / publish (push) Successful in 5m43s
2026-08-16 23:55:19 +02:00
mokhtar 0601098ab0 admin: drop the learned tag from the query tables 2026-08-16 23:55:10 +02:00
6 changed files with 26 additions and 18 deletions
+8
View File
@@ -6,6 +6,14 @@ Sections are written by hand. Nothing here is generated from commit messages: th
## [Unreleased] ## [Unreleased]
## [0.0.5] - 2026-08-16
One rendering fix on the 0.0.4 feature, caught the day it shipped.
### Changed
- The query tables no longer repeat the *learned* tag on every row: in the live page and the query log a learned name is just muted, with the address still in the row's tooltip. The clients page keeps the tag, where it appears once per client and says something.
## [0.0.4] - 2026-08-16 ## [0.0.4] - 2026-08-16
The names learned in 0.0.3 now show up where queries do: the live page and the query log name each client instead of printing its address. The names learned in 0.0.3 now show up where queries do: the live page and the query log name each client instead of printing its address.
+5 -1
View File
@@ -3,6 +3,11 @@
* with the same precedence the Clients page applies: a hand-typed `name` wins, * 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 * 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. * 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"; import { useMemo } from "react";
@@ -43,7 +48,6 @@ export function ClientName({ ip, names }: { ip: string; names: ClientNames }) {
return ( return (
<span title={ip} {...stylex.props(shared.learnedName)}> <span title={ip} {...stylex.props(shared.learnedName)}>
{client.learned_name} {client.learned_name}
<span {...stylex.props(shared.learnedTag)}>learned</span>
</span> </span>
); );
} }
+4 -7
View File
@@ -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(named.getAttribute("title")).toBe("192.0.2.10");
expect(screen.queryByText("pi.lan")).toBeNull(); expect(screen.queryByText("pi.lan")).toBeNull();
// The cell holds the learned name followed by the tag, so the match is on // A learned name reads muted and nothing more here: the "learned" tag would
// the containing span rather than on a bare text node. // repeat on every row of the table, so the Clients page carries it instead.
const learned = screen.getByText( const learned = screen.getByText("laptop.lan");
(content, element) => element?.tagName === "SPAN" && content.startsWith("laptop.lan"),
);
expect(learned.getAttribute("title")).toBe("192.0.2.11"); 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.closest("tr")!).queryByText("learned")).toBeNull();
expect(within(learned).getByText("learned")).toBeTruthy();
// A known client with neither name, and a client the loaded list has never // 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. // seen, both fall back to the bare address with no tooltip standing in.
@@ -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(named.getAttribute("title")).toBe("192.0.2.10");
expect(screen.queryByText("pi.lan")).toBeNull(); expect(screen.queryByText("pi.lan")).toBeNull();
// The cell holds the learned name followed by the tag, so the match is on // A learned name reads muted and nothing more here: the "learned" tag would
// the containing span rather than on a bare text node. // repeat on every row of the table, so the Clients page carries it instead.
const learned = screen.getByText( const learned = screen.getByText("laptop.lan");
(content, element) => element?.tagName === "SPAN" && content.startsWith("laptop.lan"),
);
expect(learned.getAttribute("title")).toBe("192.0.2.11"); 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.closest("tr")!).queryByText("learned")).toBeNull();
expect(within(learned).getByText("learned")).toBeTruthy();
// A known client with neither name, and a client the loaded list has never // 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. // seen, both fall back to the bare address with no tooltip standing in.
+4 -2
View File
@@ -169,8 +169,10 @@ export const styles = stylex.create({
}, },
/** /**
* A learned name is runtime state, not something the operator typed, so it * 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 — * reads muted wherever it appears. The Clients page adds the outlined tag,
* a screen reader announces it — because colour alone is not an affordance. * 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: { learnedName: {
color: colors.textMuted, color: colors.textMuted,
+1 -1
View File
@@ -1,6 +1,6 @@
.{ .{
.name = .nxdns, .name = .nxdns,
.version = "0.0.4", .version = "0.0.5",
.minimum_zig_version = "0.16.0", .minimum_zig_version = "0.16.0",
.paths = .{""}, .paths = .{""},
.fingerprint = 0x3307b311dded1d91, .fingerprint = 0x3307b311dded1d91,