import * as React from 'react';
import {
ComponentType,
useEffect,
isValidElement,
createElement,
useState,
ErrorInfo,
} from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { CoreAdminRoutes } from './CoreAdminRoutes';
import {
useResetErrorBoundaryOnLocationChange,
useRouterProvider,
} from '../routing';
import { Ready } from '../util';
import { DefaultTitleContextProvider } from './DefaultTitleContext';
import type {
TitleComponent,
LoginComponent,
LayoutComponent,
AdminChildren,
CatchAllComponent,
DashboardComponent,
LoadingComponent,
} from '../types';
export type ChildrenFunction = () => ComponentType[];
const DefaultLayout = ({ children }: { children: React.ReactNode }) => (
<>{children}>
);
const DefaultError = ({ error, errorInfo, resetErrorBoundary }) => {
useResetErrorBoundaryOnLocationChange(resetErrorBoundary);
return (
Error
{error.message}
{errorInfo?.componentStack}
);
};
export interface CoreAdminUIProps {
/**
* The content displayed when the user visits the /auth-callback page, used for redirection by third-party authentication providers
*
* @see https://marmelab.com/react-admin/Admin.html#authcallbackpage
* @example
* import { Admin } from 'react-admin';
* import { dataProvider } from './dataProvider';
* import { authProvider } from './authProvider';
* import MyAuthCallbackPage from './MyAuthCallbackPage';
*
* const App = () => (
*
* ...
*
* );
*/
authCallbackPage?: ComponentType | boolean;
/**
* A catch-all react component to display when the URL does not match any
*
* @see https://marmelab.com/react-admin/Admin.html#catchall
* @example
* // in src/NotFound.js
* import Card from '@mui/material/Card';
* import CardContent from '@mui/material/CardContent';
* import { Title } from 'react-admin';
*
* export const NotFound = () => (
*
*
*
* 404: Page not found
*
*
* );
*
* // in src/App.js
* import { Admin } from 'react-admin';
* import { dataProvider } from './dataProvider';
* import { NotFound } from './NotFound';
*
* const App = () => (
*
* ...
*
* );
*/
catchAll?: CatchAllComponent;
children?: AdminChildren;
/**
* The component to use for the dashboard page (displayed on the `/` route).
*
* @see https://marmelab.com/react-admin/Admin.html#dashboard
* @example
* import { Admin } from 'react-admin';
* import Dashboard from './Dashboard';
* import { dataProvider } from './dataProvider';
*
* const App = () => (
*
* ...
*
* );
*/
dashboard?: DashboardComponent;
/**
* Set to true to disable anonymous telemetry collection
*
* @see https://marmelab.com/react-admin/Admin.html#disabletelemetry
* @example
* import { Admin } from 'react-admin';
* import { dataProvider } from './dataProvider';
*
* const App = () => (
*
* ...
*
* );
*/
disableTelemetry?: boolean;
/**
* The component displayed when an error is caught in a child component
* @see https://marmelab.com/react-admin/Admin.html#error
* @example
* import { Admin } from 'react-admin';
* import { MyError } from './error';
*
* const App = () => (
*
* ...
*
* );
*/
error?: ({
errorInfo,
error,
resetErrorBoundary,
}: {
errorInfo?: ErrorInfo;
error: Error;
resetErrorBoundary: (args) => void;
}) => React.ReactNode;
/**
* The main app layout component
*
* @see https://marmelab.com/react-admin/Admin.html#layout
* @example
* import { Admin, Layout } from 'react-admin';
*
* const MyLayout = ({ children }) => (
*
* {children}
*
* );
*
* export const App = () => (
*
* ...
*
* );
*/
layout?: LayoutComponent;
/**
* The component displayed while fetching the auth provider if the admin child is an async function
*/
loading?: LoadingComponent;
/**
* The component displayed when the user visits the /login page
* @see https://marmelab.com/react-admin/Admin.html#loginpage
* @example
* import { Admin } from 'react-admin';
* import { dataProvider } from './dataProvider';
* import { authProvider } from './authProvider';
* import MyLoginPage from './MyLoginPage';
*
* const App = () => (
*
* ...
*
* );
*/
loginPage?: LoginComponent | boolean;
/**
* Flag to require authentication for all routes. Defaults to false.
*
* @see https://marmelab.com/react-admin/Admin.html#requireauth
* @example
* import { Admin } from 'react-admin';
* import { dataProvider } from './dataProvider';
* import { authProvider } from './authProvider';
*
* const App = () => (
*
* ...
*
* );
*/
requireAuth?: boolean;
/**
* The page to display when the admin has no Resource children
*
* @see https://marmelab.com/react-admin/Admin.html#ready
* @example
* import { Admin } from 'react-admin';
*
* const Ready = () => (
*
*
Admin ready
*
You can now add resources
*
* )
*
* const App = () => (
*
* ...
*
* );
*/
ready?: ComponentType;
/**
* The title of the error page
* @see https://marmelab.com/react-admin/Admin.html#title
* @example
* import { Admin } from 'react-admin';
* import { dataProvider } from './dataProvider';
*
* const App = () => (
*
* ...
*
* );
*/
title?: TitleComponent;
/**
* The page to display when an authentication error occurs
*
* @see https://marmelab.com/react-admin/Admin.html#authenticationError
* @example
* import { Admin } from 'react-admin';
*
* const AuthenticationError = () => (
*
*
Authentication Error
*
The authentication server returned an error and your credentials could not be checked.
*
* )
*
* const App = () => (
*
* ...
*
* );
*/
authenticationError?: ComponentType;
/**
* A react component to display when users don't have access to the page they're trying to access
*
* @see https://marmelab.com/react-admin/Admin.html#accessDenied
* @example
* // in src/AccessDenied.js
* import Card from '@mui/material/Card';
* import CardContent from '@mui/material/CardContent';
* import { Title } from 'react-admin';
*
* export const AccessDenied = () => (
*
*
*
* You're not authorized to see this page
*
*
* );
*
* // in src/App.js
* import { Admin } from 'react-admin';
* import { dataProvider } from './dataProvider';
* import { AccessDenied } from './AccessDenied';
*
* const App = () => (
*
* ...
*
* );
*/
accessDenied?: React.ComponentType;
}
export const CoreAdminUI = (props: CoreAdminUIProps) => {
const [errorInfo, setErrorInfo] = useState({});
const { Route, Routes } = useRouterProvider();
const {
authCallbackPage: LoginCallbackPage = false,
catchAll = Noop,
children,
dashboard,
disableTelemetry = false,
error: ErrorComponent = DefaultError,
layout = DefaultLayout,
loading = Noop,
loginPage: LoginPage = false,
ready = Ready,
requireAuth = false,
title = 'React Admin',
authenticationError = Noop,
accessDenied = Noop,
} = props;
useEffect(() => {
if (
disableTelemetry ||
process.env.NODE_ENV !== 'production' ||
typeof window === 'undefined' ||
typeof window.location === 'undefined' ||
typeof Image === 'undefined'
) {
return;
}
const img = new Image();
img.src = `https://react-admin-telemetry.marmelab.com/react-admin-telemetry?domain=${window.location.hostname}`;
}, [disableTelemetry]);
const handleError = (error: Error, info: ErrorInfo) => setErrorInfo(info);
return (
(
)}
>
{LoginPage !== false && LoginPage !== true ? (
) : null}
{LoginCallbackPage !== false &&
LoginCallbackPage !== true ? (
) : null}
{children}
}
/>
);
};
const createOrGetElement = el => (isValidElement(el) ? el : createElement(el));
const Noop = () => null;