The pull requests card gets a diff column, the lines a PR adds and removes (`+120 −8`), sortable on the total. The controller takes the counts from the forge's pull request list, so no call is added. The column that said "has all approvals" is now headed "approved".
77 lines
2.7 KiB
TypeScript
77 lines
2.7 KiB
TypeScript
// 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;
|
||
}
|
||
|
||
/** 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}`;
|
||
}
|