swarm-ui: filter the issue report by title, assignees, blocked

Three columns gain Table's filterValue/filterMode (the mechanism
hyperhive#4088 added): title (text, substring search -- there was no
way to search by title text at all), assignees (text, not select --
a row can carry more than one assignee and Table's select mode
matches one whole string per row exactly, so substring search over
the joined string is the shape that actually fits multi-value data),
and blocked (select, synthesized "blocked"/"not blocked" strings --
distinct from the existing "hide blocked" toggle, which only hides
blocked issues and has no way to show only them).

Deliberately not touched: repo (redundant with the existing repo
SelectField), labels (redundant with the existing label chip
multi-select -- chips are the better UI for a bounded label set
anyway), the three numeric columns (no clean filter shape, already
sortable). The existing hand-rolled sort (SortHeader, useLocalSetting-
persisted) is untouched too -- migrating it onto Table's own sortBy
would drop the localStorage persistence this page specifically wants,
and Table doesn't expose controlled sort state to a caller today. The
two layers compose without conflict: Table's own filter/sort runs
over whatever rows it's handed, which is already this page's own
filtered+sorted array.

Scoped on the issue first, including this exact reasoning, before
writing any code.
This commit is contained in:
iris 2026-09-08 11:35:57 +02:00 committed by mara
commit 17d22f9e16

View file

@ -309,6 +309,7 @@ export function IssueReportPage() {
),
ariaSort: ariaSortFor("title"),
render: (r) => r.title,
filterValue: (r) => r.title,
},
{
key: "labels",
@ -328,6 +329,14 @@ export function IssueReportPage() {
),
ariaSort: ariaSortFor("assignees"),
render: (r) => (r.assignees.length ? r.assignees.join(", ") : "—"),
// Text, not `"select"` — a row can carry more than one assignee,
// and `Table`'s select mode matches one whole string per row
// exactly, so a real per-assignee dropdown would need `Table`
// itself to grow multi-value filtering. Substring search over
// the joined string still finds "iris" inside "damocles, iris"
// correctly, which covers the actual gap (no way to filter by
// assignee at all today).
filterValue: (r) => r.assignees.join(", "),
},
{
key: "blocked",
@ -343,6 +352,13 @@ export function IssueReportPage() {
ariaSort: ariaSortFor("blocked"),
render: (r) =>
r.blocked ? <Badge tone="warning" value="blocked" /> : "—",
// A distinct gap from the existing "hide blocked" toggle above:
// that one only *hides* blocked issues, there was no way to see
// *only* the blocked ones. Synthesized two-value string (not the
// raw boolean) — `Table`'s select mode needs a string to match,
// same as `AgentsPage`'s `wanted ?? "no declaration"` pattern.
filterValue: (r) => (r.blocked ? "blocked" : "not blocked"),
filterMode: "select",
},
{
key: "depended_on_by_count",