diff --git a/frontend/packages/swarm-ui/src/pages/IssueReportPage.tsx b/frontend/packages/swarm-ui/src/pages/IssueReportPage.tsx index 95f84da9..6d98772c 100644 --- a/frontend/packages/swarm-ui/src/pages/IssueReportPage.tsx +++ b/frontend/packages/swarm-ui/src/pages/IssueReportPage.tsx @@ -35,6 +35,7 @@ import { useLocalSetting } from "@hive/shared/settings-storage.js"; import { Panel } from "../ui/panel/Panel.js"; import { SelectField } from "../ui/select-field/SelectField.js"; import { Table, type TableColumn } from "../ui/table/Table.js"; +import { ALL_REPOS, reportUrl, repoOptions } from "./issue-report-repo.js"; import "./IssueReportPage.css"; interface IssueReportRow { @@ -63,10 +64,6 @@ type SortKey = | "transitively_blocks_count"; type SortDir = "asc" | "desc"; -// Sentinel ` + {reposError ? ( + + ) : null} {error ? ( ({ value: r, label: r })), + ]; + if (selected !== ALL_REPOS && !(repos ?? []).includes(selected)) { + options.push({ + value: selected, + label: repos === null ? selected : `${selected} (no open issues)`, + }); + } + return options; +} diff --git a/frontend/packages/swarm-ui/test/issue-report-repo.test.mjs b/frontend/packages/swarm-ui/test/issue-report-repo.test.mjs new file mode 100644 index 00000000..25535a85 --- /dev/null +++ b/frontend/packages/swarm-ui/test/issue-report-repo.test.mjs @@ -0,0 +1,55 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { + ALL_REPOS, + reportUrl, + repoOptions, +} from "../src/pages/issue-report-repo.ts"; + +test("reportUrl: no repo means the combined report", () => { + assert.equal(reportUrl(ALL_REPOS), "/api/issue-report"); +}); + +test("reportUrl: a filter without a slash is not a repo", () => { + assert.equal(reportUrl("nope"), "/api/issue-report"); +}); + +test("reportUrl: org and name become two path segments", () => { + assert.equal( + reportUrl("hyperhive/hyperhive"), + "/api/repos/hyperhive/hyperhive/issue-report", + ); +}); + +test("reportUrl: reserved characters in a name are encoded", () => { + assert.equal( + reportUrl("org/a?b#c%d"), + "/api/repos/org/a%3Fb%23c%25d/issue-report", + ); +}); + +test("repoOptions: all repos comes first, then the list", () => { + assert.deepEqual(repoOptions(["a/x", "b/y"], ALL_REPOS), [ + { value: "", label: "all repos" }, + { value: "a/x", label: "a/x" }, + { value: "b/y", label: "b/y" }, + ]); +}); + +test("repoOptions: a listed selection adds nothing", () => { + assert.equal(repoOptions(["a/x"], "a/x").length, 2); +}); + +test("repoOptions: a remembered repo keeps an option before the list loads", () => { + assert.deepEqual(repoOptions(null, "a/x"), [ + { value: "", label: "all repos" }, + { value: "a/x", label: "a/x" }, + ]); +}); + +test("repoOptions: a remembered repo missing from the list says why", () => { + assert.deepEqual(repoOptions(["b/y"], "a/x").at(-1), { + value: "a/x", + label: "a/x (no open issues)", + }); +});