Merge pull request #733 from fabro-sh/fix/list-view-filter-options

Populate repo and workflow filters in runs list view
This commit is contained in:
Bryan Helmkamp 2026-08-20 19:31:35 -04:00 committed by GitHub
commit 7987fda25d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 57 additions and 11 deletions

View file

@ -3,6 +3,7 @@ import type { BoardColumn, Run } from "@qltysh/fabro-api-client";
import {
buildBoardColumns,
buildFilterOptions,
loadStoredRunsWorkspaceSearchParams,
placeArchivedColumnLast,
persistRunsWorkspacePreferences,
@ -11,6 +12,7 @@ import {
shouldRefreshBoardForEvent,
} from "./runs";
import { summarizeBatchLifecycleAction } from "../components/runs-list/batch-lifecycle";
import { mapRunListItem } from "../data/runs";
import { TEST_PRINCIPAL } from "../lib/test-fixtures";
function boardRun(id: string, column: BoardColumn, questionText?: string): Run {
@ -217,6 +219,38 @@ describe("runs route board mapping", () => {
});
});
describe("runs route filter options", () => {
function runWith(id: string, repoName: string, workflowName: string): Run {
const run = boardRun(id, "running");
return {
...run,
repository: { ...run.repository, name: repoName },
workflow: { ...run.workflow, name: workflowName },
};
}
test("derives sorted unique options from run items", () => {
const items = [
runWith("a", "qlty/beta", "release"),
runWith("b", "qlty/alpha", "hello"),
runWith("c", "qlty/beta", "release"),
].map(mapRunListItem);
expect(buildFilterOptions(items, (item) => item.repo, "all")).toEqual(["alpha", "beta"]);
expect(buildFilterOptions(items, (item) => item.workflow, "all")).toEqual([
"hello",
"release",
]);
});
test("keeps the active selection when no loaded run matches it", () => {
const items = [runWith("a", "qlty/beta", "release")].map(mapRunListItem);
expect(buildFilterOptions(items, (item) => item.repo, "gamma")).toEqual(["beta", "gamma"]);
expect(buildFilterOptions([], (item) => item.workflow, "release")).toEqual(["release"]);
});
});
describe("runs route workspace preferences", () => {
class MemoryStorage {
values = new Map<string, string>();

View file

@ -140,6 +140,18 @@ export function buildBoardColumns(
});
}
export function buildFilterOptions(
items: RunItem[],
pick: (item: RunItem) => string,
selected: string,
): string[] {
const values = new Set(items.map(pick));
// Keep the active selection visible even when no loaded run matches it,
// e.g. a stored repo filter while paginating the list view.
if (selected !== "all") values.add(selected);
return Array.from(values).sort();
}
export function placeArchivedColumnLast(columns: Column[], includeArchived: boolean): Column[] {
if (!includeArchived) return columns;
const archived = columns.find((column) => column.id === "archived");
@ -771,18 +783,18 @@ export default function Runs() {
);
const hasGitHubAuth = authConfig.data?.methods.includes("github") === true;
const serverUrl = systemInfo.data?.server_url;
const allRepos = Array.from(
new Set(
initialColumns.flatMap((col: Column) => col.items.map((item: RunItem) => String(item.repo))),
),
// Filter options come from the loaded runs: all runs in columns view, the
// current page in list view (until a facets endpoint provides the full set).
const filterSourceItems: RunItem[] =
view === "list"
? (listRunsPage.data?.data ?? []).map(mapRunListItem)
: initialColumns.flatMap((col: Column) => col.items);
const allRepos = buildFilterOptions(filterSourceItems, (item) => item.repo, repoFilter);
const allWorkflows = buildFilterOptions(
filterSourceItems,
(item) => item.workflow,
workflowFilter,
);
allRepos.sort();
const allWorkflows = Array.from(
new Set(
initialColumns.flatMap((col: Column) => col.items.map((item: RunItem) => String(item.workflow))),
),
);
allWorkflows.sort();
const [columnsState, setColumnsState] = useState(() => ({
base: initialColumns,
columns: initialColumns,