Repository: gitify-app/gitify
Pull request #1259 (2024-06-17 19:50:14)

feat: my quick links
simple update to add the following "quick links" to the Sidebar: 

- my issues
- my pull requests

 
![Screenshot 2024-06-17 at 3 52 58 PM](https://github.com/gitify-app/gitify/assets/386277/854c2490-dec2-4a9a-b03c-922b2e0973b1)

![Screenshot 2024-06-17 at 3 41 34 PM](https://github.com/gitify-app/gitify/assets/386277/3a65cbd4-2157-4f0e-a78f-171696d5407c)



Closes https://github.com/gitify-app/gitify/issues/498 (at least in a way that's perhaps sufficient for now)

Feedback welcomed on Sidebar layout. I did try side-by-side but it felt awkward 

setchy: In time we may consider pulling the datasets and displaying within Gitify 🤔 
afonsojramos: To be honest, I was initially a bit hesitant on adding more icons/buttons, but these are small I suppose. Looking good!

Patch:
diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx
index a10b36f5..6e64fea0 100644
--- a/src/components/Sidebar.tsx
+++ b/src/components/Sidebar.tsx
@@ -1,6 +1,8 @@
 import {
   BellIcon,
   GearIcon,
+  GitPullRequestIcon,
+  IssueOpenedIcon,
   SyncIcon,
   XCircleIcon,
 } from '@primer/octicons-react';
@@ -9,7 +11,12 @@ import { useLocation, useNavigate } from 'react-router-dom';
 import { Logo } from '../components/Logo';
 import { AppContext } from '../context/App';
 import { quitApp } from '../utils/comms';
-import { openGitHubNotifications, openGitifyRepository } from '../utils/links';
+import {
+  openGitHubIssues,
+  openGitHubNotifications,
+  openGitHubPulls,
+  openGitifyRepository,
+} from '../utils/links';
 import { getNotificationCount } from '../utils/notifications';
 import { SidebarButton } from './buttons/SidebarButton';
 
@@ -56,6 +63,18 @@ export const Sidebar: FC = () => {
           icon={BellIcon}
           onClick={() => openGitHubNotifications()}
         />
+
+        <SidebarButton
+          title="My Issues"
+          icon={IssueOpenedIcon}
+          onClick={() => openGitHubIssues()}
+        />
+
+        <SidebarButton
+          title="My Pull Requests"
+          icon={GitPullRequestIcon}
+          onClick={() => openGitHubPulls()}
+        />
       </div>
 
       <div className="px-3 py-4">
diff --git a/src/utils/links.ts b/src/utils/links.ts
index 3b6f84e6..6edd4477 100644
--- a/src/utils/links.ts
+++ b/src/utils/links.ts
@@ -19,6 +19,14 @@ export function openGitHubNotifications() {
   openExternalLink('https://github.com/notifications' as Link);
 }
 
+export function openGitHubIssues() {
+  openExternalLink('https://github.com/issues' as Link);
+}
+
+export function openGitHubPulls() {
+  openExternalLink('https://github.com/pulls' as Link);
+}
+
 export function openAccountProfile(account: Account) {
   const url = new URL(`https://${account.hostname}`);
   url.pathname = account.user.login;


Test patch:
diff --git a/src/components/Sidebar.test.tsx b/src/components/Sidebar.test.tsx
index 8c16f7ad..93b6b1d5 100644
--- a/src/components/Sidebar.test.tsx
+++ b/src/components/Sidebar.test.tsx
@@ -146,6 +146,50 @@ describe('components/Sidebar.tsx', () => {
     );
   });
 
+  it('opens my github issues page', () => {
+    const openExternalLinkMock = jest.spyOn(comms, 'openExternalLink');
+
+    render(
+      <AppContext.Provider
+        value={{
+          isLoggedIn: true,
+          notifications: mockAccountNotifications,
+        }}
+      >
+        <MemoryRouter>
+          <Sidebar />
+        </MemoryRouter>
+      </AppContext.Provider>,
+    );
+    fireEvent.click(screen.getByLabelText('My Issues'));
+    expect(openExternalLinkMock).toHaveBeenCalledTimes(1);
+    expect(openExternalLinkMock).toHaveBeenCalledWith(
+      'https://github.com/issues',
+    );
+  });
+
+  it('opens my github pull requests page', () => {
+    const openExternalLinkMock = jest.spyOn(comms, 'openExternalLink');
+
+    render(
+      <AppContext.Provider
+        value={{
+          isLoggedIn: true,
+          notifications: mockAccountNotifications,
+        }}
+      >
+        <MemoryRouter>
+          <Sidebar />
+        </MemoryRouter>
+      </AppContext.Provider>,
+    );
+    fireEvent.click(screen.getByLabelText('My Pull Requests'));
+    expect(openExternalLinkMock).toHaveBeenCalledTimes(1);
+    expect(openExternalLinkMock).toHaveBeenCalledWith(
+      'https://github.com/pulls',
+    );
+  });
+
   it('should quit the app', () => {
     const quitAppMock = jest.spyOn(comms, 'quitApp');
 
diff --git a/src/components/__snapshots__/Sidebar.test.tsx.snap b/src/components/__snapshots__/Sidebar.test.tsx.snap
index 4a2dbcf0..a4e4df9b 100644
--- a/src/components/__snapshots__/Sidebar.test.tsx.snap
+++ b/src/components/__snapshots__/Sidebar.test.tsx.snap
@@ -84,6 +84,51 @@ exports[`components/Sidebar.tsx should render itself & its children (logged in)
             </svg>
             4
           </button>
+          <button
+            class="flex justify-evenly items-center w-full my-1 cursor-pointer text-xs font-extrabold focus:outline-none disabled:text-gray-500  disabled:cursor-default text-white hover:text-gray-500 py-1"
+            title="My Issues"
+            type="button"
+          >
+            <svg
+              aria-label="My Issues"
+              class="octicon octicon-issue-opened"
+              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="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>
+          </button>
+          <button
+            class="flex justify-evenly items-center w-full my-1 cursor-pointer text-xs font-extrabold focus:outline-none disabled:text-gray-500  disabled:cursor-default text-white hover:text-gray-500 py-1"
+            title="My Pull Requests"
+            type="button"
+          >
+            <svg
+              aria-label="My Pull Requests"
+              class="octicon octicon-git-pull-request"
+              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.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"
+              />
+            </svg>
+          </button>
         </div>
         <div
           class="px-3 py-4"
@@ -193,6 +238,51 @@ exports[`components/Sidebar.tsx should render itself & its children (logged in)
           </svg>
           4
         </button>
+        <button
+          class="flex justify-evenly items-center w-full my-1 cursor-pointer text-xs font-extrabold focus:outline-none disabled:text-gray-500  disabled:cursor-default text-white hover:text-gray-500 py-1"
+          title="My Issues"
+          type="button"
+        >
+          <svg
+            aria-label="My Issues"
+            class="octicon octicon-issue-opened"
+            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="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>
+        </button>
+        <button
+          class="flex justify-evenly items-center w-full my-1 cursor-pointer text-xs font-extrabold focus:outline-none disabled:text-gray-500  disabled:cursor-default text-white hover:text-gray-500 py-1"
+          title="My Pull Requests"
+          type="button"
+        >
+          <svg
+            aria-label="My Pull Requests"
+            class="octicon octicon-git-pull-request"
+            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.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"
+            />
+          </svg>
+        </button>
       </div>
       <div
         class="px-3 py-4"
@@ -359,6 +449,51 @@ exports[`components/Sidebar.tsx should render itself & its children (logged out)
             </svg>
             4
           </button>
+          <button
+            class="flex justify-evenly items-center w-full my-1 cursor-pointer text-xs font-extrabold focus:outline-none disabled:text-gray-500  disabled:cursor-default text-white hover:text-gray-500 py-1"
+            title="My Issues"
+            type="button"
+          >
+            <svg
+              aria-label="My Issues"
+              class="octicon octicon-issue-opened"
+              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="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>
+          </button>
+          <button
+            class="flex justify-evenly items-center w-full my-1 cursor-pointer text-xs font-extrabold focus:outline-none disabled:text-gray-500  disabled:cursor-default text-white hover:text-gray-500 py-1"
+            title="My Pull Requests"
+            type="button"
+          >
+            <svg
+              aria-label="My Pull Requests"
+              class="octicon octicon-git-pull-request"
+              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.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"
+              />
+            </svg>
+          </button>
         </div>
         <div
           class="px-3 py-4"
@@ -468,6 +603,51 @@ exports[`components/Sidebar.tsx should render itself & its children (logged out)
           </svg>
           4
         </button>
+        <button
+          class="flex justify-evenly items-center w-full my-1 cursor-pointer text-xs font-extrabold focus:outline-none disabled:text-gray-500  disabled:cursor-default text-white hover:text-gray-500 py-1"
+          title="My Issues"
+          type="button"
+        >
+          <svg
+            aria-label="My Issues"
+            class="octicon octicon-issue-opened"
+            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="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>
+        </button>
+        <button
+          class="flex justify-evenly items-center w-full my-1 cursor-pointer text-xs font-extrabold focus:outline-none disabled:text-gray-500  disabled:cursor-default text-white hover:text-gray-500 py-1"
+          title="My Pull Requests"
+          type="button"
+        >
+          <svg
+            aria-label="My Pull Requests"
+            class="octicon octicon-git-pull-request"
+            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.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"
+            />
+          </svg>
+        </button>
       </div>
       <div
         class="px-3 py-4"
diff --git a/src/utils/links.test.ts b/src/utils/links.test.ts
index d01bb5e2..316fff36 100644
--- a/src/utils/links.test.ts
+++ b/src/utils/links.test.ts
@@ -10,8 +10,10 @@ import * as helpers from './helpers';
 import {
   openAccountProfile,
   openDeveloperSettings,
+  openGitHubIssues,
   openGitHubNotifications,
   openGitHubParticipatingDocs,
+  openGitHubPulls,
   openGitifyReleaseNotes,
   openGitifyRepository,
   openHost,
@@ -50,6 +52,20 @@ describe('utils/links.ts', () => {
     );
   });
 
+  it('openGitHubIssues', () => {
+    openGitHubIssues();
+    expect(comms.openExternalLink).toHaveBeenCalledWith(
+      'https://github.com/issues',
+    );
+  });
+
+  it('openGitHubPulls', () => {
+    openGitHubPulls();
+    expect(comms.openExternalLink).toHaveBeenCalledWith(
+      'https://github.com/pulls',
+    );
+  });
+
   it('openAccountProfile', () => {
     openAccountProfile(mockGitHubCloudAccount);
     expect(comms.openExternalLink).toHaveBeenCalledWith(