mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Rename ConnectedRoute component
This commit is contained in:
parent
05dbeff473
commit
2e49d2db8b
3 changed files with 48 additions and 33 deletions
|
@ -1,13 +1,13 @@
|
|||
import React, { FunctionComponent, useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import globalize from '../scripts/globalize';
|
||||
|
||||
import alert from './alert';
|
||||
import { appRouter } from './appRouter';
|
||||
import loading from './loading/loading';
|
||||
import ServerConnections from './ServerConnections';
|
||||
import globalize from '../scripts/globalize';
|
||||
|
||||
enum Routes {
|
||||
enum BounceRoutes {
|
||||
Home = '/home.html',
|
||||
Login = '/login.html',
|
||||
SelectServer = '/selectserver.html',
|
||||
|
@ -22,33 +22,38 @@ enum ConnectionState {
|
|||
ServerUpdateNeeded = 'ServerUpdateNeeded'
|
||||
}
|
||||
|
||||
type ConnectedRouteProps = {
|
||||
isAdminRoute?: boolean,
|
||||
isUserRoute?: boolean,
|
||||
roles?: string[]
|
||||
type ConnectionRequiredProps = {
|
||||
isAdminRequired?: boolean,
|
||||
isUserRequired?: boolean
|
||||
};
|
||||
|
||||
const ConnectedRoute: FunctionComponent<ConnectedRouteProps> = ({
|
||||
/**
|
||||
* A component that ensures a server connection has been established.
|
||||
* Additional parameters exist to verify a user or admin have authenticated.
|
||||
* If a condition fails, this component will navigate to the appropriate page.
|
||||
*/
|
||||
const ConnectionRequired: FunctionComponent<ConnectionRequiredProps> = ({
|
||||
children,
|
||||
isAdminRoute = false,
|
||||
isUserRoute = true
|
||||
isAdminRequired = false,
|
||||
isUserRequired = true
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [ isLoading, setIsLoading ] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const bounce = async (connectionResponse: any) => {
|
||||
switch (connectionResponse.State) {
|
||||
case ConnectionState.SignedIn:
|
||||
// Already logged in, bounce to the home page
|
||||
console.debug('[ConnectedRoute] already logged in, redirecting to home');
|
||||
navigate(Routes.Home);
|
||||
console.debug('[ConnectionRequired] already logged in, redirecting to home');
|
||||
navigate(BounceRoutes.Home);
|
||||
return;
|
||||
case ConnectionState.ServerSignIn:
|
||||
// Bounce to the login page
|
||||
console.debug('[ConnectedRoute] not logged in, redirecting to login page');
|
||||
navigate(Routes.Login, {
|
||||
console.debug('[ConnectionRequired] not logged in, redirecting to login page');
|
||||
navigate(BounceRoutes.Login, {
|
||||
state: {
|
||||
serverid: connectionResponse.ApiClient.serverId()
|
||||
}
|
||||
|
@ -56,8 +61,8 @@ const ConnectedRoute: FunctionComponent<ConnectedRouteProps> = ({
|
|||
return;
|
||||
case ConnectionState.ServerSelection:
|
||||
// Bounce to select server page
|
||||
console.debug('[ConnectedRoute] redirecting to select server page');
|
||||
navigate(Routes.SelectServer);
|
||||
console.debug('[ConnectionRequired] redirecting to select server page');
|
||||
navigate(BounceRoutes.SelectServer);
|
||||
return;
|
||||
case ConnectionState.ServerUpdateNeeded:
|
||||
// Show update needed message and bounce to select server page
|
||||
|
@ -67,14 +72,14 @@ const ConnectedRoute: FunctionComponent<ConnectedRouteProps> = ({
|
|||
html: globalize.translate('ServerUpdateNeeded', '<a href="https://github.com/jellyfin/jellyfin">https://github.com/jellyfin/jellyfin</a>')
|
||||
});
|
||||
} catch (ex) {
|
||||
console.warn('[ConnectedRoute] failed to show alert', ex);
|
||||
console.warn('[ConnectionRequired] failed to show alert', ex);
|
||||
}
|
||||
console.debug('[ConnectedRoute] server update required, redirecting to select server page');
|
||||
navigate(Routes.SelectServer);
|
||||
console.debug('[ConnectionRequired] server update required, redirecting to select server page');
|
||||
navigate(BounceRoutes.SelectServer);
|
||||
return;
|
||||
}
|
||||
|
||||
console.warn('[ConnectedRoute] unhandled connection state', connectionResponse.State);
|
||||
console.warn('[ConnectionRequired] unhandled connection state', connectionResponse.State);
|
||||
};
|
||||
|
||||
const validateConnection = async () => {
|
||||
|
@ -93,12 +98,12 @@ const ConnectedRoute: FunctionComponent<ConnectedRouteProps> = ({
|
|||
const systemInfo = await infoResponse.json();
|
||||
if (!systemInfo.StartupWizardCompleted) {
|
||||
// Bounce to the wizard
|
||||
console.info('[ConnectedRoute] startup wizard is not complete, redirecting there');
|
||||
navigate(Routes.StartWizard);
|
||||
console.info('[ConnectionRequired] startup wizard is not complete, redirecting there');
|
||||
navigate(BounceRoutes.StartWizard);
|
||||
return;
|
||||
}
|
||||
} catch (ex) {
|
||||
console.error('[ConnectedRoute] checking wizard status failed', ex);
|
||||
console.error('[ConnectionRequired] checking wizard status failed', ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,27 +117,27 @@ const ConnectedRoute: FunctionComponent<ConnectedRouteProps> = ({
|
|||
const client = ServerConnections.currentApiClient();
|
||||
|
||||
// If this is a user route, ensure a user is logged in
|
||||
if ((isAdminRoute || isUserRoute) && !client?.isLoggedIn()) {
|
||||
if ((isAdminRequired || isUserRequired) && !client?.isLoggedIn()) {
|
||||
try {
|
||||
console.warn('[ConnectedRoute] unauthenticated user attempted to access user route');
|
||||
console.warn('[ConnectionRequired] unauthenticated user attempted to access user route');
|
||||
bounce(await ServerConnections.connect());
|
||||
} catch (ex) {
|
||||
console.warn('[ConnectedRoute] error bouncing from user route', ex);
|
||||
console.warn('[ConnectionRequired] error bouncing from user route', ex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is an admin route, ensure the user has access
|
||||
if (isAdminRoute) {
|
||||
if (isAdminRequired) {
|
||||
try {
|
||||
const user = await client.getCurrentUser();
|
||||
if (!user.Policy.IsAdministrator) {
|
||||
console.warn('[ConnectedRoute] normal user attempted to access admin route');
|
||||
console.warn('[ConnectionRequired] normal user attempted to access admin route');
|
||||
bounce(await ServerConnections.connect());
|
||||
return;
|
||||
}
|
||||
} catch (ex) {
|
||||
console.warn('[ConnectedRoute] error bouncing from admin route', ex);
|
||||
console.warn('[ConnectionRequired] error bouncing from admin route', ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +147,7 @@ const ConnectedRoute: FunctionComponent<ConnectedRouteProps> = ({
|
|||
|
||||
loading.show();
|
||||
validateConnection();
|
||||
}, [ isAdminRoute, isUserRoute, navigate ]);
|
||||
}, [ isAdminRequired, isUserRequired, navigate ]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoading) {
|
||||
|
@ -159,4 +164,4 @@ const ConnectedRoute: FunctionComponent<ConnectedRouteProps> = ({
|
|||
);
|
||||
};
|
||||
|
||||
export default ConnectedRoute;
|
||||
export default ConnectionRequired;
|
|
@ -2,8 +2,16 @@ import React, { useLayoutEffect } from 'react';
|
|||
import { HistoryRouterProps, Router } from 'react-router-dom';
|
||||
import { Update } from 'history';
|
||||
|
||||
/** Strips leading "!" from paths */
|
||||
const normalizePath = (pathname: string) => pathname.replace(/^!/, '');
|
||||
|
||||
/**
|
||||
* A slightly customized version of the HistoryRouter from react-router-dom.
|
||||
* We need to use HistoryRouter to have a shared history state between react-router and appRouter, but it does not seem
|
||||
* to be properly exported in the upstream package.
|
||||
* We also needed some customizations to handle #! routes.
|
||||
* Refs: https://github.com/remix-run/react-router/blob/v6.3.0/packages/react-router-dom/index.tsx#L222
|
||||
*/
|
||||
export function HistoryRouter({ basename, children, history }: HistoryRouterProps) {
|
||||
const [state, setState] = React.useState({
|
||||
action: history.action,
|
||||
|
@ -13,6 +21,7 @@ export function HistoryRouter({ basename, children, history }: HistoryRouterProp
|
|||
useLayoutEffect(() => {
|
||||
const onHistoryChange = (update: Update) => {
|
||||
if (update.location.pathname.startsWith('!')) {
|
||||
// When the location changes, we need to check for #! paths and replace the location with the "!" stripped
|
||||
history.replace(normalizePath(update.location.pathname), update.location.state);
|
||||
} else {
|
||||
setState(update);
|
||||
|
@ -29,6 +38,7 @@ export function HistoryRouter({ basename, children, history }: HistoryRouterProp
|
|||
children={children}
|
||||
location={{
|
||||
...state.location,
|
||||
// The original location does not get replaced with the normalized version, so we need to strip it here
|
||||
pathname: normalizePath(state.location.pathname)
|
||||
}}
|
||||
navigationType={state.action}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import { Route, Routes } from 'react-router-dom';
|
||||
|
||||
import ConnectedRoute from '../components/ConnectedRoute';
|
||||
import ConnectionRequired from '../components/ConnectionRequired';
|
||||
import SearchPage from './search';
|
||||
|
||||
const AppRoutes = () => (
|
||||
|
@ -10,9 +10,9 @@ const AppRoutes = () => (
|
|||
<Route
|
||||
path='search.html'
|
||||
element={
|
||||
<ConnectedRoute>
|
||||
<ConnectionRequired>
|
||||
<SearchPage />
|
||||
</ConnectedRoute>
|
||||
</ConnectionRequired>
|
||||
}
|
||||
/>
|
||||
{/* Suppress warnings for unhandled routes */}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue