Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/frontend/packages/swarm-ui/src/pages/pr-report.ts
iris 71a4d1d255 swarm ui: the PR report's approvals column filters on whether the rule is met
The report had an approvals column (1/2) and a separate approved column.
They are one fact, so approvals now carries the filter, complete or missing,
and the approved column is gone.
2026-11-09 22:44:10 +01:00

83 lines
3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Pure pieces of the PR report: the row the controller returns, the report
// URL for a repo filter, and the words its flag columns filter on. Kept out of
// the page so the cases are unit tested.
/** One open pull request, as `GET /api/pr-report` returns it. */
export interface PrReportRow {
/** `owner/name`. */
repo: string;
number: number;
title: string;
html_url: string | null;
author: string | null;
labels: string[];
assignees: string[];
requested_reviewers: string[];
base_branch: string;
head_branch: string;
created_unix: number | null;
updated_unix: number | null;
/** Lines the PR adds and removes. */
additions: number | null;
deletions: number | null;
/** The forge's draft flag. */
wip: boolean;
has_conflicts: boolean;
/** The base branch has a branch protection rule. */
targets_protected_branch: boolean;
required_approvals: number;
approvals: number;
/** Reviewers whose latest review asks for changes. */
changes_requested: number;
/** `null` when the head has no commit status. */
ci: "success" | "pending" | "failure" | null;
}
/** The report URL for a repo filter. The path parts are encoded, so a name
* with `?`, `#` or `%` stays one path segment. A filter without a slash is
* not a repo, so it reads as all repos. */
export function prReportUrl(repoFilter: string): string {
const i = repoFilter.indexOf("/");
if (i < 0) return "/api/pr-report";
const org = encodeURIComponent(repoFilter.slice(0, i));
const name = encodeURIComponent(repoFilter.slice(i + 1));
return `/api/repos/${org}/${name}/pr-report`;
}
/** What a flag column offers as filter values. */
export function yesNo(flag: boolean): string {
return flag ? "yes" : "no";
}
/** The approvals meet the base branch's rule. An unprotected base asks for
* none, so its PRs have them all. */
export function hasAllApprovals(row: PrReportRow): boolean {
return row.approvals >= row.required_approvals;
}
/** What the approvals column filters on: whether the PR has all the approvals
* its base branch asks for. */
export function approvalsState(row: PrReportRow): "complete" | "missing" {
return hasAllApprovals(row) ? "complete" : "missing";
}
/** The diff size cell: lines added and removed, `+120 −8`. A count the forge
* did not give reads as a dash. */
export function diffText(row: PrReportRow): string {
if (row.additions === null && row.deletions === null) return "—";
return `+${row.additions ?? 0} −${row.deletions ?? 0}`;
}
/** What the diff column sorts on: lines changed in all. */
export function diffSize(row: PrReportRow): number {
return (row.additions ?? 0) + (row.deletions ?? 0);
}
/** The approvals cell: how many of the rule's approvals the PR has, or a dash
* when its base branch asks for none. */
export function approvalsText(row: PrReportRow): string {
if (!row.targets_protected_branch || row.required_approvals === 0) {
return row.approvals > 0 ? `${row.approvals}` : "—";
}
return `${row.approvals}/${row.required_approvals}`;
}