Skip to content

Commit 8b37240

Browse files
authored
PR dashboard: Identify PRs that already have a reviewer (#1254)
* Identify PRs that already have a reviewer * Progressively fill in already-being-reviewed data This speeds up the initial page load, and adds in more information as it's known.
1 parent 6fc9943 commit 8b37240

File tree

2 files changed

+59
-7
lines changed

2 files changed

+59
-7
lines changed

org-cyf-itp/assets/custom-scripts/reviews/common.mjs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ function identifyAge(date) {
1313
}
1414
}
1515

16+
const apiPrefix = "https://github-issue-proxy.illicitonion.com/cached/2/repos/CodeYourFuture/";
17+
1618
// TODO: Pull these in from config.
1719
export const modules = [
1820
"Module-User-Focused-Data",
@@ -33,7 +35,35 @@ class PR {
3335
this.createdAge = createdAge;
3436
this.updatedAge = updatedAge;
3537
this.status = status;
36-
this.comments = [];
38+
this._didLoadReviews = false;
39+
this.reviews = [];
40+
}
41+
42+
async loadReviews() {
43+
if (this._didLoadReviews) {
44+
return;
45+
}
46+
const response = await fetch(`${apiPrefix}/${this.module}/pulls/${this.number}/reviews`);
47+
const reviews = await response.json();
48+
for (const reviewResponse of reviews) {
49+
const review = new Review(reviewResponse.user.login, reviewResponse.user.login === this.userName, identifyAge(new Date(Date.parse(reviewResponse["submitted_at"]))), reviewResponse.state);
50+
this.reviews.push(review);
51+
}
52+
this._didLoadReviews = true;
53+
}
54+
55+
hasReviewer() {
56+
return this.reviews.some(review => !review.isPrAuthor);
57+
}
58+
}
59+
60+
class Review {
61+
constructor(userName, isPrAuthor, age, state) {
62+
this.userName = userName;
63+
this.isPrAuthor = isPrAuthor;
64+
this.age = age;
65+
// e.g. "COMMENTED".
66+
this.state = state;
3767
}
3868
}
3969

@@ -58,11 +88,11 @@ function getStatus(state, labels) {
5888
return "Unknown";
5989
}
6090

61-
export async function fetchPrs() {
91+
export async function fetchPrsWithoutLoadingReviews() {
6292
const prs = [];
6393
const responsePromises = [];
6494
for (const module of modules) {
65-
responsePromises.push(fetch(`https://github-issue-proxy.illicitonion.com/cached/2/repos/CodeYourFuture/${module}/pulls?state=all`).then((response) => response.json()));
95+
responsePromises.push(fetch(`${apiPrefix}/${module}/pulls?state=all`).then((response) => response.json()));
6696
}
6797
const responsesByModule = await Promise.all(responsePromises);
6898
for (let i = 0; i < responsesByModule.length; i++) {

org-cyf-itp/assets/custom-scripts/reviews/index.mjs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,24 @@ function computeStatusClass(awaitingReview) {
3636
}
3737
}
3838

39+
const state = {
40+
"prs": null,
41+
}
42+
3943
async function onLoad() {
44+
render();
45+
state.prs = (await fetchPrsWithoutLoadingReviews()).filter((pr) => pr.status === "Needs Review");
46+
render();
47+
await Promise.all(state.prs.map((pr) => pr.loadReviews()));
48+
render();
49+
}
50+
51+
function render() {
52+
if (state.prs === null) {
53+
document.querySelector("#pr-list").innerText = "Loading...";
54+
return;
55+
}
56+
4057
for (const module of modules) {
4158
awaitingReviewByAge[module] = {
4259
"this week": 0,
@@ -46,9 +63,7 @@ async function onLoad() {
4663
prsByModule[module] = [];
4764
}
4865

49-
for (const pr of (await fetchPrs()).filter(
50-
(pr) => pr.status === "Needs Review"
51-
)) {
66+
for (const pr of state.prs) {
5267
awaitingReviewByAge[pr.module][pr.updatedAge]++;
5368
prsByModule[pr.module].push(pr);
5469
}
@@ -65,6 +80,7 @@ async function onLoad() {
6580
}
6681

6782
document.querySelector("#pr-list").innerText = "";
83+
document.querySelector("#overview").innerText = "";
6884

6985
for (const module of modules) {
7086
const awaitingReview = awaitingReviewByAge[module];
@@ -105,7 +121,13 @@ async function onLoad() {
105121
.querySelector("template.pr-in-list")
106122
.content.cloneNode(true);
107123

108-
prInList.querySelector(".emoji").innerText = ageToEmoji[pr.updatedAge];
124+
const emojiElement = prInList.querySelector(".emoji");
125+
if (pr.hasReviewer()) {
126+
emojiElement.innerText = "🙋🏾";
127+
emojiElement.title = "Has reviewer";
128+
} else {
129+
emojiElement.innerText = ageToEmoji[pr.updatedAge];
130+
}
109131

110132
const prLink = prInList.querySelector("a.pr-link");
111133
prLink.href = pr.url;

0 commit comments

Comments
 (0)