mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 20:29:36 +02:00
refactor app error boundaries
This commit is contained in:
+1
-1
@@ -120,7 +120,7 @@
|
|||||||
"react-image": "^4.1.0",
|
"react-image": "^4.1.0",
|
||||||
"react-loading-skeleton": "^3.5.0",
|
"react-loading-skeleton": "^3.5.0",
|
||||||
"react-player": "^2.11.0",
|
"react-player": "^2.11.0",
|
||||||
"react-router": "^7.9.4",
|
"react-router": "^7.9.6",
|
||||||
"react-virtualized-auto-sizer": "^1.0.26",
|
"react-virtualized-auto-sizer": "^1.0.26",
|
||||||
"react-window": "1.8.11",
|
"react-window": "1.8.11",
|
||||||
"react-window-v2": "npm:react-window@^2.2.3",
|
"react-window-v2": "npm:react-window@^2.2.3",
|
||||||
|
|||||||
Generated
+27
-8
@@ -46,7 +46,7 @@ importers:
|
|||||||
version: 8.3.8(@mantine/core@8.3.8(@mantine/hooks@8.3.8(react@19.1.0))(@types/react@19.2.5)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@8.3.8(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
version: 8.3.8(@mantine/core@8.3.8(@mantine/hooks@8.3.8(react@19.1.0))(@types/react@19.2.5)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@8.3.8(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
'@offlegacy/nuqs-hash-router':
|
'@offlegacy/nuqs-hash-router':
|
||||||
specifier: ^0.1.1
|
specifier: ^0.1.1
|
||||||
version: 0.1.1(nuqs@2.7.1(react-router-dom@7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-router@7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0))(react@19.1.0)
|
version: 0.1.1(nuqs@2.7.1(react-router-dom@7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-router@7.9.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0))(react@19.1.0)
|
||||||
'@radix-ui/react-context-menu':
|
'@radix-ui/react-context-menu':
|
||||||
specifier: ^2.2.16
|
specifier: ^2.2.16
|
||||||
version: 2.2.16(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
version: 2.2.16(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
@@ -151,7 +151,7 @@ importers:
|
|||||||
version: https://codeload.github.com/jeffvli/Node-MPV/tar.gz/32b4d64395289ad710c41d481d2707a7acfc228f
|
version: https://codeload.github.com/jeffvli/Node-MPV/tar.gz/32b4d64395289ad710c41d481d2707a7acfc228f
|
||||||
nuqs:
|
nuqs:
|
||||||
specifier: ^2.7.1
|
specifier: ^2.7.1
|
||||||
version: 2.7.1(react-router-dom@7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-router@7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)
|
version: 2.7.1(react-router-dom@7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-router@7.9.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)
|
||||||
overlayscrollbars:
|
overlayscrollbars:
|
||||||
specifier: ^2.11.1
|
specifier: ^2.11.1
|
||||||
version: 2.11.3
|
version: 2.11.3
|
||||||
@@ -189,8 +189,8 @@ importers:
|
|||||||
specifier: ^2.11.0
|
specifier: ^2.11.0
|
||||||
version: 2.16.0(react@19.1.0)
|
version: 2.16.0(react@19.1.0)
|
||||||
react-router:
|
react-router:
|
||||||
specifier: ^7.9.4
|
specifier: ^7.9.6
|
||||||
version: 7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
version: 7.9.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
react-virtualized-auto-sizer:
|
react-virtualized-auto-sizer:
|
||||||
specifier: ^1.0.26
|
specifier: ^1.0.26
|
||||||
version: 1.0.26(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
version: 1.0.26(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
@@ -4610,6 +4610,16 @@ packages:
|
|||||||
react-dom:
|
react-dom:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
react-router@7.9.6:
|
||||||
|
resolution: {integrity: sha512-Y1tUp8clYRXpfPITyuifmSoE2vncSME18uVLgaqyxh9H35JWpIfzHo+9y3Fzh5odk/jxPW29IgLgzcdwxGqyNA==}
|
||||||
|
engines: {node: '>=20.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=18'
|
||||||
|
react-dom: '>=18'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
react-dom:
|
||||||
|
optional: true
|
||||||
|
|
||||||
react-style-singleton@2.2.3:
|
react-style-singleton@2.2.3:
|
||||||
resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==}
|
resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -7101,9 +7111,9 @@ snapshots:
|
|||||||
mkdirp: 1.0.4
|
mkdirp: 1.0.4
|
||||||
rimraf: 3.0.2
|
rimraf: 3.0.2
|
||||||
|
|
||||||
'@offlegacy/nuqs-hash-router@0.1.1(nuqs@2.7.1(react-router-dom@7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-router@7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0))(react@19.1.0)':
|
'@offlegacy/nuqs-hash-router@0.1.1(nuqs@2.7.1(react-router-dom@7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-router@7.9.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0))(react@19.1.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
nuqs: 2.7.1(react-router-dom@7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-router@7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)
|
nuqs: 2.7.1(react-router-dom@7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-router@7.9.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
|
|
||||||
'@pkgjs/parseargs@0.11.0':
|
'@pkgjs/parseargs@0.11.0':
|
||||||
@@ -10148,12 +10158,12 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
boolbase: 1.0.0
|
boolbase: 1.0.0
|
||||||
|
|
||||||
nuqs@2.7.1(react-router-dom@7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-router@7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0):
|
nuqs@2.7.1(react-router-dom@7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-router@7.9.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@standard-schema/spec': 1.0.0
|
'@standard-schema/spec': 1.0.0
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
react-router: 7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
react-router: 7.9.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
react-router-dom: 7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
react-router-dom: 7.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
|
|
||||||
object-assign@4.1.1: {}
|
object-assign@4.1.1: {}
|
||||||
@@ -10571,6 +10581,15 @@ snapshots:
|
|||||||
set-cookie-parser: 2.7.1
|
set-cookie-parser: 2.7.1
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
react-dom: 19.1.0(react@19.1.0)
|
react-dom: 19.1.0(react@19.1.0)
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
react-router@7.9.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||||
|
dependencies:
|
||||||
|
cookie: 1.0.2
|
||||||
|
react: 19.1.0
|
||||||
|
set-cookie-parser: 2.7.1
|
||||||
|
optionalDependencies:
|
||||||
|
react-dom: 19.1.0(react@19.1.0)
|
||||||
|
|
||||||
react-style-singleton@2.2.3(@types/react@19.2.5)(react@19.1.0):
|
react-style-singleton@2.2.3(@types/react@19.2.5)(react@19.1.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useNavigate, useRouteError } from 'react-router';
|
|
||||||
|
|
||||||
import { AppMenu } from '/@/renderer/features/titlebar/components/app-menu';
|
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
|
||||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
|
||||||
import { Button } from '/@/shared/components/button/button';
|
|
||||||
import { Center } from '/@/shared/components/center/center';
|
|
||||||
import { Divider } from '/@/shared/components/divider/divider';
|
|
||||||
import { DropdownMenu } from '/@/shared/components/dropdown-menu/dropdown-menu';
|
|
||||||
import { Group } from '/@/shared/components/group/group';
|
|
||||||
import { Icon } from '/@/shared/components/icon/icon';
|
|
||||||
import { Stack } from '/@/shared/components/stack/stack';
|
|
||||||
import { Text } from '/@/shared/components/text/text';
|
|
||||||
|
|
||||||
const RouteErrorBoundary = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const error = useRouteError() as any;
|
|
||||||
console.error('error', error);
|
|
||||||
|
|
||||||
const handleReload = () => {
|
|
||||||
navigate(0);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleReturn = () => {
|
|
||||||
navigate(-1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleHome = () => {
|
|
||||||
navigate(AppRoute.HOME);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ backgroundColor: 'var(--theme-colors-background)' }}>
|
|
||||||
<Center style={{ height: '100vh' }}>
|
|
||||||
<Stack style={{ maxWidth: '50%' }}>
|
|
||||||
<Group>
|
|
||||||
<ActionIcon
|
|
||||||
icon="arrowLeftS"
|
|
||||||
onClick={handleReturn}
|
|
||||||
px={10}
|
|
||||||
variant="subtle"
|
|
||||||
/>
|
|
||||||
<Icon fill="error" icon="error" size="lg" />
|
|
||||||
<Text size="lg">{t('error.genericError')}</Text>
|
|
||||||
</Group>
|
|
||||||
<Divider my={5} />
|
|
||||||
<Text size="sm">{error?.message}</Text>
|
|
||||||
<Group gap="sm" grow>
|
|
||||||
<Button
|
|
||||||
leftSection={<Icon icon="home" />}
|
|
||||||
onClick={handleHome}
|
|
||||||
size="md"
|
|
||||||
style={{ flex: 0.5 }}
|
|
||||||
variant="default"
|
|
||||||
>
|
|
||||||
{t('page.home.title')}
|
|
||||||
</Button>
|
|
||||||
<DropdownMenu position="bottom-start">
|
|
||||||
<DropdownMenu.Target>
|
|
||||||
<Button
|
|
||||||
leftSection={<Icon icon="menu" />}
|
|
||||||
size="md"
|
|
||||||
style={{ flex: 0.5 }}
|
|
||||||
variant="default"
|
|
||||||
>
|
|
||||||
{t('common.menu')}
|
|
||||||
</Button>
|
|
||||||
</DropdownMenu.Target>
|
|
||||||
<DropdownMenu.Dropdown>
|
|
||||||
<AppMenu />
|
|
||||||
</DropdownMenu.Dropdown>
|
|
||||||
</DropdownMenu>
|
|
||||||
</Group>
|
|
||||||
<Group grow>
|
|
||||||
<Button onClick={handleReload} size="md" variant="filled">
|
|
||||||
{t('common.reload')}
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
</Stack>
|
|
||||||
</Center>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default RouteErrorBoundary;
|
|
||||||
@@ -9,6 +9,7 @@ import { ServerCredentialRequired } from '/@/renderer/features/action-required/c
|
|||||||
import { ServerRequired } from '/@/renderer/features/action-required/components/server-required';
|
import { ServerRequired } from '/@/renderer/features/action-required/components/server-required';
|
||||||
import { ServerList } from '/@/renderer/features/servers/components/server-list';
|
import { ServerList } from '/@/renderer/features/servers/components/server-list';
|
||||||
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||||
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import { useCurrentServerWithCredential } from '/@/renderer/store';
|
import { useCurrentServerWithCredential } from '/@/renderer/store';
|
||||||
import { Button } from '/@/shared/components/button/button';
|
import { Button } from '/@/shared/components/button/button';
|
||||||
@@ -84,4 +85,12 @@ const ActionRequiredRoute = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ActionRequiredRoute;
|
const ActionRequiredRouteWithBoundary = () => {
|
||||||
|
return (
|
||||||
|
<PageErrorBoundary>
|
||||||
|
<ActionRequiredRoute />
|
||||||
|
</PageErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ActionRequiredRouteWithBoundary;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { useLocation, useNavigate } from 'react-router';
|
import { useLocation, useNavigate } from 'react-router';
|
||||||
|
|
||||||
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||||
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||||
import { Center } from '/@/shared/components/center/center';
|
import { Center } from '/@/shared/components/center/center';
|
||||||
import { Group } from '/@/shared/components/group/group';
|
import { Group } from '/@/shared/components/group/group';
|
||||||
@@ -32,4 +33,12 @@ const InvalidRoute = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default InvalidRoute;
|
const InvalidRouteWithBoundary = () => {
|
||||||
|
return (
|
||||||
|
<PageErrorBoundary>
|
||||||
|
<InvalidRoute />
|
||||||
|
</PageErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InvalidRouteWithBoundary;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
} from '/@/renderer/features/shared/components/library-background-overlay';
|
} from '/@/renderer/features/shared/components/library-background-overlay';
|
||||||
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
||||||
import { LibraryHeaderBar } from '/@/renderer/features/shared/components/library-header-bar';
|
import { LibraryHeaderBar } from '/@/renderer/features/shared/components/library-header-bar';
|
||||||
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
import { useFastAverageColor } from '/@/renderer/hooks';
|
import { useFastAverageColor } from '/@/renderer/hooks';
|
||||||
import { useCurrentServer, useGeneralSettings } from '/@/renderer/store';
|
import { useCurrentServer, useGeneralSettings } from '/@/renderer/store';
|
||||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||||
@@ -83,4 +84,12 @@ const AlbumDetailRoute = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AlbumDetailRoute;
|
const AlbumDetailRouteWithBoundary = () => {
|
||||||
|
return (
|
||||||
|
<PageErrorBoundary>
|
||||||
|
<AlbumDetailRoute />
|
||||||
|
</PageErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AlbumDetailRouteWithBoundary;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { AlbumListContent } from '/@/renderer/features/albums/components/album-l
|
|||||||
import { AlbumListHeader } from '/@/renderer/features/albums/components/album-list-header';
|
import { AlbumListHeader } from '/@/renderer/features/albums/components/album-list-header';
|
||||||
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||||
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
||||||
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
|
|
||||||
const AlbumListRoute = () => {
|
const AlbumListRoute = () => {
|
||||||
const { albumArtistId, genreId } = useParams();
|
const { albumArtistId, genreId } = useParams();
|
||||||
@@ -34,4 +35,12 @@ const AlbumListRoute = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AlbumListRoute;
|
const AlbumListRouteWithBoundary = () => {
|
||||||
|
return (
|
||||||
|
<PageErrorBoundary>
|
||||||
|
<AlbumListRoute />
|
||||||
|
</PageErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AlbumListRouteWithBoundary;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { usePlayer } from '/@/renderer/features/player/context/player-context';
|
|||||||
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||||
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
||||||
import { LibraryHeader } from '/@/renderer/features/shared/components/library-header';
|
import { LibraryHeader } from '/@/renderer/features/shared/components/library-header';
|
||||||
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
import { PlayButton } from '/@/renderer/features/shared/components/play-button';
|
import { PlayButton } from '/@/renderer/features/shared/components/play-button';
|
||||||
import { useCreateFavorite } from '/@/renderer/features/shared/mutations/create-favorite-mutation';
|
import { useCreateFavorite } from '/@/renderer/features/shared/mutations/create-favorite-mutation';
|
||||||
import { useDeleteFavorite } from '/@/renderer/features/shared/mutations/delete-favorite-mutation';
|
import { useDeleteFavorite } from '/@/renderer/features/shared/mutations/delete-favorite-mutation';
|
||||||
@@ -228,4 +229,12 @@ const DummyAlbumDetailRoute = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DummyAlbumDetailRoute;
|
const DummyAlbumDetailRouteWithBoundary = () => {
|
||||||
|
return (
|
||||||
|
<PageErrorBoundary>
|
||||||
|
<DummyAlbumDetailRoute />
|
||||||
|
</PageErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DummyAlbumDetailRouteWithBoundary;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
} from '/@/renderer/features/shared/components/library-background-overlay';
|
} from '/@/renderer/features/shared/components/library-background-overlay';
|
||||||
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
||||||
import { LibraryHeaderBar } from '/@/renderer/features/shared/components/library-header-bar';
|
import { LibraryHeaderBar } from '/@/renderer/features/shared/components/library-header-bar';
|
||||||
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
import { useFastAverageColor } from '/@/renderer/hooks';
|
import { useFastAverageColor } from '/@/renderer/hooks';
|
||||||
import { useCurrentServer, useGeneralSettings } from '/@/renderer/store';
|
import { useCurrentServer, useGeneralSettings } from '/@/renderer/store';
|
||||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||||
@@ -89,4 +90,12 @@ const AlbumArtistDetailRoute = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AlbumArtistDetailRoute;
|
const AlbumArtistDetailRouteWithBoundary = () => {
|
||||||
|
return (
|
||||||
|
<PageErrorBoundary>
|
||||||
|
<AlbumArtistDetailRoute />
|
||||||
|
</PageErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AlbumArtistDetailRouteWithBoundary;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { artistsQueries } from '/@/renderer/features/artists/api/artists-api';
|
|||||||
import { AlbumArtistDetailTopSongsListHeader } from '/@/renderer/features/artists/components/album-artist-detail-top-songs-list-header';
|
import { AlbumArtistDetailTopSongsListHeader } from '/@/renderer/features/artists/components/album-artist-detail-top-songs-list-header';
|
||||||
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||||
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
||||||
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
import { useCurrentServer } from '/@/renderer/store/auth.store';
|
import { useCurrentServer } from '/@/renderer/store/auth.store';
|
||||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||||
|
|
||||||
@@ -64,4 +65,12 @@ const AlbumArtistDetailTopSongsListRoute = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AlbumArtistDetailTopSongsListRoute;
|
const AlbumArtistDetailTopSongsListRouteWithBoundary = () => {
|
||||||
|
return (
|
||||||
|
<PageErrorBoundary>
|
||||||
|
<AlbumArtistDetailTopSongsListRoute />
|
||||||
|
</PageErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AlbumArtistDetailTopSongsListRouteWithBoundary;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { AlbumArtistListContent } from '/@/renderer/features/artists/components/
|
|||||||
import { AlbumArtistListHeader } from '/@/renderer/features/artists/components/album-artist-list-header';
|
import { AlbumArtistListHeader } from '/@/renderer/features/artists/components/album-artist-list-header';
|
||||||
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||||
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
||||||
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
import { ItemListKey } from '/@/shared/types/types';
|
import { ItemListKey } from '/@/shared/types/types';
|
||||||
|
|
||||||
const AlbumArtistListRoute = () => {
|
const AlbumArtistListRoute = () => {
|
||||||
@@ -33,4 +34,12 @@ const AlbumArtistListRoute = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AlbumArtistListRoute;
|
const AlbumArtistListRouteWithBoundary = () => {
|
||||||
|
return (
|
||||||
|
<PageErrorBoundary>
|
||||||
|
<AlbumArtistListRoute />
|
||||||
|
</PageErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AlbumArtistListRouteWithBoundary;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { ArtistListContent } from '/@/renderer/features/artists/components/artis
|
|||||||
import { ArtistListHeader } from '/@/renderer/features/artists/components/artist-list-header';
|
import { ArtistListHeader } from '/@/renderer/features/artists/components/artist-list-header';
|
||||||
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||||
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
||||||
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
import { ItemListKey } from '/@/shared/types/types';
|
import { ItemListKey } from '/@/shared/types/types';
|
||||||
|
|
||||||
const ArtistListRoute = () => {
|
const ArtistListRoute = () => {
|
||||||
@@ -33,4 +34,12 @@ const ArtistListRoute = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistListRoute;
|
const ArtistListRouteWithBoundary = () => {
|
||||||
|
return (
|
||||||
|
<PageErrorBoundary>
|
||||||
|
<ArtistListRoute />
|
||||||
|
</PageErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ArtistListRouteWithBoundary;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { GenreListContent } from '/@/renderer/features/genres/components/genre-l
|
|||||||
import { GenreListHeader } from '/@/renderer/features/genres/components/genre-list-header';
|
import { GenreListHeader } from '/@/renderer/features/genres/components/genre-list-header';
|
||||||
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||||
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
||||||
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
import { ItemListKey } from '/@/shared/types/types';
|
import { ItemListKey } from '/@/shared/types/types';
|
||||||
|
|
||||||
const GenreListRoute = () => {
|
const GenreListRoute = () => {
|
||||||
@@ -33,4 +34,12 @@ const GenreListRoute = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default GenreListRoute;
|
const GenreListRouteWithBoundary = () => {
|
||||||
|
return (
|
||||||
|
<PageErrorBoundary>
|
||||||
|
<GenreListRoute />
|
||||||
|
</PageErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GenreListRouteWithBoundary;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { FeaturedGenres } from '/@/renderer/features/home/components/featured-ge
|
|||||||
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||||
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
||||||
import { LibraryHeaderBar } from '/@/renderer/features/shared/components/library-header-bar';
|
import { LibraryHeaderBar } from '/@/renderer/features/shared/components/library-header-bar';
|
||||||
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
import {
|
import {
|
||||||
HomeItem,
|
HomeItem,
|
||||||
useCurrentServer,
|
useCurrentServer,
|
||||||
@@ -154,12 +155,14 @@ const HomeRoute = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const SuspensedHomeRoute = () => {
|
const HomeRouteWithBoundary = () => {
|
||||||
return (
|
return (
|
||||||
|
<PageErrorBoundary>
|
||||||
<Suspense fallback={<Spinner container />}>
|
<Suspense fallback={<Spinner container />}>
|
||||||
<HomeRoute />
|
<HomeRoute />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
</PageErrorBoundary>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SuspensedHomeRoute;
|
export default HomeRouteWithBoundary;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import JellyfinIcon from '/@/renderer/features/servers/assets/jellyfin.png';
|
|||||||
import NavidromeIcon from '/@/renderer/features/servers/assets/navidrome.png';
|
import NavidromeIcon from '/@/renderer/features/servers/assets/navidrome.png';
|
||||||
import SubsonicIcon from '/@/renderer/features/servers/assets/opensubsonic.png';
|
import SubsonicIcon from '/@/renderer/features/servers/assets/opensubsonic.png';
|
||||||
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||||
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import { useAuthStoreActions, useCurrentServer } from '/@/renderer/store';
|
import { useAuthStoreActions, useCurrentServer } from '/@/renderer/store';
|
||||||
import { Button } from '/@/shared/components/button/button';
|
import { Button } from '/@/shared/components/button/button';
|
||||||
@@ -200,4 +201,12 @@ const LoginRoute = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LoginRoute;
|
const LoginRouteWithBoundary = () => {
|
||||||
|
return (
|
||||||
|
<PageErrorBoundary>
|
||||||
|
<LoginRoute />
|
||||||
|
</PageErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LoginRouteWithBoundary;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { PlayQueue } from '/@/renderer/features/now-playing/components/play-queu
|
|||||||
import { PlayQueueListControls } from '/@/renderer/features/now-playing/components/play-queue-list-controls';
|
import { PlayQueueListControls } from '/@/renderer/features/now-playing/components/play-queue-list-controls';
|
||||||
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||||
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
||||||
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
import { ItemListKey } from '/@/shared/types/types';
|
import { ItemListKey } from '/@/shared/types/types';
|
||||||
|
|
||||||
const NowPlayingRoute = () => {
|
const NowPlayingRoute = () => {
|
||||||
@@ -28,4 +29,12 @@ const NowPlayingRoute = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default NowPlayingRoute;
|
const NowPlayingRouteWithBoundary = () => {
|
||||||
|
return (
|
||||||
|
<PageErrorBoundary>
|
||||||
|
<NowPlayingRoute />
|
||||||
|
</PageErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NowPlayingRouteWithBoundary;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { useCreatePlaylist } from '/@/renderer/features/playlists/mutations/crea
|
|||||||
import { useDeletePlaylist } from '/@/renderer/features/playlists/mutations/delete-playlist-mutation';
|
import { useDeletePlaylist } from '/@/renderer/features/playlists/mutations/delete-playlist-mutation';
|
||||||
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||||
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
||||||
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import { useCurrentServer, usePlaylistDetailStore } from '/@/renderer/store';
|
import { useCurrentServer, usePlaylistDetailStore } from '/@/renderer/store';
|
||||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||||
@@ -233,4 +234,12 @@ const PlaylistDetailSongListRoute = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default PlaylistDetailSongListRoute;
|
const PlaylistDetailSongListRouteWithBoundary = () => {
|
||||||
|
return (
|
||||||
|
<PageErrorBoundary>
|
||||||
|
<PlaylistDetailSongListRoute />
|
||||||
|
</PageErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PlaylistDetailSongListRouteWithBoundary;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { PlaylistListContent } from '/@/renderer/features/playlists/components/p
|
|||||||
import { PlaylistListHeader } from '/@/renderer/features/playlists/components/playlist-list-header';
|
import { PlaylistListHeader } from '/@/renderer/features/playlists/components/playlist-list-header';
|
||||||
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||||
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
||||||
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
import { ItemListKey } from '/@/shared/types/types';
|
import { ItemListKey } from '/@/shared/types/types';
|
||||||
|
|
||||||
const PlaylistListRoute = () => {
|
const PlaylistListRoute = () => {
|
||||||
@@ -35,4 +36,12 @@ const PlaylistListRoute = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default PlaylistListRoute;
|
const PlaylistListRouteWithBoundary = () => {
|
||||||
|
return (
|
||||||
|
<PageErrorBoundary>
|
||||||
|
<PlaylistListRoute />
|
||||||
|
</PageErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PlaylistListRouteWithBoundary;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { SearchContent } from '/@/renderer/features/search/components/search-con
|
|||||||
import { SearchHeader } from '/@/renderer/features/search/components/search-header';
|
import { SearchHeader } from '/@/renderer/features/search/components/search-header';
|
||||||
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||||
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
||||||
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
|
|
||||||
const SearchRoute = () => {
|
const SearchRoute = () => {
|
||||||
const { state: locationState } = useLocation();
|
const { state: locationState } = useLocation();
|
||||||
@@ -22,4 +23,12 @@ const SearchRoute = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SearchRoute;
|
const SearchRouteWithBoundary = () => {
|
||||||
|
return (
|
||||||
|
<PageErrorBoundary>
|
||||||
|
<SearchRoute />
|
||||||
|
</PageErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SearchRouteWithBoundary;
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import { ErrorBoundary } from 'react-error-boundary';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { ServerSelector } from '/@/renderer/features/sidebar/components/server-selector';
|
||||||
|
import { Box } from '/@/shared/components/box/box';
|
||||||
|
import { Button } from '/@/shared/components/button/button';
|
||||||
|
import { Center } from '/@/shared/components/center/center';
|
||||||
|
import { Code } from '/@/shared/components/code/code';
|
||||||
|
import { Group } from '/@/shared/components/group/group';
|
||||||
|
import { Icon } from '/@/shared/components/icon/icon';
|
||||||
|
import { Stack } from '/@/shared/components/stack/stack';
|
||||||
|
import { TextTitle } from '/@/shared/components/text-title/text-title';
|
||||||
|
import { Text } from '/@/shared/components/text/text';
|
||||||
|
|
||||||
|
interface PageErrorFallbackProps {
|
||||||
|
error: Error;
|
||||||
|
resetErrorBoundary: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PageErrorFallback = ({ error, resetErrorBoundary }: PageErrorFallbackProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const handleRefresh = () => {
|
||||||
|
window.location.reload();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box h="100%" pos="relative" w="100%">
|
||||||
|
<Box
|
||||||
|
style={{
|
||||||
|
padding: 'var(--theme-spacing-md)',
|
||||||
|
position: 'absolute',
|
||||||
|
right: 0,
|
||||||
|
top: 0,
|
||||||
|
zIndex: 1000,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ServerSelector />
|
||||||
|
</Box>
|
||||||
|
<Center h="100%" p="md" w="100%">
|
||||||
|
<Stack maw="800px">
|
||||||
|
<Group gap="xs">
|
||||||
|
<Icon fill="error" icon="error" size="lg" />
|
||||||
|
<TextTitle fw={700} order={3}>
|
||||||
|
{t('error.genericError', { postProcess: 'sentenceCase' })}
|
||||||
|
</TextTitle>
|
||||||
|
</Group>
|
||||||
|
<Text style={{ wordBreak: 'break-word' }}>
|
||||||
|
{error?.message || t('error.genericError', { postProcess: 'sentenceCase' })}
|
||||||
|
</Text>
|
||||||
|
{process.env.NODE_ENV === 'development' && error?.stack && (
|
||||||
|
<Code
|
||||||
|
p="md"
|
||||||
|
style={{
|
||||||
|
backgroundColor: 'var(--theme-colors-surface)',
|
||||||
|
fontFamily: 'monospace',
|
||||||
|
maxHeight: '300px',
|
||||||
|
overflow: 'auto',
|
||||||
|
wordBreak: 'break-word',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{error.stack}
|
||||||
|
</Code>
|
||||||
|
)}
|
||||||
|
<Group grow>
|
||||||
|
<Button onClick={resetErrorBoundary} size="md" variant="default">
|
||||||
|
{t('common.reload', { postProcess: 'sentenceCase' })}
|
||||||
|
</Button>
|
||||||
|
<Button onClick={handleRefresh} size="md" variant="filled">
|
||||||
|
{t('common.refresh', { postProcess: 'sentenceCase' })}
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface PageErrorBoundaryProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PageErrorBoundary = ({ children }: PageErrorBoundaryProps) => {
|
||||||
|
return (
|
||||||
|
<ErrorBoundary
|
||||||
|
FallbackComponent={PageErrorFallback}
|
||||||
|
onError={(error, errorInfo) => {
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
console.error('Page error boundary caught an error:', error, errorInfo);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onReset={() => {}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
+11
-11
@@ -5,9 +5,11 @@ import { ServerSelector } from '/@/renderer/features/sidebar/components/server-s
|
|||||||
import { Box } from '/@/shared/components/box/box';
|
import { Box } from '/@/shared/components/box/box';
|
||||||
import { Button } from '/@/shared/components/button/button';
|
import { Button } from '/@/shared/components/button/button';
|
||||||
import { Center } from '/@/shared/components/center/center';
|
import { Center } from '/@/shared/components/center/center';
|
||||||
|
import { Code } from '/@/shared/components/code/code';
|
||||||
import { Group } from '/@/shared/components/group/group';
|
import { Group } from '/@/shared/components/group/group';
|
||||||
import { Icon } from '/@/shared/components/icon/icon';
|
import { Icon } from '/@/shared/components/icon/icon';
|
||||||
import { Stack } from '/@/shared/components/stack/stack';
|
import { Stack } from '/@/shared/components/stack/stack';
|
||||||
|
import { TextTitle } from '/@/shared/components/text-title/text-title';
|
||||||
import { Text } from '/@/shared/components/text/text';
|
import { Text } from '/@/shared/components/text/text';
|
||||||
|
|
||||||
interface RouterErrorFallbackProps {
|
interface RouterErrorFallbackProps {
|
||||||
@@ -41,32 +43,30 @@ const RouterErrorFallback = ({ error, resetErrorBoundary }: RouterErrorFallbackP
|
|||||||
>
|
>
|
||||||
<ServerSelector />
|
<ServerSelector />
|
||||||
</Box>
|
</Box>
|
||||||
<Center style={{ height: '100vh' }}>
|
<Center h="100vh" p="md" w="100%">
|
||||||
<Stack style={{ maxWidth: '50%' }}>
|
<Stack maw="800px">
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
<Icon fill="error" icon="error" size="lg" />
|
<Icon fill="error" icon="error" size="lg" />
|
||||||
<Text size="lg">
|
<TextTitle fw={700} order={3}>
|
||||||
{t('error.genericError', { postProcess: 'sentenceCase' })}
|
{t('error.genericError', { postProcess: 'sentenceCase' })}
|
||||||
</Text>
|
</TextTitle>
|
||||||
</Group>
|
</Group>
|
||||||
<Text size="sm" style={{ wordBreak: 'break-word' }}>
|
<Text style={{ wordBreak: 'break-word' }}>
|
||||||
{error?.message || t('error.genericError', { postProcess: 'sentenceCase' })}
|
{error?.message || t('error.genericError', { postProcess: 'sentenceCase' })}
|
||||||
</Text>
|
</Text>
|
||||||
{process.env.NODE_ENV === 'development' && error?.stack && (
|
{process.env.NODE_ENV === 'development' && error?.stack && (
|
||||||
<Text
|
<Code
|
||||||
size="xs"
|
p="md"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: 'var(--theme-colors-error)',
|
backgroundColor: 'var(--theme-colors-surface)',
|
||||||
color: 'var(--theme-colors-errorText)',
|
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
maxHeight: '300px',
|
maxHeight: '300px',
|
||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
padding: '10px',
|
|
||||||
wordBreak: 'break-word',
|
wordBreak: 'break-word',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{error.stack}
|
{error.stack}
|
||||||
</Text>
|
</Code>
|
||||||
)}
|
)}
|
||||||
<Group grow>
|
<Group grow>
|
||||||
<Button onClick={resetErrorBoundary} size="md" variant="default">
|
<Button onClick={resetErrorBoundary} size="md" variant="default">
|
||||||
@@ -6,12 +6,13 @@ import { ListContext } from '/@/renderer/context/list-context';
|
|||||||
import { genresQueries } from '/@/renderer/features/genres/api/genres-api';
|
import { genresQueries } from '/@/renderer/features/genres/api/genres-api';
|
||||||
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||||
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
||||||
|
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
|
||||||
import { SongListContent } from '/@/renderer/features/songs/components/song-list-content';
|
import { SongListContent } from '/@/renderer/features/songs/components/song-list-content';
|
||||||
import { SongListHeader } from '/@/renderer/features/songs/components/song-list-header';
|
import { SongListHeader } from '/@/renderer/features/songs/components/song-list-header';
|
||||||
import { useCurrentServer } from '/@/renderer/store';
|
import { useCurrentServer } from '/@/renderer/store';
|
||||||
import { GenreListSort, SortOrder } from '/@/shared/types/domain-types';
|
import { GenreListSort, SortOrder } from '/@/shared/types/domain-types';
|
||||||
|
|
||||||
const TrackListRoute = () => {
|
const SongListRoute = () => {
|
||||||
const server = useCurrentServer();
|
const server = useCurrentServer();
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const { albumArtistId, genreId } = useParams();
|
const { albumArtistId, genreId } = useParams();
|
||||||
@@ -83,4 +84,12 @@ const TrackListRoute = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TrackListRoute;
|
const SongListRouteWithBoundary = () => {
|
||||||
|
return (
|
||||||
|
<PageErrorBoundary>
|
||||||
|
<SongListRoute />
|
||||||
|
</PageErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SongListRouteWithBoundary;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { lazy, Suspense } from 'react';
|
import { lazy, Suspense } from 'react';
|
||||||
import { HashRouter, Route, Routes } from 'react-router';
|
import { HashRouter, Route, Routes } from 'react-router';
|
||||||
|
|
||||||
import { RouterErrorBoundary } from '/@/renderer/components/error-boundary/router-error-boundary';
|
|
||||||
import { AddToPlaylistContextModal } from '/@/renderer/features/playlists/components/add-to-playlist-context-modal';
|
import { AddToPlaylistContextModal } from '/@/renderer/features/playlists/components/add-to-playlist-context-modal';
|
||||||
import { SettingsModal } from '/@/renderer/features/settings/components/settings-modal';
|
import { SettingsModal } from '/@/renderer/features/settings/components/settings-modal';
|
||||||
|
import { RouterErrorBoundary } from '/@/renderer/features/shared/components/router-error-boundary';
|
||||||
import { ShareItemContextModal } from '/@/renderer/features/sharing/components/share-item-context-modal';
|
import { ShareItemContextModal } from '/@/renderer/features/sharing/components/share-item-context-modal';
|
||||||
import { ResponsiveLayout } from '/@/renderer/layouts/responsive-layout';
|
import { ResponsiveLayout } from '/@/renderer/layouts/responsive-layout';
|
||||||
import { AppOutlet } from '/@/renderer/router/app-outlet';
|
import { AppOutlet } from '/@/renderer/router/app-outlet';
|
||||||
@@ -65,14 +65,9 @@ const GenreListRoute = lazy(() => import('/@/renderer/features/genres/routes/gen
|
|||||||
|
|
||||||
const SearchRoute = lazy(() => import('/@/renderer/features/search/routes/search-route'));
|
const SearchRoute = lazy(() => import('/@/renderer/features/search/routes/search-route'));
|
||||||
|
|
||||||
const RouteErrorBoundary = lazy(
|
|
||||||
() => import('/@/renderer/features/action-required/components/route-error-boundary'),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const AppRouter = () => {
|
export const AppRouter = () => {
|
||||||
const router = (
|
const router = (
|
||||||
<HashRouter>
|
<HashRouter>
|
||||||
<RouterErrorBoundary>
|
|
||||||
<ModalsProvider
|
<ModalsProvider
|
||||||
modals={{
|
modals={{
|
||||||
addToPlaylist: AddToPlaylistContextModal,
|
addToPlaylist: AddToPlaylistContextModal,
|
||||||
@@ -81,36 +76,20 @@ export const AppRouter = () => {
|
|||||||
shareItem: ShareItemContextModal,
|
shareItem: ShareItemContextModal,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<RouterErrorBoundary>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route element={<TitlebarOutlet />}>
|
<Route element={<TitlebarOutlet />}>
|
||||||
<Route element={<AppOutlet />} errorElement={<RouteErrorBoundary />}>
|
<Route element={<AppOutlet />}>
|
||||||
<Route element={<ResponsiveLayout />}>
|
<Route element={<ResponsiveLayout />}>
|
||||||
<Route
|
<Route element={<HomeRoute />} index />
|
||||||
element={<HomeRoute />}
|
<Route element={<HomeRoute />} path={AppRoute.HOME} />
|
||||||
errorElement={<RouteErrorBoundary />}
|
<Route element={<SearchRoute />} path={AppRoute.SEARCH} />
|
||||||
index
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
element={<HomeRoute />}
|
|
||||||
errorElement={<RouteErrorBoundary />}
|
|
||||||
path={AppRoute.HOME}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
element={<SearchRoute />}
|
|
||||||
errorElement={<RouteErrorBoundary />}
|
|
||||||
path={AppRoute.SEARCH}
|
|
||||||
/>
|
|
||||||
<Route
|
<Route
|
||||||
element={<NowPlayingRoute />}
|
element={<NowPlayingRoute />}
|
||||||
errorElement={<RouteErrorBoundary />}
|
|
||||||
path={AppRoute.NOW_PLAYING}
|
path={AppRoute.NOW_PLAYING}
|
||||||
/>
|
/>
|
||||||
<Route path={AppRoute.LIBRARY_GENRES}>
|
<Route path={AppRoute.LIBRARY_GENRES}>
|
||||||
<Route
|
<Route element={<GenreListRoute />} index />
|
||||||
element={<GenreListRoute />}
|
|
||||||
errorElement={<RouteErrorBoundary />}
|
|
||||||
index
|
|
||||||
/>
|
|
||||||
<Route
|
<Route
|
||||||
element={<AlbumListRoute />}
|
element={<AlbumListRoute />}
|
||||||
path={AppRoute.LIBRARY_GENRES_ALBUMS}
|
path={AppRoute.LIBRARY_GENRES_ALBUMS}
|
||||||
@@ -122,17 +101,14 @@ export const AppRouter = () => {
|
|||||||
</Route>
|
</Route>
|
||||||
<Route
|
<Route
|
||||||
element={<AlbumListRoute />}
|
element={<AlbumListRoute />}
|
||||||
errorElement={<RouteErrorBoundary />}
|
|
||||||
path={AppRoute.LIBRARY_ALBUMS}
|
path={AppRoute.LIBRARY_ALBUMS}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
element={<AlbumDetailRoute />}
|
element={<AlbumDetailRoute />}
|
||||||
errorElement={<RouteErrorBoundary />}
|
|
||||||
path={AppRoute.LIBRARY_ALBUMS_DETAIL}
|
path={AppRoute.LIBRARY_ALBUMS_DETAIL}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
element={<ArtistListRoute />}
|
element={<ArtistListRoute />}
|
||||||
errorElement={<RouteErrorBoundary />}
|
|
||||||
path={AppRoute.LIBRARY_ARTISTS}
|
path={AppRoute.LIBRARY_ARTISTS}
|
||||||
/>
|
/>
|
||||||
<Route path={AppRoute.LIBRARY_ARTISTS_DETAIL}>
|
<Route path={AppRoute.LIBRARY_ARTISTS_DETAIL}>
|
||||||
@@ -152,28 +128,21 @@ export const AppRouter = () => {
|
|||||||
</Route>
|
</Route>
|
||||||
<Route
|
<Route
|
||||||
element={<DummyAlbumDetailRoute />}
|
element={<DummyAlbumDetailRoute />}
|
||||||
errorElement={<RouteErrorBoundary />}
|
|
||||||
path={AppRoute.FAKE_LIBRARY_ALBUM_DETAILS}
|
path={AppRoute.FAKE_LIBRARY_ALBUM_DETAILS}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
element={<SongListRoute />}
|
element={<SongListRoute />}
|
||||||
errorElement={<RouteErrorBoundary />}
|
|
||||||
path={AppRoute.LIBRARY_SONGS}
|
path={AppRoute.LIBRARY_SONGS}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
element={<PlaylistListRoute />}
|
element={<PlaylistListRoute />}
|
||||||
errorElement={<RouteErrorBoundary />}
|
|
||||||
path={AppRoute.PLAYLISTS}
|
path={AppRoute.PLAYLISTS}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
element={<PlaylistDetailSongListRoute />}
|
element={<PlaylistDetailSongListRoute />}
|
||||||
errorElement={<RouteErrorBoundary />}
|
|
||||||
path={AppRoute.PLAYLISTS_DETAIL_SONGS}
|
path={AppRoute.PLAYLISTS_DETAIL_SONGS}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route path={AppRoute.LIBRARY_ALBUM_ARTISTS}>
|
||||||
errorElement={<RouteErrorBoundary />}
|
|
||||||
path={AppRoute.LIBRARY_ALBUM_ARTISTS}
|
|
||||||
>
|
|
||||||
<Route element={<AlbumArtistListRoute />} index />
|
<Route element={<AlbumArtistListRoute />} index />
|
||||||
<Route path={AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL}>
|
<Route path={AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL}>
|
||||||
<Route element={<AlbumArtistDetailRoute />} index />
|
<Route element={<AlbumArtistDetailRoute />} index />
|
||||||
@@ -209,8 +178,8 @@ export const AppRouter = () => {
|
|||||||
</Route>
|
</Route>
|
||||||
</Route>
|
</Route>
|
||||||
</Routes>
|
</Routes>
|
||||||
</ModalsProvider>
|
|
||||||
</RouterErrorBoundary>
|
</RouterErrorBoundary>
|
||||||
|
</ModalsProvider>
|
||||||
</HashRouter>
|
</HashRouter>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user