Repository: gitify-app/gitify
Pull request #885 (2024-03-15 11:26:29)

refactor(icons): use standard octicons
Replaces the refresh, settings, logout and add account icons with those from the octicons primer design system used extensively throughout our experience.

~Note: if we can find a suitable replacement for the Quit icon from https://primer.style/foundations/icons then we'll be 100% octicon powered.~

| | Light | Dark |
|-|-|-|
| **_Before_** | ![Screenshot 2024-03-15 at 7 21 30 AM](https://github.com/gitify-app/gitify/assets/386277/daf68afb-0016-4c76-866b-ec0483d98602) |  ![Screenshot 2024-03-15 at 7 21 38 AM](https://github.com/gitify-app/gitify/assets/386277/d69265c6-f9a3-43ec-bd2d-0967a46b8e41) |
| **_After_**  |  <img width="498" alt="Screenshot 2024-03-19 at 2 49 50 AM" src="https://github.com/gitify-app/gitify/assets/386277/1097e7b6-5e57-45a3-8185-7548e1df7596"> |  <img width="498" alt="Screenshot 2024-03-19 at 2 49 38 AM" src="https://github.com/gitify-app/gitify/assets/386277/d5f8e791-fc65-4ef7-bd35-8da5137676f5"> |

bmulholland: For the Quit icon, how about just an X? I know we use it elsewhere, but it's pretty standard for "close this app" and is in Octicons.
afonsojramos: I'm glad that we're now grouping them in one PR, because I truly dislike these new icons. I understand the objective here, but they just look plain ugly and the app just doesn't look right with the change.
afonsojramos: > I think that grouping these changes all in one PR truly gave us a new perspective in what the changes would entail.
> 
> From a UI cohesiveness perspective, they seem as if they don't belong, mostly the ones in the bottom bar. The size of the bottom bar also seems to have grown, but that seems like a simple mistake.
> 
> Food for thought: Maybe one alternative would be to go away with the bottom bar and adding a profile image with a dropdown with these three options, where the icons would be accompanied with a descriptive text. What do you think?

Rephrased for the sake of being more clear about the issues I see with the current change.
setchy: > The size of the bottom bar also seems to have grown, but that seems like a simple mistake.

yes, that had stuck out to me too. adjust
setchy: > Food for thought: Maybe one alternative would be to go away with the bottom bar and adding a profile image with a dropdown with these three options, where the icons would be accompanied with a descriptive text. What do you think?

i'm not a huge fan of putting these an additional click away (behind a dropdown)
setchy: > From a UI cohesiveness perspective, they seem as if they don't belong, mostly the ones in the bottom bar.

Personal taste perhaps.  🤷  

imho, this switch to fully adopt Octicons / Primer Design System makes Gitify feel more consistent and unified 🙃 

Patch:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 98284a76..2bdc0c8d 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -4,6 +4,7 @@ on:
   push:
     branches:
       - 'release/v**'
+  workflow_dispatch: #For manually running release process to verify codesigning of artifacts
 
 jobs:
   release-macos:
@@ -31,6 +32,11 @@ jobs:
           CSC_KEY_PASSWORD: ${{ secrets.mac_certs_password }}
           GH_TOKEN: ${{ secrets.gh_token }}
           NOTARIZE: true
+      - uses: actions/upload-artifact@v4
+        with:
+          name: Gitify-release-mac
+          path: dist/
+          overwrite: true
 
   release-windows:
     name: Publish Windows (electron-builder)
@@ -51,6 +57,11 @@ jobs:
       - run: pnpm make:win --publish onTagOrDraft
         env:
           GH_TOKEN: ${{ secrets.gh_token }}
+      - uses: actions/upload-artifact@v4
+        with:
+          name: Gitify-release-win
+          path: dist/
+          overwrite: true
 
   release-linux:
     name: Publish Linux (electron-builder)
@@ -71,3 +82,8 @@ jobs:
       - run: pnpm make:linux --publish onTagOrDraft
         env:
           GH_TOKEN: ${{ secrets.gh_token }}
+      - uses: actions/upload-artifact@v4
+        with:
+          name: Gitify-release-linux
+          path: dist/
+          overwrite: true
diff --git a/package.json b/package.json
index a84432a2..0d0dedf7 100644
--- a/package.json
+++ b/package.json
@@ -103,7 +103,7 @@
   },
   "dependencies": {
     "@electron/remote": "2.1.2",
-    "@primer/octicons-react": "19.8.0",
+    "@primer/octicons-react": "19.9.0",
     "axios": "1.6.8",
     "date-fns": "3.6.0",
     "electron-updater": "6.1.8",
@@ -120,23 +120,23 @@
   },
   "devDependencies": {
     "@electron/notarize": "2.3.0",
-    "@testing-library/react": "14.2.1",
+    "@testing-library/react": "14.2.2",
     "@types/jest": "29.5.12",
-    "@types/node": "20.11.28",
+    "@types/node": "20.11.30",
     "@types/nprogress": "0.2.3",
-    "@types/react": "18.2.66",
+    "@types/react": "18.2.67",
     "@types/react-router-dom": "5.3.3",
     "@types/react-test-renderer": "18.0.7",
     "@types/react-transition-group": "4.4.10",
     "autoprefixer": "10.4.18",
     "css-loader": "6.10.0",
-    "electron": "29.1.4",
+    "electron": "19.1.9",
     "electron-builder": "24.13.3",
     "husky": "9.0.11",
     "jest": "29.7.0",
     "jest-environment-jsdom": "29.7.0",
     "nock": "13.5.4",
-    "postcss": "8.4.36",
+    "postcss": "8.4.37",
     "postcss-loader": "8.1.1",
     "prettier": "3.2.5",
     "react-test-renderer": "18.2.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 23f57bc3..26737f8e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -10,10 +10,10 @@ overrides:
 dependencies:
   '@electron/remote':
     specifier: 2.1.2
-    version: 2.1.2(electron@29.1.4)
+    version: 2.1.2(electron@19.1.9)
   '@primer/octicons-react':
-    specifier: 19.8.0
-    version: 19.8.0(react@18.2.0)
+    specifier: 19.9.0
+    version: 19.9.0(react@18.2.0)
   axios:
     specifier: 1.6.8
     version: 1.6.8
@@ -28,7 +28,7 @@ dependencies:
     version: 4.20.10
   menubar:
     specifier: 9.4.0
-    version: 9.4.0(electron@29.1.4)
+    version: 9.4.0(electron@19.1.9)
   nprogress:
     specifier: 0.2.0
     version: 0.2.0
@@ -59,20 +59,20 @@ devDependencies:
     specifier: 2.3.0
     version: 2.3.0
   '@testing-library/react':
-    specifier: 14.2.1
-    version: 14.2.1(react-dom@18.2.0)(react@18.2.0)
+    specifier: 14.2.2
+    version: 14.2.2(react-dom@18.2.0)(react@18.2.0)
   '@types/jest':
     specifier: 29.5.12
     version: 29.5.12
   '@types/node':
-    specifier: 20.11.28
-    version: 20.11.28
+    specifier: 20.11.30
+    version: 20.11.30
   '@types/nprogress':
     specifier: 0.2.3
     version: 0.2.3
   '@types/react':
-    specifier: 18.2.66
-    version: 18.2.66
+    specifier: 18.2.67
+    version: 18.2.67
   '@types/react-router-dom':
     specifier: 5.3.3
     version: 5.3.3
@@ -84,13 +84,13 @@ devDependencies:
     version: 4.4.10
   autoprefixer:
     specifier: 10.4.18
-    version: 10.4.18(postcss@8.4.36)
+    version: 10.4.18(postcss@8.4.37)
   css-loader:
     specifier: 6.10.0
     version: 6.10.0(webpack@5.90.3)
   electron:
-    specifier: 29.1.4
-    version: 29.1.4
+    specifier: 19.1.9
+    version: 19.1.9
   electron-builder:
     specifier: 24.13.3
     version: 24.13.3(electron-builder-squirrel-windows@24.13.3)
@@ -99,7 +99,7 @@ devDependencies:
     version: 9.0.11
   jest:
     specifier: 29.7.0
-    version: 29.7.0(@types/node@20.11.28)
+    version: 29.7.0(@types/node@20.11.30)
   jest-environment-jsdom:
     specifier: 29.7.0
     version: 29.7.0
@@ -107,11 +107,11 @@ devDependencies:
     specifier: 13.5.4
     version: 13.5.4
   postcss:
-    specifier: 8.4.36
-    version: 8.4.36
+    specifier: 8.4.37
+    version: 8.4.37
   postcss-loader:
     specifier: 8.1.1
-    version: 8.1.1(postcss@8.4.36)(typescript@5.4.2)(webpack@5.90.3)
+    version: 8.1.1(postcss@8.4.37)(typescript@5.4.2)(webpack@5.90.3)
   prettier:
     specifier: 3.2.5
     version: 3.2.5
@@ -184,7 +184,7 @@ packages:
     engines: {node: '>=6.9.0'}
     dependencies:
       '@ampproject/remapping': 2.2.1
-      '@babel/code-frame': 7.21.4
+      '@babel/code-frame': 7.23.5
       '@babel/generator': 7.21.5
       '@babel/helper-compilation-targets': 7.21.5(@babel/core@7.21.8)
       '@babel/helper-module-transforms': 7.21.5
@@ -276,7 +276,7 @@ packages:
       '@babel/helper-module-imports': 7.21.4
       '@babel/helper-simple-access': 7.21.5
       '@babel/helper-split-export-declaration': 7.18.6
-      '@babel/helper-validator-identifier': 7.19.1
+      '@babel/helper-validator-identifier': 7.22.20
       '@babel/template': 7.20.7
       '@babel/traverse': 7.24.0
       '@babel/types': 7.21.5
@@ -519,7 +519,7 @@ packages:
     resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/code-frame': 7.21.4
+      '@babel/code-frame': 7.23.5
       '@babel/parser': 7.21.8
       '@babel/types': 7.21.5
     dev: true
@@ -556,7 +556,7 @@ packages:
     engines: {node: '>=6.9.0'}
     dependencies:
       '@babel/helper-string-parser': 7.21.5
-      '@babel/helper-validator-identifier': 7.19.1
+      '@babel/helper-validator-identifier': 7.22.20
       to-fast-properties: 2.0.0
     dev: true
 
@@ -595,19 +595,20 @@ packages:
       minimatch: 3.1.2
     dev: true
 
-  /@electron/get@2.0.3:
-    resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==}
-    engines: {node: '>=12'}
+  /@electron/get@1.14.1:
+    resolution: {integrity: sha512-BrZYyL/6m0ZXz/lDxy/nlVhQz+WF+iPS6qXolEU8atw7h6v1aYkjwJZ63m+bJMBTxDE66X+r2tPS4a/8C82sZw==}
+    engines: {node: '>=8.6'}
     dependencies:
       debug: 4.3.4
       env-paths: 2.2.1
       fs-extra: 8.1.0
-      got: 11.8.6
+      got: 9.6.0
       progress: 2.0.3
       semver: 6.3.1
       sumchecker: 3.0.1
     optionalDependencies:
       global-agent: 3.0.0
+      global-tunnel-ng: 2.7.1
     transitivePeerDependencies:
       - supports-color
 
@@ -648,12 +649,12 @@ packages:
       - supports-color
     dev: true
 
-  /@electron/remote@2.1.2(electron@29.1.4):
+  /@electron/remote@2.1.2(electron@19.1.9):
     resolution: {integrity: sha512-EPwNx+nhdrTBxyCqXt/pftoQg/ybtWDW3DUWHafejvnB1ZGGfMpv6e15D8KeempocjXe78T7WreyGGb3mlZxdA==}
     peerDependencies:
       electron: '>= 13.0.0'
     dependencies:
-      electron: 29.1.4
+      electron: 19.1.9
     dev: false
 
   /@electron/universal@1.5.1:
@@ -704,7 +705,7 @@ packages:
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
     dependencies:
       '@jest/types': 29.6.3
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       chalk: 4.1.2
       jest-message-util: 29.7.0
       jest-util: 29.7.0
@@ -725,14 +726,14 @@ packages:
       '@jest/test-result': 29.7.0
       '@jest/transform': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       ansi-escapes: 4.3.2
       chalk: 4.1.2
       ci-info: 3.8.0
       exit: 0.1.2
       graceful-fs: 4.2.11
       jest-changed-files: 29.7.0
-      jest-config: 29.7.0(@types/node@20.11.28)
+      jest-config: 29.7.0(@types/node@20.11.30)
       jest-haste-map: 29.7.0
       jest-message-util: 29.7.0
       jest-regex-util: 29.6.3
@@ -760,7 +761,7 @@ packages:
     dependencies:
       '@jest/fake-timers': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       jest-mock: 29.7.0
     dev: true
 
@@ -787,7 +788,7 @@ packages:
     dependencies:
       '@jest/types': 29.6.3
       '@sinonjs/fake-timers': 10.3.0
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       jest-message-util: 29.7.0
       jest-mock: 29.7.0
       jest-util: 29.7.0
@@ -820,7 +821,7 @@ packages:
       '@jest/transform': 29.7.0
       '@jest/types': 29.6.3
       '@jridgewell/trace-mapping': 0.3.18
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       chalk: 4.1.2
       collect-v8-coverage: 1.0.1
       exit: 0.1.2
@@ -908,7 +909,7 @@ packages:
       '@jest/schemas': 29.6.3
       '@types/istanbul-lib-coverage': 2.0.4
       '@types/istanbul-reports': 3.0.1
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       '@types/yargs': 17.0.25
       chalk: 4.1.2
     dev: true
@@ -1002,8 +1003,8 @@ packages:
     dev: true
     optional: true
 
-  /@primer/octicons-react@19.8.0(react@18.2.0):
-    resolution: {integrity: sha512-2Z+D7xTloFTLQVRUEbg0pQpe6aTL9RR+8RqBhjkrF+BFuVdM1ENOyjywaGEO7DIkPU5Zxlv0gxSlD85LQxL+sw==}
+  /@primer/octicons-react@19.9.0(react@18.2.0):
+    resolution: {integrity: sha512-Uk4XrHyfylyfzZN9d8VFjF8FpfYHEyT4sabw+9+oP+GWAJHhPvNPTz6gXvUzJZmoblAvgcTrDslIPjz8zMh76w==}
     engines: {node: '>=8'}
     peerDependencies:
       react: '>=16.3'
@@ -1020,9 +1021,9 @@ packages:
     resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
     dev: true
 
-  /@sindresorhus/is@4.6.0:
-    resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
-    engines: {node: '>=10'}
+  /@sindresorhus/is@0.14.0:
+    resolution: {integrity: sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==}
+    engines: {node: '>=6'}
 
   /@sinonjs/commons@3.0.0:
     resolution: {integrity: sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==}
@@ -1036,17 +1037,17 @@ packages:
       '@sinonjs/commons': 3.0.0
     dev: true
 
-  /@szmarczak/http-timer@4.0.6:
-    resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==}
-    engines: {node: '>=10'}
+  /@szmarczak/http-timer@1.1.2:
+    resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==}
+    engines: {node: '>=6'}
     dependencies:
-      defer-to-connect: 2.0.1
+      defer-to-connect: 1.1.3
 
   /@testing-library/dom@9.3.3:
     resolution: {integrity: sha512-fB0R+fa3AUqbLHWyxXa2kGVtf1Fe1ZZFr0Zp6AIbIAzXb2mKbEXl+PCQNUOaq5lbTab5tfctfXRNsWXxa2f7Aw==}
     engines: {node: '>=14'}
     dependencies:
-      '@babel/code-frame': 7.21.4
+      '@babel/code-frame': 7.23.5
       '@babel/runtime': 7.21.5
       '@types/aria-query': 5.0.2
       aria-query: 5.1.3
@@ -1056,8 +1057,8 @@ packages:
       pretty-format: 27.5.1
     dev: true
 
-  /@testing-library/react@14.2.1(react-dom@18.2.0)(react@18.2.0):
-    resolution: {integrity: sha512-sGdjws32ai5TLerhvzThYFbpnF9XtL65Cjf+gB0Dhr29BGqK+mAeN7SURSdu+eqgET4ANcWoC7FQpkaiGvBr+A==}
+  /@testing-library/react@14.2.2(react-dom@18.2.0)(react@18.2.0):
+    resolution: {integrity: sha512-SOUuM2ysCvjUWBXTNfQ/ztmnKDmqaiPV3SvoIuyxMUca45rbSWWAT/qB8CUs/JQ/ux/8JFs9DNdFQ3f6jH3crA==}
     engines: {node: '>=14'}
     peerDependencies:
       react: ^18.0.0
@@ -1108,14 +1109,6 @@ packages:
       '@babel/types': 7.21.5
     dev: true
 
-  /@types/cacheable-request@6.0.3:
-    resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==}
-    dependencies:
-      '@types/http-cache-semantics': 4.0.4
-      '@types/keyv': 3.1.4
-      '@types/node': 20.11.28
-      '@types/responselike': 1.0.3
-
   /@types/debug@4.1.7:
     resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==}
     dependencies:
@@ -1140,22 +1133,19 @@ packages:
   /@types/fs-extra@9.0.13:
     resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==}
     dependencies:
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
     dev: true
 
   /@types/graceful-fs@4.1.6:
     resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==}
     dependencies:
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
     dev: true
 
   /@types/history@4.7.11:
     resolution: {integrity: sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==}
     dev: true
 
-  /@types/http-cache-semantics@4.0.4:
-    resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
-
   /@types/istanbul-lib-coverage@2.0.4:
     resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==}
     dev: true
@@ -1182,7 +1172,7 @@ packages:
   /@types/jsdom@20.0.1:
     resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==}
     dependencies:
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       '@types/tough-cookie': 4.0.5
       parse5: 7.1.2
     dev: true
@@ -1193,14 +1183,17 @@ packages:
   /@types/keyv@3.1.4:
     resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
     dependencies:
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
 
   /@types/ms@0.7.31:
     resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==}
     dev: true
 
-  /@types/node@20.11.28:
-    resolution: {integrity: sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==}
+  /@types/node@16.18.91:
+    resolution: {integrity: sha512-h8Q4klc8xzc9kJKr7UYNtJde5TU2qEePVyH3WyzJaUC+3ptyc5kPQbWOIUcn8ZsG5+KSkq+P0py0kC0VqxgAXw==}
+
+  /@types/node@20.11.30:
+    resolution: {integrity: sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==}
     dependencies:
       undici-types: 5.26.5
 
@@ -1212,7 +1205,7 @@ packages:
     resolution: {integrity: sha512-ULqvZNGMv0zRFvqn8/4LSPtnmN4MfhlPNtJCTpKuIIxGVGZ2rYWzFXrvEBoh9CVyqSE7D6YFRJ1hydLHI6kbWw==}
     requiresBuild: true
     dependencies:
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       xmlbuilder: 15.1.1
     dev: true
     optional: true
@@ -1224,14 +1217,14 @@ packages:
   /@types/react-dom@18.2.8:
     resolution: {integrity: sha512-bAIvO5lN/U8sPGvs1Xm61rlRHHaq5rp5N3kp9C+NJ/Q41P8iqjkXSu0+/qu8POsjH9pNWb0OYabFez7taP7omw==}
     dependencies:
-      '@types/react': 18.2.66
+      '@types/react': 18.2.67
     dev: true
 
   /@types/react-router-dom@5.3.3:
     resolution: {integrity: sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==}
     dependencies:
       '@types/history': 4.7.11
-      '@types/react': 18.2.66
+      '@types/react': 18.2.67
       '@types/react-router': 5.1.20
     dev: true
 
@@ -1239,23 +1232,23 @@ packages:
     resolution: {integrity: sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==}
     dependencies:
       '@types/history': 4.7.11
-      '@types/react': 18.2.66
+      '@types/react': 18.2.67
     dev: true
 
   /@types/react-test-renderer@18.0.7:
     resolution: {integrity: sha512-1+ANPOWc6rB3IkSnElhjv6VLlKg2dSv/OWClUyZimbLsQyBn8Js9Vtdsi3UICJ2rIQ3k2la06dkB+C92QfhKmg==}
     dependencies:
-      '@types/react': 18.2.66
+      '@types/react': 18.2.67
     dev: true
 
   /@types/react-transition-group@4.4.10:
     resolution: {integrity: sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==}
     dependencies:
-      '@types/react': 18.2.66
+      '@types/react': 18.2.67
     dev: true
 
-  /@types/react@18.2.66:
-    resolution: {integrity: sha512-OYTmMI4UigXeFMF/j4uv0lBBEbongSgptPrHBxqME44h9+yNov+oL6Z3ocJKo0WyXR84sQUNeyIp9MRfckvZpg==}
+  /@types/react@18.2.67:
+    resolution: {integrity: sha512-vkIE2vTIMHQ/xL0rgmuoECBCkZFZeHr49HeWSc24AptMbNRo7pwSBvj73rlJJs9fGKj0koS+V7kQB1jHS0uCgw==}
     dependencies:
       '@types/prop-types': 15.7.5
       '@types/scheduler': 0.16.4
@@ -1265,7 +1258,7 @@ packages:
   /@types/responselike@1.0.3:
     resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==}
     dependencies:
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
 
   /@types/scheduler@0.16.4:
     resolution: {integrity: sha512-2L9ifAGl7wmXwP4v3pN4p2FLhD0O1qsJpvKmNin5VA8+UvNVb447UDaAEV6UdrkA+m/Xs58U1RFps44x6TFsVQ==}
@@ -1295,13 +1288,6 @@ packages:
       '@types/yargs-parser': 21.0.0
     dev: true
 
-  /@types/yauzl@2.10.3:
-    resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
-    requiresBuild: true
-    dependencies:
-      '@types/node': 20.11.28
-    optional: true
-
   /@webassemblyjs/ast@1.11.6:
     resolution: {integrity: sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==}
     dependencies:
@@ -1684,7 +1670,7 @@ packages:
     engines: {node: '>= 4.0.0'}
     dev: true
 
-  /autoprefixer@10.4.18(postcss@8.4.36):
+  /autoprefixer@10.4.18(postcss@8.4.37):
     resolution: {integrity: sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g==}
     engines: {node: ^10 || ^12 || >=14}
     hasBin: true
@@ -1696,7 +1682,7 @@ packages:
       fraction.js: 4.3.7
       normalize-range: 0.1.2
       picocolors: 1.0.0
-      postcss: 8.4.36
+      postcss: 8.4.37
       postcss-value-parser: 4.2.0
     dev: true
 
@@ -1939,21 +1925,17 @@ packages:
       - supports-color
     dev: true
 
-  /cacheable-lookup@5.0.4:
-    resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==}
-    engines: {node: '>=10.6.0'}
-
-  /cacheable-request@7.0.4:
-    resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==}
+  /cacheable-request@6.1.0:
+    resolution: {integrity: sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==}
     engines: {node: '>=8'}
     dependencies:
       clone-response: 1.0.3
       get-stream: 5.2.0
       http-cache-semantics: 4.1.1
-      keyv: 4.5.4
+      keyv: 3.1.0
       lowercase-keys: 2.0.0
-      normalize-url: 6.1.0
-      responselike: 2.0.1
+      normalize-url: 4.5.1
+      responselike: 1.0.2
 
   /call-bind@1.0.2:
     resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
@@ -2154,6 +2136,23 @@ packages:
     resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
     dev: true
 
+  /concat-stream@1.6.2:
+    resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==}
+    engines: {'0': node >= 0.8}
+    dependencies:
+      buffer-from: 1.1.2
+      inherits: 2.0.4
+      readable-stream: 2.3.8
+      typedarray: 0.0.6
+
+  /config-chain@1.1.13:
+    resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
+    requiresBuild: true
+    dependencies:
+      ini: 1.3.8
+      proto-list: 1.2.4
+    optional: true
+
   /config-file-ts@0.2.4:
     resolution: {integrity: sha512-cKSW0BfrSaAUnxpgvpXPLaaW/umg4bqg4k3GO1JqlRfpx+d5W0GDXznCMkWotJQek5Mmz1MJVChQnz3IVaeMZQ==}
     dependencies:
@@ -2172,7 +2171,6 @@ packages:
   /core-util-is@1.0.2:
     resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
     requiresBuild: true
-    dev: true
 
   /cosmiconfig@9.0.0(typescript@5.4.2):
     resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==}
@@ -2212,7 +2210,7 @@ packages:
     dev: true
     optional: true
 
-  /create-jest@29.7.0(@types/node@20.11.28):
+  /create-jest@29.7.0(@types/node@20.11.30):
     resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
     hasBin: true
@@ -2221,7 +2219,7 @@ packages:
       chalk: 4.1.2
       exit: 0.1.2
       graceful-fs: 4.2.11
-      jest-config: 29.7.0(@types/node@20.11.28)
+      jest-config: 29.7.0(@types/node@20.11.30)
       jest-util: 29.7.0
       prompts: 2.4.2
     transitivePeerDependencies:
@@ -2251,12 +2249,12 @@ packages:
       webpack:
         optional: true
     dependencies:
-      icss-utils: 5.1.0(postcss@8.4.36)
-      postcss: 8.4.36
-      postcss-modules-extract-imports: 3.0.0(postcss@8.4.36)
-      postcss-modules-local-by-default: 4.0.4(postcss@8.4.36)
-      postcss-modules-scope: 3.1.1(postcss@8.4.36)
-      postcss-modules-values: 4.0.0(postcss@8.4.36)
+      icss-utils: 5.1.0(postcss@8.4.37)
+      postcss: 8.4.37
+      postcss-modules-extract-imports: 3.0.0(postcss@8.4.37)
+      postcss-modules-local-by-default: 4.0.4(postcss@8.4.37)
+      postcss-modules-scope: 3.1.1(postcss@8.4.37)
+      postcss-modules-values: 4.0.0(postcss@8.4.37)
       postcss-value-parser: 4.2.0
       semver: 7.5.4
       webpack: 5.90.3(webpack-cli@5.1.4)
@@ -2299,6 +2297,16 @@ packages:
     resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==}
     dev: false
 
+  /debug@2.6.9:
+    resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+    dependencies:
+      ms: 2.0.0
+
   /debug@4.3.4:
     resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
     engines: {node: '>=6.0'}
@@ -2314,11 +2322,11 @@ packages:
     resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
     dev: true
 
-  /decompress-response@6.0.0:
-    resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
-    engines: {node: '>=10'}
+  /decompress-response@3.3.0:
+    resolution: {integrity: sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==}
+    engines: {node: '>=4'}
     dependencies:
-      mimic-response: 3.1.0
+      mimic-response: 1.0.1
 
   /dedent@1.5.1:
     resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==}
@@ -2357,9 +2365,8 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
-  /defer-to-connect@2.0.1:
-    resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==}
-    engines: {node: '>=10'}
+  /defer-to-connect@1.1.3:
+    resolution: {integrity: sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==}
 
   /define-data-property@1.1.1:
     resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==}
@@ -2475,6 +2482,9 @@ packages:
     engines: {node: '>=10'}
     dev: true
 
+  /duplexer3@0.1.5:
+    resolution: {integrity: sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==}
+
   /eastasianwidth@0.2.0:
     resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
     dev: true
@@ -2560,15 +2570,15 @@ packages:
       - supports-color
     dev: false
 
-  /electron@29.1.4:
-    resolution: {integrity: sha512-IWXys0SqgmIfrqXusUGQC0gGG7CCqA5vfmNsUMj8dFkAnK3lisKyjSESStWlrsste/OX/AAC5wsVlf23reUNnw==}
-    engines: {node: '>= 12.20.55'}
+  /electron@19.1.9:
+    resolution: {integrity: sha512-XT5LkTzIHB+ZtD3dTmNnKjVBWrDWReCKt9G1uAFLz6uJMEVcIUiYO+fph5pLXETiBw/QZBx8egduMEfIccLx+g==}
+    engines: {node: '>= 8.6'}
     hasBin: true
     requiresBuild: true
     dependencies:
-      '@electron/get': 2.0.3
-      '@types/node': 20.11.28
-      extract-zip: 2.0.1
+      '@electron/get': 1.14.1
+      '@types/node': 16.18.91
+      extract-zip: 1.7.0
     transitivePeerDependencies:
       - supports-color
 
@@ -2586,6 +2596,12 @@ packages:
     resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
     dev: true
 
+  /encodeurl@1.0.2:
+    resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
+    engines: {node: '>= 0.8'}
+    requiresBuild: true
+    optional: true
+
   /end-of-stream@1.4.4:
     resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
     dependencies:
@@ -2743,16 +2759,14 @@ packages:
       jest-util: 29.7.0
     dev: true
 
-  /extract-zip@2.0.1:
-    resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==}
-    engines: {node: '>= 10.17.0'}
+  /extract-zip@1.7.0:
+    resolution: {integrity: sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==}
     hasBin: true
     dependencies:
-      debug: 4.3.4
-      get-stream: 5.2.0
+      concat-stream: 1.6.2
+      debug: 2.6.9
+      mkdirp: 0.5.6
       yauzl: 2.10.0
-    optionalDependencies:
-      '@types/yauzl': 2.10.3
     transitivePeerDependencies:
       - supports-color
 
@@ -2949,6 +2963,12 @@ packages:
     engines: {node: '>=8.0.0'}
     dev: true
 
+  /get-stream@4.1.0:
+    resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==}
+    engines: {node: '>=6'}
+    dependencies:
+      pump: 3.0.0
+
   /get-stream@5.2.0:
     resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
     engines: {node: '>=8'}
@@ -3024,6 +3044,17 @@ packages:
       serialize-error: 7.0.1
     optional: true
 
+  /global-tunnel-ng@2.7.1:
+    resolution: {integrity: sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==}
+    engines: {node: '>=0.10'}
+    requiresBuild: true
+    dependencies:
+      encodeurl: 1.0.2
+      lodash: 4.17.21
+      npm-conf: 1.1.3
+      tunnel: 0.0.6
+    optional: true
+
   /globals@11.12.0:
     resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
     engines: {node: '>=4'}
@@ -3042,21 +3073,23 @@ packages:
     dependencies:
       get-intrinsic: 1.2.2
 
-  /got@11.8.6:
-    resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==}
-    engines: {node: '>=10.19.0'}
+  /got@9.6.0:
+    resolution: {integrity: sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==}
+    engines: {node: '>=8.6'}
     dependencies:
-      '@sindresorhus/is': 4.6.0
-      '@szmarczak/http-timer': 4.0.6
-      '@types/cacheable-request': 6.0.3
+      '@sindresorhus/is': 0.14.0
+      '@szmarczak/http-timer': 1.1.2
+      '@types/keyv': 3.1.4
       '@types/responselike': 1.0.3
-      cacheable-lookup: 5.0.4
-      cacheable-request: 7.0.4
-      decompress-response: 6.0.0
-      http2-wrapper: 1.0.3
-      lowercase-keys: 2.0.0
-      p-cancelable: 2.1.1
-      responselike: 2.0.1
+      cacheable-request: 6.1.0
+      decompress-response: 3.3.0
+      duplexer3: 0.1.5
+      get-stream: 4.1.0
+      lowercase-keys: 1.0.1
+      mimic-response: 1.0.1
+      p-cancelable: 1.1.0
+      to-readable-stream: 1.0.0
+      url-parse-lax: 3.0.0
 
   /graceful-fs@4.2.11:
     resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
@@ -3142,13 +3175,6 @@ packages:
       - supports-color
     dev: true
 
-  /http2-wrapper@1.0.3:
-    resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==}
-    engines: {node: '>=10.19.0'}
-    dependencies:
-      quick-lru: 5.1.1
-      resolve-alpn: 1.2.1
-
   /https-proxy-agent@5.0.1:
     resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
     engines: {node: '>= 6'}
@@ -3188,13 +3214,13 @@ packages:
       safer-buffer: 2.1.2
     dev: true
 
-  /icss-utils@5.1.0(postcss@8.4.36):
+  /icss-utils@5.1.0(postcss@8.4.37):
     resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==}
     engines: {node: ^10 || ^12 || >= 14}
     peerDependencies:
       postcss: ^8.1.0
     dependencies:
-      postcss: 8.4.36
+      postcss: 8.4.37
     dev: true
 
   /ieee754@1.2.1:
@@ -3232,7 +3258,11 @@ packages:
 
   /inherits@2.0.4:
     resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
-    dev: true
+
+  /ini@1.3.8:
+    resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
+    requiresBuild: true
+    optional: true
 
   /internal-slot@1.0.5:
     resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==}
@@ -3417,7 +3447,6 @@ packages:
 
   /isarray@1.0.0:
     resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
-    dev: true
 
   /isarray@2.0.5:
     resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
@@ -3536,7 +3565,7 @@ packages:
       '@jest/expect': 29.7.0
       '@jest/test-result': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       chalk: 4.1.2
       co: 4.6.0
       dedent: 1.5.1
@@ -3557,7 +3586,7 @@ packages:
       - supports-color
     dev: true
 
-  /jest-cli@29.7.0(@types/node@20.11.28):
+  /jest-cli@29.7.0(@types/node@20.11.30):
     resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==}
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
     hasBin: true
@@ -3571,10 +3600,10 @@ packages:
       '@jest/test-result': 29.7.0
       '@jest/types': 29.6.3
       chalk: 4.1.2
-      create-jest: 29.7.0(@types/node@20.11.28)
+      create-jest: 29.7.0(@types/node@20.11.30)
       exit: 0.1.2
       import-local: 3.1.0
-      jest-config: 29.7.0(@types/node@20.11.28)
+      jest-config: 29.7.0(@types/node@20.11.30)
       jest-util: 29.7.0
       jest-validate: 29.7.0
       yargs: 17.7.2
@@ -3585,7 +3614,7 @@ packages:
       - ts-node
     dev: true
 
-  /jest-config@29.7.0(@types/node@20.11.28):
+  /jest-config@29.7.0(@types/node@20.11.30):
     resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==}
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
     peerDependencies:
@@ -3600,7 +3629,7 @@ packages:
       '@babel/core': 7.21.8
       '@jest/test-sequencer': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       babel-jest: 29.7.0(@babel/core@7.21.8)
       chalk: 4.1.2
       ci-info: 3.8.0
@@ -3666,7 +3695,7 @@ packages:
       '@jest/fake-timers': 29.7.0
       '@jest/types': 29.6.3
       '@types/jsdom': 20.0.1
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       jest-mock: 29.7.0
       jest-util: 29.7.0
       jsdom: 20.0.3
@@ -3683,7 +3712,7 @@ packages:
       '@jest/environment': 29.7.0
       '@jest/fake-timers': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       jest-mock: 29.7.0
       jest-util: 29.7.0
     dev: true
@@ -3699,7 +3728,7 @@ packages:
     dependencies:
       '@jest/types': 29.6.3
       '@types/graceful-fs': 4.1.6
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       anymatch: 3.1.3
       fb-watchman: 2.0.2
       graceful-fs: 4.2.11
@@ -3750,7 +3779,7 @@ packages:
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
     dependencies:
       '@jest/types': 29.6.3
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       jest-util: 29.7.0
     dev: true
 
@@ -3805,7 +3834,7 @@ packages:
       '@jest/test-result': 29.7.0
       '@jest/transform': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       chalk: 4.1.2
       emittery: 0.13.1
       graceful-fs: 4.2.11
@@ -3836,7 +3865,7 @@ packages:
       '@jest/test-result': 29.7.0
       '@jest/transform': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       chalk: 4.1.2
       cjs-module-lexer: 1.2.3
       collect-v8-coverage: 1.0.1
@@ -3888,7 +3917,7 @@ packages:
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
     dependencies:
       '@jest/types': 29.6.3
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       chalk: 4.1.2
       ci-info: 3.8.0
       graceful-fs: 4.2.11
@@ -3913,7 +3942,7 @@ packages:
     dependencies:
       '@jest/test-result': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       ansi-escapes: 4.3.2
       chalk: 4.1.2
       emittery: 0.13.1
@@ -3925,7 +3954,7 @@ packages:
     resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==}
     engines: {node: '>= 10.13.0'}
     dependencies:
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       merge-stream: 2.0.0
       supports-color: 8.1.1
 
@@ -3933,13 +3962,13 @@ packages:
     resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==}
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
     dependencies:
-      '@types/node': 20.11.28
+      '@types/node': 20.11.30
       jest-util: 29.7.0
       merge-stream: 2.0.0
       supports-color: 8.1.1
     dev: true
 
-  /jest@29.7.0(@types/node@20.11.28):
+  /jest@29.7.0(@types/node@20.11.30):
     resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==}
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
     hasBin: true
@@ -3952,7 +3981,7 @@ packages:
       '@jest/core': 29.7.0
       '@jest/types': 29.6.3
       import-local: 3.1.0
-      jest-cli: 29.7.0(@types/node@20.11.28)
+      jest-cli: 29.7.0(@types/node@20.11.30)
     transitivePeerDependencies:
       - '@types/node'
       - babel-plugin-macros
@@ -4029,8 +4058,8 @@ packages:
     hasBin: true
     dev: true
 
-  /json-buffer@3.0.1:
-    resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+  /json-buffer@3.0.0:
+    resolution: {integrity: sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==}
 
   /json-parse-even-better-errors@2.3.1:
     resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
@@ -4060,10 +4089,10 @@ packages:
     optionalDependencies:
       graceful-fs: 4.2.11
 
-  /keyv@4.5.4:
-    resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+  /keyv@3.1.0:
+    resolution: {integrity: sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==}
     dependencies:
-      json-buffer: 3.0.1
+      json-buffer: 3.0.0
 
   /kind-of@6.0.3:
     resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
@@ -4142,7 +4171,6 @@ packages:
 
   /lodash@4.17.21:
     resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
-    dev: true
 
   /loose-envify@1.4.0:
     resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
@@ -4150,6 +4178,10 @@ packages:
     dependencies:
       js-tokens: 4.0.0
 
+  /lowercase-keys@1.0.1:
+    resolution: {integrity: sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==}
+    engines: {node: '>=0.10.0'}
+
   /lowercase-keys@2.0.0:
     resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==}
     engines: {node: '>=8'}
@@ -4201,12 +4233,12 @@ packages:
       escape-string-regexp: 4.0.0
     optional: true
 
-  /menubar@9.4.0(electron@29.1.4):
+  /menubar@9.4.0(electron@19.1.9):
     resolution: {integrity: sha512-Zn2si5UXiWbdBZwFSsCyQ8xfaBKkeFYceNvjWATyMUreqv6gDMUvDkvZY/ZFf89DCfo9F0SrvygDOdpZuwoWgw==}
     peerDependencies:
       electron: ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0 ||  ^23.0.0 || ^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0
     dependencies:
-      electron: 29.1.4
+      electron: 19.1.9
       electron-positioner: 4.1.0
     dev: false
 
@@ -4250,10 +4282,6 @@ packages:
     resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==}
     engines: {node: '>=4'}
 
-  /mimic-response@3.1.0:
-    resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
-    engines: {node: '>=10'}
-
   /minimatch@3.1.2:
     resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
     dependencies:
@@ -4276,7 +4304,6 @@ packages:
 
   /minimist@1.2.8:
     resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
-    dev: true
 
   /minipass@3.3.6:
     resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
@@ -4298,12 +4325,21 @@ packages:
       yallist: 4.0.0
     dev: true
 
+  /mkdirp@0.5.6:
+    resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
+    hasBin: true
+    dependencies:
+      minimist: 1.2.8
+
   /mkdirp@1.0.4:
     resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
     engines: {node: '>=10'}
     hasBin: true
     dev: true
 
+  /ms@2.0.0:
+    resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
+
   /ms@2.1.2:
     resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
 
@@ -4362,9 +4398,18 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
-  /normalize-url@6.1.0:
-    resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==}
-    engines: {node: '>=10'}
+  /normalize-url@4.5.1:
+    resolution: {integrity: sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==}
+    engines: {node: '>=8'}
+
+  /npm-conf@1.1.3:
+    resolution: {integrity: sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==}
+    engines: {node: '>=4'}
+    requiresBuild: true
+    dependencies:
+      config-chain: 1.1.13
+      pify: 3.0.0
+    optional: true
 
   /npm-run-path@4.0.1:
     resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
@@ -4429,9 +4474,9 @@ packages:
       mimic-fn: 2.1.0
     dev: true
 
-  /p-cancelable@2.1.1:
-    resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==}
-    engines: {node: '>=8'}
+  /p-cancelable@1.1.0:
+    resolution: {integrity: sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==}
+    engines: {node: '>=6'}
 
   /p-limit@2.3.0:
     resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
@@ -4518,6 +4563,12 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
+  /pify@3.0.0:
+    resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==}
+    engines: {node: '>=4'}
+    requiresBuild: true
+    optional: true
+
   /pirates@4.0.5:
     resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==}
     engines: {node: '>= 6'}
@@ -4537,29 +4588,29 @@ packages:
       xmlbuilder: 15.1.1
     dev: true
 
-  /postcss-import@15.1.0(postcss@8.4.36):
+  /postcss-import@15.1.0(postcss@8.4.37):
     resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==}
     engines: {node: '>=14.0.0'}
     peerDependencies:
       postcss: ^8.0.0
     dependencies:
-      postcss: 8.4.36
+      postcss: 8.4.37
       postcss-value-parser: 4.2.0
       read-cache: 1.0.0
       resolve: 1.22.2
     dev: true
 
-  /postcss-js@4.0.1(postcss@8.4.36):
+  /postcss-js@4.0.1(postcss@8.4.37):
     resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
     engines: {node: ^12 || ^14 || >= 16}
     peerDependencies:
       postcss: ^8.4.21
     dependencies:
       camelcase-css: 2.0.1
-      postcss: 8.4.36
+      postcss: 8.4.37
     dev: true
 
-  /postcss-load-config@4.0.1(postcss@8.4.36):
+  /postcss-load-config@4.0.1(postcss@8.4.37):
     resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==}
     engines: {node: '>= 14'}
     peerDependencies:
@@ -4572,11 +4623,11 @@ packages:
         optional: true
     dependencies:
       lilconfig: 2.1.0
-      postcss: 8.4.36
+      postcss: 8.4.37
       yaml: 2.3.2
     dev: true
 
-  /postcss-loader@8.1.1(postcss@8.4.36)(typescript@5.4.2)(webpack@5.90.3):
+  /postcss-loader@8.1.1(postcss@8.4.37)(typescript@5.4.2)(webpack@5.90.3):
     resolution: {integrity: sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==}
     engines: {node: '>= 18.12.0'}
     peerDependencies:
@@ -4591,61 +4642,61 @@ packages:
     dependencies:
       cosmiconfig: 9.0.0(typescript@5.4.2)
       jiti: 1.20.0
-      postcss: 8.4.36
+      postcss: 8.4.37
       semver: 7.5.4
       webpack: 5.90.3(webpack-cli@5.1.4)
     transitivePeerDependencies:
       - typescript
     dev: true
 
-  /postcss-modules-extract-imports@3.0.0(postcss@8.4.36):
+  /postcss-modules-extract-imports@3.0.0(postcss@8.4.37):
     resolution: {integrity: sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==}
     engines: {node: ^10 || ^12 || >= 14}
     peerDependencies:
       postcss: ^8.1.0
     dependencies:
-      postcss: 8.4.36
+      postcss: 8.4.37
     dev: true
 
-  /postcss-modules-local-by-default@4.0.4(postcss@8.4.36):
+  /postcss-modules-local-by-default@4.0.4(postcss@8.4.37):
     resolution: {integrity: sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q==}
     engines: {node: ^10 || ^12 || >= 14}
     peerDependencies:
       postcss: ^8.1.0
     dependencies:
-      icss-utils: 5.1.0(postcss@8.4.36)
-      postcss: 8.4.36
+      icss-utils: 5.1.0(postcss@8.4.37)
+      postcss: 8.4.37
       postcss-selector-parser: 6.0.13
       postcss-value-parser: 4.2.0
     dev: true
 
-  /postcss-modules-scope@3.1.1(postcss@8.4.36):
+  /postcss-modules-scope@3.1.1(postcss@8.4.37):
     resolution: {integrity: sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA==}
     engines: {node: ^10 || ^12 || >= 14}
     peerDependencies:
       postcss: ^8.1.0
     dependencies:
-      postcss: 8.4.36
+      postcss: 8.4.37
       postcss-selector-parser: 6.0.13
     dev: true
 
-  /postcss-modules-values@4.0.0(postcss@8.4.36):
+  /postcss-modules-values@4.0.0(postcss@8.4.37):
     resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==}
     engines: {node: ^10 || ^12 || >= 14}
     peerDependencies:
       postcss: ^8.1.0
     dependencies:
-      icss-utils: 5.1.0(postcss@8.4.36)
-      postcss: 8.4.36
+      icss-utils: 5.1.0(postcss@8.4.37)
+      postcss: 8.4.37
     dev: true
 
-  /postcss-nested@6.0.1(postcss@8.4.36):
+  /postcss-nested@6.0.1(postcss@8.4.37):
     resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==}
     engines: {node: '>=12.0'}
     peerDependencies:
       postcss: ^8.2.14
     dependencies:
-      postcss: 8.4.36
+      postcss: 8.4.37
       postcss-selector-parser: 6.0.13
     dev: true
 
@@ -4661,15 +4712,19 @@ packages:
     resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
     dev: true
 
-  /postcss@8.4.36:
-    resolution: {integrity: sha512-/n7eumA6ZjFHAsbX30yhHup/IMkOmlmvtEi7P+6RMYf+bGJSUHc3geH4a0NSZxAz/RJfiS9tooCTs9LAVYUZKw==}
+  /postcss@8.4.37:
+    resolution: {integrity: sha512-7iB/v/r7Woof0glKLH8b1SPHrsX7uhdO+Geb41QpF/+mWZHU3uxxSlN+UXGVit1PawOYDToO+AbZzhBzWRDwbQ==}
     engines: {node: ^10 || ^12 || >=14}
     dependencies:
       nanoid: 3.3.7
       picocolors: 1.0.0
-      source-map-js: 1.1.0
+      source-map-js: 1.2.0
     dev: true
 
+  /prepend-http@2.0.0:
+    resolution: {integrity: sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==}
+    engines: {node: '>=4'}
+
   /prettier@3.2.5:
     resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==}
     engines: {node: '>=14'}
@@ -4696,7 +4751,6 @@ packages:
 
   /process-nextick-args@2.0.1:
     resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
-    dev: true
 
   /progress@2.0.3:
     resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
@@ -4731,6 +4785,11 @@ packages:
     engines: {node: '>= 8'}
     dev: true
 
+  /proto-list@1.2.4:
+    resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
+    requiresBuild: true
+    optional: true
+
   /proxy-from-env@1.1.0:
     resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
     dev: false
@@ -4761,10 +4820,6 @@ packages:
     resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
     dev: true
 
-  /quick-lru@5.1.1:
-    resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
-    engines: {node: '>=10'}
-
   /randombytes@2.1.0:
     resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
     dependencies:
@@ -4894,7 +4949,6 @@ packages:
       safe-buffer: 5.1.2
       string_decoder: 1.1.1
       util-deprecate: 1.0.2
-    dev: true
 
   /readable-stream@3.6.2:
     resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
@@ -4945,9 +4999,6 @@ packages:
     resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
     dev: true
 
-  /resolve-alpn@1.2.1:
-    resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
-
   /resolve-cwd@3.0.0:
     resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
     engines: {node: '>=8'}
@@ -4976,10 +5027,10 @@ packages:
       path-parse: 1.0.7
       supports-preserve-symlinks-flag: 1.0.0
 
-  /responselike@2.0.1:
-    resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==}
+  /responselike@1.0.2:
+    resolution: {integrity: sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==}
     dependencies:
-      lowercase-keys: 2.0.0
+      lowercase-keys: 1.0.1
 
   /retry@0.12.0:
     resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==}
@@ -5027,7 +5078,6 @@ packages:
 
   /safe-buffer@5.1.2:
     resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
-    dev: true
 
   /safe-buffer@5.2.1:
     resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
@@ -5170,8 +5220,8 @@ packages:
     dev: true
     optional: true
 
-  /source-map-js@1.1.0:
-    resolution: {integrity: sha512-9vC2SfsJzlej6MAaMPLu8HiBSHGdRAJ9hVFYN1ibZoNkeanmDmLUcIrj6G9DGL7XMJ54AKg/G75akXl1/izTOw==}
+  /source-map-js@1.2.0:
+    resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
     engines: {node: '>=0.10.0'}
     dev: true
 
@@ -5255,7 +5305,6 @@ packages:
     resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
     dependencies:
       safe-buffer: 5.1.2
-    dev: true
 
   /string_decoder@1.3.0:
     resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
@@ -5369,11 +5418,11 @@ packages:
       normalize-path: 3.0.0
       object-hash: 3.0.0
       picocolors: 1.0.0
-      postcss: 8.4.36
-      postcss-import: 15.1.0(postcss@8.4.36)
-      postcss-js: 4.0.1(postcss@8.4.36)
-      postcss-load-config: 4.0.1(postcss@8.4.36)
-      postcss-nested: 6.0.1(postcss@8.4.36)
+      postcss: 8.4.37
+      postcss-import: 15.1.0(postcss@8.4.37)
+      postcss-js: 4.0.1(postcss@8.4.37)
+      postcss-load-config: 4.0.1(postcss@8.4.37)
+      postcss-nested: 6.0.1(postcss@8.4.37)
       postcss-selector-parser: 6.0.13
       resolve: 1.22.2
       sucrase: 3.34.0
@@ -5496,6 +5545,10 @@ packages:
     engines: {node: '>=4'}
     dev: true
 
+  /to-readable-stream@1.0.0:
+    resolution: {integrity: sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==}
+    engines: {node: '>=6'}
+
   /to-regex-range@5.0.1:
     resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
     engines: {node: '>=8.0'}
@@ -5553,7 +5606,7 @@ packages:
       '@babel/core': 7.21.8
       bs-logger: 0.2.6
       fast-json-stable-stringify: 2.1.0
-      jest: 29.7.0(@types/node@20.11.28)
+      jest: 29.7.0(@types/node@20.11.30)
       jest-util: 29.7.0
       json5: 2.2.3
       lodash.memoize: 4.1.2
@@ -5579,6 +5632,12 @@ packages:
       webpack: 5.90.3(webpack-cli@5.1.4)
     dev: false
 
+  /tunnel@0.0.6:
+    resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==}
+    engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'}
+    requiresBuild: true
+    optional: true
+
   /type-detect@4.0.8:
     resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
     engines: {node: '>=4'}
@@ -5595,6 +5654,9 @@ packages:
     engines: {node: '>=10'}
     dev: true
 
+  /typedarray@0.0.6:
+    resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
+
   /typescript@4.9.5:
     resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==}
     engines: {node: '>=4.2.0'}
@@ -5649,6 +5711,12 @@ packages:
     dependencies:
       punycode: 2.3.0
 
+  /url-parse-lax@3.0.0:
+    resolution: {integrity: sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==}
+    engines: {node: '>=4'}
+    dependencies:
+      prepend-http: 2.0.0
+
   /url-parse@1.5.10:
     resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
     dependencies:
@@ -5662,7 +5730,6 @@ packages:
 
   /util-deprecate@1.0.2:
     resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
-    dev: true
 
   /v8-to-istanbul@9.1.0:
     resolution: {integrity: sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==}
diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx
index 8e56231a..5ce79fd5 100644
--- a/src/components/Sidebar.tsx
+++ b/src/components/Sidebar.tsx
@@ -1,13 +1,15 @@
-import { BellIcon } from '@primer/octicons-react';
+import {
+  BellIcon,
+  GearIcon,
+  SyncIcon,
+  XCircleIcon,
+} from '@primer/octicons-react';
 import { ipcRenderer } from 'electron';
 import React, { useCallback, useContext, useMemo } from 'react';
 import { useNavigate, useLocation } from 'react-router-dom';
 
 import { Logo } from '../components/Logo';
 import { AppContext } from '../context/App';
-import { IconCog } from '../icons/Cog';
-import { IconQuit } from '../icons/Quit';
-import { IconRefresh } from '../icons/Refresh';
 import { Constants } from '../utils/constants';
 import { openExternalLink } from '../utils/comms';
 
@@ -78,10 +80,7 @@ export const Sidebar: React.FC = () => {
                 fetchNotifications();
               }}
             >
-              <IconRefresh
-                className="w-3.5 h-3.5"
-                aria-label="Refresh Notifications"
-              />
+              <SyncIcon size={16} aria-label="Refresh Notifications" />
             </button>
 
             <button
@@ -95,7 +94,7 @@ export const Sidebar: React.FC = () => {
                 }
               }}
             >
-              <IconCog className="w-4 h-4" aria-label="Settings" />
+              <GearIcon size={16} aria-label="Settings" />
             </button>
           </>
         )}
@@ -107,7 +106,7 @@ export const Sidebar: React.FC = () => {
             aria-label="Quit Gitify"
             onClick={quitApp}
           >
-            <IconQuit className="w-3.5 h-3.5" />
+            <XCircleIcon size={16} aria-label="Quit Gitify" />
           </button>
         )}
       </div>
diff --git a/src/icons/AddAccount.tsx b/src/icons/AddAccount.tsx
deleted file mode 100644
index febf87a8..00000000
--- a/src/icons/AddAccount.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import * as React from 'react';
-
-export const IconAddAccount = ({ className = '' }: { className?: string }) => {
-  return (
-    <svg
-      aria-hidden="true"
-      className={className}
-      xmlns="http://www.w3.org/2000/svg"
-      viewBox="0 0 640 512"
-      role="img"
-      aria-labelledby="iconAddAccountId"
-    >
-      <title id="iconAddAccountId">Add Account</title>
-      <g>
-        <path
-          fill="currentColor"
-          d="M640 224v32a16 16 0 01-16 16h-64v64a16 16 0 01-16 16h-32a16 16 0 01-16-16v-64h-64a16 16 0 01-16-16v-32a16 16 0 0116-16h64v-64a16 16 0 0116-16h32a16 16 0 0116 16v64h64a16 16 0 0116 16z"
-          opacity={0.4}
-        />
-        <path
-          fill="currentColor"
-          d="M224 256A128 128 0 1096 128a128 128 0 00128 128zm89.6 32h-16.7a174.08 174.08 0 01-145.8 0h-16.7A134.43 134.43 0 000 422.4V464a48 48 0 0048 48h352a48 48 0 0048-48v-41.6A134.43 134.43 0 00313.6 288z"
-        />
-      </g>
-    </svg>
-  );
-};
diff --git a/src/icons/Cog.tsx b/src/icons/Cog.tsx
deleted file mode 100644
index 57809145..00000000
--- a/src/icons/Cog.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import * as React from 'react';
-
-export const IconCog = ({ className = '' }: { className?: string }) => {
-  return (
-    <svg
-      aria-hidden="true"
-      className={className}
-      xmlns="http://www.w3.org/2000/svg"
-      viewBox="0 0 512 512"
-    >
-      <g className="prefix__fa-group">
-        <path
-          className="prefix__fa-secondary"
-          fill="currentColor"
-          d="M487.75 315.6l-42.6-24.6a192.62 192.62 0 000-70.2l42.6-24.6a12.11 12.11 0 005.5-14 249.2 249.2 0 00-54.7-94.6 12 12 0 00-14.8-2.3l-42.6 24.6a188.83 188.83 0 00-60.8-35.1V25.7A12 12 0 00311 14a251.43 251.43 0 00-109.2 0 12 12 0 00-9.4 11.7v49.2a194.59 194.59 0 00-60.8 35.1L89.05 85.4a11.88 11.88 0 00-14.8 2.3 247.66 247.66 0 00-54.7 94.6 12 12 0 005.5 14l42.6 24.6a192.62 192.62 0 000 70.2l-42.6 24.6a12.08 12.08 0 00-5.5 14 249 249 0 0054.7 94.6 12 12 0 0014.8 2.3l42.6-24.6a188.54 188.54 0 0060.8 35.1v49.2a12 12 0 009.4 11.7 251.43 251.43 0 00109.2 0 12 12 0 009.4-11.7v-49.2a194.7 194.7 0 0060.8-35.1l42.6 24.6a11.89 11.89 0 0014.8-2.3 247.52 247.52 0 0054.7-94.6 12.36 12.36 0 00-5.6-14.1zm-231.4 36.2a95.9 95.9 0 1195.9-95.9 95.89 95.89 0 01-95.9 95.9z"
-          opacity={0.4}
-        />
-        <path
-          className="prefix__fa-primary"
-          fill="currentColor"
-          d="M256.35 319.8a63.9 63.9 0 1163.9-63.9 63.9 63.9 0 01-63.9 63.9z"
-        />
-      </g>
-    </svg>
-  );
-};
diff --git a/src/icons/Logout.tsx b/src/icons/Logout.tsx
deleted file mode 100644
index d96f08f5..00000000
--- a/src/icons/Logout.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import * as React from 'react';
-
-export const IconLogOut = ({ className = '' }: { className?: string }) => {
-  return (
-    <svg
-      aria-hidden="true"
-      className={className}
-      xmlns="http://www.w3.org/2000/svg"
-      viewBox="0 0 512 512"
-      role="img"
-      aria-labelledby="iconLogoutId"
-    >
-      <title id="iconLogoutId">Logout from all accounts</title>
-      <g>
-        <path
-          fill="currentColor"
-          d="M180 448H96a96 96 0 01-96-96V160a96 96 0 0196-96h84a12 12 0 0112 12v40a12 12 0 01-12 12H96a32 32 0 00-32 32v192a32 32 0 0032 32h84a12 12 0 0112 12v40a12 12 0 01-12 12z"
-          opacity={0.4}
-        />
-        <path
-          fill="currentColor"
-          d="M353 88.3l151.9 150.6a24 24 0 010 34.1l-152 150.8a24.08 24.08 0 01-33.9-.1l-21.9-21.9a24.07 24.07 0 01.8-34.7l77.6-71.1H184a23.94 23.94 0 01-24-24v-32a23.94 23.94 0 0124-24h191.5l-77.6-71.1a24 24 0 01-.7-34.6l21.9-21.9a24 24 0 0133.9-.1z"
-        />
-      </g>
-    </svg>
-  );
-};
diff --git a/src/icons/Quit.tsx b/src/icons/Quit.tsx
deleted file mode 100644
index 858641a5..00000000
--- a/src/icons/Quit.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import * as React from 'react';
-
-export const IconQuit = ({ className = '' }: { className?: string }) => {
-  return (
-    <svg
-      aria-hidden="true"
-      className={className}
-      xmlns="http://www.w3.org/2000/svg"
-      viewBox="0 0 512 512"
-      role="img"
-      aria-labelledby="iconQuitId"
-    >
-      <title id="iconQuitId">Quit Application</title>
-      <g>
-        <path
-          fill="currentColor"
-          d="M272 0a23.94 23.94 0 0124 24v240a23.94 23.94 0 01-24 24h-32a23.94 23.94 0 01-24-24V24a23.94 23.94 0 0124-24z"
-          opacity={0.4}
-        />
-        <path
-          fill="currentColor"
-          d="M504 256c0 136.8-110.8 247.7-247.5 248C120 504.3 8.2 393 8 256.4A248 248 0 01111.8 54.2a24.07 24.07 0 0135 7.7L162.6 90a24 24 0 01-6.6 31 168 168 0 00100 303c91.6 0 168.6-74.2 168-169.1a168.07 168.07 0 00-68.1-134 23.86 23.86 0 01-6.5-30.9l15.8-28.1a24 24 0 0134.8-7.8A247.51 247.51 0 01504 256z"
-        />
-      </g>
-    </svg>
-  );
-};
diff --git a/src/icons/Refresh.tsx b/src/icons/Refresh.tsx
deleted file mode 100644
index 605b459c..00000000
--- a/src/icons/Refresh.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import * as React from 'react';
-
-export const IconRefresh = ({ className = '' }: { className?: string }) => {
-  return (
-    <svg
-      aria-hidden="true"
-      className={className}
-      xmlns="http://www.w3.org/2000/svg"
-      viewBox="0 0 512 512"
-    >
-      <g className="prefix__fa-group">
-        <path
-          className="prefix__fa-secondary"
-          fill="currentColor"
-          d="M0 500V299.67a12 12 0 0112-12h200.33a12 12 0 0112 12v47.41a12 12 0 01-12.57 12l-101.87-4.88a176.07 176.07 0 00317.25-56.94 12 12 0 0111.67-9.26h49.09a12 12 0 0111.8 14.18C478.07 417.08 377.19 504 256 504a247.43 247.43 0 01-188.76-87.17l4.13 82.57a12 12 0 01-12 12.6H12a12 12 0 01-12-12z"
-          opacity={0.4}
-        />
-        <path
-          className="prefix__fa-primary"
-          fill="currentColor"
-          d="M12.3 209.82C33.93 94.92 134.81 8 256 8a247.4 247.4 0 01188.9 87.34l-4-82.77A12 12 0 01452.92 0h47.41a12 12 0 0112 12v200.33a12 12 0 01-12 12H300a12 12 0 01-12-12v-47.41a12 12 0 0112.57-12l101.53 4.88a176.07 176.07 0 00-317.24 56.94A12 12 0 0173.19 224H24.1a12 12 0 01-11.8-14.18z"
-        />
-      </g>
-    </svg>
-  );
-};
diff --git a/src/routes/Settings.tsx b/src/routes/Settings.tsx
index 9ee9585c..6c3c77b3 100644
--- a/src/routes/Settings.tsx
+++ b/src/routes/Settings.tsx
@@ -1,4 +1,9 @@
-import { ArrowLeftIcon } from '@primer/octicons-react';
+import {
+  ArrowLeftIcon,
+  PersonAddIcon,
+  SignOutIcon,
+  XCircleIcon,
+} from '@primer/octicons-react';
 import { ipcRenderer } from 'electron';
 import React, {
   useCallback,
@@ -12,9 +17,6 @@ import { useNavigate } from 'react-router-dom';
 import { FieldCheckbox } from '../components/fields/Checkbox';
 import { FieldRadioGroup } from '../components/fields/RadioGroup';
 import { AppContext } from '../context/App';
-import { IconAddAccount } from '../icons/AddAccount';
-import { IconLogOut } from '../icons/Logout';
-import { IconQuit } from '../icons/Quit';
 import { Appearance } from '../types';
 import { apiRequestAuth } from '../utils/api-requests';
 import { setAppearance } from '../utils/appearance';
@@ -172,8 +174,8 @@ export const SettingsRoute: React.FC = () => {
             title="Login with GitHub Enterprise"
             onClick={goToEnterprise}
           >
-            <IconAddAccount
-              className="w-5 h-5"
+            <PersonAddIcon
+              size={20}
               aria-label="Login with GitHub Enterprise"
             />
           </button>
@@ -183,7 +185,7 @@ export const SettingsRoute: React.FC = () => {
             title="Logout"
             onClick={logoutUser}
           >
-            <IconLogOut className="w-5 h-5" aria-label="Logout" />
+            <SignOutIcon size={18} aria-label="Logout" />
           </button>
 
           <button
@@ -191,7 +193,7 @@ export const SettingsRoute: React.FC = () => {
             title="Quit Gitify"
             onClick={quitApp}
           >
-            <IconQuit className="w-5 h-5" aria-label="Quit Gitify" />
+            <XCircleIcon size={18} aria-label="Quit Gitify" />
           </button>
         </div>
       </div>
diff --git a/src/typesGithub.ts b/src/typesGithub.ts
index 49f3354f..8649b543 100644
--- a/src/typesGithub.ts
+++ b/src/typesGithub.ts
@@ -245,6 +245,22 @@ export interface IssueComments {
   body: string;
 }
 
+export interface ReleaseComments {
+  url: string;
+  assets_url: string;
+  html_url: string;
+  id: number;
+  author: User;
+  node_id: string;
+  tag_name: string;
+  name: string;
+  draft: boolean;
+  prerelease: boolean;
+  created_at: string;
+  published_at: string;
+  body: string;
+}
+
 export interface GraphQLSearch<T> {
   data: {
     data: {
diff --git a/src/utils/api-requests.ts b/src/utils/api-requests.ts
index 8938d52b..47e0066e 100644
--- a/src/utils/api-requests.ts
+++ b/src/utils/api-requests.ts
@@ -4,7 +4,7 @@ export function apiRequest(
   url: string,
   method: Method,
   data = {},
-): AxiosPromise {
+): AxiosPromise | null {
   axios.defaults.headers.common['Accept'] = 'application/json';
   axios.defaults.headers.common['Content-Type'] = 'application/json';
   axios.defaults.headers.common['Cache-Control'] = 'no-cache';
@@ -16,7 +16,7 @@ export function apiRequestAuth(
   method: Method,
   token: string,
   data = {},
-): AxiosPromise {
+): AxiosPromise | null {
   axios.defaults.headers.common['Accept'] = 'application/json';
   axios.defaults.headers.common['Authorization'] = `token ${token}`;
   axios.defaults.headers.common['Cache-Control'] = 'no-cache';
diff --git a/src/utils/github-api.ts b/src/utils/github-api.ts
index f237040f..f153d6ed 100644
--- a/src/utils/github-api.ts
+++ b/src/utils/github-api.ts
@@ -20,7 +20,6 @@ import {
   RocketIcon,
   SkipIcon,
   StopIcon,
-  SyncIcon,
   TagIcon,
   XIcon,
 } from '@primer/octicons-react';
@@ -104,7 +103,7 @@ export function getNotificationTypeIcon(
         case 'success':
           return CheckIcon;
         default:
-          return SyncIcon;
+          return RocketIcon;
       }
     case 'Commit':
       return GitCommitIcon;
diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts
index 6da0b252..016605e8 100644
--- a/src/utils/helpers.ts
+++ b/src/utils/helpers.ts
@@ -136,8 +136,9 @@ async function getDiscussionUrl(
 
     let latestCommentId: string | number;
 
-    if (comments?.length) {
-      latestCommentId = getLatestDiscussionComment(comments)?.databaseId;
+    latestCommentId = getLatestDiscussionComment(comments)?.databaseId;
+
+    if (latestCommentId) {
       url += `#discussioncomment-${latestCommentId}`;
     }
   }
@@ -218,9 +219,13 @@ export async function fetchDiscussion(
 export function getLatestDiscussionComment(
   comments: DiscussionCommentNode[],
 ): DiscussionSubcommentNode | null {
+  if (!comments || comments.length == 0) {
+    return null;
+  }
+
   return comments
     .flatMap((comment) => comment.replies.nodes)
-    .concat([comments.at(-1)])
+    .concat([comments[comments.length - 1]])
     .reduce((a, b) => (a.createdAt > b.createdAt ? a : b));
 }
 
diff --git a/src/utils/subject.ts b/src/utils/subject.ts
index a1c9e7cd..96969a12 100644
--- a/src/utils/subject.ts
+++ b/src/utils/subject.ts
@@ -9,6 +9,7 @@ import {
   Notification,
   PullRequest,
   PullRequestStateType,
+  ReleaseComments,
   User,
   WorkflowRunAttributes,
 } from '../typesGithub';
@@ -27,6 +28,8 @@ export async function getGitifySubjectDetails(
       return await getGitifySubjectForIssue(notification, token);
     case 'PullRequest':
       return await getGitifySubjectForPullRequest(notification, token);
+    case 'Release':
+      return await getGitifySubjectForRelease(notification, token);
     case 'WorkflowRun':
       return getGitifySubjectForWorkflowRun(notification);
     default:
@@ -104,16 +107,12 @@ async function getGitifySubjectForDiscussion(
     }
   }
 
-  let comments = discussion.comments.nodes;
-  let discussionUser = null;
-
-  if (comments?.length) {
-    discussionUser = getLatestDiscussionComment(comments)?.author.login;
-  }
+  const discussionUser = getLatestDiscussionComment(discussion.comments.nodes)
+    ?.author.login;
 
   return {
     state: discussionState,
-    user: discussionUser,
+    user: discussionUser ?? null,
   };
 }
 
@@ -129,7 +128,7 @@ async function getGitifySubjectForIssue(
 
   return {
     state: issue.state_reason ?? issue.state,
-    user: issueCommentUser.login,
+    user: issueCommentUser?.login ?? null,
   };
 }
 
@@ -141,8 +140,6 @@ async function getGitifySubjectForPullRequest(
     await apiRequestAuth(notification.subject.url, 'GET', token)
   ).data;
 
-  const prCommentUser = await getLatestCommentUser(notification, token);
-
   let prState: PullRequestStateType = pr.state;
   if (pr.merged) {
     prState = 'merged';
@@ -150,9 +147,23 @@ async function getGitifySubjectForPullRequest(
     prState = 'draft';
   }
 
+  const prCommentUser = await getLatestCommentUser(notification, token);
+
   return {
     state: prState,
-    user: prCommentUser.login,
+    user: prCommentUser?.login ?? null,
+  };
+}
+
+async function getGitifySubjectForRelease(
+  notification: Notification,
+  token: string,
+): Promise<GitifySubject> {
+  const releaseCommentUser = await getLatestCommentUser(notification, token);
+
+  return {
+    state: null,
+    user: releaseCommentUser.login,
   };
 }
 
@@ -202,10 +213,16 @@ function getWorkflowRunStatus(statusDisplayName: string): CheckSuiteStatus {
 async function getLatestCommentUser(
   notification: Notification,
   token: string,
-): Promise<User> {
-  const response: IssueComments = (
+): Promise<User> | null {
+  if (!notification.subject.latest_comment_url) {
+    return null;
+  }
+
+  const response: IssueComments | ReleaseComments = (
     await apiRequestAuth(notification.subject.latest_comment_url, 'GET', token)
-  ).data;
+  )?.data;
 
-  return response.user;
+  return (
+    (response as IssueComments)?.user ?? (response as ReleaseComments).author
+  );
 }


Test patch:
diff --git a/src/components/AllRead.test.tsx b/src/components/AllRead.test.tsx
index e262e641..fc3e0655 100644
--- a/src/components/AllRead.test.tsx
+++ b/src/components/AllRead.test.tsx
@@ -5,7 +5,7 @@ import { mockMathRandom } from './test-utils';
 
 import { AllRead } from './AllRead';
 
-describe('components/all-read.tsx', function () {
+describe('components/AllRead.tsx', function () {
   // The read emoji randomly rotates, but then the snapshots would never match
   // Have to make it consistent so the emojis are always the same
   mockMathRandom(0.1);
diff --git a/src/components/Loading.test.tsx b/src/components/Loading.test.tsx
index 21b06474..5e96865f 100644
--- a/src/components/Loading.test.tsx
+++ b/src/components/Loading.test.tsx
@@ -12,7 +12,7 @@ jest.mock('nprogress', () => ({
   remove: jest.fn(),
 }));
 
-describe('components/Loading.js', () => {
+describe('components/Loading.tsx', () => {
   beforeEach(() => {
     jest.clearAllMocks();
   });
diff --git a/src/components/Logo.test.tsx b/src/components/Logo.test.tsx
index 2821b090..10ab08db 100644
--- a/src/components/Logo.test.tsx
+++ b/src/components/Logo.test.tsx
@@ -4,7 +4,7 @@ import { fireEvent, render } from '@testing-library/react';
 
 import { Logo } from './Logo';
 
-describe('components/ui/logo.tsx', () => {
+describe('components/Logo.tsx', () => {
   it('renders correctly (light)', () => {
     const tree = TestRenderer.create(<Logo />);
 
diff --git a/src/components/NotificationRow.test.tsx b/src/components/NotificationRow.test.tsx
index 9158a62d..035a7722 100644
--- a/src/components/NotificationRow.test.tsx
+++ b/src/components/NotificationRow.test.tsx
@@ -9,7 +9,7 @@ import { mockedSingleNotification } from '../__mocks__/mockedData';
 import { NotificationRow } from './NotificationRow';
 import { mockAccounts, mockSettings } from '../__mocks__/mock-state';
 
-describe('components/Notification.js', () => {
+describe('components/NotificationRow.tsx', () => {
   beforeEach(() => {
     jest.spyOn(helpers, 'openInBrowser');
   });
diff --git a/src/components/Oops.test.tsx b/src/components/Oops.test.tsx
index 816fa702..68aa3ee7 100644
--- a/src/components/Oops.test.tsx
+++ b/src/components/Oops.test.tsx
@@ -5,7 +5,7 @@ import { mockMathRandom } from './test-utils';
 
 import { Oops } from './Oops';
 
-describe('components/oops.tsx', function () {
+describe('components/Oops.tsx', function () {
   // The error emoji randomly rotates, but then the snapshots would never match
   // Have to make it consistent so the emojis are always the same
   mockMathRandom(0.1);
diff --git a/src/components/__snapshots__/AccountNotifications.test.tsx.snap b/src/components/__snapshots__/AccountNotifications.test.tsx.snap
index 1e14664e..7bb967d1 100644
--- a/src/components/__snapshots__/AccountNotifications.test.tsx.snap
+++ b/src/components/__snapshots__/AccountNotifications.test.tsx.snap
@@ -12,7 +12,6 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
       fill="currentColor"
       focusable="false"
       height={20}
-      role="img"
       style={
         {
           "display": "inline-block",
@@ -46,7 +45,6 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
     fill="currentColor"
     focusable="false"
     height={20}
-    role="img"
     style={
       {
         "display": "inline-block",
diff --git a/src/components/__snapshots__/AllRead.test.tsx.snap b/src/components/__snapshots__/AllRead.test.tsx.snap
index 704062fd..b1874989 100644
--- a/src/components/__snapshots__/AllRead.test.tsx.snap
+++ b/src/components/__snapshots__/AllRead.test.tsx.snap
@@ -1,6 +1,6 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`components/all-read.tsx should render itself & its children 1`] = `
+exports[`components/AllRead.tsx should render itself & its children 1`] = `
 <div
   className="flex flex-1 flex-col justify-center items-center p-4 bg-white dark:bg-gray-dark text-black dark:text-white"
 >
diff --git a/src/components/__snapshots__/Logo.test.tsx.snap b/src/components/__snapshots__/Logo.test.tsx.snap
index 96060c7d..635657bb 100644
--- a/src/components/__snapshots__/Logo.test.tsx.snap
+++ b/src/components/__snapshots__/Logo.test.tsx.snap
@@ -1,6 +1,6 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`components/ui/logo.tsx renders correctly (light) 1`] = `
+exports[`components/Logo.tsx renders correctly (light) 1`] = `
 <svg
   className=""
   onClick={[Function]}
@@ -47,7 +47,7 @@ exports[`components/ui/logo.tsx renders correctly (light) 1`] = `
 </svg>
 `;
 
-exports[`components/ui/logo.tsx renders correctly(dark) 1`] = `
+exports[`components/Logo.tsx renders correctly(dark) 1`] = `
 <svg
   className=""
   onClick={[Function]}
diff --git a/src/components/__snapshots__/NotificationRow.test.tsx.snap b/src/components/__snapshots__/NotificationRow.test.tsx.snap
index 0f107e1f..b671daa4 100644
--- a/src/components/__snapshots__/NotificationRow.test.tsx.snap
+++ b/src/components/__snapshots__/NotificationRow.test.tsx.snap
@@ -1,6 +1,6 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`components/Notification.js should render itself & its children 1`] = `
+exports[`components/NotificationRow.tsx should render itself & its children 1`] = `
 <div
   className="flex space-x-3 py-2 px-3 bg-white dark:bg-gray-dark dark:text-white hover:bg-gray-100 dark:hover:bg-gray-darker border-b border-gray-100 dark:border-gray-darker group"
 >
@@ -9,7 +9,6 @@ exports[`components/Notification.js should render itself & its children 1`] = `
     title="Open Issue"
   >
     <svg
-      aria-hidden="false"
       aria-label="Issue"
       className="octicon octicon-issue-opened"
       fill="currentColor"
@@ -72,7 +71,6 @@ exports[`components/Notification.js should render itself & its children 1`] = `
       title="Mark as Done"
     >
       <svg
-        aria-hidden="false"
         aria-label="Mark as Done"
         className="octicon octicon-check"
         fill="currentColor"
@@ -101,7 +99,6 @@ exports[`components/Notification.js should render itself & its children 1`] = `
       title="Unsubscribe"
     >
       <svg
-        aria-hidden="false"
         aria-label="Unsubscribe"
         className="octicon octicon-bell-slash"
         fill="currentColor"
@@ -130,7 +127,6 @@ exports[`components/Notification.js should render itself & its children 1`] = `
       title="Mark as Read"
     >
       <svg
-        aria-hidden="false"
         aria-label="Mark as Read"
         className="octicon octicon-read"
         fill="currentColor"
diff --git a/src/components/__snapshots__/Oops.test.tsx.snap b/src/components/__snapshots__/Oops.test.tsx.snap
index c6ef9f63..661f8d20 100644
--- a/src/components/__snapshots__/Oops.test.tsx.snap
+++ b/src/components/__snapshots__/Oops.test.tsx.snap
@@ -1,6 +1,6 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`components/oops.tsx should render itself & its children 1`] = `
+exports[`components/Oops.tsx should render itself & its children 1`] = `
 <div
   className="flex flex-1 flex-col justify-center items-center p-4 bg-white dark:bg-gray-dark text-black dark:text-white"
 >
diff --git a/src/components/__snapshots__/Repository.test.tsx.snap b/src/components/__snapshots__/Repository.test.tsx.snap
index a7059bbf..cacb209b 100644
--- a/src/components/__snapshots__/Repository.test.tsx.snap
+++ b/src/components/__snapshots__/Repository.test.tsx.snap
@@ -27,7 +27,6 @@ exports[`components/Repository.tsx should render itself & its children 1`] = `
         title="Mark Repository as Done"
       >
         <svg
-          aria-hidden="false"
           aria-label="Mark Repository as Done"
           className="octicon octicon-check"
           fill="currentColor"
@@ -59,7 +58,6 @@ exports[`components/Repository.tsx should render itself & its children 1`] = `
         title="Mark Repository as Read"
       >
         <svg
-          aria-hidden="false"
           aria-label="Mark Repository as Read"
           className="octicon octicon-read"
           fill="currentColor"
diff --git a/src/components/__snapshots__/Sidebar.test.tsx.snap b/src/components/__snapshots__/Sidebar.test.tsx.snap
index 8db67adc..7107d61c 100644
--- a/src/components/__snapshots__/Sidebar.test.tsx.snap
+++ b/src/components/__snapshots__/Sidebar.test.tsx.snap
@@ -65,7 +65,6 @@ exports[`components/Sidebar.tsx should render itself & its children (logged in)
       title="4 Unread Notifications"
     >
       <svg
-        aria-hidden="false"
         aria-label="4 Unread Notifications"
         className="octicon octicon-bell"
         fill="currentColor"
@@ -100,29 +99,27 @@ exports[`components/Sidebar.tsx should render itself & its children (logged in)
       title="Quit Gitify"
     >
       <svg
-        aria-hidden="true"
-        aria-labelledby="iconQuitId"
-        className="w-3.5 h-3.5"
+        aria-hidden="false"
+        aria-label="Quit Gitify"
+        className="octicon octicon-x-circle"
+        fill="currentColor"
+        focusable="false"
+        height={16}
         role="img"
-        viewBox="0 0 512 512"
-        xmlns="http://www.w3.org/2000/svg"
+        style={
+          {
+            "display": "inline-block",
+            "overflow": "visible",
+            "userSelect": "none",
+            "verticalAlign": "text-bottom",
+          }
+        }
+        viewBox="0 0 16 16"
+        width={16}
       >
-        <title
-          id="iconQuitId"
-        >
-          Quit Application
-        </title>
-        <g>
-          <path
-            d="M272 0a23.94 23.94 0 0124 24v240a23.94 23.94 0 01-24 24h-32a23.94 23.94 0 01-24-24V24a23.94 23.94 0 0124-24z"
-            fill="currentColor"
-            opacity={0.4}
-          />
-          <path
-            d="M504 256c0 136.8-110.8 247.7-247.5 248C120 504.3 8.2 393 8 256.4A248 248 0 01111.8 54.2a24.07 24.07 0 0135 7.7L162.6 90a24 24 0 01-6.6 31 168 168 0 00100 303c91.6 0 168.6-74.2 168-169.1a168.07 168.07 0 00-68.1-134 23.86 23.86 0 01-6.5-30.9l15.8-28.1a24 24 0 0134.8-7.8A247.51 247.51 0 01504 256z"
-            fill="currentColor"
-          />
-        </g>
+        <path
+          d="M2.344 2.343h-.001a8 8 0 0 1 11.314 11.314A8.002 8.002 0 0 1 .234 10.089a8 8 0 0 1 2.11-7.746Zm1.06 10.253a6.5 6.5 0 1 0 9.108-9.275 6.5 6.5 0 0 0-9.108 9.275ZM6.03 4.97 8 6.94l1.97-1.97a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l1.97 1.97a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-1.97 1.97a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L6.94 8 4.97 6.03a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018Z"
+        />
       </svg>
     </button>
   </div>
@@ -194,7 +191,6 @@ exports[`components/Sidebar.tsx should render itself & its children (logged out)
       title="4 Unread Notifications"
     >
       <svg
-        aria-hidden="false"
         aria-label="4 Unread Notifications"
         className="octicon octicon-bell"
         fill="currentColor"
@@ -229,29 +225,27 @@ exports[`components/Sidebar.tsx should render itself & its children (logged out)
       title="Quit Gitify"
     >
       <svg
-        aria-hidden="true"
-        aria-labelledby="iconQuitId"
-        className="w-3.5 h-3.5"
+        aria-hidden="false"
+        aria-label="Quit Gitify"
+        className="octicon octicon-x-circle"
+        fill="currentColor"
+        focusable="false"
+        height={16}
         role="img"
-        viewBox="0 0 512 512"
-        xmlns="http://www.w3.org/2000/svg"
+        style={
+          {
+            "display": "inline-block",
+            "overflow": "visible",
+            "userSelect": "none",
+            "verticalAlign": "text-bottom",
+          }
+        }
+        viewBox="0 0 16 16"
+        width={16}
       >
-        <title
-          id="iconQuitId"
-        >
-          Quit Application
-        </title>
-        <g>
-          <path
-            d="M272 0a23.94 23.94 0 0124 24v240a23.94 23.94 0 01-24 24h-32a23.94 23.94 0 01-24-24V24a23.94 23.94 0 0124-24z"
-            fill="currentColor"
-            opacity={0.4}
-          />
-          <path
-            d="M504 256c0 136.8-110.8 247.7-247.5 248C120 504.3 8.2 393 8 256.4A248 248 0 01111.8 54.2a24.07 24.07 0 0135 7.7L162.6 90a24 24 0 01-6.6 31 168 168 0 00100 303c91.6 0 168.6-74.2 168-169.1a168.07 168.07 0 00-68.1-134 23.86 23.86 0 01-6.5-30.9l15.8-28.1a24 24 0 0134.8-7.8A247.51 247.51 0 01504 256z"
-            fill="currentColor"
-          />
-        </g>
+        <path
+          d="M2.344 2.343h-.001a8 8 0 0 1 11.314 11.314A8.002 8.002 0 0 1 .234 10.089a8 8 0 0 1 2.11-7.746Zm1.06 10.253a6.5 6.5 0 1 0 9.108-9.275 6.5 6.5 0 0 0-9.108 9.275ZM6.03 4.97 8 6.94l1.97-1.97a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l1.97 1.97a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-1.97 1.97a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L6.94 8 4.97 6.03a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018Z"
+        />
       </svg>
     </button>
   </div>
diff --git a/src/routes/LoginEnterprise.test.tsx b/src/routes/LoginEnterprise.test.tsx
index f6c31c0f..64c69f7d 100644
--- a/src/routes/LoginEnterprise.test.tsx
+++ b/src/routes/LoginEnterprise.test.tsx
@@ -16,7 +16,7 @@ jest.mock('react-router-dom', () => ({
   useNavigate: () => mockNavigate,
 }));
 
-describe('routes/LoginEnterprise.js', () => {
+describe('routes/LoginEnterprise.tsx', () => {
   const mockAccounts: AuthState = {
     enterpriseAccounts: [],
     user: null,
diff --git a/src/routes/LoginWithToken.test.tsx b/src/routes/LoginWithToken.test.tsx
index a1e0d0eb..1e34d288 100644
--- a/src/routes/LoginWithToken.test.tsx
+++ b/src/routes/LoginWithToken.test.tsx
@@ -13,7 +13,7 @@ jest.mock('react-router-dom', () => ({
   useNavigate: () => mockNavigate,
 }));
 
-describe('routes/LoginWithToken.js', () => {
+describe('routes/LoginWithToken.tsx', () => {
   const openExternalMock = jest.spyOn(shell, 'openExternal');
 
   const mockValidateToken = jest.fn();
diff --git a/src/routes/Notifications.test.tsx b/src/routes/Notifications.test.tsx
index 89e37d7a..9f7f8ee6 100644
--- a/src/routes/Notifications.test.tsx
+++ b/src/routes/Notifications.test.tsx
@@ -17,7 +17,7 @@ jest.mock('../components/Oops', () => ({
   Oops: 'Oops',
 }));
 
-describe('routes/Notifications.ts', () => {
+describe('routes/Notifications.tsx', () => {
   it('should render itself & its children (with notifications)', () => {
     const tree = TestRenderer.create(
       <AppContext.Provider
diff --git a/src/routes/__snapshots__/LoginEnterprise.test.tsx.snap b/src/routes/__snapshots__/LoginEnterprise.test.tsx.snap
index 8e139ef8..43d74e23 100644
--- a/src/routes/__snapshots__/LoginEnterprise.test.tsx.snap
+++ b/src/routes/__snapshots__/LoginEnterprise.test.tsx.snap
@@ -1,6 +1,6 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`routes/LoginEnterprise.js renders correctly 1`] = `
+exports[`routes/LoginEnterprise.tsx renders correctly 1`] = `
 <div
   className="flex-1 bg-white dark:bg-gray-dark dark:text-white"
 >
@@ -13,7 +13,6 @@ exports[`routes/LoginEnterprise.js renders correctly 1`] = `
       title="Go Back"
     >
       <svg
-        aria-hidden="false"
         aria-label="Go Back"
         className="hover:text-gray-400"
         fill="currentColor"
diff --git a/src/routes/__snapshots__/LoginWithToken.test.tsx.snap b/src/routes/__snapshots__/LoginWithToken.test.tsx.snap
index b3532293..8be1db86 100644
--- a/src/routes/__snapshots__/LoginWithToken.test.tsx.snap
+++ b/src/routes/__snapshots__/LoginWithToken.test.tsx.snap
@@ -1,6 +1,6 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`routes/LoginWithToken.js renders correctly 1`] = `
+exports[`routes/LoginWithToken.tsx renders correctly 1`] = `
 <div
   className="flex-1 bg-white dark:bg-gray-dark dark:text-white"
 >
@@ -13,7 +13,6 @@ exports[`routes/LoginWithToken.js renders correctly 1`] = `
       title="Go Back"
     >
       <svg
-        aria-hidden="false"
         aria-label="Go Back"
         className="hover:text-gray-400"
         fill="currentColor"
diff --git a/src/routes/__snapshots__/Notifications.test.tsx.snap b/src/routes/__snapshots__/Notifications.test.tsx.snap
index 1f16aa3d..ab3a6744 100644
--- a/src/routes/__snapshots__/Notifications.test.tsx.snap
+++ b/src/routes/__snapshots__/Notifications.test.tsx.snap
@@ -1,10 +1,10 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`routes/Notifications.ts should render itself & its children (all read notifications) 1`] = `<AllRead />`;
+exports[`routes/Notifications.tsx should render itself & its children (all read notifications) 1`] = `<AllRead />`;
 
-exports[`routes/Notifications.ts should render itself & its children (error page - oops) 1`] = `<Oops />`;
+exports[`routes/Notifications.tsx should render itself & its children (error page - oops) 1`] = `<Oops />`;
 
-exports[`routes/Notifications.ts should render itself & its children (with notifications) 1`] = `
+exports[`routes/Notifications.tsx should render itself & its children (with notifications) 1`] = `
 <div
   className="flex flex-col flex-1 bg-white dark:bg-gray-dark"
 >
diff --git a/src/routes/__snapshots__/Settings.test.tsx.snap b/src/routes/__snapshots__/Settings.test.tsx.snap
index c0c3c21e..c233cbf2 100644
--- a/src/routes/__snapshots__/Settings.test.tsx.snap
+++ b/src/routes/__snapshots__/Settings.test.tsx.snap
@@ -41,7 +41,6 @@ exports[`routes/Settings.tsx should render itself & its children 1`] = `
       title="Go Back"
     >
       <svg
-        aria-hidden="false"
         aria-label="Go Back"
         class="hover:text-gray-400"
         fill="currentColor"
@@ -293,29 +292,20 @@ exports[`routes/Settings.tsx should render itself & its children 1`] = `
         title="Login with GitHub Enterprise"
       >
         <svg
-          aria-hidden="true"
-          aria-labelledby="iconAddAccountId"
-          class="w-5 h-5"
+          aria-hidden="false"
+          aria-label="Login with GitHub Enterprise"
+          class="octicon octicon-person-add"
+          fill="currentColor"
+          focusable="false"
+          height="20"
           role="img"
-          viewBox="0 0 640 512"
-          xmlns="http://www.w3.org/2000/svg"
+          style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+          viewBox="0 0 16 16"
+          width="20"
         >
-          <title
-            id="iconAddAccountId"
-          >
-            Add Account
-          </title>
-          <g>
-            <path
-              d="M640 224v32a16 16 0 01-16 16h-64v64a16 16 0 01-16 16h-32a16 16 0 01-16-16v-64h-64a16 16 0 01-16-16v-32a16 16 0 0116-16h64v-64a16 16 0 0116-16h32a16 16 0 0116 16v64h64a16 16 0 0116 16z"
-              fill="currentColor"
-              opacity="0.4"
-            />
-            <path
-              d="M224 256A128 128 0 1096 128a128 128 0 00128 128zm89.6 32h-16.7a174.08 174.08 0 01-145.8 0h-16.7A134.43 134.43 0 000 422.4V464a48 48 0 0048 48h352a48 48 0 0048-48v-41.6A134.43 134.43 0 00313.6 288z"
-              fill="currentColor"
-            />
-          </g>
+          <path
+            d="M7.9 8.548h-.001a5.528 5.528 0 0 1 3.1 4.659.75.75 0 1 1-1.498.086A4.01 4.01 0 0 0 5.5 9.5a4.01 4.01 0 0 0-4.001 3.793.75.75 0 1 1-1.498-.085 5.527 5.527 0 0 1 3.1-4.66 3.5 3.5 0 1 1 4.799 0ZM13.25 0a.75.75 0 0 1 .75.75V2h1.25a.75.75 0 0 1 0 1.5H14v1.25a.75.75 0 0 1-1.5 0V3.5h-1.25a.75.75 0 0 1 0-1.5h1.25V.75a.75.75 0 0 1 .75-.75ZM5.5 4a2 2 0 1 0-.001 3.999A2 2 0 0 0 5.5 4Z"
+          />
         </svg>
       </button>
       <button
@@ -323,29 +313,20 @@ exports[`routes/Settings.tsx should render itself & its children 1`] = `
         title="Logout"
       >
         <svg
-          aria-hidden="true"
-          aria-labelledby="iconLogoutId"
-          class="w-5 h-5"
+          aria-hidden="false"
+          aria-label="Logout"
+          class="octicon octicon-sign-out"
+          fill="currentColor"
+          focusable="false"
+          height="18"
           role="img"
-          viewBox="0 0 512 512"
-          xmlns="http://www.w3.org/2000/svg"
+          style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+          viewBox="0 0 16 16"
+          width="18"
         >
-          <title
-            id="iconLogoutId"
-          >
-            Logout from all accounts
-          </title>
-          <g>
-            <path
-              d="M180 448H96a96 96 0 01-96-96V160a96 96 0 0196-96h84a12 12 0 0112 12v40a12 12 0 01-12 12H96a32 32 0 00-32 32v192a32 32 0 0032 32h84a12 12 0 0112 12v40a12 12 0 01-12 12z"
-              fill="currentColor"
-              opacity="0.4"
-            />
-            <path
-              d="M353 88.3l151.9 150.6a24 24 0 010 34.1l-152 150.8a24.08 24.08 0 01-33.9-.1l-21.9-21.9a24.07 24.07 0 01.8-34.7l77.6-71.1H184a23.94 23.94 0 01-24-24v-32a23.94 23.94 0 0124-24h191.5l-77.6-71.1a24 24 0 01-.7-34.6l21.9-21.9a24 24 0 0133.9-.1z"
-              fill="currentColor"
-            />
-          </g>
+          <path
+            d="M2 2.75C2 1.784 2.784 1 3.75 1h2.5a.75.75 0 0 1 0 1.5h-2.5a.25.25 0 0 0-.25.25v10.5c0 .138.112.25.25.25h2.5a.75.75 0 0 1 0 1.5h-2.5A1.75 1.75 0 0 1 2 13.25Zm10.44 4.5-1.97-1.97a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734l1.97-1.97H6.75a.75.75 0 0 1 0-1.5Z"
+          />
         </svg>
       </button>
       <button
@@ -353,29 +334,20 @@ exports[`routes/Settings.tsx should render itself & its children 1`] = `
         title="Quit Gitify"
       >
         <svg
-          aria-hidden="true"
-          aria-labelledby="iconQuitId"
-          class="w-5 h-5"
+          aria-hidden="false"
+          aria-label="Quit Gitify"
+          class="octicon octicon-x-circle"
+          fill="currentColor"
+          focusable="false"
+          height="18"
           role="img"
-          viewBox="0 0 512 512"
-          xmlns="http://www.w3.org/2000/svg"
+          style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+          viewBox="0 0 16 16"
+          width="18"
         >
-          <title
-            id="iconQuitId"
-          >
-            Quit Application
-          </title>
-          <g>
-            <path
-              d="M272 0a23.94 23.94 0 0124 24v240a23.94 23.94 0 01-24 24h-32a23.94 23.94 0 01-24-24V24a23.94 23.94 0 0124-24z"
-              fill="currentColor"
-              opacity="0.4"
-            />
-            <path
-              d="M504 256c0 136.8-110.8 247.7-247.5 248C120 504.3 8.2 393 8 256.4A248 248 0 01111.8 54.2a24.07 24.07 0 0135 7.7L162.6 90a24 24 0 01-6.6 31 168 168 0 00100 303c91.6 0 168.6-74.2 168-169.1a168.07 168.07 0 00-68.1-134 23.86 23.86 0 01-6.5-30.9l15.8-28.1a24 24 0 0134.8-7.8A247.51 247.51 0 01504 256z"
-              fill="currentColor"
-            />
-          </g>
+          <path
+            d="M2.344 2.343h-.001a8 8 0 0 1 11.314 11.314A8.002 8.002 0 0 1 .234 10.089a8 8 0 0 1 2.11-7.746Zm1.06 10.253a6.5 6.5 0 1 0 9.108-9.275 6.5 6.5 0 0 0-9.108 9.275ZM6.03 4.97 8 6.94l1.97-1.97a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l1.97 1.97a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-1.97 1.97a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L6.94 8 4.97 6.03a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018Z"
+          />
         </svg>
       </button>
     </div>
diff --git a/src/utils/__snapshots__/api-requests.test.ts.snap b/src/utils/__snapshots__/api-requests.test.ts.snap
index 86a0ee8e..420db2eb 100644
--- a/src/utils/__snapshots__/api-requests.test.ts.snap
+++ b/src/utils/__snapshots__/api-requests.test.ts.snap
@@ -1,34 +1,34 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`apiRequest should make a request with the correct parameters 1`] = `
+exports[`apiRequestAuth should make an authenticated request with the correct parameters 1`] = `
 {
   "Accept": "application/json",
+  "Authorization": "token yourAuthToken",
   "Cache-Control": "no-cache",
   "Content-Type": "application/json",
 }
 `;
 
-exports[`apiRequest should make a request with the correct parameters and default data 1`] = `
+exports[`apiRequestAuth should make an authenticated request with the correct parameters and default data 1`] = `
 {
   "Accept": "application/json",
+  "Authorization": "token yourAuthToken",
   "Cache-Control": "no-cache",
   "Content-Type": "application/json",
 }
 `;
 
-exports[`apiRequestAuth should make an authenticated request with the correct parameters 1`] = `
+exports[`utils/api-requests.ts should make a request with the correct parameters 1`] = `
 {
   "Accept": "application/json",
-  "Authorization": "token yourAuthToken",
   "Cache-Control": "no-cache",
   "Content-Type": "application/json",
 }
 `;
 
-exports[`apiRequestAuth should make an authenticated request with the correct parameters and default data 1`] = `
+exports[`utils/api-requests.ts should make a request with the correct parameters and default data 1`] = `
 {
   "Accept": "application/json",
-  "Authorization": "token yourAuthToken",
   "Cache-Control": "no-cache",
   "Content-Type": "application/json",
 }
diff --git a/src/utils/__snapshots__/github-api.test.ts.snap b/src/utils/__snapshots__/github-api.test.ts.snap
index 2ad7e8e9..b12b53e8 100644
--- a/src/utils/__snapshots__/github-api.test.ts.snap
+++ b/src/utils/__snapshots__/github-api.test.ts.snap
@@ -1,143 +1,143 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`formatReason should format the notification reason 1`] = `
+exports[`utils/github-api.ts formatReason - should format the notification reason 1`] = `
 {
   "description": "You were requested to review and approve a deployment.",
   "type": "Approval Requested",
 }
 `;
 
-exports[`formatReason should format the notification reason 2`] = `
+exports[`utils/github-api.ts formatReason - should format the notification reason 2`] = `
 {
   "description": "You were assigned to the issue.",
   "type": "Assign",
 }
 `;
 
-exports[`formatReason should format the notification reason 3`] = `
+exports[`utils/github-api.ts formatReason - should format the notification reason 3`] = `
 {
   "description": "You created the thread.",
   "type": "Author",
 }
 `;
 
-exports[`formatReason should format the notification reason 4`] = `
+exports[`utils/github-api.ts formatReason - should format the notification reason 4`] = `
 {
   "description": "A GitHub Actions workflow run was triggered for your repository",
   "type": "Workflow Run",
 }
 `;
 
-exports[`formatReason should format the notification reason 5`] = `
+exports[`utils/github-api.ts formatReason - should format the notification reason 5`] = `
 {
   "description": "You commented on the thread.",
   "type": "Comment",
 }
 `;
 
-exports[`formatReason should format the notification reason 6`] = `
+exports[`utils/github-api.ts formatReason - should format the notification reason 6`] = `
 {
   "description": "You accepted an invitation to contribute to the repository.",
   "type": "Invitation",
 }
 `;
 
-exports[`formatReason should format the notification reason 7`] = `
+exports[`utils/github-api.ts formatReason - should format the notification reason 7`] = `
 {
   "description": "You subscribed to the thread (via an issue or pull request).",
   "type": "Manual",
 }
 `;
 
-exports[`formatReason should format the notification reason 8`] = `
+exports[`utils/github-api.ts formatReason - should format the notification reason 8`] = `
 {
   "description": "Organization members have requested to enable a feature such as Draft Pull Requests or CoPilot.",
   "type": "Member Feature Requested",
 }
 `;
 
-exports[`formatReason should format the notification reason 9`] = `
+exports[`utils/github-api.ts formatReason - should format the notification reason 9`] = `
 {
   "description": "You were specifically @mentioned in the content.",
   "type": "Mention",
 }
 `;
 
-exports[`formatReason should format the notification reason 10`] = `
+exports[`utils/github-api.ts formatReason - should format the notification reason 10`] = `
 {
   "description": "You, or a team you're a member of, were requested to review a pull request.",
   "type": "Review Requested",
 }
 `;
 
-exports[`formatReason should format the notification reason 11`] = `
+exports[`utils/github-api.ts formatReason - should format the notification reason 11`] = `
 {
   "description": "You were credited for contributing to a security advisory.",
   "type": "Security Advisory Credit",
 }
 `;
 
-exports[`formatReason should format the notification reason 12`] = `
+exports[`utils/github-api.ts formatReason - should format the notification reason 12`] = `
 {
   "description": "GitHub discovered a security vulnerability in your repository.",
   "type": "Security Alert",
 }
 `;
 
-exports[`formatReason should format the notification reason 13`] = `
+exports[`utils/github-api.ts formatReason - should format the notification reason 13`] = `
 {
   "description": "You changed the thread state (for example, closing an issue or merging a pull request).",
   "type": "State Change",
 }
 `;
 
-exports[`formatReason should format the notification reason 14`] = `
+exports[`utils/github-api.ts formatReason - should format the notification reason 14`] = `
 {
   "description": "You're watching the repository.",
   "type": "Subscribed",
 }
 `;
 
-exports[`formatReason should format the notification reason 15`] = `
+exports[`utils/github-api.ts formatReason - should format the notification reason 15`] = `
 {
   "description": "You were on a team that was mentioned.",
   "type": "Team Mention",
 }
 `;
 
-exports[`formatReason should format the notification reason 16`] = `
+exports[`utils/github-api.ts formatReason - should format the notification reason 16`] = `
 {
   "description": "The reason for this notification is not supported by the app.",
   "type": "Unknown",
 }
 `;
 
-exports[`getNotificationTypeIconColor should format the notification color for check suite 1`] = `"text-gray-500"`;
+exports[`utils/github-api.ts getNotificationTypeIconColor should format the notification color for check suite 1`] = `"text-gray-500"`;
 
-exports[`getNotificationTypeIconColor should format the notification color for check suite 2`] = `"text-red-500"`;
+exports[`utils/github-api.ts getNotificationTypeIconColor should format the notification color for check suite 2`] = `"text-red-500"`;
 
-exports[`getNotificationTypeIconColor should format the notification color for check suite 3`] = `"text-gray-500"`;
+exports[`utils/github-api.ts getNotificationTypeIconColor should format the notification color for check suite 3`] = `"text-gray-500"`;
 
-exports[`getNotificationTypeIconColor should format the notification color for check suite 4`] = `"text-green-500"`;
+exports[`utils/github-api.ts getNotificationTypeIconColor should format the notification color for check suite 4`] = `"text-green-500"`;
 
-exports[`getNotificationTypeIconColor should format the notification color for check suite 5`] = `"text-gray-500"`;
+exports[`utils/github-api.ts getNotificationTypeIconColor should format the notification color for check suite 5`] = `"text-gray-500"`;
 
-exports[`getNotificationTypeIconColor should format the notification color for state 1`] = `"text-green-500"`;
+exports[`utils/github-api.ts getNotificationTypeIconColor should format the notification color for state 1`] = `"text-green-500"`;
 
-exports[`getNotificationTypeIconColor should format the notification color for state 2`] = `"text-red-500"`;
+exports[`utils/github-api.ts getNotificationTypeIconColor should format the notification color for state 2`] = `"text-red-500"`;
 
-exports[`getNotificationTypeIconColor should format the notification color for state 3`] = `"text-purple-500"`;
+exports[`utils/github-api.ts getNotificationTypeIconColor should format the notification color for state 3`] = `"text-purple-500"`;
 
-exports[`getNotificationTypeIconColor should format the notification color for state 4`] = `"text-gray-500"`;
+exports[`utils/github-api.ts getNotificationTypeIconColor should format the notification color for state 4`] = `"text-gray-500"`;
 
-exports[`getNotificationTypeIconColor should format the notification color for state 5`] = `"text-purple-500"`;
+exports[`utils/github-api.ts getNotificationTypeIconColor should format the notification color for state 5`] = `"text-purple-500"`;
 
-exports[`getNotificationTypeIconColor should format the notification color for state 6`] = `"text-gray-500"`;
+exports[`utils/github-api.ts getNotificationTypeIconColor should format the notification color for state 6`] = `"text-gray-500"`;
 
-exports[`getNotificationTypeIconColor should format the notification color for state 7`] = `"text-green-500"`;
+exports[`utils/github-api.ts getNotificationTypeIconColor should format the notification color for state 7`] = `"text-green-500"`;
 
-exports[`getNotificationTypeIconColor should format the notification color for state 8`] = `"text-green-500"`;
+exports[`utils/github-api.ts getNotificationTypeIconColor should format the notification color for state 8`] = `"text-green-500"`;
 
-exports[`getNotificationTypeIconColor should format the notification color for state 9`] = `"text-purple-500"`;
+exports[`utils/github-api.ts getNotificationTypeIconColor should format the notification color for state 9`] = `"text-purple-500"`;
 
-exports[`getNotificationTypeIconColor should format the notification color for state 10`] = `"text-gray-500"`;
+exports[`utils/github-api.ts getNotificationTypeIconColor should format the notification color for state 10`] = `"text-gray-500"`;
diff --git a/src/utils/api-requests.test.ts b/src/utils/api-requests.test.ts
index 9bb71648..7d0bc663 100644
--- a/src/utils/api-requests.test.ts
+++ b/src/utils/api-requests.test.ts
@@ -6,7 +6,11 @@ jest.mock('axios');
 const url = 'https://example.com';
 const method = 'get';
 
-describe('apiRequest', () => {
+describe('utils/api-requests.ts', () => {
+  afterEach(() => {
+    jest.resetAllMocks();
+  });
+
   it('should make a request with the correct parameters', async () => {
     const data = { key: 'value' };
 
@@ -38,6 +42,10 @@ describe('apiRequest', () => {
 describe('apiRequestAuth', () => {
   const token = 'yourAuthToken';
 
+  afterEach(() => {
+    jest.resetAllMocks();
+  });
+
   it('should make an authenticated request with the correct parameters', async () => {
     const data = { key: 'value' };
 
diff --git a/src/utils/appearance.test.ts b/src/utils/appearance.test.ts
index a9d7f0b0..a6f8005e 100644
--- a/src/utils/appearance.test.ts
+++ b/src/utils/appearance.test.ts
@@ -3,7 +3,7 @@ import { setAppearance } from './appearance';
 
 import * as appearanceHelpers from './appearance';
 
-describe('utils/appearance.tsx', () => {
+describe('utils/appearance.ts', () => {
   beforeAll(() => {
     jest.spyOn(appearanceHelpers, 'setLightMode');
     jest.spyOn(appearanceHelpers, 'setDarkMode');
diff --git a/src/utils/github-api.test.ts b/src/utils/github-api.test.ts
index dbb5fe92..df5273f2 100644
--- a/src/utils/github-api.test.ts
+++ b/src/utils/github-api.test.ts
@@ -5,8 +5,8 @@ import {
 } from './github-api';
 import { Reason, StateType, Subject, SubjectType } from '../typesGithub';
 
-describe('formatReason', () => {
-  it('should format the notification reason', () => {
+describe('utils/github-api.ts', () => {
+  it('formatReason - should format the notification reason', () => {
     expect(formatReason('approval_requested')).toMatchSnapshot();
     expect(formatReason('assign')).toMatchSnapshot();
     expect(formatReason('author')).toMatchSnapshot();
@@ -24,15 +24,13 @@ describe('formatReason', () => {
     expect(formatReason('team_mention')).toMatchSnapshot();
     expect(formatReason('something_else_unknown' as Reason)).toMatchSnapshot();
   });
-});
 
-describe('getNotificationTypeIcon', () => {
-  it('should get the notification type icon', () => {
+  describe('getNotificationTypeIcon - should get the notification type icon', () => {
     expect(
       getNotificationTypeIcon(
         createSubjectMock({ type: 'CheckSuite', state: null }),
       ).displayName,
-    ).toBe('SyncIcon');
+    ).toBe('RocketIcon');
     expect(
       getNotificationTypeIcon(
         createSubjectMock({
@@ -188,88 +186,90 @@ describe('getNotificationTypeIcon', () => {
       'QuestionIcon',
     );
   });
-});
 
-describe('getNotificationTypeIconColor', () => {
-  it('should format the notification color for check suite', () => {
-    expect(
-      getNotificationTypeIconColor(
-        createSubjectMock({
-          type: 'CheckSuite',
-          state: 'cancelled',
-        }),
-      ),
-    ).toMatchSnapshot();
-    expect(
-      getNotificationTypeIconColor(
-        createSubjectMock({
-          type: 'CheckSuite',
-          state: 'failure',
-        }),
-      ),
-    ).toMatchSnapshot();
+  describe('getNotificationTypeIconColor', () => {
+    it('should format the notification color for check suite', () => {
+      expect(
+        getNotificationTypeIconColor(
+          createSubjectMock({
+            type: 'CheckSuite',
+            state: 'cancelled',
+          }),
+        ),
+      ).toMatchSnapshot();
+      expect(
+        getNotificationTypeIconColor(
+          createSubjectMock({
+            type: 'CheckSuite',
+            state: 'failure',
+          }),
+        ),
+      ).toMatchSnapshot();
 
-    expect(
-      getNotificationTypeIconColor(
-        createSubjectMock({
-          type: 'CheckSuite',
-          state: 'skipped',
-        }),
-      ),
-    ).toMatchSnapshot();
-    expect(
-      getNotificationTypeIconColor(
-        createSubjectMock({
-          type: 'CheckSuite',
-          state: 'success',
-        }),
-      ),
-    ).toMatchSnapshot();
-    expect(
-      getNotificationTypeIconColor(
-        createSubjectMock({
-          type: 'CheckSuite',
-          state: null,
-        }),
-      ),
-    ).toMatchSnapshot();
-  });
+      expect(
+        getNotificationTypeIconColor(
+          createSubjectMock({
+            type: 'CheckSuite',
+            state: 'skipped',
+          }),
+        ),
+      ).toMatchSnapshot();
+      expect(
+        getNotificationTypeIconColor(
+          createSubjectMock({
+            type: 'CheckSuite',
+            state: 'success',
+          }),
+        ),
+      ).toMatchSnapshot();
+      expect(
+        getNotificationTypeIconColor(
+          createSubjectMock({
+            type: 'CheckSuite',
+            state: null,
+          }),
+        ),
+      ).toMatchSnapshot();
+    });
 
-  it('should format the notification color for state', () => {
-    expect(
-      getNotificationTypeIconColor(createSubjectMock({ state: 'ANSWERED' })),
-    ).toMatchSnapshot();
-    expect(
-      getNotificationTypeIconColor(createSubjectMock({ state: 'closed' })),
-    ).toMatchSnapshot();
-    expect(
-      getNotificationTypeIconColor(createSubjectMock({ state: 'completed' })),
-    ).toMatchSnapshot();
-    expect(
-      getNotificationTypeIconColor(createSubjectMock({ state: 'draft' })),
-    ).toMatchSnapshot();
-    expect(
-      getNotificationTypeIconColor(createSubjectMock({ state: 'merged' })),
-    ).toMatchSnapshot();
-    expect(
-      getNotificationTypeIconColor(createSubjectMock({ state: 'not_planned' })),
-    ).toMatchSnapshot();
-    expect(
-      getNotificationTypeIconColor(createSubjectMock({ state: 'open' })),
-    ).toMatchSnapshot();
-    expect(
-      getNotificationTypeIconColor(createSubjectMock({ state: 'reopened' })),
-    ).toMatchSnapshot();
-    expect(
-      getNotificationTypeIconColor(createSubjectMock({ state: 'RESOLVED' })),
-    ).toMatchSnapshot();
-    expect(
-      getNotificationTypeIconColor(
-        createSubjectMock({
-          state: 'something_else_unknown' as StateType,
-        }),
-      ),
-    ).toMatchSnapshot();
+    it('should format the notification color for state', () => {
+      expect(
+        getNotificationTypeIconColor(createSubjectMock({ state: 'ANSWERED' })),
+      ).toMatchSnapshot();
+      expect(
+        getNotificationTypeIconColor(createSubjectMock({ state: 'closed' })),
+      ).toMatchSnapshot();
+      expect(
+        getNotificationTypeIconColor(createSubjectMock({ state: 'completed' })),
+      ).toMatchSnapshot();
+      expect(
+        getNotificationTypeIconColor(createSubjectMock({ state: 'draft' })),
+      ).toMatchSnapshot();
+      expect(
+        getNotificationTypeIconColor(createSubjectMock({ state: 'merged' })),
+      ).toMatchSnapshot();
+      expect(
+        getNotificationTypeIconColor(
+          createSubjectMock({ state: 'not_planned' }),
+        ),
+      ).toMatchSnapshot();
+      expect(
+        getNotificationTypeIconColor(createSubjectMock({ state: 'open' })),
+      ).toMatchSnapshot();
+      expect(
+        getNotificationTypeIconColor(createSubjectMock({ state: 'reopened' })),
+      ).toMatchSnapshot();
+      expect(
+        getNotificationTypeIconColor(createSubjectMock({ state: 'RESOLVED' })),
+      ).toMatchSnapshot();
+      expect(
+        getNotificationTypeIconColor(
+          createSubjectMock({
+            state: 'something_else_unknown' as StateType,
+          }),
+        ),
+      ).toMatchSnapshot();
+    });
   });
 });
 
diff --git a/src/utils/helpers.test.ts b/src/utils/helpers.test.ts
index bea3101c..dfe3f6e7 100644
--- a/src/utils/helpers.test.ts
+++ b/src/utils/helpers.test.ts
@@ -445,6 +445,34 @@ describe('utils/helpers.ts', () => {
           `https://github.com/manosim/notifications-test/discussions/612?${mockedNotificationReferrer}#discussioncomment-2300902`,
         );
       });
+
+      it('default to base discussions url when graphql query fails', async () => {
+        const subject = {
+          title: '1.16.0',
+          url: null,
+          latest_comment_url: null,
+          type: 'Discussion' as SubjectType,
+        };
+
+        const requestPromise = new Promise((resolve) =>
+          resolve(null as AxiosResponse),
+        ) as AxiosPromise;
+
+        apiRequestAuthMock.mockResolvedValue(requestPromise);
+
+        const result = await generateGitHubWebUrl(
+          {
+            ...mockedSingleNotification,
+            subject: subject,
+          },
+          mockAccounts,
+        );
+
+        expect(apiRequestAuthMock).toHaveBeenCalledTimes(1);
+        expect(result).toBe(
+          `https://github.com/manosim/notifications-test/discussions?${mockedNotificationReferrer}`,
+        );
+      });
     });
 
     it('Repository Invitation url', async () => {
diff --git a/src/utils/remove-notifications.test.ts b/src/utils/remove-notifications.test.ts
index 5c9da500..0ec62a90 100644
--- a/src/utils/remove-notifications.test.ts
+++ b/src/utils/remove-notifications.test.ts
@@ -5,7 +5,7 @@ import {
 } from '../__mocks__/mockedData';
 import { removeNotifications } from './remove-notifications';
 
-describe('utils/remove-notification.ts', () => {
+describe('utils/remove-notifications.ts', () => {
   const repoSlug = mockedSingleNotification.repository.full_name;
   const hostname = mockedSingleAccountNotifications[0].hostname;
 
diff --git a/src/utils/subject.test.ts b/src/utils/subject.test.ts
index b4c659af..77f3c2dd 100644
--- a/src/utils/subject.test.ts
+++ b/src/utils/subject.test.ts
@@ -9,7 +9,7 @@ import {
   getWorkflowRunAttributes,
 } from './subject';
 import { SubjectType } from '../typesGithub';
-describe('utils/state.ts', () => {
+describe('utils/subject.ts', () => {
   beforeEach(() => {
     // axios will default to using the XHR adapter which can't be intercepted
     // by nock. So, configure axios to use the node adapter.
@@ -134,460 +134,528 @@ describe('utils/state.ts', () => {
     });
   });
 
-  describe('getGitifySubjectForDiscussion', () => {
-    it('answered discussion state', async () => {
-      const mockNotification = {
-        ...mockedSingleNotification,
-        subject: {
-          ...mockedSingleNotification.subject,
-          title: 'This is an answered discussion',
-          type: 'Discussion' as SubjectType,
-        },
-      };
-
-      nock('https://api.github.com')
-        .post('/graphql')
-        .reply(200, {
-          data: {
-            search: {
-              nodes: [
-                {
-                  title: 'This is an answered discussion',
-                  viewerSubscription: 'SUBSCRIBED',
-                  stateReason: null,
-                  isAnswered: true,
-                  comments: {
-                    nodes: [], //TODO - Update this to have real data
+  describe('getGitifySubjectDetails', () => {
+    describe('Discussions', () => {
+      it('answered discussion state', async () => {
+        const mockNotification = {
+          ...mockedSingleNotification,
+          subject: {
+            ...mockedSingleNotification.subject,
+            title: 'This is an answered discussion',
+            type: 'Discussion' as SubjectType,
+          },
+        };
+
+        nock('https://api.github.com')
+          .post('/graphql')
+          .reply(200, {
+            data: {
+              search: {
+                nodes: [
+                  {
+                    title: 'This is an answered discussion',
+                    viewerSubscription: 'SUBSCRIBED',
+                    stateReason: null,
+                    isAnswered: true,
+                    comments: {
+                      nodes: [], //TODO - Update this to have real data
+                    },
                   },
-                },
-              ],
+                ],
+              },
             },
+          });
+
+        const result = await getGitifySubjectDetails(
+          mockNotification,
+          mockAccounts.token,
+        );
+
+        expect(result.state).toBe('ANSWERED');
+        expect(result.user).toBe(null);
+      });
+
+      it('duplicate discussion state', async () => {
+        const mockNotification = {
+          ...mockedSingleNotification,
+          subject: {
+            ...mockedSingleNotification.subject,
+            title: 'This is a duplicate discussion',
+            type: 'Discussion' as SubjectType,
           },
-        });
-
-      const result = await getGitifySubjectDetails(
-        mockNotification,
-        mockAccounts.token,
-      );
-
-      expect(result.state).toBe('ANSWERED');
-      expect(result.user).toBe(null);
-    });
-
-    it('duplicate discussion state', async () => {
-      const mockNotification = {
-        ...mockedSingleNotification,
-        subject: {
-          ...mockedSingleNotification.subject,
-          title: 'This is a duplicate discussion',
-          type: 'Discussion' as SubjectType,
-        },
-      };
-
-      nock('https://api.github.com')
-        .post('/graphql')
-        .reply(200, {
-          data: {
-            search: {
-              nodes: [
-                {
-                  title: 'This is a duplicate discussion',
-                  viewerSubscription: 'SUBSCRIBED',
-                  stateReason: 'DUPLICATE',
-                  isAnswered: false,
-                  comments: {
-                    nodes: [], //TODO - Update this to have real data
+        };
+
+        nock('https://api.github.com')
+          .post('/graphql')
+          .reply(200, {
+            data: {
+              search: {
+                nodes: [
+                  {
+                    title: 'This is a duplicate discussion',
+                    viewerSubscription: 'SUBSCRIBED',
+                    stateReason: 'DUPLICATE',
+                    isAnswered: false,
+                    comments: {
+                      nodes: [], //TODO - Update this to have real data
+                    },
                   },
-                },
-              ],
+                ],
+              },
             },
+          });
+
+        const result = await getGitifySubjectDetails(
+          mockNotification,
+          mockAccounts.token,
+        );
+
+        expect(result.state).toBe('DUPLICATE');
+        expect(result.user).toBe(null);
+      });
+
+      it('open discussion state', async () => {
+        const mockNotification = {
+          ...mockedSingleNotification,
+          subject: {
+            ...mockedSingleNotification.subject,
+            title: 'This is an open discussion',
+            type: 'Discussion' as SubjectType,
           },
-        });
-
-      const result = await getGitifySubjectDetails(
-        mockNotification,
-        mockAccounts.token,
-      );
-
-      expect(result.state).toBe('DUPLICATE');
-      expect(result.user).toBe(null);
-    });
-
-    it('open discussion state', async () => {
-      const mockNotification = {
-        ...mockedSingleNotification,
-        subject: {
-          ...mockedSingleNotification.subject,
-          title: 'This is an open discussion',
-          type: 'Discussion' as SubjectType,
-        },
-      };
-
-      nock('https://api.github.com')
-        .post('/graphql')
-        .reply(200, {
-          data: {
-            search: {
-              nodes: [
-                {
-                  title: 'This is an open discussion',
-                  viewerSubscription: 'SUBSCRIBED',
-                  stateReason: null,
-                  isAnswered: false,
-                  comments: {
-                    nodes: [], //TODO - Update this to have real data
+        };
+
+        nock('https://api.github.com')
+          .post('/graphql')
+          .reply(200, {
+            data: {
+              search: {
+                nodes: [
+                  {
+                    title: 'This is an open discussion',
+                    viewerSubscription: 'SUBSCRIBED',
+                    stateReason: null,
+                    isAnswered: false,
+                    comments: {
+                      nodes: [], //TODO - Update this to have real data
+                    },
                   },
-                },
-              ],
+                ],
+              },
             },
+          });
+
+        const result = await getGitifySubjectDetails(
+          mockNotification,
+          mockAccounts.token,
+        );
+
+        expect(result.state).toBe('OPEN');
+        expect(result.user).toBe(null);
+      });
+
+      it('outdated discussion state', async () => {
+        const mockNotification = {
+          ...mockedSingleNotification,
+          subject: {
+            ...mockedSingleNotification.subject,
+            title: 'This is an outdated discussion',
+            type: 'Discussion' as SubjectType,
           },
-        });
-
-      const result = await getGitifySubjectDetails(
-        mockNotification,
-        mockAccounts.token,
-      );
-
-      expect(result.state).toBe('OPEN');
-      expect(result.user).toBe(null);
-    });
-
-    it('outdated discussion state', async () => {
-      const mockNotification = {
-        ...mockedSingleNotification,
-        subject: {
-          ...mockedSingleNotification.subject,
-          title: 'This is an outdated discussion',
-          type: 'Discussion' as SubjectType,
-        },
-      };
-
-      nock('https://api.github.com')
-        .post('/graphql')
-        .reply(200, {
-          data: {
-            search: {
-              nodes: [
-                {
-                  title: 'This is an outdated discussion',
-                  viewerSubscription: 'SUBSCRIBED',
-                  stateReason: 'OUTDATED',
-                  isAnswered: false,
-                  comments: {
-                    nodes: [], //TODO - Update this to have real data
+        };
+
+        nock('https://api.github.com')
+          .post('/graphql')
+          .reply(200, {
+            data: {
+              search: {
+                nodes: [
+                  {
+                    title: 'This is an outdated discussion',
+                    viewerSubscription: 'SUBSCRIBED',
+                    stateReason: 'OUTDATED',
+                    isAnswered: false,
+                    comments: {
+                      nodes: [], //TODO - Update this to have real data
+                    },
                   },
-                },
-              ],
+                ],
+              },
             },
+          });
+
+        const result = await getGitifySubjectDetails(
+          mockNotification,
+          mockAccounts.token,
+        );
+
+        expect(result.state).toBe('OUTDATED');
+        expect(result.user).toBe(null);
+      });
+
+      it('reopened discussion state', async () => {
+        const mockNotification = {
+          ...mockedSingleNotification,
+          subject: {
+            ...mockedSingleNotification.subject,
+            title: 'This is a reopened discussion',
+            type: 'Discussion' as SubjectType,
           },
-        });
+        };
+
+        nock('https://api.github.com')
+          .post('/graphql')
+          .reply(200, {
+            data: {
+              search: {
+                nodes: [
+                  {
+                    title: 'This is a reopened discussion',
+                    viewerSubscription: 'SUBSCRIBED',
+                    stateReason: 'REOPENED',
+                    isAnswered: false,
+                    comments: {
+                      nodes: [], //TODO - Update this to have real data
+                    },
+                  },
+                ],
+              },
+            },
+          });
+
+        const result = await getGitifySubjectDetails(
+          mockNotification,
+          mockAccounts.token,
+        );
+
+        expect(result.state).toBe('REOPENED');
+        expect(result.user).toBe(null);
+      });
+
+      it('resolved discussion state', async () => {
+        const mockNotification = {
+          ...mockedSingleNotification,
+          subject: {
+            ...mockedSingleNotification.subject,
+            title: 'This is a resolved discussion',
+            type: 'Discussion' as SubjectType,
+          },
+        };
+
+        nock('https://api.github.com')
+          .post('/graphql')
+          .reply(200, {
+            data: {
+              search: {
+                nodes: [
+                  {
+                    title: 'This is a resolved discussion',
+                    viewerSubscription: 'SUBSCRIBED',
+                    stateReason: 'RESOLVED',
+                    isAnswered: false,
+                    comments: {
+                      nodes: [], //TODO - Update this to have real data
+                    },
+                  },
+                ],
+              },
+            },
+          });
+
+        const result = await getGitifySubjectDetails(
+          mockNotification,
+          mockAccounts.token,
+        );
+
+        expect(result.state).toBe('RESOLVED');
+        expect(result.user).toBe(null);
+      });
+
+      it('filtered response by subscribed', async () => {
+        const mockNotification = {
+          ...mockedSingleNotification,
+          subject: {
+            ...mockedSingleNotification.subject,
+            title: 'This is a discussion',
+            type: 'Discussion' as SubjectType,
+          },
+        };
+
+        nock('https://api.github.com')
+          .post('/graphql')
+          .reply(200, {
+            data: {
+              search: {
+                nodes: [
+                  {
+                    title: 'This is a discussion',
+                    viewerSubscription: 'SUBSCRIBED',
+                    stateReason: null,
+                    isAnswered: false,
+                    comments: {
+                      nodes: [], //TODO - Update this to have real data
+                    },
+                  },
+                  {
+                    title: 'This is a discussion',
+                    viewerSubscription: 'IGNORED',
+                    stateReason: null,
+                    isAnswered: true,
+                    comments: {
+                      nodes: [], //TODO - Update this to have real data
+                    },
+                  },
+                ],
+              },
+            },
+          });
 
-      const result = await getGitifySubjectDetails(
-        mockNotification,
-        mockAccounts.token,
-      );
+        const result = await getGitifySubjectDetails(
+          mockNotification,
+          mockAccounts.token,
+        );
 
-      expect(result.state).toBe('OUTDATED');
-      expect(result.user).toBe(null);
+        expect(result.state).toBe('OPEN');
+        expect(result.user).toBe(null);
+      });
     });
 
-    it('reopened discussion state', async () => {
-      const mockNotification = {
-        ...mockedSingleNotification,
-        subject: {
-          ...mockedSingleNotification.subject,
-          title: 'This is a reopened discussion',
-          type: 'Discussion' as SubjectType,
-        },
-      };
-
-      nock('https://api.github.com')
-        .post('/graphql')
-        .reply(200, {
-          data: {
-            search: {
-              nodes: [
-                {
-                  title: 'This is a reopened discussion',
-                  viewerSubscription: 'SUBSCRIBED',
-                  stateReason: 'REOPENED',
-                  isAnswered: false,
-                  comments: {
-                    nodes: [], //TODO - Update this to have real data
-                  },
-                },
-              ],
+    describe('Issues', () => {
+      it('open issue state', async () => {
+        nock('https://api.github.com')
+          .get('/repos/manosim/notifications-test/issues/1')
+          .reply(200, { state: 'open' });
+
+        nock('https://api.github.com')
+          .get('/repos/manosim/notifications-test/issues/comments/302888448')
+          .reply(200, { user: { login: 'some-user' } });
+
+        const result = await getGitifySubjectDetails(
+          mockedSingleNotification,
+          mockAccounts.token,
+        );
+
+        expect(result.state).toBe('open');
+        expect(result.user).toBe('some-user');
+      });
+
+      it('closed issue state', async () => {
+        nock('https://api.github.com')
+          .get('/repos/manosim/notifications-test/issues/1')
+          .reply(200, { state: 'closed' });
+
+        nock('https://api.github.com')
+          .get('/repos/manosim/notifications-test/issues/comments/302888448')
+          .reply(200, { user: { login: 'some-user' } });
+
+        const result = await getGitifySubjectDetails(
+          mockedSingleNotification,
+          mockAccounts.token,
+        );
+
+        expect(result.state).toBe('closed');
+        expect(result.user).toBe('some-user');
+      });
+
+      it('completed issue state', async () => {
+        nock('https://api.github.com')
+          .get('/repos/manosim/notifications-test/issues/1')
+          .reply(200, { state: 'closed', state_reason: 'completed' });
+
+        nock('https://api.github.com')
+          .get('/repos/manosim/notifications-test/issues/comments/302888448')
+          .reply(200, { user: { login: 'some-user' } });
+
+        const result = await getGitifySubjectDetails(
+          mockedSingleNotification,
+          mockAccounts.token,
+        );
+
+        expect(result.state).toBe('completed');
+        expect(result.user).toBe('some-user');
+      });
+
+      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' });
+
+        nock('https://api.github.com')
+          .get('/repos/manosim/notifications-test/issues/comments/302888448')
+          .reply(200, { user: { login: 'some-user' } });
+
+        const result = await getGitifySubjectDetails(
+          mockedSingleNotification,
+          mockAccounts.token,
+        );
+
+        expect(result.state).toBe('not_planned');
+        expect(result.user).toBe('some-user');
+      });
+
+      it('reopened issue state', async () => {
+        nock('https://api.github.com')
+          .get('/repos/manosim/notifications-test/issues/1')
+          .reply(200, { state: 'open', state_reason: 'reopened' });
+
+        nock('https://api.github.com')
+          .get('/repos/manosim/notifications-test/issues/comments/302888448')
+          .reply(200, { user: { login: 'some-user' } });
+
+        const result = await getGitifySubjectDetails(
+          mockedSingleNotification,
+          mockAccounts.token,
+        );
+
+        expect(result.state).toBe('reopened');
+        expect(result.user).toBe('some-user');
+      });
+
+      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 });
+
+        const result = await getGitifySubjectDetails(
+          {
+            ...mockedSingleNotification,
+            subject: {
+              ...mockedSingleNotification.subject,
+              latest_comment_url: null,
             },
           },
-        });
+          mockAccounts.token,
+        );
 
-      const result = await getGitifySubjectDetails(
-        mockNotification,
-        mockAccounts.token,
-      );
-
-      expect(result.state).toBe('REOPENED');
-      expect(result.user).toBe(null);
+        expect(result.state).toBe('open');
+        expect(result.user).toBeNull();
+      });
     });
 
-    it('resolved discussion state', async () => {
+    describe('Pull Requests', () => {
       const mockNotification = {
         ...mockedSingleNotification,
         subject: {
           ...mockedSingleNotification.subject,
-          title: 'This is a resolved discussion',
-          type: 'Discussion' as SubjectType,
+          type: 'PullRequest' as SubjectType,
         },
       };
 
-      nock('https://api.github.com')
-        .post('/graphql')
-        .reply(200, {
-          data: {
-            search: {
-              nodes: [
-                {
-                  title: 'This is a resolved discussion',
-                  viewerSubscription: 'SUBSCRIBED',
-                  stateReason: 'RESOLVED',
-                  isAnswered: false,
-                  comments: {
-                    nodes: [], //TODO - Update this to have real data
-                  },
-                },
-              ],
+      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 });
+
+        nock('https://api.github.com')
+          .get('/repos/manosim/notifications-test/issues/comments/302888448')
+          .reply(200, { user: { login: 'some-user' } });
+
+        const result = await getGitifySubjectDetails(
+          mockNotification,
+          mockAccounts.token,
+        );
+
+        expect(result.state).toBe('closed');
+        expect(result.user).toBe('some-user');
+      });
+
+      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 });
+
+        nock('https://api.github.com')
+          .get('/repos/manosim/notifications-test/issues/comments/302888448')
+          .reply(200, { user: { login: 'some-user' } });
+
+        const result = await getGitifySubjectDetails(
+          mockNotification,
+          mockAccounts.token,
+        );
+
+        expect(result.state).toBe('draft');
+        expect(result.user).toBe('some-user');
+      });
+
+      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 });
+
+        nock('https://api.github.com')
+          .get('/repos/manosim/notifications-test/issues/comments/302888448')
+          .reply(200, { user: { login: 'some-user' } });
+
+        const result = await getGitifySubjectDetails(
+          mockNotification,
+          mockAccounts.token,
+        );
+
+        expect(result.state).toBe('merged');
+        expect(result.user).toBe('some-user');
+      });
+
+      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 });
+
+        nock('https://api.github.com')
+          .get('/repos/manosim/notifications-test/issues/comments/302888448')
+          .reply(200, { user: { login: 'some-user' } });
+
+        const result = await getGitifySubjectDetails(
+          mockNotification,
+          mockAccounts.token,
+        );
+
+        expect(result.state).toBe('open');
+        expect(result.user).toBe('some-user');
+      });
+
+      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 });
+
+        const result = await getGitifySubjectDetails(
+          {
+            ...mockNotification,
+            subject: {
+              ...mockNotification.subject,
+              latest_comment_url: null,
             },
           },
-        });
+          mockAccounts.token,
+        );
 
-      const result = await getGitifySubjectDetails(
-        mockNotification,
-        mockAccounts.token,
-      );
-
-      expect(result.state).toBe('RESOLVED');
-      expect(result.user).toBe(null);
+        expect(result.state).toBe('open');
+        expect(result.user).toBeNull();
+      });
     });
+  });
 
-    it('filtered response by subscribed', async () => {
+  describe('getGitifySubjectForRelease', () => {
+    it('release notification', async () => {
       const mockNotification = {
         ...mockedSingleNotification,
         subject: {
           ...mockedSingleNotification.subject,
-          title: 'This is a discussion',
-          type: 'Discussion' as SubjectType,
+          type: 'Release' as SubjectType,
+          url: 'https://api.github.com/repos/manosim/notifications-test/releases/1',
+          latest_comment_url:
+            'https://api.github.com/repos/manosim/notifications-test/releases/1',
         },
       };
 
       nock('https://api.github.com')
-        .post('/graphql')
-        .reply(200, {
-          data: {
-            search: {
-              nodes: [
-                {
-                  title: 'This is a discussion',
-                  viewerSubscription: 'SUBSCRIBED',
-                  stateReason: null,
-                  isAnswered: false,
-                  comments: {
-                    nodes: [], //TODO - Update this to have real data
-                  },
-                },
-                {
-                  title: 'This is a discussion',
-                  viewerSubscription: 'IGNORED',
-                  stateReason: null,
-                  isAnswered: true,
-                  comments: {
-                    nodes: [], //TODO - Update this to have real data
-                  },
-                },
-              ],
-            },
-          },
-        });
-
-      const result = await getGitifySubjectDetails(
-        mockNotification,
-        mockAccounts.token,
-      );
-
-      expect(result.state).toBe('OPEN');
-      expect(result.user).toBe(null);
-    });
-  });
-
-  describe('getGitifySubjectForIssue', () => {
-    it('open issue state', async () => {
-      nock('https://api.github.com')
-        .get('/repos/manosim/notifications-test/issues/1')
-        .reply(200, { state: 'open' });
-
-      nock('https://api.github.com')
-        .get('/repos/manosim/notifications-test/issues/comments/302888448')
-        .reply(200, { user: { login: 'some-user' } });
-
-      const result = await getGitifySubjectDetails(
-        mockedSingleNotification,
-        mockAccounts.token,
-      );
-
-      expect(result.state).toBe('open');
-      expect(result.user).toBe('some-user');
-    });
-
-    it('closed issue state', async () => {
-      nock('https://api.github.com')
-        .get('/repos/manosim/notifications-test/issues/1')
-        .reply(200, { state: 'closed' });
-
-      nock('https://api.github.com')
-        .get('/repos/manosim/notifications-test/issues/comments/302888448')
-        .reply(200, { user: { login: 'some-user' } });
-
-      const result = await getGitifySubjectDetails(
-        mockedSingleNotification,
-        mockAccounts.token,
-      );
-
-      expect(result.state).toBe('closed');
-      expect(result.user).toBe('some-user');
-    });
-
-    it('completed issue state', async () => {
-      nock('https://api.github.com')
-        .get('/repos/manosim/notifications-test/issues/1')
-        .reply(200, { state: 'closed', state_reason: 'completed' });
-
-      nock('https://api.github.com')
-        .get('/repos/manosim/notifications-test/issues/comments/302888448')
-        .reply(200, { user: { login: 'some-user' } });
-
-      const result = await getGitifySubjectDetails(
-        mockedSingleNotification,
-        mockAccounts.token,
-      );
-
-      expect(result.state).toBe('completed');
-      expect(result.user).toBe('some-user');
-    });
-
-    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' });
-
-      nock('https://api.github.com')
-        .get('/repos/manosim/notifications-test/issues/comments/302888448')
-        .reply(200, { user: { login: 'some-user' } });
-
-      const result = await getGitifySubjectDetails(
-        mockedSingleNotification,
-        mockAccounts.token,
-      );
-
-      expect(result.state).toBe('not_planned');
-      expect(result.user).toBe('some-user');
-    });
-
-    it('reopened issue state', async () => {
-      nock('https://api.github.com')
-        .get('/repos/manosim/notifications-test/issues/1')
-        .reply(200, { state: 'open', state_reason: 'reopened' });
-
-      nock('https://api.github.com')
-        .get('/repos/manosim/notifications-test/issues/comments/302888448')
-        .reply(200, { user: { login: 'some-user' } });
-
-      const result = await getGitifySubjectDetails(
-        mockedSingleNotification,
-        mockAccounts.token,
-      );
-
-      expect(result.state).toBe('reopened');
-      expect(result.user).toBe('some-user');
-    });
-  });
-
-  describe('getGitifySubjectForPullRequest', () => {
-    const mockNotification = {
-      ...mockedSingleNotification,
-      subject: {
-        ...mockedSingleNotification.subject,
-        type: 'PullRequest' as SubjectType,
-      },
-    };
-
-    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 });
-
-      nock('https://api.github.com')
-        .get('/repos/manosim/notifications-test/issues/comments/302888448')
-        .reply(200, { user: { login: 'some-user' } });
-
-      const result = await getGitifySubjectDetails(
-        mockNotification,
-        mockAccounts.token,
-      );
-
-      expect(result.state).toBe('closed');
-      expect(result.user).toBe('some-user');
-    });
-
-    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 });
-
-      nock('https://api.github.com')
-        .get('/repos/manosim/notifications-test/issues/comments/302888448')
-        .reply(200, { user: { login: 'some-user' } });
-
-      const result = await getGitifySubjectDetails(
-        mockNotification,
-        mockAccounts.token,
-      );
-
-      expect(result.state).toBe('draft');
-      expect(result.user).toBe('some-user');
-    });
-
-    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 });
-
-      nock('https://api.github.com')
-        .get('/repos/manosim/notifications-test/issues/comments/302888448')
-        .reply(200, { user: { login: 'some-user' } });
-
-      const result = await getGitifySubjectDetails(
-        mockNotification,
-        mockAccounts.token,
-      );
-
-      expect(result.state).toBe('merged');
-      expect(result.user).toBe('some-user');
-    });
-
-    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 });
-
-      nock('https://api.github.com')
-        .get('/repos/manosim/notifications-test/issues/comments/302888448')
-        .reply(200, { user: { login: 'some-user' } });
+        .get('/repos/manosim/notifications-test/releases/1')
+        .reply(200, { author: { login: 'some-user' } });
 
       const result = await getGitifySubjectDetails(
         mockNotification,
         mockAccounts.token,
       );
 
-      expect(result.state).toBe('open');
       expect(result.user).toBe('some-user');
     });
   });