Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apps/web/src/components/pullRequest/PullRequestsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
pullRequestOverrideAfterAction,
reusePullRequestEntries,
settlePullRequestOverrides,
comparePullRequestsByRecency,
largestPullRequestReadCount,
} from "./pullRequestList.logic";
import {
Expand Down Expand Up @@ -560,7 +561,7 @@ export function PullRequestsPage() {
const held = new Set(ordered.entries.map(pullRequestEntryKey));
const arrived = answered.entries.filter((entry) => !held.has(pullRequestEntryKey(entry)));
const appended = rankPullRequestMatches(
arrived.toSorted((left, right) => right.updatedAt.localeCompare(left.updatedAt)),
arrived.toSorted(comparePullRequestsByRecency),
sentParsed.text,
);
setOrdered({ key: filterKey, source: answered, entries: [...ordered.entries, ...appended] });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,19 @@ describe("review verdicts", () => {
});

describe("pull request timeline", () => {
it("orders host timestamps by instant across offsets and fractional seconds", () => {
const events = buildPullRequestTimeline({
...TIMELINE_SOURCE,
createdAt: "2026-07-05T01:00:00+02:00",
commits: [{ oid: "commit", messageHeadline: "", committedDate: "2026-07-05T00:30:00Z" }],
comments: [{ ...TIMELINE_SOURCE.comments[0]!, createdAt: "2026-07-05T00:30:00.5Z" }],
mergedAt: null,
closedAt: null,
});

expect(events.map((event) => event.id)).toEqual(["c1", "commit", "created"]);
});

it("drops a body that is nothing but a bot's HTML comment, and keeps one that says more", () => {
const events = buildPullRequestTimeline({
...TIMELINE_SOURCE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,7 @@ export function buildPullRequestTimeline(
},
]
: []),
].toSorted((left, right) => right.at.localeCompare(left.at));
].toSorted((left, right) => (instant(right.at) || 0) - (instant(left.at) || 0));
}

const FINDING_LIMIT = 20;
Expand Down
14 changes: 14 additions & 0 deletions apps/web/src/components/pullRequest/pullRequestList.logic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,20 @@ describe("merging the environments' own listings", () => {
...overrides,
}) as Parameters<typeof mergePullRequestLists>[0][number][1];

it("orders host timestamps by instant across offsets and fractional seconds", () => {
const entries = [
entry({ number: 1, updatedAt: "2026-07-05T01:00:00+02:00" }),
entry({ number: 2, updatedAt: "2026-07-05T00:30:00Z" }),
entry({ number: 3, updatedAt: "2026-07-05T00:30:00.5Z" }),
];
const merged = mergePullRequestLists([
[ENV_1, answer({ entries: entries.slice(0, 2) })],
[ENV_2, answer({ entries: entries.slice(2) })],
]);

expect(merged?.entries.map((row) => row.number)).toEqual([3, 2, 1]);
});

it("tags every row with the environment that read it, newest first", () => {
const merged = mergePullRequestLists([
[ENV_1, answer({ entries: [entry({ number: 1, updatedAt: "2026-07-01T00:00:00Z" })] })],
Expand Down
38 changes: 24 additions & 14 deletions apps/web/src/components/pullRequest/pullRequestList.logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,11 +404,16 @@ export function partitionPullRequestsWithPriority<Entry extends PullRequestListE
others.push(entry);
}
}
const byRecency = (left: Entry, right: Entry) => right.updatedAt.localeCompare(left.updatedAt);
return (
[
{ key: "authored", entries: [...authoredByKey.values()].toSorted(byRecency) },
{ key: "reviewRequested", entries: [...reviewByKey.values()].toSorted(byRecency) },
{
key: "authored",
entries: [...authoredByKey.values()].toSorted(comparePullRequestsByRecency),
},
{
key: "reviewRequested",
entries: [...reviewByKey.values()].toSorted(comparePullRequestsByRecency),
},
{ key: "others", entries: others },
] as const
)
Expand Down Expand Up @@ -503,7 +508,7 @@ export function mergePullRequestLists(
return {
viewers,
providers: [...providers.values()],
entries: entries.toSorted((left, right) => right.updatedAt.localeCompare(left.updatedAt)),
entries: entries.toSorted(comparePullRequestsByRecency),
errors,
truncated,
nextCursors,
Expand Down Expand Up @@ -697,7 +702,7 @@ export function rankPullRequestMatches<Entry extends PullRequestListEntry>(
if (query.trim().length === 0) return entries;
return entries.toSorted((left, right) => {
const byScore = scorePullRequestMatch(right, query) - scorePullRequestMatch(left, query);
return byScore !== 0 ? byScore : right.updatedAt.localeCompare(left.updatedAt);
return byScore !== 0 ? byScore : comparePullRequestsByRecency(left, right);
});
}

Expand All @@ -718,24 +723,29 @@ export function rankPullRequestsByMergeReadiness<Entry extends PullRequestListEn
if (byTier !== 0) return byTier;
const measured = Number(hasMeasuredSize(right)) - Number(hasMeasuredSize(left));
const sized = left.additions + left.deletions - (right.additions + right.deletions);
return measured || sized || right.updatedAt.localeCompare(left.updatedAt);
return measured || sized || comparePullRequestsByRecency(left, right);
});
}

export function comparePullRequestsByRecency(
left: PullRequestListEntry,
right: PullRequestListEntry,
) {
const leftUpdated = toSortableTimestamp(left.updatedAt);
const rightUpdated = toSortableTimestamp(right.updatedAt);
const measured = Number(leftUpdated === null) - Number(rightUpdated === null);
if (measured !== 0) return measured;
if (leftUpdated === null || rightUpdated === null) return 0;
return rightUpdated - leftUpdated;
}

function rankByTierThenRecency<Entry extends PullRequestListEntry>(
entries: ReadonlyArray<Entry>,
tier: (entry: Entry) => number,
): ReadonlyArray<Entry> {
const timestamp = (entry: Entry) => toSortableTimestamp(entry.updatedAt);
return entries.toSorted((left, right) => {
const byTier = tier(left) - tier(right);
if (byTier !== 0) return byTier;
const leftUpdated = timestamp(left);
const rightUpdated = timestamp(right);
const measured = Number(leftUpdated === null) - Number(rightUpdated === null);
if (measured !== 0) return measured;
if (leftUpdated === null || rightUpdated === null) return 0;
return rightUpdated - leftUpdated;
return byTier !== 0 ? byTier : comparePullRequestsByRecency(left, right);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
import type { PullRequestTabStatusSeed } from "~/components/RightPanelTabs";
import { pullRequestSurfaceId } from "~/rightPanelStore";
import {
comparePullRequestsByRecency,
filterPullRequestsByInvolvement,
groupPullRequestsByInvolvement,
matchesPullRequestFilters,
Expand Down Expand Up @@ -68,9 +69,7 @@ export function pullRequestGroups({
)
: involvementEntries;
if (text.length === 0) {
return narrowedEntries.toSorted((left, right) =>
right.updatedAt.localeCompare(left.updatedAt),
);
return narrowedEntries.toSorted(comparePullRequestsByRecency);
}
return narrowedEntries.filter(
(entry) =>
Expand Down
Loading