Repository: gitify-app/gitify
Pull request #925 (2024-03-25 20:54:23)

feat: link version number to release notes
Hyperlink app version information in Settings page to the matching Gitify release notes


Patch:
diff --git a/src/__mocks__/mockedData.ts b/src/__mocks__/mockedData.ts
index 27ec5fa6..987b26c7 100644
--- a/src/__mocks__/mockedData.ts
+++ b/src/__mocks__/mockedData.ts
@@ -3,7 +3,7 @@ import {
   Notification,
   Repository,
   GraphQLSearch,
-  DiscussionSearchResultNode,
+  Discussion,
 } from '../typesGithub';
 
 export const mockedEnterpriseAccounts: EnterpriseAccount[] = [
@@ -281,240 +281,239 @@ export const mockedSingleAccountNotifications: AccountNotifications[] = [
   },
 ];
 
-export const mockedGraphQLResponse: GraphQLSearch<DiscussionSearchResultNode> =
-  {
+export const mockedGraphQLResponse: GraphQLSearch<Discussion> = {
+  data: {
     data: {
-      data: {
-        search: {
-          nodes: [
-            {
-              viewerSubscription: 'SUBSCRIBED',
-              title: '1.16.0',
-              isAnswered: false,
-              stateReason: null,
-              url: 'https://github.com/manosim/notifications-test/discussions/612',
-              comments: {
-                nodes: [
-                  {
-                    databaseId: 2215656,
-                    createdAt: '2022-02-20T18:33:39Z',
-                    author: {
-                      login: 'comment-user',
-                    },
-                    replies: {
-                      nodes: [],
-                    },
+      search: {
+        nodes: [
+          {
+            viewerSubscription: 'SUBSCRIBED',
+            title: '1.16.0',
+            isAnswered: false,
+            stateReason: null,
+            url: 'https://github.com/manosim/notifications-test/discussions/612',
+            comments: {
+              nodes: [
+                {
+                  databaseId: 2215656,
+                  createdAt: '2022-02-20T18:33:39Z',
+                  author: {
+                    login: 'comment-user',
+                  },
+                  replies: {
+                    nodes: [],
+                  },
+                },
+                {
+                  databaseId: 2217789,
+                  createdAt: '2022-02-21T03:30:42Z',
+                  author: {
+                    login: 'comment-user',
                   },
-                  {
-                    databaseId: 2217789,
-                    createdAt: '2022-02-21T03:30:42Z',
-                    author: {
-                      login: 'comment-user',
-                    },
-                    replies: {
-                      nodes: [],
-                    },
+                  replies: {
+                    nodes: [],
                   },
-                  {
-                    databaseId: 2223243,
-                    createdAt: '2022-02-21T18:26:27Z',
-                    author: {
-                      login: 'comment-user',
-                    },
-                    replies: {
-                      nodes: [
-                        {
-                          databaseId: 2232922,
-                          createdAt: '2022-02-23T00:57:58Z',
-                          author: {
-                            login: 'reply-user',
-                          },
+                },
+                {
+                  databaseId: 2223243,
+                  createdAt: '2022-02-21T18:26:27Z',
+                  author: {
+                    login: 'comment-user',
+                  },
+                  replies: {
+                    nodes: [
+                      {
+                        databaseId: 2232922,
+                        createdAt: '2022-02-23T00:57:58Z',
+                        author: {
+                          login: 'reply-user',
                         },
-                      ],
-                    },
+                      },
+                    ],
+                  },
+                },
+                {
+                  databaseId: 2232921,
+                  createdAt: '2022-02-23T00:57:49Z',
+                  author: {
+                    login: 'comment-user',
                   },
-                  {
-                    databaseId: 2232921,
-                    createdAt: '2022-02-23T00:57:49Z',
-                    author: {
-                      login: 'comment-user',
-                    },
-                    replies: {
-                      nodes: [],
-                    },
+                  replies: {
+                    nodes: [],
                   },
-                  {
-                    databaseId: 2258799,
-                    createdAt: '2022-02-27T01:22:20Z',
-                    author: {
-                      login: 'comment-user',
-                    },
-                    replies: {
-                      nodes: [
-                        {
-                          databaseId: 2300902,
-                          createdAt: '2022-03-05T17:43:52Z',
-                          author: {
-                            login: 'reply-user',
-                          },
+                },
+                {
+                  databaseId: 2258799,
+                  createdAt: '2022-02-27T01:22:20Z',
+                  author: {
+                    login: 'comment-user',
+                  },
+                  replies: {
+                    nodes: [
+                      {
+                        databaseId: 2300902,
+                        createdAt: '2022-03-05T17:43:52Z',
+                        author: {
+                          login: 'reply-user',
                         },
-                      ],
-                    },
+                      },
+                    ],
+                  },
+                },
+                {
+                  databaseId: 2297637,
+                  createdAt: '2022-03-04T20:39:44Z',
+                  author: {
+                    login: 'comment-user',
                   },
-                  {
-                    databaseId: 2297637,
-                    createdAt: '2022-03-04T20:39:44Z',
-                    author: {
-                      login: 'comment-user',
-                    },
-                    replies: {
-                      nodes: [
-                        {
-                          databaseId: 2300893,
-                          createdAt: '2022-03-05T17:41:04Z',
-                          author: {
-                            login: 'reply-user',
-                          },
+                  replies: {
+                    nodes: [
+                      {
+                        databaseId: 2300893,
+                        createdAt: '2022-03-05T17:41:04Z',
+                        author: {
+                          login: 'reply-user',
                         },
-                      ],
-                    },
+                      },
+                    ],
                   },
-                  {
-                    databaseId: 2299763,
-                    createdAt: '2022-03-05T11:05:42Z',
-                    author: {
-                      login: 'comment-user',
-                    },
-                    replies: {
-                      nodes: [
-                        {
-                          databaseId: 2300895,
-                          createdAt: '2022-03-05T17:41:44Z',
-                          author: {
-                            login: 'reply-user',
-                          },
+                },
+                {
+                  databaseId: 2299763,
+                  createdAt: '2022-03-05T11:05:42Z',
+                  author: {
+                    login: 'comment-user',
+                  },
+                  replies: {
+                    nodes: [
+                      {
+                        databaseId: 2300895,
+                        createdAt: '2022-03-05T17:41:44Z',
+                        author: {
+                          login: 'reply-user',
                         },
-                      ],
-                    },
+                      },
+                    ],
                   },
-                ],
-              },
+                },
+              ],
             },
-            {
-              viewerSubscription: 'IGNORED',
-              title: '1.16.0',
-              isAnswered: false,
-              stateReason: null,
-              url: 'https://github.com/manosim/notifications-test/discussions/612',
-              comments: {
-                nodes: [
-                  {
-                    databaseId: 2215656,
-                    createdAt: '2022-02-20T18:33:39Z',
-                    author: {
-                      login: 'comment-user',
-                    },
-                    replies: {
-                      nodes: [],
-                    },
+          },
+          {
+            viewerSubscription: 'IGNORED',
+            title: '1.16.0',
+            isAnswered: false,
+            stateReason: null,
+            url: 'https://github.com/manosim/notifications-test/discussions/612',
+            comments: {
+              nodes: [
+                {
+                  databaseId: 2215656,
+                  createdAt: '2022-02-20T18:33:39Z',
+                  author: {
+                    login: 'comment-user',
+                  },
+                  replies: {
+                    nodes: [],
                   },
-                  {
-                    databaseId: 2217789,
-                    createdAt: '2022-02-21T03:30:42Z',
-                    author: {
-                      login: 'comment-user',
-                    },
-                    replies: {
-                      nodes: [],
-                    },
+                },
+                {
+                  databaseId: 2217789,
+                  createdAt: '2022-02-21T03:30:42Z',
+                  author: {
+                    login: 'comment-user',
                   },
-                  {
-                    databaseId: 2223243,
-                    createdAt: '2022-02-21T18:26:27Z',
-                    author: {
-                      login: 'comment-user',
-                    },
-                    replies: {
-                      nodes: [
-                        {
-                          databaseId: 2232922,
-                          createdAt: '2022-02-23T00:57:58Z',
-                          author: {
-                            login: 'reply-user',
-                          },
+                  replies: {
+                    nodes: [],
+                  },
+                },
+                {
+                  databaseId: 2223243,
+                  createdAt: '2022-02-21T18:26:27Z',
+                  author: {
+                    login: 'comment-user',
+                  },
+                  replies: {
+                    nodes: [
+                      {
+                        databaseId: 2232922,
+                        createdAt: '2022-02-23T00:57:58Z',
+                        author: {
+                          login: 'reply-user',
                         },
-                      ],
-                    },
+                      },
+                    ],
+                  },
+                },
+                {
+                  databaseId: 2232921,
+                  createdAt: '2022-02-23T00:57:49Z',
+                  author: {
+                    login: 'comment-user',
+                  },
+                  replies: {
+                    nodes: [],
                   },
-                  {
-                    databaseId: 2232921,
-                    createdAt: '2022-02-23T00:57:49Z',
-                    author: {
-                      login: 'comment-user',
-                    },
-                    replies: {
-                      nodes: [],
-                    },
+                },
+                {
+                  databaseId: 2258799,
+                  createdAt: '2022-02-27T01:22:20Z',
+                  author: {
+                    login: 'comment-user',
                   },
-                  {
-                    databaseId: 2258799,
-                    createdAt: '2022-02-27T01:22:20Z',
-                    author: {
-                      login: 'comment-user',
-                    },
-                    replies: {
-                      nodes: [
-                        {
-                          databaseId: 2300902,
-                          createdAt: '2022-03-05T17:43:52Z',
-                          author: {
-                            login: 'reply-user',
-                          },
+                  replies: {
+                    nodes: [
+                      {
+                        databaseId: 2300902,
+                        createdAt: '2022-03-05T17:43:52Z',
+                        author: {
+                          login: 'reply-user',
                         },
-                      ],
-                    },
+                      },
+                    ],
                   },
-                  {
-                    databaseId: 2297637,
-                    createdAt: '2022-03-04T20:39:44Z',
-                    author: {
-                      login: 'comment-user',
-                    },
-                    replies: {
-                      nodes: [
-                        {
-                          databaseId: 2300893,
-                          createdAt: '2022-03-05T17:41:04Z',
-                          author: {
-                            login: 'reply-user',
-                          },
+                },
+                {
+                  databaseId: 2297637,
+                  createdAt: '2022-03-04T20:39:44Z',
+                  author: {
+                    login: 'comment-user',
+                  },
+                  replies: {
+                    nodes: [
+                      {
+                        databaseId: 2300893,
+                        createdAt: '2022-03-05T17:41:04Z',
+                        author: {
+                          login: 'reply-user',
                         },
-                      ],
-                    },
+                      },
+                    ],
+                  },
+                },
+                {
+                  databaseId: 2299763,
+                  createdAt: '2022-03-05T11:05:42Z',
+                  author: {
+                    login: 'comment-user',
                   },
-                  {
-                    databaseId: 2299763,
-                    createdAt: '2022-03-05T11:05:42Z',
-                    author: {
-                      login: 'comment-user',
-                    },
-                    replies: {
-                      nodes: [
-                        {
-                          databaseId: 2300895,
-                          createdAt: '2022-03-05T17:41:44Z',
-                          author: {
-                            login: 'reply-user',
-                          },
+                  replies: {
+                    nodes: [
+                      {
+                        databaseId: 2300895,
+                        createdAt: '2022-03-05T17:41:44Z',
+                        author: {
+                          login: 'reply-user',
                         },
-                      ],
-                    },
+                      },
+                    ],
                   },
-                ],
-              },
+                },
+              ],
             },
-          ],
-        },
+          },
+        ],
       },
     },
-  };
+  },
+};
diff --git a/src/routes/Settings.tsx b/src/routes/Settings.tsx
index 6c3c77b3..c811940e 100644
--- a/src/routes/Settings.tsx
+++ b/src/routes/Settings.tsx
@@ -20,7 +20,7 @@ import { AppContext } from '../context/App';
 import { Appearance } from '../types';
 import { apiRequestAuth } from '../utils/api-requests';
 import { setAppearance } from '../utils/appearance';
-import { updateTrayIcon } from '../utils/comms';
+import { openExternalLink, updateTrayIcon } from '../utils/comms';
 import Constants from '../utils/constants';
 import { generateGitHubAPIUrl } from '../utils/helpers';
 
@@ -32,6 +32,12 @@ export const SettingsRoute: React.FC = () => {
   const [appVersion, setAppVersion] = useState<string | null>(null);
   const [colorScope, setColorScope] = useState<boolean>(false);
 
+  const openGitHubReleaseNotes = useCallback((version) => {
+    openExternalLink(
+      `https://github.com/${Constants.REPO_SLUG}/releases/tag/v${version}`,
+    );
+  }, []);
+
   useEffect(() => {
     ipcRenderer.invoke('get-platform').then((result: string) => {
       setIsLinux(result === 'linux');
@@ -166,8 +172,13 @@ export const SettingsRoute: React.FC = () => {
       </div>
 
       <div className="flex justify-between items-center bg-gray-200 dark:bg-gray-darker py-4 px-8">
-        <small className="font-semibold">Gitify v{appVersion}</small>
-
+        <small
+          className="font-semibold cursor-pointer"
+          title="View release notes"
+          onClick={() => openGitHubReleaseNotes(appVersion)}
+        >
+          Gitify v{appVersion}
+        </small>
         <div>
           <button
             className={footerButtonClass}
diff --git a/src/typesGithub.ts b/src/typesGithub.ts
index 86393325..2c640ef8 100644
--- a/src/typesGithub.ts
+++ b/src/typesGithub.ts
@@ -327,32 +327,26 @@ export interface GraphQLSearch<T> {
   };
 }
 
-export interface DiscussionSearchResultNode {
+export interface Discussion {
   viewerSubscription: ViewerSubscription;
   title: string;
   stateReason: DiscussionStateType;
   isAnswered: boolean;
   url: string;
   comments: {
-    nodes: DiscussionCommentNode[];
+    nodes: DiscussionComment[];
   };
 }
 
-export interface DiscussionCommentNode {
+export interface DiscussionComment {
   databaseId: string | number;
   createdAt: string;
   author: DiscussionAuthor;
-  replies: {
-    nodes: DiscussionSubcommentNode[];
+  replies?: {
+    nodes: DiscussionComment[];
   };
 }
 
-export interface DiscussionSubcommentNode {
-  databaseId: string | number;
-  createdAt: string;
-  author: DiscussionAuthor;
-}
-
 export interface CheckSuiteAttributes {
   workflowName: string;
   attemptNumber?: number;
diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts
index 016605e8..91d1dd9f 100644
--- a/src/utils/helpers.ts
+++ b/src/utils/helpers.ts
@@ -2,12 +2,11 @@ import { EnterpriseAccount, AuthState } from '../types';
 import {
   Notification,
   GraphQLSearch,
-  DiscussionCommentNode,
-  DiscussionSearchResultNode,
+  Discussion,
   PullRequest,
   Issue,
   IssueComments,
-  DiscussionSubcommentNode,
+  DiscussionComment,
 } from '../typesGithub';
 import { apiRequestAuth } from '../utils/api-requests';
 import { openExternalLink } from '../utils/comms';
@@ -149,10 +148,22 @@ async function getDiscussionUrl(
 export async function fetchDiscussion(
   notification: Notification,
   token: string,
-): Promise<DiscussionSearchResultNode | null> {
-  const response: GraphQLSearch<DiscussionSearchResultNode> =
-    await apiRequestAuth(`https://api.github.com/graphql`, 'POST', token, {
-      query: `query fetchDiscussions(
+): Promise<Discussion | null> {
+  const response: GraphQLSearch<Discussion> = await apiRequestAuth(
+    `https://api.github.com/graphql`,
+    'POST',
+    token,
+    {
+      query: `
+        fragment CommentFields on DiscussionComment {
+          databaseId
+          createdAt
+          author {
+            login
+          }
+        }
+      
+        query fetchDiscussions(
           $queryStatement: String!,
           $type: SearchType!,
           $firstDiscussions: Int,
@@ -169,18 +180,10 @@ export async function fetchDiscussion(
                 url
                 comments(last: $lastComments){
                   nodes {
-                    databaseId
-                    createdAt
-                    author {
-                      login
-                    }
+                    ...CommentFields
                     replies(last: $firstReplies) {
                       nodes {
-                        databaseId
-                        createdAt
-                        author {
-                          login
-                        }
+                        ...CommentFields
                       }
                     }
                   }
@@ -201,7 +204,8 @@ export async function fetchDiscussion(
         lastComments: 100,
         firstReplies: 1,
       },
-    });
+    },
+  );
 
   let discussions =
     response?.data?.data.search.nodes.filter(
@@ -217,8 +221,8 @@ export async function fetchDiscussion(
 }
 
 export function getLatestDiscussionComment(
-  comments: DiscussionCommentNode[],
-): DiscussionSubcommentNode | null {
+  comments: DiscussionComment[],
+): DiscussionComment | null {
   if (!comments || comments.length == 0) {
     return null;
   }


Test patch:
diff --git a/src/routes/Settings.test.tsx b/src/routes/Settings.test.tsx
index fedbd5c7..d0b71382 100644
--- a/src/routes/Settings.test.tsx
+++ b/src/routes/Settings.test.tsx
@@ -10,6 +10,7 @@ import { AppContext } from '../context/App';
 import * as apiRequests from '../utils/api-requests';
 import Constants from '../utils/constants';
 import { SettingsRoute } from './Settings';
+import { shell } from 'electron';
 
 const mockNavigate = jest.fn();
 jest.mock('react-router-dom', () => ({
@@ -390,4 +391,30 @@ describe('routes/Settings.tsx', () => {
       ).parentNode.parentNode,
     ).toMatchSnapshot();
   });
+
+  it('should open release notes', async () => {
+    let getByTitle;
+
+    await act(async () => {
+      const { getByTitle: getByTitleLocal } = render(
+        <AppContext.Provider
+          value={{
+            settings: mockSettings,
+            accounts: mockAccounts,
+          }}
+        >
+          <MemoryRouter>
+            <SettingsRoute />
+          </MemoryRouter>
+        </AppContext.Provider>,
+      );
+      getByTitle = getByTitleLocal;
+    });
+
+    fireEvent.click(getByTitle('View release notes'));
+    expect(shell.openExternal).toHaveBeenCalledTimes(1);
+    expect(shell.openExternal).toHaveBeenCalledWith(
+      'https://github.com/gitify-app/gitify/releases/tag/v0.0.1',
+    );
+  });
 });
diff --git a/src/routes/__snapshots__/Settings.test.tsx.snap b/src/routes/__snapshots__/Settings.test.tsx.snap
index 0ed966e7..6778ba75 100644
--- a/src/routes/__snapshots__/Settings.test.tsx.snap
+++ b/src/routes/__snapshots__/Settings.test.tsx.snap
@@ -281,7 +281,8 @@ exports[`routes/Settings.tsx should render itself & its children 1`] = `
     class="flex justify-between items-center bg-gray-200 dark:bg-gray-darker py-4 px-8"
   >
     <small
-      class="font-semibold"
+      class="font-semibold cursor-pointer"
+      title="View release notes"
     >
       Gitify v
       0.0.1