Skip to content

Commit 9794bb8

Browse files
committed
feat: enhance GitHub notifications fetching and rendering logic
1 parent 331de65 commit 9794bb8

File tree

6 files changed

+65
-31
lines changed

6 files changed

+65
-31
lines changed

src/home/fetch-github/fetch-notifications.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,29 @@ import { Octokit } from "@octokit/rest";
22
import { GitHubNotification } from "../github-types";
33

44
export async function fetchNotifications(octokit: Octokit): Promise<GitHubNotification[]> {
5-
const { data: notifications } = await octokit.activity.listNotificationsForAuthenticatedUser({
6-
all: true,
7-
per_page: 100,
8-
});
5+
const allNotifications: GitHubNotification[] = [];
6+
let page = 1;
7+
const perPage = 100; // Maximum allowed by GitHub API
8+
const maxPages = 5; // Limit to 5 pages
99

10-
return notifications;
10+
while (page <= maxPages) {
11+
const { data: notifications, headers } = await octokit.activity.listNotificationsForAuthenticatedUser({
12+
all: true,
13+
per_page: perPage,
14+
page,
15+
});
16+
17+
allNotifications.push(...notifications);
18+
19+
// Check if there are more pages
20+
const linkHeader = headers.link;
21+
if (!linkHeader || !linkHeader.includes('rel="next"')) {
22+
break; // No more pages
23+
}
24+
25+
page++; // Move to the next page
26+
}
27+
28+
console.trace({ allNotifications });
29+
return allNotifications;
1130
}
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
import { GitHubNotification } from "../../github-types";
21
import { setUpNotificationElement } from "./set-up-notification-element";
2+
import { EnrichedGitHubNotification } from "./render-github-notifications";
33

4-
export function createNewNotification({ notification, container }: { notification: GitHubNotification; container: HTMLDivElement }) {
4+
export function createNewNotification({ notification, container }: { notification: EnrichedGitHubNotification; container: HTMLElement }) {
55
const notificationWrapper = document.createElement("div");
66
const notificationElement = document.createElement("div");
77
notificationElement.setAttribute("data-notification-id", notification.id);
88
notificationElement.classList.add("notification-element-inner");
99

10-
setUpNotificationElement(notificationElement, notification);
11-
notificationWrapper.appendChild(notificationElement);
10+
const link = document.createElement("a");
11+
link.href = notification.subject.url.replace("api.github.com/repos", "github.com").replace("/pulls/", "/pull/");
12+
link.appendChild(notificationElement);
1213

14+
setUpNotificationElement(notificationElement, notification);
15+
notificationWrapper.appendChild(link);
1316
container.appendChild(notificationWrapper);
1417
return notificationWrapper;
1518
}

src/home/rendering/github-notifications/is-associated-with-task.ts

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,26 @@ type GraphQlTaskResponse = {
1616

1717
export async function isAssociatedWithTask(notification: GitHubNotification, octokit: Octokit): Promise<boolean> {
1818
if (notification.subject.type === "Issue") {
19-
// Have to load it because devpool-issues.json doesn't show assigned tasks.
20-
// If they are working on it then they should be assigned.
21-
// @TODO: load all issues, even if assigned, in the directory. This will save network requests from the client.
19+
const owner = notification.repository.owner.login;
20+
const repo = notification.repository.name;
21+
const issueNumber = parseInt(notification.subject.url.split("/").pop() || "0", 10);
2222

23-
const issueLabels = await octokit.issues.listLabelsOnIssue({
24-
owner: notification.repository.owner.login,
25-
repo: notification.repository.name,
26-
issue_number: parseInt(notification.subject.url.split("/").pop() || "0", 10),
27-
});
23+
try {
24+
const issueLabels = await octokit.issues.listLabelsOnIssue({
25+
owner,
26+
repo,
27+
issue_number: issueNumber,
28+
});
2829

29-
const hasPriceLabel = issueLabels.data.some((label) => label.name.startsWith("Price: "));
30-
if (hasPriceLabel) {
31-
return true;
30+
const hasPriceLabel = issueLabels.data.some((label) => label.name.startsWith("Price: "));
31+
return hasPriceLabel;
32+
} catch (error) {
33+
console.error("Error fetching issue labels:", error);
34+
if (error.status === 404) {
35+
console.error("404 Not Found. This could mean the issue doesn't exist or the authenticated user doesn't have access.");
36+
}
37+
// If we can't fetch the labels, we'll assume it's not associated with a task
38+
return false;
3239
}
3340
} else if (notification.subject.type === "PullRequest") {
3441
try {
@@ -77,16 +84,19 @@ export async function isAssociatedWithTask(notification: GitHubNotification, oct
7784

7885
const response: GraphQlTaskResponse = await octokit.graphql(query, variables);
7986

80-
const linkedItems = response.repository.pullRequest.timelineItems.nodes;
87+
const linkedItems = response.repository.pullRequest.timelineItems.nodes.filter(Boolean);
8188

8289
for (const item of linkedItems) {
8390
const labels = item.subject?.labels?.nodes || item.source?.labels?.nodes;
84-
if (labels && labels.some((label) => label.name.toLowerCase().startsWith("priority: "))) {
91+
if (labels && labels.some((label) => label.name.startsWith("Price: "))) {
8592
return true;
8693
}
8794
}
8895
} catch (error) {
89-
console.error("Error checking linked issues for priority labels:", error);
96+
console.error("Error checking linked issues for price labels:", error);
97+
if (error.status === 404) {
98+
console.error("404 Not Found. This could mean the repository is private and the authenticated user doesn't have access.");
99+
}
90100
}
91101
}
92102
return false;

src/home/rendering/github-notifications/render-github-notifications.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,21 @@ export async function renderGitHubNotifications() {
2020
container.innerHTML = "";
2121
}
2222

23-
const processedNotifications = await processNotifications(notifications, octokit);
23+
// Filter for unread notifications
24+
const unreadNotifications = notifications.filter(notification => !notification.unread);
2425

25-
console.trace({ processedNotifications });
26+
const processedNotifications = await processNotifications(unreadNotifications, octokit);
27+
28+
// console.trace({ processedNotifications });
2629

2730
const filteredNotifications = processedNotifications.filter(
2831
(notification): notification is EnrichedGitHubNotification => notification !== null && !notification.isDraft
2932
);
3033

31-
console.trace({ filteredNotifications });
34+
// console.trace({ filteredNotifications });
3235

3336
const finalNotifications = filteredNotifications.sort((a, b) => calculateNotificationScore(b) - calculateNotificationScore(a));
34-
console.trace({ finalNotifications });
37+
// console.trace({ finalNotifications });
3538

3639
const existingNotificationIds = new Set(
3740
Array.from(container.querySelectorAll(".notification-element-inner")).map((element) => element.getAttribute("data-notification-id"))
@@ -59,7 +62,7 @@ export async function renderGitHubNotifications() {
5962
}
6063

6164
async function processNotifications(notifications: GitHubNotification[], octokit: Octokit): Promise<(EnrichedGitHubNotification | null)[]> {
62-
console.trace("processNotifications");
65+
// console.trace("processNotifications");
6366
return Promise.all(
6467
notifications.map(async (notification) => {
6568
const isAssociated = await isAssociatedWithTask(notification, octokit);

src/home/rendering/github-notifications/set-up-notification-element.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ export function setUpNotificationElement(notificationElement: HTMLDivElement, no
1919
}
2020

2121
const formattedReason = notification.reason.replace(/_/g, " ");
22-
2322
notificationElement.innerHTML = `
2423
<div class="info">
2524
<div class="title">
@@ -28,13 +27,13 @@ export function setUpNotificationElement(notificationElement: HTMLDivElement, no
2827
</div>
2928
<div class="details">
3029
<p class="repository-name">${notification.repository.full_name}</p>
31-
<!-- <p class="notification-type">${notification.subject.type}</p> -->
3230
<p class="notification-reason">${formattedReason}</p>
3331
</div>
3432
</div>
3533
<div class="status">${notification.unread ? "🔵" : ""}</div>
3634
`;
3735

36+
3837
notificationElement.addEventListener("click", () => {
3938
try {
4039
const notificationWrapper = notificationElement.parentElement;

src/home/rendering/render-github-login-button.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export const authenticationElement = document.getElementById("authentication") a
5555
export function renderGitHubLoginButton() {
5656
gitHubLoginButton.id = "github-login-button";
5757
gitHubLoginButton.innerHTML = "<span>Login</span><span class='full'>&nbsp;With GitHub</span>";
58-
gitHubLoginButton.addEventListener("click", () => gitHubLoginButtonHandler("public_repo read:org notifications"));
58+
gitHubLoginButton.addEventListener("click", () => gitHubLoginButtonHandler("repo read:org notifications"));
5959
if (authenticationElement) {
6060
authenticationElement.appendChild(gitHubLoginButton);
6161
authenticationElement.classList.add("ready");

0 commit comments

Comments
 (0)