Repository: gitify-app/gitify
Pull request #916 (2024-03-21 03:14:38)

feat: fallback to issue/pr user
Use issue/pr user as default case which increases the coverage of notification scenarios


Patch:
diff --git a/src/components/Repository.tsx b/src/components/Repository.tsx
index 2ece7124..6c7a4ce5 100644
--- a/src/components/Repository.tsx
+++ b/src/components/Repository.tsx
@@ -1,5 +1,5 @@
 import React, { useCallback, useContext } from 'react';
-import { ReadIcon, CheckIcon } from '@primer/octicons-react';
+import { ReadIcon, CheckIcon, MarkGithubIcon } from '@primer/octicons-react';
 import { CSSTransition, TransitionGroup } from 'react-transition-group';
 
 import { AppContext } from '../context/App';
@@ -42,7 +42,11 @@ export const RepositoryNotifications: React.FC<IProps> = ({
     <>
       <div className="flex py-2 px-3 bg-gray-100 dark:bg-gray-darker dark:text-white group">
         <div className="flex flex-1 space-x-3 items-center mt-0 text-sm font-medium overflow-hidden overflow-ellipsis whitespace-nowrap">
-          <img className="rounded w-5 h-5" src={avatarUrl} />
+          {avatarUrl ? (
+            <img className="rounded w-5 h-5" src={avatarUrl} />
+          ) : (
+            <MarkGithubIcon size={18} />
+          )}
           <span onClick={openBrowser}>{repoName}</span>
         </div>
 
diff --git a/src/utils/subject.ts b/src/utils/subject.ts
index 96969a12..10ce5ae3 100644
--- a/src/utils/subject.ts
+++ b/src/utils/subject.ts
@@ -128,7 +128,7 @@ async function getGitifySubjectForIssue(
 
   return {
     state: issue.state_reason ?? issue.state,
-    user: issueCommentUser?.login ?? null,
+    user: issueCommentUser?.login ?? issue.user.login,
   };
 }
 
@@ -151,7 +151,7 @@ async function getGitifySubjectForPullRequest(
 
   return {
     state: prState,
-    user: prCommentUser?.login ?? null,
+    user: prCommentUser?.login ?? pr.user.login,
   };
 }
 


Test patch:
diff --git a/src/components/Repository.test.tsx b/src/components/Repository.test.tsx
index 9eaa7aec..9e472670 100644
--- a/src/components/Repository.test.tsx
+++ b/src/components/Repository.test.tsx
@@ -81,4 +81,15 @@ describe('components/Repository.tsx', () => {
       'github.com',
     );
   });
+
+  it('should use default repository icon when avatar is not available', () => {
+    props.repoNotifications[0].repository.owner.avatar_url = '';
+
+    const tree = TestRenderer.create(
+      <AppContext.Provider value={{}}>
+        <RepositoryNotifications {...props} />
+      </AppContext.Provider>,
+    );
+    expect(tree).toMatchSnapshot();
+  });
 });
diff --git a/src/components/__snapshots__/Repository.test.tsx.snap b/src/components/__snapshots__/Repository.test.tsx.snap
index cacb209b..a47cf4cb 100644
--- a/src/components/__snapshots__/Repository.test.tsx.snap
+++ b/src/components/__snapshots__/Repository.test.tsx.snap
@@ -92,3 +92,113 @@ exports[`components/Repository.tsx should render itself & its children 1`] = `
   </div>,
 ]
 `;
+
+exports[`components/Repository.tsx should use default repository icon when avatar is not available 1`] = `
+[
+  <div
+    className="flex py-2 px-3 bg-gray-100 dark:bg-gray-darker dark:text-white group"
+  >
+    <div
+      className="flex flex-1 space-x-3 items-center mt-0 text-sm font-medium overflow-hidden overflow-ellipsis whitespace-nowrap"
+    >
+      <svg
+        aria-hidden="true"
+        className="octicon octicon-mark-github"
+        fill="currentColor"
+        focusable="false"
+        height={18}
+        style={
+          {
+            "display": "inline-block",
+            "overflow": "visible",
+            "userSelect": "none",
+            "verticalAlign": "text-bottom",
+          }
+        }
+        viewBox="0 0 16 16"
+        width={18}
+      >
+        <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>
+      <span
+        onClick={[Function]}
+      >
+        manosim/gitify
+      </span>
+    </div>
+    <div
+      className="flex justify-center items-center gap-2 opacity-0 group-hover:opacity-80 transition-opacity"
+    >
+      <button
+        className="focus:outline-none h-full hover:text-green-500"
+        onClick={[Function]}
+        title="Mark Repository as Done"
+      >
+        <svg
+          aria-label="Mark Repository as Done"
+          className="octicon octicon-check"
+          fill="currentColor"
+          focusable="false"
+          height={16}
+          role="img"
+          style={
+            {
+              "display": "inline-block",
+              "overflow": "visible",
+              "userSelect": "none",
+              "verticalAlign": "text-bottom",
+            }
+          }
+          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>
+      <div
+        className="w-[14px]"
+      />
+      <button
+        className="focus:outline-none h-full hover:text-green-500"
+        onClick={[Function]}
+        title="Mark Repository as Read"
+      >
+        <svg
+          aria-label="Mark Repository as Read"
+          className="octicon octicon-read"
+          fill="currentColor"
+          focusable="false"
+          height={14}
+          role="img"
+          style={
+            {
+              "display": "inline-block",
+              "overflow": "visible",
+              "userSelect": "none",
+              "verticalAlign": "text-bottom",
+            }
+          }
+          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>
+    <div>
+      NotificationRow
+    </div>
+    <div>
+      NotificationRow
+    </div>
+  </div>,
+]
+`;
diff --git a/src/utils/subject.test.ts b/src/utils/subject.test.ts
index 77f3c2dd..657f4e3e 100644
--- a/src/utils/subject.test.ts
+++ b/src/utils/subject.test.ts
@@ -423,11 +423,11 @@ describe('utils/subject.ts', () => {
       it('open issue state', async () => {
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/1')
-          .reply(200, { state: 'open' });
+          .reply(200, { state: 'open', user: { login: 'some-user' } });
 
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/comments/302888448')
-          .reply(200, { user: { login: 'some-user' } });
+          .reply(200, { user: { login: 'some-commenter' } });
 
         const result = await getGitifySubjectDetails(
           mockedSingleNotification,
@@ -435,17 +435,17 @@ describe('utils/subject.ts', () => {
         );
 
         expect(result.state).toBe('open');
-        expect(result.user).toBe('some-user');
+        expect(result.user).toBe('some-commenter');
       });
 
       it('closed issue state', async () => {
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/1')
-          .reply(200, { state: 'closed' });
+          .reply(200, { state: 'closed', user: { login: 'some-user' } });
 
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/comments/302888448')
-          .reply(200, { user: { login: 'some-user' } });
+          .reply(200, { user: { login: 'some-commenter' } });
 
         const result = await getGitifySubjectDetails(
           mockedSingleNotification,
@@ -453,17 +453,21 @@ describe('utils/subject.ts', () => {
         );
 
         expect(result.state).toBe('closed');
-        expect(result.user).toBe('some-user');
+        expect(result.user).toBe('some-commenter');
       });
 
       it('completed issue state', async () => {
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/1')
-          .reply(200, { state: 'closed', state_reason: 'completed' });
+          .reply(200, {
+            state: 'closed',
+            state_reason: 'completed',
+            user: { login: 'some-user' },
+          });
 
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/comments/302888448')
-          .reply(200, { user: { login: 'some-user' } });
+          .reply(200, { user: { login: 'some-commenter' } });
 
         const result = await getGitifySubjectDetails(
           mockedSingleNotification,
@@ -471,17 +475,21 @@ describe('utils/subject.ts', () => {
         );
 
         expect(result.state).toBe('completed');
-        expect(result.user).toBe('some-user');
+        expect(result.user).toBe('some-commenter');
       });
 
       it('not_planned issue state', async () => {
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/1')
-          .reply(200, { state: 'open', state_reason: 'not_planned' });
+          .reply(200, {
+            state: 'open',
+            state_reason: 'not_planned',
+            user: { login: 'some-user' },
+          });
 
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/comments/302888448')
-          .reply(200, { user: { login: 'some-user' } });
+          .reply(200, { user: { login: 'some-commenter' } });
 
         const result = await getGitifySubjectDetails(
           mockedSingleNotification,
@@ -489,17 +497,21 @@ describe('utils/subject.ts', () => {
         );
 
         expect(result.state).toBe('not_planned');
-        expect(result.user).toBe('some-user');
+        expect(result.user).toBe('some-commenter');
       });
 
       it('reopened issue state', async () => {
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/1')
-          .reply(200, { state: 'open', state_reason: 'reopened' });
+          .reply(200, {
+            state: 'open',
+            state_reason: 'reopened',
+            user: { login: 'some-user' },
+          });
 
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/comments/302888448')
-          .reply(200, { user: { login: 'some-user' } });
+          .reply(200, { user: { login: 'some-commenter' } });
 
         const result = await getGitifySubjectDetails(
           mockedSingleNotification,
@@ -507,13 +519,18 @@ describe('utils/subject.ts', () => {
         );
 
         expect(result.state).toBe('reopened');
-        expect(result.user).toBe('some-user');
+        expect(result.user).toBe('some-commenter');
       });
 
       it('handle issues without latest_comment_url', async () => {
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/1')
-          .reply(200, { state: 'open', draft: false, merged: false });
+          .reply(200, {
+            state: 'open',
+            draft: false,
+            merged: false,
+            user: { login: 'some-user' },
+          });
 
         const result = await getGitifySubjectDetails(
           {
@@ -527,7 +544,7 @@ describe('utils/subject.ts', () => {
         );
 
         expect(result.state).toBe('open');
-        expect(result.user).toBeNull();
+        expect(result.user).toBe('some-user');
       });
     });
 
@@ -543,11 +560,16 @@ describe('utils/subject.ts', () => {
       it('closed pull request state', async () => {
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/1')
-          .reply(200, { state: 'closed', draft: false, merged: false });
+          .reply(200, {
+            state: 'closed',
+            draft: false,
+            merged: false,
+            user: { login: 'some-user' },
+          });
 
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/comments/302888448')
-          .reply(200, { user: { login: 'some-user' } });
+          .reply(200, { user: { login: 'some-commenter' } });
 
         const result = await getGitifySubjectDetails(
           mockNotification,
@@ -555,17 +577,22 @@ describe('utils/subject.ts', () => {
         );
 
         expect(result.state).toBe('closed');
-        expect(result.user).toBe('some-user');
+        expect(result.user).toBe('some-commenter');
       });
 
       it('draft pull request state', async () => {
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/1')
-          .reply(200, { state: 'open', draft: true, merged: false });
+          .reply(200, {
+            state: 'open',
+            draft: true,
+            merged: false,
+            user: { login: 'some-user' },
+          });
 
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/comments/302888448')
-          .reply(200, { user: { login: 'some-user' } });
+          .reply(200, { user: { login: 'some-commenter' } });
 
         const result = await getGitifySubjectDetails(
           mockNotification,
@@ -573,17 +600,22 @@ describe('utils/subject.ts', () => {
         );
 
         expect(result.state).toBe('draft');
-        expect(result.user).toBe('some-user');
+        expect(result.user).toBe('some-commenter');
       });
 
       it('merged pull request state', async () => {
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/1')
-          .reply(200, { state: 'open', draft: false, merged: true });
+          .reply(200, {
+            state: 'open',
+            draft: false,
+            merged: true,
+            user: { login: 'some-user' },
+          });
 
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/comments/302888448')
-          .reply(200, { user: { login: 'some-user' } });
+          .reply(200, { user: { login: 'some-commenter' } });
 
         const result = await getGitifySubjectDetails(
           mockNotification,
@@ -591,17 +623,22 @@ describe('utils/subject.ts', () => {
         );
 
         expect(result.state).toBe('merged');
-        expect(result.user).toBe('some-user');
+        expect(result.user).toBe('some-commenter');
       });
 
       it('open pull request state', async () => {
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/1')
-          .reply(200, { state: 'open', draft: false, merged: false });
+          .reply(200, {
+            state: 'open',
+            draft: false,
+            merged: false,
+            user: { login: 'some-user' },
+          });
 
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/comments/302888448')
-          .reply(200, { user: { login: 'some-user' } });
+          .reply(200, { user: { login: 'some-commenter' } });
 
         const result = await getGitifySubjectDetails(
           mockNotification,
@@ -609,13 +646,18 @@ describe('utils/subject.ts', () => {
         );
 
         expect(result.state).toBe('open');
-        expect(result.user).toBe('some-user');
+        expect(result.user).toBe('some-commenter');
       });
 
       it('handle pull request without latest_comment_url', async () => {
         nock('https://api.github.com')
           .get('/repos/manosim/notifications-test/issues/1')
-          .reply(200, { state: 'open', draft: false, merged: false });
+          .reply(200, {
+            state: 'open',
+            draft: false,
+            merged: false,
+            user: { login: 'some-user' },
+          });
 
         const result = await getGitifySubjectDetails(
           {
@@ -629,7 +671,7 @@ describe('utils/subject.ts', () => {
         );
 
         expect(result.state).toBe('open');
-        expect(result.user).toBeNull();
+        expect(result.user).toBe('some-user');
       });
     });
   });