mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge pull request #6601 from thornbill/catch-all-route
This commit is contained in:
commit
411601ff68
5 changed files with 98 additions and 10 deletions
|
@ -17,6 +17,10 @@ $drawer-width: 240px;
|
||||||
left: $drawer-width;
|
left: $drawer-width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// The fallback page has no drawer
|
||||||
|
#fallbackPage {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Hide some items from the user "settings" page that are in the drawer
|
// Hide some items from the user "settings" page that are in the drawer
|
||||||
#myPreferencesMenuPage {
|
#myPreferencesMenuPage {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import ConnectionRequired from 'components/ConnectionRequired';
|
||||||
import { toAsyncPageRoute } from 'components/router/AsyncRoute';
|
import { toAsyncPageRoute } from 'components/router/AsyncRoute';
|
||||||
import { toViewManagerPageRoute } from 'components/router/LegacyRoute';
|
import { toViewManagerPageRoute } from 'components/router/LegacyRoute';
|
||||||
import ErrorBoundary from 'components/router/ErrorBoundary';
|
import ErrorBoundary from 'components/router/ErrorBoundary';
|
||||||
|
import FallbackRoute from 'components/router/FallbackRoute';
|
||||||
|
|
||||||
import { ASYNC_USER_ROUTES } from './asyncRoutes';
|
import { ASYNC_USER_ROUTES } from './asyncRoutes';
|
||||||
import { LEGACY_PUBLIC_ROUTES, LEGACY_USER_ROUTES } from './legacyRoutes';
|
import { LEGACY_PUBLIC_ROUTES, LEGACY_USER_ROUTES } from './legacyRoutes';
|
||||||
|
@ -15,9 +16,11 @@ export const EXPERIMENTAL_APP_ROUTES: RouteObject[] = [
|
||||||
path: '/*',
|
path: '/*',
|
||||||
lazy: () => import('../AppLayout'),
|
lazy: () => import('../AppLayout'),
|
||||||
children: [
|
children: [
|
||||||
|
{ index: true, element: <Navigate replace to='/home.html' /> },
|
||||||
|
|
||||||
{
|
{
|
||||||
/* User routes: Any child route of this layout is authenticated */
|
/* User routes */
|
||||||
element: <ConnectionRequired isUserRequired />,
|
Component: ConnectionRequired,
|
||||||
children: [
|
children: [
|
||||||
...ASYNC_USER_ROUTES.map(toAsyncPageRoute),
|
...ASYNC_USER_ROUTES.map(toAsyncPageRoute),
|
||||||
...LEGACY_USER_ROUTES.map(toViewManagerPageRoute),
|
...LEGACY_USER_ROUTES.map(toViewManagerPageRoute),
|
||||||
|
@ -25,15 +28,26 @@ export const EXPERIMENTAL_APP_ROUTES: RouteObject[] = [
|
||||||
// The video page is special since it combines new controls with the legacy view
|
// The video page is special since it combines new controls with the legacy view
|
||||||
{
|
{
|
||||||
path: 'video',
|
path: 'video',
|
||||||
element: <VideoPage />
|
Component: VideoPage
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
ErrorBoundary
|
ErrorBoundary
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
/* Public routes */
|
/* Public routes */
|
||||||
{ index: true, element: <Navigate replace to='/home.html' /> },
|
element: <ConnectionRequired isUserRequired={false} />,
|
||||||
...LEGACY_PUBLIC_ROUTES.map(toViewManagerPageRoute)
|
children: [
|
||||||
|
...LEGACY_PUBLIC_ROUTES.map(toViewManagerPageRoute),
|
||||||
|
|
||||||
|
/* Fallback route for invalid paths */
|
||||||
|
{
|
||||||
|
path: '*',
|
||||||
|
Component: FallbackRoute
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
@ -5,6 +5,7 @@ import ConnectionRequired from 'components/ConnectionRequired';
|
||||||
import { toAsyncPageRoute } from 'components/router/AsyncRoute';
|
import { toAsyncPageRoute } from 'components/router/AsyncRoute';
|
||||||
import { toViewManagerPageRoute } from 'components/router/LegacyRoute';
|
import { toViewManagerPageRoute } from 'components/router/LegacyRoute';
|
||||||
import ErrorBoundary from 'components/router/ErrorBoundary';
|
import ErrorBoundary from 'components/router/ErrorBoundary';
|
||||||
|
import FallbackRoute from 'components/router/FallbackRoute';
|
||||||
|
|
||||||
import AppLayout from '../AppLayout';
|
import AppLayout from '../AppLayout';
|
||||||
|
|
||||||
|
@ -16,9 +17,11 @@ export const STABLE_APP_ROUTES: RouteObject[] = [
|
||||||
path: '/*',
|
path: '/*',
|
||||||
Component: AppLayout,
|
Component: AppLayout,
|
||||||
children: [
|
children: [
|
||||||
|
{ index: true, element: <Navigate replace to='/home.html' /> },
|
||||||
|
|
||||||
{
|
{
|
||||||
/* User routes */
|
/* User routes */
|
||||||
element: <ConnectionRequired isUserRequired />,
|
Component: ConnectionRequired,
|
||||||
children: [
|
children: [
|
||||||
...ASYNC_USER_ROUTES.map(toAsyncPageRoute),
|
...ASYNC_USER_ROUTES.map(toAsyncPageRoute),
|
||||||
...LEGACY_USER_ROUTES.map(toViewManagerPageRoute)
|
...LEGACY_USER_ROUTES.map(toViewManagerPageRoute)
|
||||||
|
@ -26,9 +29,19 @@ export const STABLE_APP_ROUTES: RouteObject[] = [
|
||||||
ErrorBoundary
|
ErrorBoundary
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
/* Public routes */
|
/* Public routes */
|
||||||
{ index: true, element: <Navigate replace to='/home.html' /> },
|
element: <ConnectionRequired isUserRequired={false} />,
|
||||||
...LEGACY_PUBLIC_ROUTES.map(toViewManagerPageRoute)
|
children: [
|
||||||
|
...LEGACY_PUBLIC_ROUTES.map(toViewManagerPageRoute),
|
||||||
|
/* Fallback route for invalid paths */
|
||||||
|
{
|
||||||
|
path: '*',
|
||||||
|
Component: FallbackRoute
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
55
src/components/router/FallbackRoute.tsx
Normal file
55
src/components/router/FallbackRoute.tsx
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import { Navigate, useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
|
import Page from 'components/Page';
|
||||||
|
import globalize from 'lib/globalize';
|
||||||
|
import LinkButton from 'elements/emby-button/LinkButton';
|
||||||
|
|
||||||
|
const FallbackRoute = () => {
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
// Check if the requested path should be redirected
|
||||||
|
const to = useMemo(() => {
|
||||||
|
const _to = {
|
||||||
|
search: location.search,
|
||||||
|
hash: location.hash
|
||||||
|
};
|
||||||
|
|
||||||
|
// If a path ends in ".html", redirect to the path with it removed
|
||||||
|
if (location.pathname.endsWith('.html')) {
|
||||||
|
return { ..._to, pathname: location.pathname.slice(0, -5) };
|
||||||
|
}
|
||||||
|
}, [ location ]);
|
||||||
|
|
||||||
|
if (to) {
|
||||||
|
console.warn('[FallbackRoute] You are using a deprecated URL format. This will stop working in a future Jellyfin update.');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Navigate
|
||||||
|
replace
|
||||||
|
to={to}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Page
|
||||||
|
id='fallbackPage'
|
||||||
|
title={globalize.translate('HeaderPageNotFound')}
|
||||||
|
className='mainAnimatedPage libraryPage'
|
||||||
|
>
|
||||||
|
<div className='padded-left padded-right'>
|
||||||
|
<h1>{globalize.translate('HeaderPageNotFound')}</h1>
|
||||||
|
<p>{globalize.translate('PageNotFound')}</p>
|
||||||
|
<LinkButton
|
||||||
|
className='button-link'
|
||||||
|
href='#/home.html'
|
||||||
|
>
|
||||||
|
{globalize.translate('GoHome')}
|
||||||
|
</LinkButton>
|
||||||
|
</div>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FallbackRoute;
|
|
@ -473,6 +473,7 @@
|
||||||
"HeaderNoLyrics": "No lyrics found",
|
"HeaderNoLyrics": "No lyrics found",
|
||||||
"HeaderOnNow": "On Now",
|
"HeaderOnNow": "On Now",
|
||||||
"HeaderOtherItems": "Other Items",
|
"HeaderOtherItems": "Other Items",
|
||||||
|
"HeaderPageNotFound": "Page not found",
|
||||||
"HeaderParentalRatings": "Parental Ratings",
|
"HeaderParentalRatings": "Parental Ratings",
|
||||||
"HeaderPassword": "Password",
|
"HeaderPassword": "Password",
|
||||||
"HeaderPasswordReset": "Password Reset",
|
"HeaderPasswordReset": "Password Reset",
|
||||||
|
@ -1315,6 +1316,7 @@
|
||||||
"PackageInstallCancelled": "{0} (version {1}) installation cancelled.",
|
"PackageInstallCancelled": "{0} (version {1}) installation cancelled.",
|
||||||
"PackageInstallCompleted": "{0} (version {1}) installation completed.",
|
"PackageInstallCompleted": "{0} (version {1}) installation completed.",
|
||||||
"PackageInstallFailed": "{0} (version {1}) installation failed.",
|
"PackageInstallFailed": "{0} (version {1}) installation failed.",
|
||||||
|
"PageNotFound": "This is not the page you are looking for.",
|
||||||
"ParentalRating": "Parental rating",
|
"ParentalRating": "Parental rating",
|
||||||
"PasswordMatchError": "Password and password confirmation must match.",
|
"PasswordMatchError": "Password and password confirmation must match.",
|
||||||
"PasswordRequiredForAdmin": "A password is required for admin accounts.",
|
"PasswordRequiredForAdmin": "A password is required for admin accounts.",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue