Repository: gitify-app/gitify
Pull request #1343 (2024-07-08 18:11:31)

feat: settings header icon
use the new Legend component for Header icons


Patch:
diff --git a/src/__mocks__/state-mocks.ts b/src/__mocks__/state-mocks.ts
index 68278bc8..5226657c 100644
--- a/src/__mocks__/state-mocks.ts
+++ b/src/__mocks__/state-mocks.ts
@@ -84,6 +84,7 @@ export const mockSettings: SettingsState = {
   showAccountHostname: false,
   delayNotificationState: false,
   showPills: true,
+  showNumber: true,
   keyboardShortcut: true,
   groupBy: GroupBy.REPOSITORY,
   filterReasons: [],
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index 98698d86..3ecddb9e 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -1,18 +1,17 @@
-import { ArrowLeftIcon } from '@primer/octicons-react';
-import { type FC, type ReactNode, useContext } from 'react';
+import { ArrowLeftIcon, type Icon } from '@primer/octicons-react';
+import { type FC, useContext } from 'react';
 import { useNavigate } from 'react-router-dom';
 import { AppContext } from '../context/App';
 import { Size } from '../types';
+import { Legend } from './settings/Legend';
 
 interface IHeader {
-  children: ReactNode;
+  icon: Icon;
+  children: string;
   fetchOnBack?: boolean;
 }
 
-export const Header: FC<IHeader> = ({
-  children,
-  fetchOnBack = false,
-}: IHeader) => {
+export const Header: FC<IHeader> = (props: IHeader) => {
   const navigate = useNavigate();
 
   const { fetchNotifications } = useContext(AppContext);
@@ -25,7 +24,7 @@ export const Header: FC<IHeader> = ({
         title="Go Back"
         onClick={() => {
           navigate(-1);
-          if (fetchOnBack) {
+          if (props.fetchOnBack) {
             fetchNotifications();
           }
         }}
@@ -37,7 +36,9 @@ export const Header: FC<IHeader> = ({
         />
       </button>
 
-      <h3 className="text-lg font-semibold">{children}</h3>
+      <h3 className="text-lg font-semibold flex items-center">
+        <Legend icon={props.icon}>{props.children}</Legend>
+      </h3>
     </div>
   );
 };
diff --git a/src/components/NotificationRow.tsx b/src/components/NotificationRow.tsx
index bfcead59..5f635e21 100644
--- a/src/components/NotificationRow.tsx
+++ b/src/components/NotificationRow.tsx
@@ -71,6 +71,13 @@ export const NotificationRow: FC<INotificationRow> = ({
     notification.subject.type,
   ]);
 
+  const notificationNumber = notification.subject?.number
+    ? `#${notification.subject.number}`
+    : '';
+
+  const notificationTitle =
+    `${notification.subject.title} ${notificationNumber}`.trim();
+
   const groupByDate = settings.groupBy === 'DATE';
 
   return (
@@ -102,9 +109,18 @@ export const NotificationRow: FC<INotificationRow> = ({
         <div
           className="mb-1 truncate text-sm"
           role="main"
-          title={notification.subject.title}
+          title={notificationTitle}
         >
           {notification.subject.title}
+          <span
+            className={cn(
+              'text-xxs ml-1',
+              Opacity.READ,
+              !settings.showNumber && 'hidden',
+            )}
+          >
+            {notificationNumber}
+          </span>
         </div>
 
         <NotificationFooter notification={notification} />
diff --git a/src/components/settings/AppearanceSettings.tsx b/src/components/settings/AppearanceSettings.tsx
index 1d0da8e5..ae0b959b 100644
--- a/src/components/settings/AppearanceSettings.tsx
+++ b/src/components/settings/AppearanceSettings.tsx
@@ -1,6 +1,7 @@
 import {
   CheckIcon,
   CommentIcon,
+  GitPullRequestIcon,
   IssueClosedIcon,
   MilestoneIcon,
   PaintbrushIcon,
@@ -99,6 +100,41 @@ export const AppearanceSettings: FC = () => {
           </div>
         }
       />
+      <Checkbox
+        name="showNumber"
+        label="Show number"
+        checked={settings.detailedNotifications && settings.showNumber}
+        onChange={(evt) =>
+          settings.detailedNotifications &&
+          updateSetting('showNumber', evt.target.checked)
+        }
+        disabled={!settings.detailedNotifications}
+        tooltip={
+          <div>
+            <div>Show GitHub number for:</div>
+            <div className="pl-6">
+              <ul className="list-disc">
+                <li>
+                  <CommentIcon size={Size.MEDIUM} className="pr-1" />
+                  Discussion
+                </li>
+                <li>
+                  <IssueClosedIcon size={Size.MEDIUM} className="pr-1" />
+                  Issue
+                </li>
+                <li>
+                  <GitPullRequestIcon size={Size.MEDIUM} className="pr-1" />
+                  Pull Request
+                </li>
+              </ul>
+            </div>
+            <div className="pt-3 text-orange-600">
+              ⚠️ This setting requires <strong>Detailed Notifications</strong> to
+              be enabled.
+            </div>
+          </div>
+        }
+      />
       <Checkbox
         name="showAccountHostname"
         label="Show account hostname"
diff --git a/src/context/App.tsx b/src/context/App.tsx
index 05ac5594..36ea4742 100644
--- a/src/context/App.tsx
+++ b/src/context/App.tsx
@@ -67,6 +67,7 @@ export const defaultSettings: SettingsState = {
   showAccountHostname: false,
   delayNotificationState: false,
   showPills: true,
+  showNumber: true,
   keyboardShortcut: true,
   groupBy: GroupBy.REPOSITORY,
   ...defaultFilters,
diff --git a/src/routes/Accounts.tsx b/src/routes/Accounts.tsx
index 41a859ff..60e77c57 100644
--- a/src/routes/Accounts.tsx
+++ b/src/routes/Accounts.tsx
@@ -45,7 +45,7 @@ export const AccountsRoute: FC = () => {
 
   return (
     <div className="flex h-screen flex-col" data-testid="accounts">
-      <Header>Accounts</Header>
+      <Header icon={PersonIcon}>Accounts</Header>
       <div className="flex-grow overflow-x-auto px-8">
         <div className="mt-4 flex flex-col text-sm">
           {auth.accounts.map((account) => (
diff --git a/src/routes/Filters.tsx b/src/routes/Filters.tsx
index 295044fd..7b40c5d9 100644
--- a/src/routes/Filters.tsx
+++ b/src/routes/Filters.tsx
@@ -1,11 +1,13 @@
 import {
   FeedPersonIcon,
+  FilterIcon,
   FilterRemoveIcon,
   NoteIcon,
 } from '@primer/octicons-react';
 import { type FC, useContext } from 'react';
 import { Header } from '../components/Header';
 import { Checkbox } from '../components/fields/Checkbox';
+import { Legend } from '../components/settings/Legend';
 import { AppContext } from '../context/App';
 import { BUTTON_CLASS_NAME } from '../styles/gitify';
 import { Size } from '../types';
@@ -33,13 +35,12 @@ export const FiltersRoute: FC = () => {
 
   return (
     <div className="flex h-screen flex-col" data-testid="filters">
-      <Header fetchOnBack={true}>Filters</Header>
+      <Header fetchOnBack={true} icon={FilterIcon}>
+        Filters
+      </Header>
       <div className="flex-grow overflow-x-auto px-8">
         <fieldset className="mb-3">
-          <legend id="notifications" className="mb-1 mt-2 font-semibold">
-            <FeedPersonIcon className="mr-2" />
-            Users
-          </legend>
+          <Legend icon={FeedPersonIcon}>Users</Legend>
           <Checkbox
             name="hideBots"
             label="Hide notifications from Bot accounts"
@@ -65,10 +66,7 @@ export const FiltersRoute: FC = () => {
         </fieldset>
 
         <fieldset className="mb-3">
-          <legend id="appearance" className="mb-1 mt-2 font-semibold">
-            <NoteIcon className="mr-2" />
-            Reason
-          </legend>
+          <Legend icon={NoteIcon}>Reason</Legend>
           <span className="text-xs italic">
             Note: if no reasons are selected, all notifications will be shown.
           </span>
diff --git a/src/routes/LoginWithOAuthApp.tsx b/src/routes/LoginWithOAuthApp.tsx
index bd3b2657..9d0e7df3 100644
--- a/src/routes/LoginWithOAuthApp.tsx
+++ b/src/routes/LoginWithOAuthApp.tsx
@@ -128,10 +128,7 @@ export const LoginWithOAuthApp: FC = () => {
 
   return (
     <div>
-      <Header>
-        <PersonIcon size={Size.XLARGE} className="mr-2" />
-        Login with OAuth App
-      </Header>
+      <Header icon={PersonIcon}>Login with OAuth App</Header>
       <div className="px-8">
         <Form
           initialValues={{
diff --git a/src/routes/LoginWithPersonalAccessToken.tsx b/src/routes/LoginWithPersonalAccessToken.tsx
index b5d6d6e8..e792ef12 100644
--- a/src/routes/LoginWithPersonalAccessToken.tsx
+++ b/src/routes/LoginWithPersonalAccessToken.tsx
@@ -133,10 +133,7 @@ export const LoginWithPersonalAccessToken: FC = () => {
 
   return (
     <>
-      <Header>
-        <KeyIcon size={Size.LARGE} className="mr-2" />
-        Login with Personal Access Token
-      </Header>
+      <Header icon={KeyIcon}>Login with Personal Access Token</Header>
 
       <div className="px-8">
         <Form
diff --git a/src/routes/Settings.tsx b/src/routes/Settings.tsx
index 1149199e..8a84c117 100644
--- a/src/routes/Settings.tsx
+++ b/src/routes/Settings.tsx
@@ -1,3 +1,4 @@
+import { GearIcon } from '@primer/octicons-react';
 import { type FC, useContext } from 'react';
 import { Header } from '../components/Header';
 import { AppearanceSettings } from '../components/settings/AppearanceSettings';
@@ -10,7 +11,9 @@ export const SettingsRoute: FC = () => {
   const { resetSettings } = useContext(AppContext);
   return (
     <div className="flex h-screen flex-col" data-testid="settings">
-      <Header fetchOnBack>Settings</Header>
+      <Header fetchOnBack icon={GearIcon}>
+        Settings
+      </Header>
 
       <div className="flex flex-col flex-grow overflow-x-auto px-8 gap-3">
         <AppearanceSettings />
diff --git a/src/types.ts b/src/types.ts
index 6fe2d25c..f60c03f7 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -63,6 +63,7 @@ interface AppearanceSettingsState {
   detailedNotifications: boolean;
   showAccountHostname: boolean;
   showPills: boolean;
+  showNumber: boolean;
 }
 
 interface NotificationSettingsState {
diff --git a/src/typesGitHub.ts b/src/typesGitHub.ts
index 2fed9d32..39e56723 100644
--- a/src/typesGitHub.ts
+++ b/src/typesGitHub.ts
@@ -261,6 +261,7 @@ interface GitHubSubject {
 
 // This is not in the GitHub API, but we add it to the type to make it easier to work with
 export interface GitifySubject {
+  number?: number;
   state?: StateType;
   user?: SubjectUser;
   reviews?: GitifyPullRequestReview[];
@@ -494,6 +495,7 @@ export interface GraphQLSearch<T> {
 }
 
 export interface Discussion {
+  number: number;
   title: string;
   stateReason: DiscussionStateType;
   isAnswered: boolean;
diff --git a/src/utils/api/__mocks__/response-mocks.ts b/src/utils/api/__mocks__/response-mocks.ts
index 74097fb3..714635ab 100644
--- a/src/utils/api/__mocks__/response-mocks.ts
+++ b/src/utils/api/__mocks__/response-mocks.ts
@@ -419,6 +419,7 @@ export const mockGraphQLResponse: GraphQLSearch<Discussion> = {
     search: {
       nodes: [
         {
+          number: 123,
           title: '1.16.0',
           isAnswered: false,
           stateReason: 'OPEN',
diff --git a/src/utils/api/graphql/discussions.ts b/src/utils/api/graphql/discussions.ts
index b5ce239a..93ec4c91 100644
--- a/src/utils/api/graphql/discussions.ts
+++ b/src/utils/api/graphql/discussions.ts
@@ -31,6 +31,7 @@ export const QUERY_SEARCH_DISCUSSIONS = gql`
     search(query: $queryStatement, type: DISCUSSION, first: $firstDiscussions) {
       nodes {
         ... on Discussion {
+          number
           title
           stateReason
           isAnswered
diff --git a/src/utils/notifications.ts b/src/utils/notifications.ts
index 801530d3..44ffcc0e 100644
--- a/src/utils/notifications.ts
+++ b/src/utils/notifications.ts
@@ -103,7 +103,7 @@ export const raiseNativeNotification = (notifications: Notification[]) => {
 };
 
 export const raiseSoundNotification = () => {
-  const audio = new Audio('assets/sounds/clearly.mp3');
+  const audio = new Audio('../../assets/sounds/clearly.mp3');
   audio.volume = 0.2;
   audio.play();
 };
diff --git a/src/utils/subject.ts b/src/utils/subject.ts
index ba0c7853..a4063c0a 100644
--- a/src/utils/subject.ts
+++ b/src/utils/subject.ts
@@ -183,6 +183,7 @@ async function getGitifySubjectForDiscussion(
   }
 
   return {
+    number: discussion.number,
     state: discussionState,
     user: discussionUser,
     comments: discussion.comments.totalCount,
@@ -226,6 +227,7 @@ async function getGitifySubjectForIssue(
   }
 
   return {
+    number: issue.number,
     state: issue.state_reason ?? issue.state,
     user: {
       login: issueCommentUser?.login ?? issue.user.login,
@@ -272,6 +274,7 @@ async function getGitifySubjectForPullRequest(
   const linkedIssues = parseLinkedIssuesFromPr(pr);
 
   return {
+    number: pr.number,
     state: prState,
     user: {
       login: prCommentUser?.login ?? pr.user.login,


Test patch:
diff --git a/src/components/Header.test.tsx b/src/components/Header.test.tsx
index a381c8be..7633858c 100644
--- a/src/components/Header.test.tsx
+++ b/src/components/Header.test.tsx
@@ -1,3 +1,4 @@
+import { MarkGithubIcon } from '@primer/octicons-react';
 import { fireEvent, render, screen } from '@testing-library/react';
 import { AppContext } from '../context/App';
 import { Header } from './Header';
@@ -16,13 +17,13 @@ describe('components/Header.tsx', () => {
   });
 
   it('should render itself & its children', () => {
-    const tree = render(<Header>Test Header</Header>);
+    const tree = render(<Header icon={MarkGithubIcon}>Test Header</Header>);
 
     expect(tree).toMatchSnapshot();
   });
 
   it('should navigate back', () => {
-    render(<Header>Test Header</Header>);
+    render(<Header icon={MarkGithubIcon}>Test Header</Header>);
 
     fireEvent.click(screen.getByLabelText('Go Back'));
 
@@ -36,7 +37,9 @@ describe('components/Header.tsx', () => {
           fetchNotifications,
         }}
       >
-        <Header fetchOnBack={true}>Test Header</Header>
+        <Header fetchOnBack={true} icon={MarkGithubIcon}>
+          Test Header
+        </Header>
       </AppContext.Provider>,
     );
 
diff --git a/src/components/NotificationRow.test.tsx b/src/components/NotificationRow.test.tsx
index bb781f14..15a6abb5 100644
--- a/src/components/NotificationRow.test.tsx
+++ b/src/components/NotificationRow.test.tsx
@@ -61,6 +61,26 @@ describe('components/NotificationRow.tsx', () => {
     expect(tree).toMatchSnapshot();
   });
 
+  it('should render itself & its children - hide numbers', async () => {
+    jest
+      .spyOn(global.Date, 'now')
+      .mockImplementation(() => new Date('2024').valueOf());
+
+    const props = {
+      notification: mockSingleNotification,
+      account: mockGitHubCloudAccount,
+    };
+
+    const tree = render(
+      <AppContext.Provider
+        value={{ settings: { ...mockSettings, showNumber: false } }}
+      >
+        <NotificationRow {...props} />
+      </AppContext.Provider>,
+    );
+    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__/AccountNotifications.test.tsx.snap b/src/components/__snapshots__/AccountNotifications.test.tsx.snap
index 9250db70..cec4888c 100644
--- a/src/components/__snapshots__/AccountNotifications.test.tsx.snap
+++ b/src/components/__snapshots__/AccountNotifications.test.tsx.snap
@@ -121,6 +121,9 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
             title="I am a robot and this is a test!"
           >
             I am a robot and this is a test!
+            <span
+              class="text-xxs ml-1 opacity-50"
+            />
           </div>
           <div
             class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
@@ -317,6 +320,9 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
             title="Improve the UI"
           >
             Improve the UI
+            <span
+              class="text-xxs ml-1 opacity-50"
+            />
           </div>
           <div
             class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
@@ -539,6 +545,9 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
           title="I am a robot and this is a test!"
         >
           I am a robot and this is a test!
+          <span
+            class="text-xxs ml-1 opacity-50"
+          />
         </div>
         <div
           class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
@@ -735,6 +744,9 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
           title="Improve the UI"
         >
           Improve the UI
+          <span
+            class="text-xxs ml-1 opacity-50"
+          />
         </div>
         <div
           class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
diff --git a/src/components/__snapshots__/Header.test.tsx.snap b/src/components/__snapshots__/Header.test.tsx.snap
index 98717155..b5bf11c5 100644
--- a/src/components/__snapshots__/Header.test.tsx.snap
+++ b/src/components/__snapshots__/Header.test.tsx.snap
@@ -30,9 +30,28 @@ exports[`components/Header.tsx should render itself & its children 1`] = `
           </svg>
         </button>
         <h3
-          class="text-lg font-semibold"
+          class="text-lg font-semibold flex items-center"
         >
-          Test Header
+          <legend
+            class="mb-1 mt-2 font-semibold flex items-center"
+            id="test-header"
+          >
+            <svg
+              aria-hidden="true"
+              class="mr-2"
+              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 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"
+              />
+            </svg>
+            Test Header
+          </legend>
         </h3>
       </div>
     </div>
@@ -63,9 +82,28 @@ exports[`components/Header.tsx should render itself & its children 1`] = `
         </svg>
       </button>
       <h3
-        class="text-lg font-semibold"
+        class="text-lg font-semibold flex items-center"
       >
-        Test Header
+        <legend
+          class="mb-1 mt-2 font-semibold flex items-center"
+          id="test-header"
+        >
+          <svg
+            aria-hidden="true"
+            class="mr-2"
+            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 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"
+            />
+          </svg>
+          Test Header
+        </legend>
       </h3>
     </div>
   </div>,
diff --git a/src/components/__snapshots__/NotificationRow.test.tsx.snap b/src/components/__snapshots__/NotificationRow.test.tsx.snap
index 30e7c1cd..c30e3a4b 100644
--- a/src/components/__snapshots__/NotificationRow.test.tsx.snap
+++ b/src/components/__snapshots__/NotificationRow.test.tsx.snap
@@ -58,6 +58,9 @@ exports[`components/NotificationRow.tsx should render itself & its children - gr
             title="I am a robot and this is a test!"
           >
             I am a robot and this is a test!
+            <span
+              class="text-xxs ml-1 opacity-50"
+            />
           </div>
           <div
             class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
@@ -257,6 +260,9 @@ exports[`components/NotificationRow.tsx should render itself & its children - gr
           title="I am a robot and this is a test!"
         >
           I am a robot and this is a test!
+          <span
+            class="text-xxs ml-1 opacity-50"
+          />
         </div>
         <div
           class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
@@ -496,6 +502,436 @@ exports[`components/NotificationRow.tsx should render itself & its children - gr
             title="I am a robot and this is a test!"
           >
             I am a robot and this is a test!
+            <span
+              class="text-xxs ml-1 opacity-50"
+            />
+          </div>
+          <div
+            class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
+          >
+            <button
+              class="flex-shrink-0"
+              title="View User Profile"
+              type="button"
+            >
+              <img
+                alt="gitify-app's avatar"
+                class="rounded-full object-cover size-4"
+                src="https://avatars.githubusercontent.com/u/133795385?s=200&v=4"
+              />
+            </button>
+            <div
+              title="You're watching the repository."
+            >
+              Updated
+            </div>
+            <div
+              title="gitify-app updated 7 years ago"
+            >
+              7 years ago
+            </div>
+            <div
+              class="flex"
+            >
+              <button
+                class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                title="octocat approved these changes"
+                type="button"
+              >
+                <svg
+                  aria-label="octocat approved these changes"
+                  class="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>
+              <button
+                class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+                title="gitify-app requested changes"
+                type="button"
+              >
+                <svg
+                  aria-label="gitify-app requested changes"
+                  class="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>
+            </div>
+          </div>
+        </div>
+        <div
+          class="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80"
+        >
+          <button
+            class="h-full hover:text-green-500 focus:outline-none"
+            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="h-full hover:text-green-500 focus:outline-none"
+            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>
+          <button
+            class="h-full hover:text-green-500 focus:outline-none"
+            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>
+        </div>
+      </div>
+    </div>
+  </body>,
+  "container": <div>
+    <div
+      class="group flex border-b border-gray-100 bg-white px-3 py-2 hover:bg-gray-100 dark:border-gray-darker dark:bg-gray-dark dark:text-white dark:hover:bg-gray-darker"
+      id="138661096"
+    >
+      <div
+        class="mr-3 flex items-center justify-center text-green-500"
+        title="Open Issue"
+      >
+        <svg
+          aria-label="Issue"
+          class="octicon octicon-issue-opened"
+          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="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 overflow-ellipsis whitespace-nowrap cursor-pointer"
+      >
+        <div
+          class="mb-1 truncate text-sm"
+          role="main"
+          title="I am a robot and this is a test!"
+        >
+          I am a robot and this is a test!
+          <span
+            class="text-xxs ml-1 opacity-50"
+          />
+        </div>
+        <div
+          class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
+        >
+          <button
+            class="flex-shrink-0"
+            title="View User Profile"
+            type="button"
+          >
+            <img
+              alt="gitify-app's avatar"
+              class="rounded-full object-cover size-4"
+              src="https://avatars.githubusercontent.com/u/133795385?s=200&v=4"
+            />
+          </button>
+          <div
+            title="You're watching the repository."
+          >
+            Updated
+          </div>
+          <div
+            title="gitify-app updated 7 years ago"
+          >
+            7 years ago
+          </div>
+          <div
+            class="flex"
+          >
+            <button
+              class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+              title="octocat approved these changes"
+              type="button"
+            >
+              <svg
+                aria-label="octocat approved these changes"
+                class="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>
+            <button
+              class="flex gap-1 items-center m-0.5 rounded-full bg-gray-100 px-1 text-xxs hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700"
+              title="gitify-app requested changes"
+              type="button"
+            >
+              <svg
+                aria-label="gitify-app requested changes"
+                class="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>
+          </div>
+        </div>
+      </div>
+      <div
+        class="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80"
+      >
+        <button
+          class="h-full hover:text-green-500 focus:outline-none"
+          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="h-full hover:text-green-500 focus:outline-none"
+          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>
+        <button
+          class="h-full hover:text-green-500 focus:outline-none"
+          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>
+      </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 should render itself & its children - hide numbers 1`] = `
+{
+  "asFragment": [Function],
+  "baseElement": <body>
+    <div>
+      <div
+        class="group flex border-b border-gray-100 bg-white px-3 py-2 hover:bg-gray-100 dark:border-gray-darker dark:bg-gray-dark dark:text-white dark:hover:bg-gray-darker"
+        id="138661096"
+      >
+        <div
+          class="mr-3 flex items-center justify-center text-green-500"
+          title="Open Issue"
+        >
+          <svg
+            aria-label="Issue"
+            class="octicon octicon-issue-opened"
+            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="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 overflow-ellipsis whitespace-nowrap cursor-pointer"
+        >
+          <div
+            class="mb-1 truncate text-sm"
+            role="main"
+            title="I am a robot and this is a test!"
+          >
+            I am a robot and this is a test!
+            <span
+              class="text-xxs ml-1 opacity-50 hidden"
+            />
           </div>
           <div
             class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
@@ -678,6 +1114,9 @@ exports[`components/NotificationRow.tsx should render itself & its children - gr
           title="I am a robot and this is a test!"
         >
           I am a robot and this is a test!
+          <span
+            class="text-xxs ml-1 opacity-50 hidden"
+          />
         </div>
         <div
           class="flex flex-wrap items-center gap-1 text-xs capitalize opacity-80"
diff --git a/src/components/settings/AppearanceSettings.test.tsx b/src/components/settings/AppearanceSettings.test.tsx
index dcf8a6d0..d7ea2138 100644
--- a/src/components/settings/AppearanceSettings.test.tsx
+++ b/src/components/settings/AppearanceSettings.test.tsx
@@ -84,6 +84,31 @@ describe('routes/components/settings/AppearanceSettings.tsx', () => {
     expect(updateSetting).toHaveBeenCalledWith('showPills', false);
   });
 
+  it('should toggle show number checkbox', async () => {
+    await act(async () => {
+      render(
+        <AppContext.Provider
+          value={{
+            auth: mockAuth,
+            settings: mockSettings,
+            updateSetting,
+          }}
+        >
+          <MemoryRouter>
+            <AppearanceSettings />
+          </MemoryRouter>
+        </AppContext.Provider>,
+      );
+    });
+
+    await screen.findByLabelText('Show number');
+
+    fireEvent.click(screen.getByLabelText('Show number'));
+
+    expect(updateSetting).toHaveBeenCalledTimes(1);
+    expect(updateSetting).toHaveBeenCalledWith('showNumber', false);
+  });
+
   it('should toggle account hostname checkbox', async () => {
     await act(async () => {
       render(
diff --git a/src/context/App.test.tsx b/src/context/App.test.tsx
index 415aac0b..121fdc68 100644
--- a/src/context/App.test.tsx
+++ b/src/context/App.test.tsx
@@ -379,6 +379,7 @@ describe('context/App.tsx', () => {
           showAccountHostname: false,
           delayNotificationState: false,
           showPills: true,
+          showNumber: true,
           keyboardShortcut: true,
           groupBy: 'REPOSITORY',
           filterReasons: [],
@@ -433,6 +434,7 @@ describe('context/App.tsx', () => {
           showAccountHostname: false,
           delayNotificationState: false,
           showPills: true,
+          showNumber: true,
           keyboardShortcut: true,
           groupBy: 'REPOSITORY',
           filterReasons: [],
diff --git a/src/routes/__snapshots__/Accounts.test.tsx.snap b/src/routes/__snapshots__/Accounts.test.tsx.snap
index 30e6212d..da96fff2 100644
--- a/src/routes/__snapshots__/Accounts.test.tsx.snap
+++ b/src/routes/__snapshots__/Accounts.test.tsx.snap
@@ -30,9 +30,28 @@ exports[`routes/Accounts.tsx General should render itself & its children 1`] = `
       </svg>
     </button>
     <h3
-      class="text-lg font-semibold"
+      class="text-lg font-semibold flex items-center"
     >
-      Accounts
+      <legend
+        class="mb-1 mt-2 font-semibold flex items-center"
+        id="accounts"
+      >
+        <svg
+          aria-hidden="true"
+          class="mr-2"
+          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="M10.561 8.073a6.005 6.005 0 0 1 3.432 5.142.75.75 0 1 1-1.498.07 4.5 4.5 0 0 0-8.99 0 .75.75 0 0 1-1.498-.07 6.004 6.004 0 0 1 3.431-5.142 3.999 3.999 0 1 1 5.123 0ZM10.5 5a2.5 2.5 0 1 0-5 0 2.5 2.5 0 0 0 5 0Z"
+          />
+        </svg>
+        Accounts
+      </legend>
     </h3>
   </div>
   <div
diff --git a/src/routes/__snapshots__/Filters.test.tsx.snap b/src/routes/__snapshots__/Filters.test.tsx.snap
index fc2c4fba..33eae1d6 100644
--- a/src/routes/__snapshots__/Filters.test.tsx.snap
+++ b/src/routes/__snapshots__/Filters.test.tsx.snap
@@ -30,9 +30,28 @@ exports[`routes/Filters.tsx General should render itself & its children 1`] = `
       </svg>
     </button>
     <h3
-      class="text-lg font-semibold"
+      class="text-lg font-semibold flex items-center"
     >
-      Filters
+      <legend
+        class="mb-1 mt-2 font-semibold flex items-center"
+        id="filters"
+      >
+        <svg
+          aria-hidden="true"
+          class="mr-2"
+          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="M.75 3h14.5a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1 0-1.5ZM3 7.75A.75.75 0 0 1 3.75 7h8.5a.75.75 0 0 1 0 1.5h-8.5A.75.75 0 0 1 3 7.75Zm3 4a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z"
+          />
+        </svg>
+        Filters
+      </legend>
     </h3>
   </div>
   <div
@@ -42,8 +61,8 @@ exports[`routes/Filters.tsx General should render itself & its children 1`] = `
       class="mb-3"
     >
       <legend
-        class="mb-1 mt-2 font-semibold"
-        id="notifications"
+        class="mb-1 mt-2 font-semibold flex items-center"
+        id="users"
       >
         <svg
           aria-hidden="true"
@@ -113,8 +132,8 @@ exports[`routes/Filters.tsx General should render itself & its children 1`] = `
       class="mb-3"
     >
       <legend
-        class="mb-1 mt-2 font-semibold"
-        id="appearance"
+        class="mb-1 mt-2 font-semibold flex items-center"
+        id="reason"
       >
         <svg
           aria-hidden="true"
diff --git a/src/routes/__snapshots__/LoginWithOAuthApp.test.tsx.snap b/src/routes/__snapshots__/LoginWithOAuthApp.test.tsx.snap
index 582a6354..5d4c7ad1 100644
--- a/src/routes/__snapshots__/LoginWithOAuthApp.test.tsx.snap
+++ b/src/routes/__snapshots__/LoginWithOAuthApp.test.tsx.snap
@@ -31,23 +31,28 @@ exports[`routes/LoginWithOAuthApp.tsx renders correctly 1`] = `
             </svg>
           </button>
           <h3
-            class="text-lg font-semibold"
+            class="text-lg font-semibold flex items-center"
           >
-            <svg
-              aria-hidden="true"
-              class="mr-2"
-              fill="currentColor"
-              focusable="false"
-              height="20"
-              style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-              viewBox="0 0 16 16"
-              width="20"
+            <legend
+              class="mb-1 mt-2 font-semibold flex items-center"
+              id="login-with oauth app"
             >
-              <path
-                d="M10.561 8.073a6.005 6.005 0 0 1 3.432 5.142.75.75 0 1 1-1.498.07 4.5 4.5 0 0 0-8.99 0 .75.75 0 0 1-1.498-.07 6.004 6.004 0 0 1 3.431-5.142 3.999 3.999 0 1 1 5.123 0ZM10.5 5a2.5 2.5 0 1 0-5 0 2.5 2.5 0 0 0 5 0Z"
-              />
-            </svg>
-            Login with OAuth App
+              <svg
+                aria-hidden="true"
+                class="mr-2"
+                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="M10.561 8.073a6.005 6.005 0 0 1 3.432 5.142.75.75 0 1 1-1.498.07 4.5 4.5 0 0 0-8.99 0 .75.75 0 0 1-1.498-.07 6.004 6.004 0 0 1 3.431-5.142 3.999 3.999 0 1 1 5.123 0ZM10.5 5a2.5 2.5 0 1 0-5 0 2.5 2.5 0 0 0 5 0Z"
+                />
+              </svg>
+              Login with OAuth App
+            </legend>
           </h3>
         </div>
         <div
@@ -229,23 +234,28 @@ exports[`routes/LoginWithOAuthApp.tsx renders correctly 1`] = `
           </svg>
         </button>
         <h3
-          class="text-lg font-semibold"
+          class="text-lg font-semibold flex items-center"
         >
-          <svg
-            aria-hidden="true"
-            class="mr-2"
-            fill="currentColor"
-            focusable="false"
-            height="20"
-            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-            viewBox="0 0 16 16"
-            width="20"
+          <legend
+            class="mb-1 mt-2 font-semibold flex items-center"
+            id="login-with oauth app"
           >
-            <path
-              d="M10.561 8.073a6.005 6.005 0 0 1 3.432 5.142.75.75 0 1 1-1.498.07 4.5 4.5 0 0 0-8.99 0 .75.75 0 0 1-1.498-.07 6.004 6.004 0 0 1 3.431-5.142 3.999 3.999 0 1 1 5.123 0ZM10.5 5a2.5 2.5 0 1 0-5 0 2.5 2.5 0 0 0 5 0Z"
-            />
-          </svg>
-          Login with OAuth App
+            <svg
+              aria-hidden="true"
+              class="mr-2"
+              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="M10.561 8.073a6.005 6.005 0 0 1 3.432 5.142.75.75 0 1 1-1.498.07 4.5 4.5 0 0 0-8.99 0 .75.75 0 0 1-1.498-.07 6.004 6.004 0 0 1 3.431-5.142 3.999 3.999 0 1 1 5.123 0ZM10.5 5a2.5 2.5 0 1 0-5 0 2.5 2.5 0 0 0 5 0Z"
+              />
+            </svg>
+            Login with OAuth App
+          </legend>
         </h3>
       </div>
       <div
diff --git a/src/routes/__snapshots__/LoginWithPersonalAccessToken.test.tsx.snap b/src/routes/__snapshots__/LoginWithPersonalAccessToken.test.tsx.snap
index b0aa2dc5..dd349269 100644
--- a/src/routes/__snapshots__/LoginWithPersonalAccessToken.test.tsx.snap
+++ b/src/routes/__snapshots__/LoginWithPersonalAccessToken.test.tsx.snap
@@ -30,23 +30,28 @@ exports[`routes/LoginWithPersonalAccessToken.tsx renders correctly 1`] = `
           </svg>
         </button>
         <h3
-          class="text-lg font-semibold"
+          class="text-lg font-semibold flex items-center"
         >
-          <svg
-            aria-hidden="true"
-            class="mr-2"
-            fill="currentColor"
-            focusable="false"
-            height="18"
-            style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-            viewBox="0 0 16 16"
-            width="18"
+          <legend
+            class="mb-1 mt-2 font-semibold flex items-center"
+            id="login-with personal access token"
           >
-            <path
-              d="M10.5 0a5.499 5.499 0 1 1-1.288 10.848l-.932.932a.749.749 0 0 1-.53.22H7v.75a.749.749 0 0 1-.22.53l-.5.5a.749.749 0 0 1-.53.22H5v.75a.749.749 0 0 1-.22.53l-.5.5a.749.749 0 0 1-.53.22h-2A1.75 1.75 0 0 1 0 14.25v-2c0-.199.079-.389.22-.53l4.932-4.932A5.5 5.5 0 0 1 10.5 0Zm-4 5.5c-.001.431.069.86.205 1.269a.75.75 0 0 1-.181.768L1.5 12.56v1.69c0 .138.112.25.25.25h1.69l.06-.06v-1.19a.75.75 0 0 1 .75-.75h1.19l.06-.06v-1.19a.75.75 0 0 1 .75-.75h1.19l1.023-1.025a.75.75 0 0 1 .768-.18A4 4 0 1 0 6.5 5.5ZM11 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"
-            />
-          </svg>
-          Login with Personal Access Token
+            <svg
+              aria-hidden="true"
+              class="mr-2"
+              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="M10.5 0a5.499 5.499 0 1 1-1.288 10.848l-.932.932a.749.749 0 0 1-.53.22H7v.75a.749.749 0 0 1-.22.53l-.5.5a.749.749 0 0 1-.53.22H5v.75a.749.749 0 0 1-.22.53l-.5.5a.749.749 0 0 1-.53.22h-2A1.75 1.75 0 0 1 0 14.25v-2c0-.199.079-.389.22-.53l4.932-4.932A5.5 5.5 0 0 1 10.5 0Zm-4 5.5c-.001.431.069.86.205 1.269a.75.75 0 0 1-.181.768L1.5 12.56v1.69c0 .138.112.25.25.25h1.69l.06-.06v-1.19a.75.75 0 0 1 .75-.75h1.19l.06-.06v-1.19a.75.75 0 0 1 .75-.75h1.19l1.023-1.025a.75.75 0 0 1 .768-.18A4 4 0 1 0 6.5 5.5ZM11 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"
+              />
+            </svg>
+            Login with Personal Access Token
+          </legend>
         </h3>
       </div>
       <div
@@ -215,23 +220,28 @@ exports[`routes/LoginWithPersonalAccessToken.tsx renders correctly 1`] = `
         </svg>
       </button>
       <h3
-        class="text-lg font-semibold"
+        class="text-lg font-semibold flex items-center"
       >
-        <svg
-          aria-hidden="true"
-          class="mr-2"
-          fill="currentColor"
-          focusable="false"
-          height="18"
-          style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
-          viewBox="0 0 16 16"
-          width="18"
+        <legend
+          class="mb-1 mt-2 font-semibold flex items-center"
+          id="login-with personal access token"
         >
-          <path
-            d="M10.5 0a5.499 5.499 0 1 1-1.288 10.848l-.932.932a.749.749 0 0 1-.53.22H7v.75a.749.749 0 0 1-.22.53l-.5.5a.749.749 0 0 1-.53.22H5v.75a.749.749 0 0 1-.22.53l-.5.5a.749.749 0 0 1-.53.22h-2A1.75 1.75 0 0 1 0 14.25v-2c0-.199.079-.389.22-.53l4.932-4.932A5.5 5.5 0 0 1 10.5 0Zm-4 5.5c-.001.431.069.86.205 1.269a.75.75 0 0 1-.181.768L1.5 12.56v1.69c0 .138.112.25.25.25h1.69l.06-.06v-1.19a.75.75 0 0 1 .75-.75h1.19l.06-.06v-1.19a.75.75 0 0 1 .75-.75h1.19l1.023-1.025a.75.75 0 0 1 .768-.18A4 4 0 1 0 6.5 5.5ZM11 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"
-          />
-        </svg>
-        Login with Personal Access Token
+          <svg
+            aria-hidden="true"
+            class="mr-2"
+            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="M10.5 0a5.499 5.499 0 1 1-1.288 10.848l-.932.932a.749.749 0 0 1-.53.22H7v.75a.749.749 0 0 1-.22.53l-.5.5a.749.749 0 0 1-.53.22H5v.75a.749.749 0 0 1-.22.53l-.5.5a.749.749 0 0 1-.53.22h-2A1.75 1.75 0 0 1 0 14.25v-2c0-.199.079-.389.22-.53l4.932-4.932A5.5 5.5 0 0 1 10.5 0Zm-4 5.5c-.001.431.069.86.205 1.269a.75.75 0 0 1-.181.768L1.5 12.56v1.69c0 .138.112.25.25.25h1.69l.06-.06v-1.19a.75.75 0 0 1 .75-.75h1.19l.06-.06v-1.19a.75.75 0 0 1 .75-.75h1.19l1.023-1.025a.75.75 0 0 1 .768-.18A4 4 0 1 0 6.5 5.5ZM11 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"
+            />
+          </svg>
+          Login with Personal Access Token
+        </legend>
       </h3>
     </div>
     <div
diff --git a/src/routes/__snapshots__/Settings.test.tsx.snap b/src/routes/__snapshots__/Settings.test.tsx.snap
index 0e2fa07a..9f2426b8 100644
--- a/src/routes/__snapshots__/Settings.test.tsx.snap
+++ b/src/routes/__snapshots__/Settings.test.tsx.snap
@@ -30,9 +30,28 @@ exports[`routes/Settings.tsx should render itself & its children 1`] = `
       </svg>
     </button>
     <h3
-      class="text-lg font-semibold"
+      class="text-lg font-semibold flex items-center"
     >
-      Settings
+      <legend
+        class="mb-1 mt-2 font-semibold flex items-center"
+        id="settings"
+      >
+        <svg
+          aria-hidden="true"
+          class="mr-2"
+          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 0a8.2 8.2 0 0 1 .701.031C9.444.095 9.99.645 10.16 1.29l.288 1.107c.018.066.079.158.212.224.231.114.454.243.668.386.123.082.233.09.299.071l1.103-.303c.644-.176 1.392.021 1.82.63.27.385.506.792.704 1.218.315.675.111 1.422-.364 1.891l-.814.806c-.049.048-.098.147-.088.294.016.257.016.515 0 .772-.01.147.038.246.088.294l.814.806c.475.469.679 1.216.364 1.891a7.977 7.977 0 0 1-.704 1.217c-.428.61-1.176.807-1.82.63l-1.102-.302c-.067-.019-.177-.011-.3.071a5.909 5.909 0 0 1-.668.386c-.133.066-.194.158-.211.224l-.29 1.106c-.168.646-.715 1.196-1.458 1.26a8.006 8.006 0 0 1-1.402 0c-.743-.064-1.289-.614-1.458-1.26l-.289-1.106c-.018-.066-.079-.158-.212-.224a5.738 5.738 0 0 1-.668-.386c-.123-.082-.233-.09-.299-.071l-1.103.303c-.644.176-1.392-.021-1.82-.63a8.12 8.12 0 0 1-.704-1.218c-.315-.675-.111-1.422.363-1.891l.815-.806c.05-.048.098-.147.088-.294a6.214 6.214 0 0 1 0-.772c.01-.147-.038-.246-.088-.294l-.815-.806C.635 6.045.431 5.298.746 4.623a7.92 7.92 0 0 1 .704-1.217c.428-.61 1.176-.807 1.82-.63l1.102.302c.067.019.177.011.3-.071.214-.143.437-.272.668-.386.133-.066.194-.158.211-.224l.29-1.106C6.009.645 6.556.095 7.299.03 7.53.01 7.764 0 8 0Zm-.571 1.525c-.036.003-.108.036-.137.146l-.289 1.105c-.147.561-.549.967-.998 1.189-.173.086-.34.183-.5.29-.417.278-.97.423-1.529.27l-1.103-.303c-.109-.03-.175.016-.195.045-.22.312-.412.644-.573.99-.014.031-.021.11.059.19l.815.806c.411.406.562.957.53 1.456a4.709 4.709 0 0 0 0 .582c.032.499-.119 1.05-.53 1.456l-.815.806c-.081.08-.073.159-.059.19.162.346.353.677.573.989.02.03.085.076.195.046l1.102-.303c.56-.153 1.113-.008 1.53.27.161.107.328.204.501.29.447.222.85.629.997 1.189l.289 1.105c.029.109.101.143.137.146a6.6 6.6 0 0 0 1.142 0c.036-.003.108-.036.137-.146l.289-1.105c.147-.561.549-.967.998-1.189.173-.086.34-.183.5-.29.417-.278.97-.423 1.529-.27l1.103.303c.109.029.175-.016.195-.045.22-.313.411-.644.573-.99.014-.031.021-.11-.059-.19l-.815-.806c-.411-.406-.562-.957-.53-1.456a4.709 4.709 0 0 0 0-.582c-.032-.499.119-1.05.53-1.456l.815-.806c.081-.08.073-.159.059-.19a6.464 6.464 0 0 0-.573-.989c-.02-.03-.085-.076-.195-.046l-1.102.303c-.56.153-1.113.008-1.53-.27a4.44 4.44 0 0 0-.501-.29c-.447-.222-.85-.629-.997-1.189l-.289-1.105c-.029-.11-.101-.143-.137-.146a6.6 6.6 0 0 0-1.142 0ZM11 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0ZM9.5 8a1.5 1.5 0 1 0-3.001.001A1.5 1.5 0 0 0 9.5 8Z"
+          />
+        </svg>
+        Settings
+      </legend>
     </h3>
   </div>
   <div
@@ -231,6 +250,54 @@ exports[`routes/Settings.tsx should render itself & its children 1`] = `
           </div>
         </div>
       </div>
+      <div
+        class="mb-3 mt-1 text-sm"
+      >
+        <div
+          class="flex items-start"
+        >
+          <div
+            class="flex h-5 items-center"
+          >
+            <input
+              checked=""
+              class="size-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
+              id="showNumber"
+              type="checkbox"
+            />
+          </div>
+          <div
+            class="ml-3"
+          >
+            <label
+              class="font-medium text-gray-700 dark:text-gray-200"
+              for="showNumber"
+            >
+              Show number
+              <span
+                aria-label="tooltip-showNumber"
+                class="relative"
+                id="tooltip-showNumber"
+              >
+                <svg
+                  aria-hidden="true"
+                  class="ml-1 text-blue-500"
+                  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="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.92 6.085h.001a.749.749 0 1 1-1.342-.67c.169-.339.436-.701.849-.977C6.845 4.16 7.369 4 8 4a2.756 2.756 0 0 1 1.637.525c.503.377.863.965.863 1.725 0 .448-.115.83-.329 1.15-.205.307-.47.513-.692.662-.109.072-.22.138-.313.195l-.006.004a6.24 6.24 0 0 0-.26.16.952.952 0 0 0-.276.245.75.75 0 0 1-1.248-.832c.184-.264.42-.489.692-.661.103-.067.207-.132.313-.195l.007-.004c.1-.061.182-.11.258-.161a.969.969 0 0 0 .277-.245C8.96 6.514 9 6.427 9 6.25a.612.612 0 0 0-.262-.525A1.27 1.27 0 0 0 8 5.5c-.369 0-.595.09-.74.187a1.01 1.01 0 0 0-.34.398ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"
+                  />
+                </svg>
+              </span>
+            </label>
+          </div>
+        </div>
+      </div>
       <div
         class="mb-3 mt-1 text-sm"
       >
diff --git a/src/utils/subject.test.ts b/src/utils/subject.test.ts
index 5b030539..bb53ac8c 100644
--- a/src/utils/subject.test.ts
+++ b/src/utils/subject.test.ts
@@ -221,6 +221,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'ANSWERED',
           user: {
             login: mockDiscussionAuthor.login,
@@ -247,6 +248,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'DUPLICATE',
           user: {
             login: mockDiscussionAuthor.login,
@@ -273,6 +275,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'OPEN',
           user: {
             login: mockDiscussionAuthor.login,
@@ -299,6 +302,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'OUTDATED',
           user: {
             login: mockDiscussionAuthor.login,
@@ -325,6 +329,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'REOPENED',
           user: {
             login: mockDiscussionAuthor.login,
@@ -351,6 +356,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'RESOLVED',
           user: {
             login: mockDiscussionAuthor.login,
@@ -385,6 +391,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'ANSWERED',
           user: {
             login: mockDiscussionAuthor.login,
@@ -414,7 +421,12 @@ describe('utils/subject.ts', () => {
       it('open issue state', async () => {
         nock('https://api.github.com')
           .get('/repos/gitify-app/notifications-test/issues/1')
-          .reply(200, { state: 'open', user: mockAuthor, labels: [] });
+          .reply(200, {
+            number: 123,
+            state: 'open',
+            user: mockAuthor,
+            labels: [],
+          });
 
         nock('https://api.github.com')
           .get('/repos/gitify-app/notifications-test/issues/comments/302888448')
@@ -423,6 +435,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'open',
           user: {
             login: mockCommenter.login,
@@ -437,7 +450,12 @@ describe('utils/subject.ts', () => {
       it('closed issue state', async () => {
         nock('https://api.github.com')
           .get('/repos/gitify-app/notifications-test/issues/1')
-          .reply(200, { state: 'closed', user: mockAuthor, labels: [] });
+          .reply(200, {
+            number: 123,
+            state: 'closed',
+            user: mockAuthor,
+            labels: [],
+          });
 
         nock('https://api.github.com')
           .get('/repos/gitify-app/notifications-test/issues/comments/302888448')
@@ -446,6 +464,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'closed',
           user: {
             login: mockCommenter.login,
@@ -461,6 +480,7 @@ describe('utils/subject.ts', () => {
         nock('https://api.github.com')
           .get('/repos/gitify-app/notifications-test/issues/1')
           .reply(200, {
+            number: 123,
             state: 'closed',
             state_reason: 'completed',
             user: mockAuthor,
@@ -474,6 +494,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'completed',
           user: {
             login: mockCommenter.login,
@@ -489,6 +510,7 @@ describe('utils/subject.ts', () => {
         nock('https://api.github.com')
           .get('/repos/gitify-app/notifications-test/issues/1')
           .reply(200, {
+            number: 123,
             state: 'open',
             state_reason: 'not_planned',
             user: mockAuthor,
@@ -502,6 +524,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'not_planned',
           user: {
             login: mockCommenter.login,
@@ -517,6 +540,7 @@ describe('utils/subject.ts', () => {
         nock('https://api.github.com')
           .get('/repos/gitify-app/notifications-test/issues/1')
           .reply(200, {
+            number: 123,
             state: 'open',
             state_reason: 'reopened',
             user: mockAuthor,
@@ -530,6 +554,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'reopened',
           user: {
             login: mockCommenter.login,
@@ -547,6 +572,7 @@ describe('utils/subject.ts', () => {
         nock('https://api.github.com')
           .get('/repos/gitify-app/notifications-test/issues/1')
           .reply(200, {
+            number: 123,
             state: 'open',
             draft: false,
             merged: false,
@@ -557,6 +583,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'open',
           user: {
             login: mockAuthor.login,
@@ -573,6 +600,7 @@ describe('utils/subject.ts', () => {
           nock('https://api.github.com')
             .get('/repos/gitify-app/notifications-test/issues/1')
             .reply(200, {
+              number: 123,
               state: 'open',
               user: mockAuthor,
               labels: [{ name: 'enhancement' }],
@@ -587,6 +615,7 @@ describe('utils/subject.ts', () => {
           const result = await getGitifySubjectDetails(mockNotification);
 
           expect(result).toEqual({
+            number: 123,
             state: 'open',
             user: {
               login: mockCommenter.login,
@@ -602,6 +631,7 @@ describe('utils/subject.ts', () => {
           nock('https://api.github.com')
             .get('/repos/gitify-app/notifications-test/issues/1')
             .reply(200, {
+              number: 123,
               state: 'open',
               user: mockAuthor,
               labels: null,
@@ -616,6 +646,7 @@ describe('utils/subject.ts', () => {
           const result = await getGitifySubjectDetails(mockNotification);
 
           expect(result).toEqual({
+            number: 123,
             state: 'open',
             user: {
               login: mockCommenter.login,
@@ -646,6 +677,7 @@ describe('utils/subject.ts', () => {
         nock('https://api.github.com')
           .get('/repos/gitify-app/notifications-test/pulls/1')
           .reply(200, {
+            number: 123,
             state: 'closed',
             draft: false,
             merged: false,
@@ -664,6 +696,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'closed',
           user: {
             login: mockCommenter.login,
@@ -681,6 +714,7 @@ describe('utils/subject.ts', () => {
         nock('https://api.github.com')
           .get('/repos/gitify-app/notifications-test/pulls/1')
           .reply(200, {
+            number: 123,
             state: 'open',
             draft: true,
             merged: false,
@@ -699,6 +733,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'draft',
           user: {
             login: mockCommenter.login,
@@ -716,6 +751,7 @@ describe('utils/subject.ts', () => {
         nock('https://api.github.com')
           .get('/repos/gitify-app/notifications-test/pulls/1')
           .reply(200, {
+            number: 123,
             state: 'open',
             draft: false,
             merged: true,
@@ -734,6 +770,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'merged',
           user: {
             login: mockCommenter.login,
@@ -751,6 +788,7 @@ describe('utils/subject.ts', () => {
         nock('https://api.github.com')
           .get('/repos/gitify-app/notifications-test/pulls/1')
           .reply(200, {
+            number: 123,
             state: 'open',
             draft: false,
             merged: false,
@@ -769,6 +807,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'open',
           user: {
             login: mockCommenter.login,
@@ -789,6 +828,7 @@ describe('utils/subject.ts', () => {
         nock('https://api.github.com')
           .get('/repos/gitify-app/notifications-test/pulls/1')
           .reply(200, {
+            number: 123,
             state: 'open',
             draft: false,
             merged: false,
@@ -803,6 +843,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'open',
           user: {
             login: mockAuthor.login,
@@ -822,6 +863,7 @@ describe('utils/subject.ts', () => {
         nock('https://api.github.com')
           .get('/repos/gitify-app/notifications-test/pulls/1')
           .reply(200, {
+            number: 123,
             state: 'open',
             draft: false,
             merged: false,
@@ -836,6 +878,7 @@ describe('utils/subject.ts', () => {
         const result = await getGitifySubjectDetails(mockNotification);
 
         expect(result).toEqual({
+          number: 123,
           state: 'open',
           user: {
             login: mockAuthor.login,
@@ -912,6 +955,7 @@ describe('utils/subject.ts', () => {
           nock('https://api.github.com')
             .get('/repos/gitify-app/notifications-test/pulls/1')
             .reply(200, {
+              number: 123,
               state: 'open',
               draft: false,
               merged: false,
@@ -932,6 +976,7 @@ describe('utils/subject.ts', () => {
           const result = await getGitifySubjectDetails(mockNotification);
 
           expect(result).toEqual({
+            number: 123,
             state: 'open',
             user: {
               login: mockCommenter.login,
@@ -949,6 +994,7 @@ describe('utils/subject.ts', () => {
           nock('https://api.github.com')
             .get('/repos/gitify-app/notifications-test/pulls/1')
             .reply(200, {
+              number: 123,
               state: 'open',
               draft: false,
               merged: false,
@@ -969,6 +1015,7 @@ describe('utils/subject.ts', () => {
           const result = await getGitifySubjectDetails(mockNotification);
 
           expect(result).toEqual({
+            number: 123,
             state: 'open',
             user: {
               login: mockCommenter.login,
@@ -1293,6 +1340,7 @@ function mockDiscussionNode(
   isAnswered: boolean,
 ): Discussion {
   return {
+    number: 123,
     title: 'This is a mock discussion',
     url: 'https://github.com/gitify-app/notifications-test/discussions/1' as Link,
     stateReason: state,