Repository: gitify-app/gitify
Pull request #1160 (2024-05-31 02:40:55)

feat: linked issue indicator
Parse PR body to extract linked issues/prs and display a visual indicator with appropriate mouse-over text

![Screenshot 2024-05-30 at 10 27 55 PM](https://github.com/gitify-app/gitify/assets/386277/317869f5-5b5e-4685-96d6-fc3e40b3786c)


bmulholland: Is this something you'd use? I wouldn't, so would just be visual noise for me
setchy: > Is this something you'd use? I wouldn't, so would just be visual noise for me

I'm on the fence too...  It's in the GitHub Web UI, but not their mobile apps (as best as I can tell)...
bmulholland: Copying the Github UI is a good argument for doing it, noise or not :)
setchy: Will update this to use a "pill" once #1169 is merged
setchy: Updated to use "pill" format as to be introduced via #1169 

<img width="500" alt="Screenshot 2024-06-02 at 3 29 54 PM" src="https://github.com/gitify-app/gitify/assets/386277/f6738cdc-b02c-448c-a34f-db88bb910b6f">




Patch:
diff --git a/src/components/NotificationRow.tsx b/src/components/NotificationRow.tsx
index a98eb5c8..d9cd9b9f 100644
--- a/src/components/NotificationRow.tsx
+++ b/src/components/NotificationRow.tsx
@@ -3,6 +3,7 @@ import {
   CheckIcon,
   CommentIcon,
   FeedPersonIcon,
+  IssueClosedIcon,
   ReadIcon,
 } from '@primer/octicons-react';
 import {
@@ -91,6 +92,10 @@ export const NotificationRow: FC<IProps> = ({ notification, hostname }) => {
     notification.subject.comments > 1 ? 'comments' : 'comment'
   }`;
 
+  const linkedIssuesPillDescription = `Linked to ${
+    notification.subject.linkedIssues?.length > 1 ? 'issues' : 'issue'
+  } ${notification.subject?.linkedIssues?.join(', ')}`;
+
   return (
     <div
       id={notification.id}
@@ -144,6 +149,18 @@ export const NotificationRow: FC<IProps> = ({ notification, hostname }) => {
                 {reason.title}
               </span>
               <span className="ml-1">{updatedAt}</span>
+              {notification.subject?.linkedIssues?.length > 0 && (
+                <span className="ml-1" title={linkedIssuesPillDescription}>
+                  <button type="button" className={Constants.PILL_CLASS_NAME}>
+                    <IssueClosedIcon
+                      size={12}
+                      className={`mr-1 ${IconColor.GREEN}`}
+                      aria-label={linkedIssuesPillDescription}
+                    />
+                    {notification.subject.linkedIssues.length}
+                  </button>
+                </span>
+              )}
               {notification.subject.reviews
                 ? notification.subject.reviews.map((review) => {
                     const icon = getPullRequestReviewIcon(review);
diff --git a/src/typesGitHub.ts b/src/typesGitHub.ts
index 416b0164..46f0ee94 100644
--- a/src/typesGitHub.ts
+++ b/src/typesGitHub.ts
@@ -264,6 +264,7 @@ export interface GitifySubject {
   state?: StateType;
   user?: SubjectUser;
   reviews?: GitifyPullRequestReview[];
+  linkedIssues?: string[];
   comments?: number;
 }
 
diff --git a/src/utils/subject.ts b/src/utils/subject.ts
index ffcbe2c0..45085a41 100644
--- a/src/utils/subject.ts
+++ b/src/utils/subject.ts
@@ -264,6 +264,7 @@ async function getGitifySubjectForPullRequest(
   }
 
   const reviews = await getLatestReviewForReviewers(notification);
+  const linkedIssues = parseLinkedIssuesFromPrBody(pr.body);
 
   return {
     state: prState,
@@ -275,6 +276,7 @@ async function getGitifySubjectForPullRequest(
     },
     reviews: reviews,
     comments: pr.comments,
+    linkedIssues: linkedIssues,
   };
 }
 
@@ -329,6 +331,26 @@ export async function getLatestReviewForReviewers(
   });
 }
 
+export function parseLinkedIssuesFromPrBody(body: string): string[] {
+  const linkedIssues: string[] = [];
+
+  if (!body) {
+    return linkedIssues;
+  }
+
+  const regexPattern = /\s*#(\d+)\s*/gi;
+
+  const matches = body.matchAll(regexPattern);
+
+  for (const match of matches) {
+    if (match[0]) {
+      linkedIssues.push(match[0].trim());
+    }
+  }
+
+  return linkedIssues;
+}
+
 async function getGitifySubjectForRelease(
   notification: Notification,
 ): Promise<GitifySubject> {


Test patch:
diff --git a/src/components/NotificationRow.test.tsx b/src/components/NotificationRow.test.tsx
index 7a2a0548..af7b1627 100644
--- a/src/components/NotificationRow.test.tsx
+++ b/src/components/NotificationRow.test.tsx
@@ -117,6 +117,42 @@ describe('components/NotificationRow.tsx', () => {
     });
   });
 
+  describe('linked issues/prs', () => {
+    it('should render when linked to one issue/pr', async () => {
+      jest
+        .spyOn(global.Date, 'now')
+        .mockImplementation(() => new Date('2024').valueOf());
+
+      const mockNotification = mockSingleNotification;
+      mockNotification.subject.linkedIssues = ['#1'];
+
+      const props = {
+        notification: mockNotification,
+        hostname: 'github.com',
+      };
+
+      const tree = render(<NotificationRow {...props} />);
+      expect(tree).toMatchSnapshot();
+    });
+
+    it('should render when linked to multiple issues/prs', async () => {
+      jest
+        .spyOn(global.Date, 'now')
+        .mockImplementation(() => new Date('2024').valueOf());
+
+      const mockNotification = mockSingleNotification;
+      mockNotification.subject.linkedIssues = ['#1', '#2'];
+
+      const props = {
+        notification: mockNotification,
+        hostname: 'github.com',
+      };
+
+      const tree = render(<NotificationRow {...props} />);
+      expect(tree).toMatchSnapshot();
+    });
+  });
+
   describe('notification interactions', () => {
     it('should open a notification in the browser - click', () => {
       const removeNotificationFromState = jest.fn();
diff --git a/src/components/__snapshots__/NotificationRow.test.tsx.snap b/src/components/__snapshots__/NotificationRow.test.tsx.snap
index 58f5668d..6479765a 100644
--- a/src/components/__snapshots__/NotificationRow.test.tsx.snap
+++ b/src/components/__snapshots__/NotificationRow.test.tsx.snap
@@ -1,5 +1,1143 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`components/NotificationRow.tsx linked issues/prs should render when linked to multiple issues/prs 1`] = `
+{
+  "asFragment": [Function],
+  "baseElement": <body>
+    <div>
+      <div
+        class="flex space-x-3 py-2 px-3 bg-white dark:bg-gray-dark dark:text-white hover:bg-gray-100 dark:hover:bg-gray-darker border-b border-gray-100 dark:border-gray-darker group"
+        id="138661096"
+      >
+        <div
+          class="flex justify-center items-center w-5 text-green-500"
+          title="Open Issue"
+        >
+          <svg
+            aria-label="Issue"
+            class="octicon octicon-issue-opened"
+            fill="currentColor"
+            focusable="false"
+            height="18"
+            role="img"
+            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+            viewBox="0 0 16 16"
+            width="18"
+          >
+            <path
+              d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"
+            />
+            <path
+              d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"
+            />
+          </svg>
+        </div>
+        <div
+          class="flex-1 overflow-hidden"
+        >
+          <div
+            class="mb-1 text-sm whitespace-nowrap overflow-ellipsis overflow-hidden cursor-pointer"
+            role="main"
+            title="I am a robot and this is a test!"
+          >
+            I am a robot and this is a test!
+          </div>
+          <div
+            class="text-xs text-capitalize whitespace-nowrap overflow-ellipsis overflow-hidden"
+          >
+            <span
+              class="flex items-center"
+            >
+              <span
+                class="flex"
+                title="Updated over 6 years ago"
+              >
+                <span>
+                  <svg
+                    aria-hidden="true"
+                    class="text-gray-500 dark:text-gray-300"
+                    fill="currentColor"
+                    focusable="false"
+                    height="16"
+                    style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                    viewBox="0 0 16 16"
+                    width="16"
+                  >
+                    <path
+                      d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16Zm.847-8.145a2.502 2.502 0 1 0-1.694 0C5.471 8.261 4 9.775 4 11c0 .395.145.995 1 .995h6c.855 0 1-.6 1-.995 0-1.224-1.47-2.74-3.153-3.145Z"
+                    />
+                  </svg>
+                </span>
+                <span
+                  class="ml-1"
+                  title="You're watching the repository."
+                >
+                  Updated
+                </span>
+                <span
+                  class="ml-1"
+                >
+                  over 6 years ago
+                </span>
+                <span
+                  class="ml-1"
+                  title="Linked to issues #1, #2"
+                >
+                  <button
+                    class="rounded-full text-xs px-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                    type="button"
+                  >
+                    <svg
+                      aria-label="Linked to issues #1, #2"
+                      class="mr-1 text-green-500"
+                      fill="currentColor"
+                      focusable="false"
+                      height="12"
+                      role="img"
+                      style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                      viewBox="0 0 16 16"
+                      width="12"
+                    >
+                      <path
+                        d="M11.28 6.78a.75.75 0 0 0-1.06-1.06L7.25 8.69 5.78 7.22a.75.75 0 0 0-1.06 1.06l2 2a.75.75 0 0 0 1.06 0l3.5-3.5Z"
+                      />
+                      <path
+                        d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0Zm-1.5 0a6.5 6.5 0 1 0-13 0 6.5 6.5 0 0 0 13 0Z"
+                      />
+                    </svg>
+                    2
+                  </button>
+                </span>
+                <span
+                  class="ml-1"
+                  title="octocat approved these changes"
+                >
+                  <button
+                    class="rounded-full text-xs px-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                    type="button"
+                  >
+                    <svg
+                      aria-label="octocat approved these changes"
+                      class="mr-1 text-green-500"
+                      fill="currentColor"
+                      focusable="false"
+                      height="12"
+                      role="img"
+                      style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                      viewBox="0 0 16 16"
+                      width="12"
+                    >
+                      <path
+                        d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
+                      />
+                    </svg>
+                    1
+                  </button>
+                </span>
+                <span
+                  class="ml-1"
+                  title="gitify-app requested changes"
+                >
+                  <button
+                    class="rounded-full text-xs px-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                    type="button"
+                  >
+                    <svg
+                      aria-label="gitify-app requested changes"
+                      class="mr-1 text-red-500"
+                      fill="currentColor"
+                      focusable="false"
+                      height="12"
+                      role="img"
+                      style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                      viewBox="0 0 16 16"
+                      width="12"
+                    >
+                      <path
+                        d="M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25Zm-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z"
+                      />
+                    </svg>
+                    1
+                  </button>
+                </span>
+                <span
+                  class="ml-1"
+                  title="2 comments"
+                >
+                  <button
+                    class="rounded-full text-xs px-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                    type="button"
+                  >
+                    <svg
+                      aria-label="2 comments"
+                      class="mr-1 text-gray-500 dark:text-gray-300"
+                      fill="currentColor"
+                      focusable="false"
+                      height="12"
+                      role="img"
+                      style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                      viewBox="0 0 16 16"
+                      width="12"
+                    >
+                      <path
+                        d="M1 2.75C1 1.784 1.784 1 2.75 1h10.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 13.25 12H9.06l-2.573 2.573A1.458 1.458 0 0 1 4 13.543V12H2.75A1.75 1.75 0 0 1 1 10.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h4.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"
+                      />
+                    </svg>
+                    2
+                  </button>
+                </span>
+              </span>
+            </span>
+          </div>
+        </div>
+        <div
+          class="flex justify-center items-center gap-2 opacity-0 group-hover:opacity-80 transition-opacity"
+        >
+          <button
+            class="focus:outline-none h-full hover:text-green-500"
+            title="Mark as Done"
+            type="button"
+          >
+            <svg
+              aria-label="Mark as Done"
+              class="octicon octicon-check"
+              fill="currentColor"
+              focusable="false"
+              height="16"
+              role="img"
+              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+              viewBox="0 0 16 16"
+              width="16"
+            >
+              <path
+                d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
+              />
+            </svg>
+          </button>
+          <button
+            class="focus:outline-none h-full hover:text-red-500"
+            title="Unsubscribe from Thread"
+            type="button"
+          >
+            <svg
+              aria-label="Unsubscribe from Thread"
+              class="octicon octicon-bell-slash"
+              fill="currentColor"
+              focusable="false"
+              height="14"
+              role="img"
+              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+              viewBox="0 0 16 16"
+              width="14"
+            >
+              <path
+                d="m4.182 4.31.016.011 10.104 7.316.013.01 1.375.996a.75.75 0 1 1-.88 1.214L13.626 13H2.518a1.516 1.516 0 0 1-1.263-2.36l1.703-2.554A.255.255 0 0 0 3 7.947V5.305L.31 3.357a.75.75 0 1 1 .88-1.214Zm7.373 7.19L4.5 6.391v1.556c0 .346-.102.683-.294.97l-1.703 2.556a.017.017 0 0 0-.003.01c0 .005.002.009.005.012l.006.004.007.001ZM8 1.5c-.997 0-1.895.416-2.534 1.086A.75.75 0 1 1 4.38 1.55 5 5 0 0 1 13 5v2.373a.75.75 0 0 1-1.5 0V5A3.5 3.5 0 0 0 8 1.5ZM8 16a2 2 0 0 1-1.985-1.75c-.017-.137.097-.25.235-.25h3.5c.138 0 .252.113.235.25A2 2 0 0 1 8 16Z"
+              />
+            </svg>
+          </button>
+          <button
+            class="focus:outline-none h-full hover:text-green-500"
+            title="Mark as Read"
+            type="button"
+          >
+            <svg
+              aria-label="Mark as Read"
+              class="octicon octicon-read"
+              fill="currentColor"
+              focusable="false"
+              height="14"
+              role="img"
+              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+              viewBox="0 0 16 16"
+              width="14"
+            >
+              <path
+                d="M7.115.65a1.752 1.752 0 0 1 1.77 0l6.25 3.663c.536.314.865.889.865 1.51v6.427A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25V5.823c0-.621.33-1.196.865-1.51Zm1.011 1.293a.252.252 0 0 0-.252 0l-5.72 3.353L6.468 7.76a2.748 2.748 0 0 1 3.066 0l4.312-2.464-5.719-3.353ZM13.15 12.5 8.772 9.06a1.25 1.25 0 0 0-1.544 0L2.85 12.5Zm1.35-5.85-3.687 2.106 3.687 2.897ZM5.187 8.756 1.5 6.65v5.003Z"
+              />
+            </svg>
+          </button>
+        </div>
+      </div>
+    </div>
+  </body>,
+  "container": <div>
+    <div
+      class="flex space-x-3 py-2 px-3 bg-white dark:bg-gray-dark dark:text-white hover:bg-gray-100 dark:hover:bg-gray-darker border-b border-gray-100 dark:border-gray-darker group"
+      id="138661096"
+    >
+      <div
+        class="flex justify-center items-center w-5 text-green-500"
+        title="Open Issue"
+      >
+        <svg
+          aria-label="Issue"
+          class="octicon octicon-issue-opened"
+          fill="currentColor"
+          focusable="false"
+          height="18"
+          role="img"
+          style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+          viewBox="0 0 16 16"
+          width="18"
+        >
+          <path
+            d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"
+          />
+          <path
+            d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"
+          />
+        </svg>
+      </div>
+      <div
+        class="flex-1 overflow-hidden"
+      >
+        <div
+          class="mb-1 text-sm whitespace-nowrap overflow-ellipsis overflow-hidden cursor-pointer"
+          role="main"
+          title="I am a robot and this is a test!"
+        >
+          I am a robot and this is a test!
+        </div>
+        <div
+          class="text-xs text-capitalize whitespace-nowrap overflow-ellipsis overflow-hidden"
+        >
+          <span
+            class="flex items-center"
+          >
+            <span
+              class="flex"
+              title="Updated over 6 years ago"
+            >
+              <span>
+                <svg
+                  aria-hidden="true"
+                  class="text-gray-500 dark:text-gray-300"
+                  fill="currentColor"
+                  focusable="false"
+                  height="16"
+                  style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                  viewBox="0 0 16 16"
+                  width="16"
+                >
+                  <path
+                    d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16Zm.847-8.145a2.502 2.502 0 1 0-1.694 0C5.471 8.261 4 9.775 4 11c0 .395.145.995 1 .995h6c.855 0 1-.6 1-.995 0-1.224-1.47-2.74-3.153-3.145Z"
+                  />
+                </svg>
+              </span>
+              <span
+                class="ml-1"
+                title="You're watching the repository."
+              >
+                Updated
+              </span>
+              <span
+                class="ml-1"
+              >
+                over 6 years ago
+              </span>
+              <span
+                class="ml-1"
+                title="Linked to issues #1, #2"
+              >
+                <button
+                  class="rounded-full text-xs px-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                  type="button"
+                >
+                  <svg
+                    aria-label="Linked to issues #1, #2"
+                    class="mr-1 text-green-500"
+                    fill="currentColor"
+                    focusable="false"
+                    height="12"
+                    role="img"
+                    style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                    viewBox="0 0 16 16"
+                    width="12"
+                  >
+                    <path
+                      d="M11.28 6.78a.75.75 0 0 0-1.06-1.06L7.25 8.69 5.78 7.22a.75.75 0 0 0-1.06 1.06l2 2a.75.75 0 0 0 1.06 0l3.5-3.5Z"
+                    />
+                    <path
+                      d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0Zm-1.5 0a6.5 6.5 0 1 0-13 0 6.5 6.5 0 0 0 13 0Z"
+                    />
+                  </svg>
+                  2
+                </button>
+              </span>
+              <span
+                class="ml-1"
+                title="octocat approved these changes"
+              >
+                <button
+                  class="rounded-full text-xs px-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                  type="button"
+                >
+                  <svg
+                    aria-label="octocat approved these changes"
+                    class="mr-1 text-green-500"
+                    fill="currentColor"
+                    focusable="false"
+                    height="12"
+                    role="img"
+                    style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                    viewBox="0 0 16 16"
+                    width="12"
+                  >
+                    <path
+                      d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
+                    />
+                  </svg>
+                  1
+                </button>
+              </span>
+              <span
+                class="ml-1"
+                title="gitify-app requested changes"
+              >
+                <button
+                  class="rounded-full text-xs px-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                  type="button"
+                >
+                  <svg
+                    aria-label="gitify-app requested changes"
+                    class="mr-1 text-red-500"
+                    fill="currentColor"
+                    focusable="false"
+                    height="12"
+                    role="img"
+                    style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                    viewBox="0 0 16 16"
+                    width="12"
+                  >
+                    <path
+                      d="M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25Zm-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z"
+                    />
+                  </svg>
+                  1
+                </button>
+              </span>
+              <span
+                class="ml-1"
+                title="2 comments"
+              >
+                <button
+                  class="rounded-full text-xs px-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                  type="button"
+                >
+                  <svg
+                    aria-label="2 comments"
+                    class="mr-1 text-gray-500 dark:text-gray-300"
+                    fill="currentColor"
+                    focusable="false"
+                    height="12"
+                    role="img"
+                    style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                    viewBox="0 0 16 16"
+                    width="12"
+                  >
+                    <path
+                      d="M1 2.75C1 1.784 1.784 1 2.75 1h10.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 13.25 12H9.06l-2.573 2.573A1.458 1.458 0 0 1 4 13.543V12H2.75A1.75 1.75 0 0 1 1 10.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h4.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"
+                    />
+                  </svg>
+                  2
+                </button>
+              </span>
+            </span>
+          </span>
+        </div>
+      </div>
+      <div
+        class="flex justify-center items-center gap-2 opacity-0 group-hover:opacity-80 transition-opacity"
+      >
+        <button
+          class="focus:outline-none h-full hover:text-green-500"
+          title="Mark as Done"
+          type="button"
+        >
+          <svg
+            aria-label="Mark as Done"
+            class="octicon octicon-check"
+            fill="currentColor"
+            focusable="false"
+            height="16"
+            role="img"
+            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+            viewBox="0 0 16 16"
+            width="16"
+          >
+            <path
+              d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
+            />
+          </svg>
+        </button>
+        <button
+          class="focus:outline-none h-full hover:text-red-500"
+          title="Unsubscribe from Thread"
+          type="button"
+        >
+          <svg
+            aria-label="Unsubscribe from Thread"
+            class="octicon octicon-bell-slash"
+            fill="currentColor"
+            focusable="false"
+            height="14"
+            role="img"
+            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+            viewBox="0 0 16 16"
+            width="14"
+          >
+            <path
+              d="m4.182 4.31.016.011 10.104 7.316.013.01 1.375.996a.75.75 0 1 1-.88 1.214L13.626 13H2.518a1.516 1.516 0 0 1-1.263-2.36l1.703-2.554A.255.255 0 0 0 3 7.947V5.305L.31 3.357a.75.75 0 1 1 .88-1.214Zm7.373 7.19L4.5 6.391v1.556c0 .346-.102.683-.294.97l-1.703 2.556a.017.017 0 0 0-.003.01c0 .005.002.009.005.012l.006.004.007.001ZM8 1.5c-.997 0-1.895.416-2.534 1.086A.75.75 0 1 1 4.38 1.55 5 5 0 0 1 13 5v2.373a.75.75 0 0 1-1.5 0V5A3.5 3.5 0 0 0 8 1.5ZM8 16a2 2 0 0 1-1.985-1.75c-.017-.137.097-.25.235-.25h3.5c.138 0 .252.113.235.25A2 2 0 0 1 8 16Z"
+            />
+          </svg>
+        </button>
+        <button
+          class="focus:outline-none h-full hover:text-green-500"
+          title="Mark as Read"
+          type="button"
+        >
+          <svg
+            aria-label="Mark as Read"
+            class="octicon octicon-read"
+            fill="currentColor"
+            focusable="false"
+            height="14"
+            role="img"
+            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+            viewBox="0 0 16 16"
+            width="14"
+          >
+            <path
+              d="M7.115.65a1.752 1.752 0 0 1 1.77 0l6.25 3.663c.536.314.865.889.865 1.51v6.427A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25V5.823c0-.621.33-1.196.865-1.51Zm1.011 1.293a.252.252 0 0 0-.252 0l-5.72 3.353L6.468 7.76a2.748 2.748 0 0 1 3.066 0l4.312-2.464-5.719-3.353ZM13.15 12.5 8.772 9.06a1.25 1.25 0 0 0-1.544 0L2.85 12.5Zm1.35-5.85-3.687 2.106 3.687 2.897ZM5.187 8.756 1.5 6.65v5.003Z"
+            />
+          </svg>
+        </button>
+      </div>
+    </div>
+  </div>,
+  "debug": [Function],
+  "findAllByAltText": [Function],
+  "findAllByDisplayValue": [Function],
+  "findAllByLabelText": [Function],
+  "findAllByPlaceholderText": [Function],
+  "findAllByRole": [Function],
+  "findAllByTestId": [Function],
+  "findAllByText": [Function],
+  "findAllByTitle": [Function],
+  "findByAltText": [Function],
+  "findByDisplayValue": [Function],
+  "findByLabelText": [Function],
+  "findByPlaceholderText": [Function],
+  "findByRole": [Function],
+  "findByTestId": [Function],
+  "findByText": [Function],
+  "findByTitle": [Function],
+  "getAllByAltText": [Function],
+  "getAllByDisplayValue": [Function],
+  "getAllByLabelText": [Function],
+  "getAllByPlaceholderText": [Function],
+  "getAllByRole": [Function],
+  "getAllByTestId": [Function],
+  "getAllByText": [Function],
+  "getAllByTitle": [Function],
+  "getByAltText": [Function],
+  "getByDisplayValue": [Function],
+  "getByLabelText": [Function],
+  "getByPlaceholderText": [Function],
+  "getByRole": [Function],
+  "getByTestId": [Function],
+  "getByText": [Function],
+  "getByTitle": [Function],
+  "queryAllByAltText": [Function],
+  "queryAllByDisplayValue": [Function],
+  "queryAllByLabelText": [Function],
+  "queryAllByPlaceholderText": [Function],
+  "queryAllByRole": [Function],
+  "queryAllByTestId": [Function],
+  "queryAllByText": [Function],
+  "queryAllByTitle": [Function],
+  "queryByAltText": [Function],
+  "queryByDisplayValue": [Function],
+  "queryByLabelText": [Function],
+  "queryByPlaceholderText": [Function],
+  "queryByRole": [Function],
+  "queryByTestId": [Function],
+  "queryByText": [Function],
+  "queryByTitle": [Function],
+  "rerender": [Function],
+  "unmount": [Function],
+}
+`;
+
+exports[`components/NotificationRow.tsx linked issues/prs should render when linked to one issue/pr 1`] = `
+{
+  "asFragment": [Function],
+  "baseElement": <body>
+    <div>
+      <div
+        class="flex space-x-3 py-2 px-3 bg-white dark:bg-gray-dark dark:text-white hover:bg-gray-100 dark:hover:bg-gray-darker border-b border-gray-100 dark:border-gray-darker group"
+        id="138661096"
+      >
+        <div
+          class="flex justify-center items-center w-5 text-green-500"
+          title="Open Issue"
+        >
+          <svg
+            aria-label="Issue"
+            class="octicon octicon-issue-opened"
+            fill="currentColor"
+            focusable="false"
+            height="18"
+            role="img"
+            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+            viewBox="0 0 16 16"
+            width="18"
+          >
+            <path
+              d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"
+            />
+            <path
+              d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"
+            />
+          </svg>
+        </div>
+        <div
+          class="flex-1 overflow-hidden"
+        >
+          <div
+            class="mb-1 text-sm whitespace-nowrap overflow-ellipsis overflow-hidden cursor-pointer"
+            role="main"
+            title="I am a robot and this is a test!"
+          >
+            I am a robot and this is a test!
+          </div>
+          <div
+            class="text-xs text-capitalize whitespace-nowrap overflow-ellipsis overflow-hidden"
+          >
+            <span
+              class="flex items-center"
+            >
+              <span
+                class="flex"
+                title="Updated over 6 years ago"
+              >
+                <span>
+                  <svg
+                    aria-hidden="true"
+                    class="text-gray-500 dark:text-gray-300"
+                    fill="currentColor"
+                    focusable="false"
+                    height="16"
+                    style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                    viewBox="0 0 16 16"
+                    width="16"
+                  >
+                    <path
+                      d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16Zm.847-8.145a2.502 2.502 0 1 0-1.694 0C5.471 8.261 4 9.775 4 11c0 .395.145.995 1 .995h6c.855 0 1-.6 1-.995 0-1.224-1.47-2.74-3.153-3.145Z"
+                    />
+                  </svg>
+                </span>
+                <span
+                  class="ml-1"
+                  title="You're watching the repository."
+                >
+                  Updated
+                </span>
+                <span
+                  class="ml-1"
+                >
+                  over 6 years ago
+                </span>
+                <span
+                  class="ml-1"
+                  title="Linked to issue #1"
+                >
+                  <button
+                    class="rounded-full text-xs px-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                    type="button"
+                  >
+                    <svg
+                      aria-label="Linked to issue #1"
+                      class="mr-1 text-green-500"
+                      fill="currentColor"
+                      focusable="false"
+                      height="12"
+                      role="img"
+                      style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                      viewBox="0 0 16 16"
+                      width="12"
+                    >
+                      <path
+                        d="M11.28 6.78a.75.75 0 0 0-1.06-1.06L7.25 8.69 5.78 7.22a.75.75 0 0 0-1.06 1.06l2 2a.75.75 0 0 0 1.06 0l3.5-3.5Z"
+                      />
+                      <path
+                        d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0Zm-1.5 0a6.5 6.5 0 1 0-13 0 6.5 6.5 0 0 0 13 0Z"
+                      />
+                    </svg>
+                    1
+                  </button>
+                </span>
+                <span
+                  class="ml-1"
+                  title="octocat approved these changes"
+                >
+                  <button
+                    class="rounded-full text-xs px-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                    type="button"
+                  >
+                    <svg
+                      aria-label="octocat approved these changes"
+                      class="mr-1 text-green-500"
+                      fill="currentColor"
+                      focusable="false"
+                      height="12"
+                      role="img"
+                      style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                      viewBox="0 0 16 16"
+                      width="12"
+                    >
+                      <path
+                        d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
+                      />
+                    </svg>
+                    1
+                  </button>
+                </span>
+                <span
+                  class="ml-1"
+                  title="gitify-app requested changes"
+                >
+                  <button
+                    class="rounded-full text-xs px-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                    type="button"
+                  >
+                    <svg
+                      aria-label="gitify-app requested changes"
+                      class="mr-1 text-red-500"
+                      fill="currentColor"
+                      focusable="false"
+                      height="12"
+                      role="img"
+                      style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                      viewBox="0 0 16 16"
+                      width="12"
+                    >
+                      <path
+                        d="M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25Zm-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z"
+                      />
+                    </svg>
+                    1
+                  </button>
+                </span>
+                <span
+                  class="ml-1"
+                  title="2 comments"
+                >
+                  <button
+                    class="rounded-full text-xs px-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                    type="button"
+                  >
+                    <svg
+                      aria-label="2 comments"
+                      class="mr-1 text-gray-500 dark:text-gray-300"
+                      fill="currentColor"
+                      focusable="false"
+                      height="12"
+                      role="img"
+                      style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                      viewBox="0 0 16 16"
+                      width="12"
+                    >
+                      <path
+                        d="M1 2.75C1 1.784 1.784 1 2.75 1h10.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 13.25 12H9.06l-2.573 2.573A1.458 1.458 0 0 1 4 13.543V12H2.75A1.75 1.75 0 0 1 1 10.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h4.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"
+                      />
+                    </svg>
+                    2
+                  </button>
+                </span>
+              </span>
+            </span>
+          </div>
+        </div>
+        <div
+          class="flex justify-center items-center gap-2 opacity-0 group-hover:opacity-80 transition-opacity"
+        >
+          <button
+            class="focus:outline-none h-full hover:text-green-500"
+            title="Mark as Done"
+            type="button"
+          >
+            <svg
+              aria-label="Mark as Done"
+              class="octicon octicon-check"
+              fill="currentColor"
+              focusable="false"
+              height="16"
+              role="img"
+              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+              viewBox="0 0 16 16"
+              width="16"
+            >
+              <path
+                d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
+              />
+            </svg>
+          </button>
+          <button
+            class="focus:outline-none h-full hover:text-red-500"
+            title="Unsubscribe from Thread"
+            type="button"
+          >
+            <svg
+              aria-label="Unsubscribe from Thread"
+              class="octicon octicon-bell-slash"
+              fill="currentColor"
+              focusable="false"
+              height="14"
+              role="img"
+              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+              viewBox="0 0 16 16"
+              width="14"
+            >
+              <path
+                d="m4.182 4.31.016.011 10.104 7.316.013.01 1.375.996a.75.75 0 1 1-.88 1.214L13.626 13H2.518a1.516 1.516 0 0 1-1.263-2.36l1.703-2.554A.255.255 0 0 0 3 7.947V5.305L.31 3.357a.75.75 0 1 1 .88-1.214Zm7.373 7.19L4.5 6.391v1.556c0 .346-.102.683-.294.97l-1.703 2.556a.017.017 0 0 0-.003.01c0 .005.002.009.005.012l.006.004.007.001ZM8 1.5c-.997 0-1.895.416-2.534 1.086A.75.75 0 1 1 4.38 1.55 5 5 0 0 1 13 5v2.373a.75.75 0 0 1-1.5 0V5A3.5 3.5 0 0 0 8 1.5ZM8 16a2 2 0 0 1-1.985-1.75c-.017-.137.097-.25.235-.25h3.5c.138 0 .252.113.235.25A2 2 0 0 1 8 16Z"
+              />
+            </svg>
+          </button>
+          <button
+            class="focus:outline-none h-full hover:text-green-500"
+            title="Mark as Read"
+            type="button"
+          >
+            <svg
+              aria-label="Mark as Read"
+              class="octicon octicon-read"
+              fill="currentColor"
+              focusable="false"
+              height="14"
+              role="img"
+              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+              viewBox="0 0 16 16"
+              width="14"
+            >
+              <path
+                d="M7.115.65a1.752 1.752 0 0 1 1.77 0l6.25 3.663c.536.314.865.889.865 1.51v6.427A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25V5.823c0-.621.33-1.196.865-1.51Zm1.011 1.293a.252.252 0 0 0-.252 0l-5.72 3.353L6.468 7.76a2.748 2.748 0 0 1 3.066 0l4.312-2.464-5.719-3.353ZM13.15 12.5 8.772 9.06a1.25 1.25 0 0 0-1.544 0L2.85 12.5Zm1.35-5.85-3.687 2.106 3.687 2.897ZM5.187 8.756 1.5 6.65v5.003Z"
+              />
+            </svg>
+          </button>
+        </div>
+      </div>
+    </div>
+  </body>,
+  "container": <div>
+    <div
+      class="flex space-x-3 py-2 px-3 bg-white dark:bg-gray-dark dark:text-white hover:bg-gray-100 dark:hover:bg-gray-darker border-b border-gray-100 dark:border-gray-darker group"
+      id="138661096"
+    >
+      <div
+        class="flex justify-center items-center w-5 text-green-500"
+        title="Open Issue"
+      >
+        <svg
+          aria-label="Issue"
+          class="octicon octicon-issue-opened"
+          fill="currentColor"
+          focusable="false"
+          height="18"
+          role="img"
+          style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+          viewBox="0 0 16 16"
+          width="18"
+        >
+          <path
+            d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"
+          />
+          <path
+            d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"
+          />
+        </svg>
+      </div>
+      <div
+        class="flex-1 overflow-hidden"
+      >
+        <div
+          class="mb-1 text-sm whitespace-nowrap overflow-ellipsis overflow-hidden cursor-pointer"
+          role="main"
+          title="I am a robot and this is a test!"
+        >
+          I am a robot and this is a test!
+        </div>
+        <div
+          class="text-xs text-capitalize whitespace-nowrap overflow-ellipsis overflow-hidden"
+        >
+          <span
+            class="flex items-center"
+          >
+            <span
+              class="flex"
+              title="Updated over 6 years ago"
+            >
+              <span>
+                <svg
+                  aria-hidden="true"
+                  class="text-gray-500 dark:text-gray-300"
+                  fill="currentColor"
+                  focusable="false"
+                  height="16"
+                  style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                  viewBox="0 0 16 16"
+                  width="16"
+                >
+                  <path
+                    d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16Zm.847-8.145a2.502 2.502 0 1 0-1.694 0C5.471 8.261 4 9.775 4 11c0 .395.145.995 1 .995h6c.855 0 1-.6 1-.995 0-1.224-1.47-2.74-3.153-3.145Z"
+                  />
+                </svg>
+              </span>
+              <span
+                class="ml-1"
+                title="You're watching the repository."
+              >
+                Updated
+              </span>
+              <span
+                class="ml-1"
+              >
+                over 6 years ago
+              </span>
+              <span
+                class="ml-1"
+                title="Linked to issue #1"
+              >
+                <button
+                  class="rounded-full text-xs px-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                  type="button"
+                >
+                  <svg
+                    aria-label="Linked to issue #1"
+                    class="mr-1 text-green-500"
+                    fill="currentColor"
+                    focusable="false"
+                    height="12"
+                    role="img"
+                    style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                    viewBox="0 0 16 16"
+                    width="12"
+                  >
+                    <path
+                      d="M11.28 6.78a.75.75 0 0 0-1.06-1.06L7.25 8.69 5.78 7.22a.75.75 0 0 0-1.06 1.06l2 2a.75.75 0 0 0 1.06 0l3.5-3.5Z"
+                    />
+                    <path
+                      d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0Zm-1.5 0a6.5 6.5 0 1 0-13 0 6.5 6.5 0 0 0 13 0Z"
+                    />
+                  </svg>
+                  1
+                </button>
+              </span>
+              <span
+                class="ml-1"
+                title="octocat approved these changes"
+              >
+                <button
+                  class="rounded-full text-xs px-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                  type="button"
+                >
+                  <svg
+                    aria-label="octocat approved these changes"
+                    class="mr-1 text-green-500"
+                    fill="currentColor"
+                    focusable="false"
+                    height="12"
+                    role="img"
+                    style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                    viewBox="0 0 16 16"
+                    width="12"
+                  >
+                    <path
+                      d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
+                    />
+                  </svg>
+                  1
+                </button>
+              </span>
+              <span
+                class="ml-1"
+                title="gitify-app requested changes"
+              >
+                <button
+                  class="rounded-full text-xs px-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                  type="button"
+                >
+                  <svg
+                    aria-label="gitify-app requested changes"
+                    class="mr-1 text-red-500"
+                    fill="currentColor"
+                    focusable="false"
+                    height="12"
+                    role="img"
+                    style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                    viewBox="0 0 16 16"
+                    width="12"
+                  >
+                    <path
+                      d="M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25Zm-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z"
+                    />
+                  </svg>
+                  1
+                </button>
+              </span>
+              <span
+                class="ml-1"
+                title="2 comments"
+              >
+                <button
+                  class="rounded-full text-xs px-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                  type="button"
+                >
+                  <svg
+                    aria-label="2 comments"
+                    class="mr-1 text-gray-500 dark:text-gray-300"
+                    fill="currentColor"
+                    focusable="false"
+                    height="12"
+                    role="img"
+                    style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+                    viewBox="0 0 16 16"
+                    width="12"
+                  >
+                    <path
+                      d="M1 2.75C1 1.784 1.784 1 2.75 1h10.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 13.25 12H9.06l-2.573 2.573A1.458 1.458 0 0 1 4 13.543V12H2.75A1.75 1.75 0 0 1 1 10.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h4.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"
+                    />
+                  </svg>
+                  2
+                </button>
+              </span>
+            </span>
+          </span>
+        </div>
+      </div>
+      <div
+        class="flex justify-center items-center gap-2 opacity-0 group-hover:opacity-80 transition-opacity"
+      >
+        <button
+          class="focus:outline-none h-full hover:text-green-500"
+          title="Mark as Done"
+          type="button"
+        >
+          <svg
+            aria-label="Mark as Done"
+            class="octicon octicon-check"
+            fill="currentColor"
+            focusable="false"
+            height="16"
+            role="img"
+            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+            viewBox="0 0 16 16"
+            width="16"
+          >
+            <path
+              d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
+            />
+          </svg>
+        </button>
+        <button
+          class="focus:outline-none h-full hover:text-red-500"
+          title="Unsubscribe from Thread"
+          type="button"
+        >
+          <svg
+            aria-label="Unsubscribe from Thread"
+            class="octicon octicon-bell-slash"
+            fill="currentColor"
+            focusable="false"
+            height="14"
+            role="img"
+            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+            viewBox="0 0 16 16"
+            width="14"
+          >
+            <path
+              d="m4.182 4.31.016.011 10.104 7.316.013.01 1.375.996a.75.75 0 1 1-.88 1.214L13.626 13H2.518a1.516 1.516 0 0 1-1.263-2.36l1.703-2.554A.255.255 0 0 0 3 7.947V5.305L.31 3.357a.75.75 0 1 1 .88-1.214Zm7.373 7.19L4.5 6.391v1.556c0 .346-.102.683-.294.97l-1.703 2.556a.017.017 0 0 0-.003.01c0 .005.002.009.005.012l.006.004.007.001ZM8 1.5c-.997 0-1.895.416-2.534 1.086A.75.75 0 1 1 4.38 1.55 5 5 0 0 1 13 5v2.373a.75.75 0 0 1-1.5 0V5A3.5 3.5 0 0 0 8 1.5ZM8 16a2 2 0 0 1-1.985-1.75c-.017-.137.097-.25.235-.25h3.5c.138 0 .252.113.235.25A2 2 0 0 1 8 16Z"
+            />
+          </svg>
+        </button>
+        <button
+          class="focus:outline-none h-full hover:text-green-500"
+          title="Mark as Read"
+          type="button"
+        >
+          <svg
+            aria-label="Mark as Read"
+            class="octicon octicon-read"
+            fill="currentColor"
+            focusable="false"
+            height="14"
+            role="img"
+            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+            viewBox="0 0 16 16"
+            width="14"
+          >
+            <path
+              d="M7.115.65a1.752 1.752 0 0 1 1.77 0l6.25 3.663c.536.314.865.889.865 1.51v6.427A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25V5.823c0-.621.33-1.196.865-1.51Zm1.011 1.293a.252.252 0 0 0-.252 0l-5.72 3.353L6.468 7.76a2.748 2.748 0 0 1 3.066 0l4.312-2.464-5.719-3.353ZM13.15 12.5 8.772 9.06a1.25 1.25 0 0 0-1.544 0L2.85 12.5Zm1.35-5.85-3.687 2.106 3.687 2.897ZM5.187 8.756 1.5 6.65v5.003Z"
+            />
+          </svg>
+        </button>
+      </div>
+    </div>
+  </div>,
+  "debug": [Function],
+  "findAllByAltText": [Function],
+  "findAllByDisplayValue": [Function],
+  "findAllByLabelText": [Function],
+  "findAllByPlaceholderText": [Function],
+  "findAllByRole": [Function],
+  "findAllByTestId": [Function],
+  "findAllByText": [Function],
+  "findAllByTitle": [Function],
+  "findByAltText": [Function],
+  "findByDisplayValue": [Function],
+  "findByLabelText": [Function],
+  "findByPlaceholderText": [Function],
+  "findByRole": [Function],
+  "findByTestId": [Function],
+  "findByText": [Function],
+  "findByTitle": [Function],
+  "getAllByAltText": [Function],
+  "getAllByDisplayValue": [Function],
+  "getAllByLabelText": [Function],
+  "getAllByPlaceholderText": [Function],
+  "getAllByRole": [Function],
+  "getAllByTestId": [Function],
+  "getAllByText": [Function],
+  "getAllByTitle": [Function],
+  "getByAltText": [Function],
+  "getByDisplayValue": [Function],
+  "getByLabelText": [Function],
+  "getByPlaceholderText": [Function],
+  "getByRole": [Function],
+  "getByTestId": [Function],
+  "getByText": [Function],
+  "getByTitle": [Function],
+  "queryAllByAltText": [Function],
+  "queryAllByDisplayValue": [Function],
+  "queryAllByLabelText": [Function],
+  "queryAllByPlaceholderText": [Function],
+  "queryAllByRole": [Function],
+  "queryAllByTestId": [Function],
+  "queryAllByText": [Function],
+  "queryAllByTitle": [Function],
+  "queryByAltText": [Function],
+  "queryByDisplayValue": [Function],
+  "queryByLabelText": [Function],
+  "queryByPlaceholderText": [Function],
+  "queryByRole": [Function],
+  "queryByTestId": [Function],
+  "queryByText": [Function],
+  "queryByTitle": [Function],
+  "rerender": [Function],
+  "unmount": [Function],
+}
+`;
+
 exports[`components/NotificationRow.tsx rendering for notification comments count should render when 1 comment 1`] = `
 {
   "asFragment": [Function],
diff --git a/src/utils/auth/utils.test.ts b/src/utils/auth/utils.test.ts
index 6afe6d7e..19ab1e62 100644
--- a/src/utils/auth/utils.test.ts
+++ b/src/utils/auth/utils.test.ts
@@ -112,8 +112,8 @@ describe('utils/auth/utils.ts', () => {
     });
 
     describe('should add GitHub Cloud account', () => {
-      it('should add personal access token account', async () => {
-        const result = await auth.addAccount(
+      it('should add personal access token account', () => {
+        const result = auth.addAccount(
           mockAuthState,
           'Personal Access Token',
           '123-456',
@@ -131,8 +131,8 @@ describe('utils/auth/utils.ts', () => {
         ]);
       });
 
-      it('should add oauth app account', async () => {
-        const result = await auth.addAccount(
+      it('should add oauth app account', () => {
+        const result = auth.addAccount(
           mockAuthState,
           'OAuth App',
           '123-456',
@@ -152,8 +152,8 @@ describe('utils/auth/utils.ts', () => {
     });
 
     describe('should add GitHub Enterprise Server account', () => {
-      it('should add personal access token account', async () => {
-        const result = await auth.addAccount(
+      it('should add personal access token account', () => {
+        const result = auth.addAccount(
           mockAuthState,
           'Personal Access Token',
           '123-456',
@@ -171,8 +171,8 @@ describe('utils/auth/utils.ts', () => {
         ]);
       });
 
-      it('should add oauth app account', async () => {
-        const result = await auth.addAccount(
+      it('should add oauth app account', () => {
+        const result = auth.addAccount(
           mockAuthState,
           'OAuth App',
           '123-456',
diff --git a/src/utils/subject.test.ts b/src/utils/subject.test.ts
index 43419582..9ea16cad 100644
--- a/src/utils/subject.test.ts
+++ b/src/utils/subject.test.ts
@@ -17,6 +17,7 @@ import {
   getGitifySubjectDetails,
   getLatestReviewForReviewers,
   getWorkflowRunAttributes,
+  parseLinkedIssuesFromPrBody,
 } from './subject';
 
 const mockAuthor = partialMockUser('some-author');
@@ -557,6 +558,7 @@ describe('utils/subject.ts', () => {
             type: mockCommenter.type,
           },
           reviews: null,
+          linkedIssues: [],
         });
       });
 
@@ -589,6 +591,7 @@ describe('utils/subject.ts', () => {
             type: mockCommenter.type,
           },
           reviews: null,
+          linkedIssues: [],
         });
       });
 
@@ -621,6 +624,7 @@ describe('utils/subject.ts', () => {
             type: mockCommenter.type,
           },
           reviews: null,
+          linkedIssues: [],
         });
       });
 
@@ -653,6 +657,7 @@ describe('utils/subject.ts', () => {
             type: mockCommenter.type,
           },
           reviews: null,
+          linkedIssues: [],
         });
       });
 
@@ -684,6 +689,7 @@ describe('utils/subject.ts', () => {
             type: mockAuthor.type,
           },
           reviews: null,
+          linkedIssues: [],
         });
       });
 
@@ -714,6 +720,7 @@ describe('utils/subject.ts', () => {
             type: mockAuthor.type,
           },
           reviews: null,
+          linkedIssues: [],
         });
       });
 
@@ -774,6 +781,19 @@ describe('utils/subject.ts', () => {
           expect(result).toBeNull();
         });
       });
+
+      describe('Pull Request Reviews - Extract Linked Issues', () => {
+        it('returns empty if no pr body', () => {
+          const result = parseLinkedIssuesFromPrBody(null);
+          expect(result).toEqual([]);
+        });
+
+        it('returns linked issues', () => {
+          const mockPrBody = 'This PR is linked to #1, #2, and #3';
+          const result = parseLinkedIssuesFromPrBody(mockPrBody);
+          expect(result).toEqual(['#1', '#2', '#3']);
+        });
+      });
     });
 
     describe('Releases', () => {