Fix public-key node search field switching and non-hex input

This commit is contained in:
MrAlders0n committed 2026-07-24 06:19:19 -04:00
1 parent badd919e0d
commit 948cfa25b0
3 files changed
+51 -5

No files matched your search

+16 -5
View File
@@ -14,6 +14,7 @@ import { ObserverIcon } from "../../components/ObserverIcon";
import { DataTable, type Column } from "../../components/DataTable";
import { LoadingPill } from "../../components/LoadingPill";
import { NodeFilterBar, type MultibyteFilter } from "./NodeFilterBar";
import { nodeSearchParams } from "./node-search";
import { patchNodeSummary } from "./node-updates";
import type { NodeSummary } from "./types";
import type { CursorPage } from "../../types/api";
@@ -138,9 +139,19 @@ export function NodeTable({ wsManager, selectedNodeId, onSelectNode }: NodeTable
useTick();
// switching the field flips what the box means (a name vs a hex prefix), so stale text mustn't carry over
const handleSearchFieldChange = useCallback((field: string) => {
setSearchField(field);
setSearch("");
}, []);
// derive the actual server params (name vs pubkeyPrefix, hex-guarded) and key the query on THOSE,
// so toggling the field with an empty box is a no-op and a name never gets sent as a hex prefix
const { name: nameParam, pubkeyPrefix: pubkeyPrefixParam } = nodeSearchParams(searchField, search);
const queryKey = useMemo(
() => ["nodes", regionKey, typeFilter, pathsFilter, tracesFilter, search, searchField],
[regionKey, typeFilter, pathsFilter, tracesFilter, search, searchField],
() => ["nodes", regionKey, typeFilter, pathsFilter, tracesFilter, nameParam, pubkeyPrefixParam],
[regionKey, typeFilter, pathsFilter, tracesFilter, nameParam, pubkeyPrefixParam],
);
// page the region's nodes 50 at a time (filters stay server-side, in the query key); rows stream
@@ -151,8 +162,8 @@ export function NodeTable({ wsManager, selectedNodeId, onSelectNode }: NodeTable
getNodesPage(iatas, {
cursor,
type: typeFilter || undefined,
name: searchField === "name" ? search || undefined : undefined,
pubkeyPrefix: searchField === "pubkey" ? search || undefined : undefined,
name: nameParam,
pubkeyPrefix: pubkeyPrefixParam,
supportsMultibytePaths: pathsFilter || undefined,
supportsMultibyteTraces: tracesFilter || undefined,
}),
@@ -189,7 +200,7 @@ export function NodeTable({ wsManager, selectedNodeId, onSelectNode }: NodeTable
search={search}
onSearchChange={setSearch}
searchField={searchField}
onSearchFieldChange={setSearchField}
onSearchFieldChange={handleSearchFieldChange}
typeFilter={typeFilter}
onTypeChange={setTypeFilter}
pathsFilter={pathsFilter}
+12
View File
@@ -0,0 +1,12 @@
// Maps the Nodes-table search box (one shared input + a field selector) to the server params.
// The Public Key field is a hex prefix; non-hex input is dropped rather than sent, because the
// backend 400s on a non-hex pubkeyPrefix — so a stray character shows the unfiltered list instead
// of erroring the whole table.
export function nodeSearchParams(searchField: string, search: string): { name?: string; pubkeyPrefix?: string } {
const value = search.trim();
if (searchField === "pubkey") {
const hex = value.toLowerCase();
return { pubkeyPrefix: /^[0-9a-f]+$/.test(hex) ? hex : undefined };
}
return { name: value || undefined };
}
+23
View File
@@ -0,0 +1,23 @@
import { describe, it, expect } from "vitest";
import { nodeSearchParams } from "../../../src/features/nodes/node-search";
describe("nodeSearchParams", () => {
it("maps the name field to the name param", () => {
expect(nodeSearchParams("name", "alpha")).toEqual({ name: "alpha" });
});
it("maps the pubkey field to a lowercased hex prefix", () => {
expect(nodeSearchParams("pubkey", "AB12")).toEqual({ pubkeyPrefix: "ab12" });
});
it("drops a non-hex pubkey prefix instead of firing a request the server 400s", () => {
// names/spaces are non-hex; sending them as pubkeyPrefix would 400 the whole table
expect(nodeSearchParams("pubkey", "alice")).toEqual({ pubkeyPrefix: undefined });
expect(nodeSearchParams("pubkey", "de ad")).toEqual({ pubkeyPrefix: undefined });
});
it("treats blank input as no filter on either field", () => {
expect(nodeSearchParams("name", " ")).toEqual({ name: undefined });
expect(nodeSearchParams("pubkey", "")).toEqual({ pubkeyPrefix: undefined });
});
});