core-app-api: FlatRoutes react-router stable compatibility

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2022-03-25 16:39:07 +01:00
parent 37e8c5e128
commit 70299c99d5
2 changed files with 38 additions and 13 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-app-api': minor
---
Updated `FlatRoutes` to be compatible with `react-router` v6 stable.
@@ -18,6 +18,8 @@ import React, { ReactNode } from 'react';
import { useRoutes } from 'react-router-dom';
import { useApp, useElementFilter } from '@backstage/core-plugin-api';
let warned = false;
type RouteObject = {
path: string;
element: ReactNode;
@@ -49,7 +51,11 @@ export const FlatRoutes = (props: FlatRoutesProps): JSX.Element | null => {
const { NotFoundErrorPage } = app.getComponents();
const routes = useElementFilter(props.children, elements =>
elements
.getElements<{ path?: string; children: ReactNode }>()
.getElements<{
path?: string;
element?: ReactNode;
children?: ReactNode;
}>()
.flatMap<RouteObject>(child => {
let path = child.props.path;
@@ -59,16 +65,30 @@ export const FlatRoutes = (props: FlatRoutesProps): JSX.Element | null => {
}
path = path?.replace(/\/\*$/, '') ?? '/';
let element = child.props.element;
if (!element) {
element = child;
if (!warned && process.env.NODE_ENV !== 'test') {
// eslint-disable-next-line no-console
console.warn(
'DEPRECATION WARNING: All elements within <FlatRoutes> must be of type <Route> with an element prop. ' +
'Existing usages of <Navigate key=[path] to=[to] /> should be replaced with <Route path=[path] element={<Navigate to=[to] />} />',
);
warned = true;
}
}
return [
{
// Each route matches any sub route, except for the explicit root path
path,
element: child,
element,
children: child.props.children
? [
// These are the children of each route, which we all add in under a catch-all
// subroute in order to make them available to `useOutlet`
{
path: path === '/' ? '/' : '/*', // The root path must require an exact match
path: path === '/' ? '/' : '*', // The root path must require an exact match
element: child.props.children,
},
]
@@ -77,19 +97,19 @@ export const FlatRoutes = (props: FlatRoutesProps): JSX.Element | null => {
];
})
// Routes are sorted to work around a bug where prefixes are unexpectedly matched
// TODO(Rugvip): This can be removed once react-router v6 beta is no longer supported
.sort((a, b) => b.path.localeCompare(a.path))
// We make sure all routes have '/*' appended, except '/'
.map(obj => {
obj.path = obj.path === '/' ? '/' : `${obj.path}/*`;
return obj;
}),
.map(obj => ({ ...obj, path: obj.path === '/' ? '/' : `${obj.path}/*` })),
);
// TODO(Rugvip): Possibly add a way to skip this, like a noNotFoundPage prop
routes.push({
element: <NotFoundErrorPage />,
path: '/*',
});
const withNotFound = [
...routes,
{
path: '/*',
element: <NotFoundErrorPage />,
},
];
return useRoutes(routes);
return useRoutes(withNotFound);
};