diff --git a/packages/desktop-client/src/components/ManageRulesPage.tsx b/packages/desktop-client/src/components/ManageRulesPage.tsx index 59e2327e44..615f256e17 100644 --- a/packages/desktop-client/src/components/ManageRulesPage.tsx +++ b/packages/desktop-client/src/components/ManageRulesPage.tsx @@ -1,14 +1,19 @@ import React from 'react'; +import { ErrorBoundary } from 'react-error-boundary'; import { useTranslation } from 'react-i18next'; +import { FeatureErrorFallback } from '#components/FeatureErrorFallback'; + import { ManageRules } from './ManageRules'; import { Page } from './Page'; export function ManageRulesPage() { const { t } = useTranslation(); return ( - - - + + + + + ); } diff --git a/packages/desktop-client/src/components/accounts/Account.tsx b/packages/desktop-client/src/components/accounts/Account.tsx index 39615c68d8..cc7255cce2 100644 --- a/packages/desktop-client/src/components/accounts/Account.tsx +++ b/packages/desktop-client/src/components/accounts/Account.tsx @@ -1,5 +1,6 @@ import React, { createRef, PureComponent, useEffect, useMemo } from 'react'; import type { ReactElement, RefObject } from 'react'; +import { ErrorBoundary } from 'react-error-boundary'; import { Trans } from 'react-i18next'; import { Navigate, useLocation, useParams } from 'react-router'; @@ -43,6 +44,7 @@ import { useUpdateAccountMutation, } from '#accounts'; import { markAccountRead } from '#accounts/accountsSlice'; +import { FeatureErrorFallback } from '#components/FeatureErrorFallback'; import type { SavedFilter } from '#components/filters/SavedFilterMenuButton'; import { TransactionList } from '#components/transactions/TransactionList'; import { validateAccountName } from '#components/util/accountValidation'; @@ -2031,48 +2033,50 @@ export function Account() { createPayee.mutateAsync({ name }); return ( - - - - setShowBalances(String(showBalances)) - } - showNetWorthChart={String(showNetWorthChart) === 'true'} - setShowNetWorthChart={val => setShowNetWorthChart(String(val))} - showCleared={String(hideCleared) !== 'true'} - setShowCleared={val => setHideCleared(String(!val))} - showReconciled={String(hideReconciled) !== 'true'} - setShowReconciled={val => setHideReconciled(String(!val))} - showExtraBalances={String(showExtraBalances) === 'true'} - setShowExtraBalances={extraBalances => - setShowExtraBalances(String(extraBalances)) - } - payees={payees} - modalShowing={modalShowing} - accountsSyncing={accountsSyncing} - filterConditions={filterConditions} - categoryGroups={categoryGroups} - accountId={params.id} - categoryId={location?.state?.categoryId} - location={location} - savedFilters={savedFiters} - onReopenAccount={onReopenAccount} - onUpdateAccount={onUpdateAccount} - onUnlinkAccount={onUnlinkAccount} - onSyncAndDownload={onSyncAndDownload} - onCreatePayee={onCreatePayee} - /> - - + + + + + setShowBalances(String(showBalances)) + } + showNetWorthChart={String(showNetWorthChart) === 'true'} + setShowNetWorthChart={val => setShowNetWorthChart(String(val))} + showCleared={String(hideCleared) !== 'true'} + setShowCleared={val => setHideCleared(String(!val))} + showReconciled={String(hideReconciled) !== 'true'} + setShowReconciled={val => setHideReconciled(String(!val))} + showExtraBalances={String(showExtraBalances) === 'true'} + setShowExtraBalances={extraBalances => + setShowExtraBalances(String(extraBalances)) + } + payees={payees} + modalShowing={modalShowing} + accountsSyncing={accountsSyncing} + filterConditions={filterConditions} + categoryGroups={categoryGroups} + accountId={params.id} + categoryId={location?.state?.categoryId} + location={location} + savedFilters={savedFiters} + onReopenAccount={onReopenAccount} + onUpdateAccount={onUpdateAccount} + onUnlinkAccount={onUnlinkAccount} + onSyncAndDownload={onSyncAndDownload} + onCreatePayee={onCreatePayee} + /> + + + ); } diff --git a/packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx b/packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx index 1ac488b49b..88a8debc8f 100644 --- a/packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx +++ b/packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx @@ -1,12 +1,14 @@ // @ts-strict-ignore import React, { useEffect } from 'react'; import type { ComponentProps } from 'react'; +import { ErrorBoundary } from 'react-error-boundary'; import { useHotkeys } from 'react-hotkeys-hook'; import { AutoSizer } from 'react-virtualized-auto-sizer'; import { View } from '@actual-app/components/view'; import * as monthUtils from '@actual-app/core/shared/months'; +import { FeatureErrorFallback } from '#components/FeatureErrorFallback'; import { useGlobalPref } from '#hooks/useGlobalPref'; import { useBudgetMonthCount } from './BudgetMonthCountContext'; @@ -131,20 +133,22 @@ const DynamicBudgetTable = ({ }} > - - + + + + ); diff --git a/packages/desktop-client/src/components/schedules/index.tsx b/packages/desktop-client/src/components/schedules/index.tsx index 587855c997..0b640bd32e 100644 --- a/packages/desktop-client/src/components/schedules/index.tsx +++ b/packages/desktop-client/src/components/schedules/index.tsx @@ -1,4 +1,5 @@ import React, { useCallback, useMemo, useState } from 'react'; +import { ErrorBoundary } from 'react-error-boundary'; import { Trans, useTranslation } from 'react-i18next'; import { Button } from '@actual-app/components/button'; @@ -9,6 +10,7 @@ import { q } from '@actual-app/core/shared/query'; import type { ScheduleEntity } from '@actual-app/core/types/models'; import { Search } from '#components/common/Search'; +import { FeatureErrorFallback } from '#components/FeatureErrorFallback'; import { Page } from '#components/Page'; import { useSchedules } from '#hooks/useSchedules'; import { pushModal } from '#modals/modalsSlice'; @@ -85,66 +87,68 @@ export function Schedules() { } = useSchedules({ query: schedulesQuery }); return ( - - - - - - - - - - + + - - + + + - - - + + ); } diff --git a/packages/desktop-client/src/components/sidebar/Sidebar.tsx b/packages/desktop-client/src/components/sidebar/Sidebar.tsx index 61db2565f7..1cd658eac0 100644 --- a/packages/desktop-client/src/components/sidebar/Sidebar.tsx +++ b/packages/desktop-client/src/components/sidebar/Sidebar.tsx @@ -1,5 +1,6 @@ import React, { useState } from 'react'; import type { CSSProperties } from 'react'; +import { ErrorBoundary } from 'react-error-boundary'; import { useTranslation } from 'react-i18next'; import { useResponsive } from '@actual-app/components/hooks/useResponsive'; @@ -11,6 +12,7 @@ import * as Platform from '@actual-app/core/shared/platform'; import { css } from '@emotion/css'; import { Resizable } from 're-resizable'; +import { FeatureErrorFallback } from '#components/FeatureErrorFallback'; import { useGlobalPref } from '#hooks/useGlobalPref'; import { useLocalPref } from '#hooks/useLocalPref'; import { useResizeObserver } from '#hooks/useResizeObserver'; @@ -67,69 +69,75 @@ export function Sidebar() { }); return ( - - + - - {!sidebar.alwaysFloats && ( - - )} - - - + + {!sidebar.alwaysFloats && ( + + )} + - + + - + + + + - - + + ); } diff --git a/packages/desktop-client/src/components/transactions/TransactionList.tsx b/packages/desktop-client/src/components/transactions/TransactionList.tsx index b22ef7c93c..09d2cc8167 100644 --- a/packages/desktop-client/src/components/transactions/TransactionList.tsx +++ b/packages/desktop-client/src/components/transactions/TransactionList.tsx @@ -2,6 +2,7 @@ // TODO: remove strict import { useCallback, useLayoutEffect, useRef } from 'react'; import type { RefObject } from 'react'; +import { ErrorBoundary } from 'react-error-boundary'; import { useTranslation } from 'react-i18next'; import { theme } from '@actual-app/components/theme'; @@ -29,6 +30,7 @@ import type { TransactionFilterEntity, } from '@actual-app/core/types/models'; +import { FeatureErrorFallback } from '#components/FeatureErrorFallback'; import type { TableHandleRef } from '#components/table'; import { isValidBoundaryDrop } from '#hooks/useDragDrop'; import type { DropPosition } from '#hooks/useDragDrop'; @@ -722,53 +724,55 @@ export function TransactionList({ ); return ( - + + + ); } diff --git a/upcoming-release-notes/7497.md b/upcoming-release-notes/7497.md new file mode 100644 index 0000000000..19f9f5da05 --- /dev/null +++ b/upcoming-release-notes/7497.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [tempiz] +--- + +Add scoped error boundaries to prevent feature-level crashes from taking down the entire app