From b8bdd7e61156291f649b394c17351ba023f0faf2 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 28 Jul 2024 07:58:01 +1000 Subject: [PATCH] feat: multi account gracefully degrade --- src/__mocks__/notifications-mocks.ts | 3 +++ src/components/AccountNotifications.tsx | 5 ++++- src/hooks/useNotifications.ts | 20 ++++++++++------- src/routes/Notifications.tsx | 1 + src/types.ts | 1 + src/utils/notifications.ts | 30 ++++++++++++++++--------- 6 files changed, 41 insertions(+), 19 deletions(-) diff --git a/src/__mocks__/notifications-mocks.ts b/src/__mocks__/notifications-mocks.ts index 438ab37b0..0abbe39cc 100644 --- a/src/__mocks__/notifications-mocks.ts +++ b/src/__mocks__/notifications-mocks.ts @@ -12,10 +12,12 @@ export const mockAccountNotifications: AccountNotifications[] = [ { account: mockGitHubCloudAccount, notifications: mockGitHubNotifications, + error: null, }, { account: mockGitHubEnterpriseServerAccount, notifications: mockEnterpriseNotifications, + error: null, }, ]; @@ -23,5 +25,6 @@ export const mockSingleAccountNotifications: AccountNotifications[] = [ { account: mockGitHubCloudAccount, notifications: [mockGitHubNotifications[0]], + error: null, }, ]; diff --git a/src/components/AccountNotifications.tsx b/src/components/AccountNotifications.tsx index 5d9f1552a..16173e7a8 100644 --- a/src/components/AccountNotifications.tsx +++ b/src/components/AccountNotifications.tsx @@ -5,12 +5,13 @@ import { } from '@primer/octicons-react'; import { type FC, type MouseEvent, useContext, useState } from 'react'; import { AppContext } from '../context/App'; -import { type Account, Opacity, Size } from '../types'; +import { type Account, type GitifyError, Opacity, Size } from '../types'; import type { Notification } from '../typesGitHub'; import { cn } from '../utils/cn'; import { openAccountProfile } from '../utils/links'; import { HoverGroup } from './HoverGroup'; import { NotificationRow } from './NotificationRow'; +import { Oops } from './Oops'; import { RepositoryNotifications } from './RepositoryNotifications'; import { InteractionButton } from './buttons/InteractionButton'; import { PlatformIcon } from './icons/PlatformIcon'; @@ -18,6 +19,7 @@ import { PlatformIcon } from './icons/PlatformIcon'; interface IAccountNotifications { account: Account; notifications: Notification[]; + error?: GitifyError; showAccountHostname: boolean; } @@ -103,6 +105,7 @@ export const AccountNotifications: FC = ( {showAccountNotifications && ( <> + {props?.error && } {groupByRepository ? Object.values(groupedNotifications).map((repoNotifications) => { const repoSlug = repoNotifications[0].repository.full_name; diff --git a/src/hooks/useNotifications.ts b/src/hooks/useNotifications.ts index b8fb28499..daaab0076 100644 --- a/src/hooks/useNotifications.ts +++ b/src/hooks/useNotifications.ts @@ -12,7 +12,6 @@ import { markNotificationThreadAsRead, markRepositoryNotificationsAsRead, } from '../utils/api/client'; -import { determineFailureType } from '../utils/api/errors'; import { getAccountUUID } from '../utils/auth/utils'; import { getAllNotifications, @@ -61,16 +60,21 @@ export const useNotifications = (): NotificationsState => { async (state: GitifyState) => { setStatus('loading'); - try { - const fetchedNotifications = await getAllNotifications(state); + const fetchedNotifications = await getAllNotifications(state); - setNotifications(fetchedNotifications); - triggerNativeNotifications(notifications, fetchedNotifications, state); - setStatus('success'); - } catch (err) { + if ( + fetchedNotifications.every((account) => { + return account.error !== null; + }) + ) { setStatus('error'); - setErrorDetails(determineFailureType(err)); + setErrorDetails(fetchedNotifications[0].error); + return; } + + setNotifications(fetchedNotifications); + triggerNativeNotifications(notifications, fetchedNotifications, state); + setStatus('success'); }, [notifications], ); diff --git a/src/routes/Notifications.tsx b/src/routes/Notifications.tsx index 6d8019c23..1e500902a 100644 --- a/src/routes/Notifications.tsx +++ b/src/routes/Notifications.tsx @@ -39,6 +39,7 @@ export const NotificationsRoute: FC = () => { key={getAccountUUID(accountNotifications.account)} account={accountNotifications.account} notifications={accountNotifications.notifications} + error={accountNotifications.error} showAccountHostname={ hasMultipleAccounts || settings.showAccountHostname } diff --git a/src/types.ts b/src/types.ts index a51c648e5..e7cac771f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -123,6 +123,7 @@ export type RadioGroupItem = { export interface AccountNotifications { account: Account; notifications: Notification[]; + error: GitifyError | null; } export interface GitifyUser { diff --git a/src/utils/notifications.ts b/src/utils/notifications.ts index 44ffcc0e2..35ad9d2a5 100644 --- a/src/utils/notifications.ts +++ b/src/utils/notifications.ts @@ -5,6 +5,7 @@ import type { } from '../types'; import { Notification } from '../typesGitHub'; import { listNotificationsForAuthenticatedUser } from './api/client'; +import { determineFailureType } from './api/errors'; import { getAccountUUID } from './auth/utils'; import { hideWindow, showWindow, updateTrayIcon } from './comms'; import { openNotification } from './links'; @@ -129,21 +130,30 @@ export async function getAllNotifications( responses .filter((response) => !!response) .map(async (accountNotifications) => { - let notifications = (await accountNotifications.notifications).data.map( - (notification: Notification) => ({ + try { + let notifications = ( + await accountNotifications.notifications + ).data.map((notification: Notification) => ({ ...notification, account: accountNotifications.account, - }), - ); + })); - notifications = await enrichNotifications(notifications, state); + notifications = await enrichNotifications(notifications, state); - notifications = filterNotifications(notifications, state.settings); + notifications = filterNotifications(notifications, state.settings); - return { - account: accountNotifications.account, - notifications: notifications, - }; + return { + account: accountNotifications.account, + notifications: notifications, + error: null, + }; + } catch (error) { + return { + account: accountNotifications.account, + notifications: [], + error: determineFailureType(error), + }; + } }), );