packages/core-api: move router component inside app and configure it with base path
This commit is contained in:
@@ -16,7 +16,6 @@
|
||||
|
||||
import { createApp, AlertDisplay, OAuthRequestDialog } from '@backstage/core';
|
||||
import React, { FC } from 'react';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import Root from './components/Root';
|
||||
import * as plugins from './plugins';
|
||||
import apis from './apis';
|
||||
@@ -33,11 +32,9 @@ const App: FC<{}> = () => (
|
||||
<AppProvider>
|
||||
<AlertDisplay />
|
||||
<OAuthRequestDialog />
|
||||
<Router>
|
||||
<Root>
|
||||
<AppComponent />
|
||||
</Root>
|
||||
</Router>
|
||||
<Root>
|
||||
<AppComponent />
|
||||
</Root>
|
||||
</AppProvider>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import { createApp } from '@backstage/core';
|
||||
import React, { FC } from 'react';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import * as plugins from './plugins';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
@@ -33,9 +32,7 @@ const App: FC<{}> = () => {
|
||||
useStyles();
|
||||
return (
|
||||
<AppProvider>
|
||||
<Router>
|
||||
<AppComponent />
|
||||
</Router>
|
||||
<AppComponent />
|
||||
</AppProvider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { ComponentType, FC } from 'react';
|
||||
import React, { ComponentType, FC, useMemo } from 'react';
|
||||
import { Route, Switch, Redirect } from 'react-router-dom';
|
||||
import { AppContextProvider } from './AppContext';
|
||||
import { BackstageApp, AppComponents, AppConfigLoader } from './types';
|
||||
@@ -161,30 +161,58 @@ export class PrivateAppImpl implements BackstageApp {
|
||||
|
||||
getProvider(): ComponentType<{}> {
|
||||
const Provider: FC<{}> = ({ children }) => {
|
||||
const appThemeApi = useMemo(
|
||||
() => AppThemeSelector.createWithStorage(this.themes),
|
||||
[],
|
||||
);
|
||||
|
||||
// Keeping this synchronous when a config loader isn't set simplifies tests a lot
|
||||
const hasConfig = Boolean(this.configLoader);
|
||||
const config = useAsync(this.configLoader || (() => Promise.resolve([])));
|
||||
|
||||
let childNode = children;
|
||||
let noConfigNode = undefined;
|
||||
|
||||
if (hasConfig && config.loading) {
|
||||
const { Progress } = this.components;
|
||||
childNode = <Progress />;
|
||||
noConfigNode = <Progress />;
|
||||
} else if (config.error) {
|
||||
const { BootErrorPage } = this.components;
|
||||
childNode = <BootErrorPage step="load-config" error={config.error} />;
|
||||
noConfigNode = (
|
||||
<BootErrorPage step="load-config" error={config.error} />
|
||||
);
|
||||
}
|
||||
|
||||
// Before the config is loaded we can't use a router, so exit early
|
||||
if (noConfigNode) {
|
||||
return (
|
||||
<ApiProvider apis={ApiRegistry.from([[appThemeApiRef, appThemeApi]])}>
|
||||
<AppThemeProvider>{noConfigNode}</AppThemeProvider>
|
||||
</ApiProvider>
|
||||
);
|
||||
}
|
||||
|
||||
const configReader = ConfigReader.fromConfigs(config.value ?? []);
|
||||
const appApis = ApiRegistry.from([
|
||||
[appThemeApiRef, AppThemeSelector.createWithStorage(this.themes)],
|
||||
[configApiRef, ConfigReader.fromConfigs(config.value ?? [])],
|
||||
[configApiRef, configReader],
|
||||
]);
|
||||
const apis = new ApiAggregator(this.apis, appApis);
|
||||
|
||||
const { Router } = this.components;
|
||||
let { pathname } = new URL(
|
||||
configReader.getString('app.baseUrl') ?? '/',
|
||||
'http://dummy.dev', // baseUrl can be specified as just a path
|
||||
);
|
||||
if (pathname.endsWith('/')) {
|
||||
pathname = pathname.replace(/\/$/, '');
|
||||
}
|
||||
|
||||
return (
|
||||
<ApiProvider apis={apis}>
|
||||
<AppContextProvider app={this}>
|
||||
<AppThemeProvider>{childNode}</AppThemeProvider>
|
||||
<AppThemeProvider>
|
||||
<Router basename={pathname}>{children}</Router>
|
||||
</AppThemeProvider>
|
||||
</AppContextProvider>
|
||||
</ApiProvider>
|
||||
);
|
||||
|
||||
@@ -30,6 +30,7 @@ export type AppComponents = {
|
||||
NotFoundErrorPage: ComponentType<{}>;
|
||||
BootErrorPage: ComponentType<BootErrorPageProps>;
|
||||
Progress: ComponentType<{}>;
|
||||
Router: ComponentType<{ basename?: string }>;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,7 @@ import privateExports, {
|
||||
BootErrorPageProps,
|
||||
AppConfigLoader,
|
||||
} from '@backstage/core-api';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import { BrowserRouter, MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import { ErrorPage } from '../layout/ErrorPage';
|
||||
import Progress from '../components/Progress';
|
||||
@@ -87,9 +87,9 @@ export function createApp(options?: AppOptions) {
|
||||
}
|
||||
// TODO: figure out a nicer way to handle routing on the error page, when it can be done.
|
||||
return (
|
||||
<Router>
|
||||
<MemoryRouter>
|
||||
<ErrorPage status="501" statusMessage={message} />
|
||||
</Router>
|
||||
</MemoryRouter>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -100,6 +100,7 @@ export function createApp(options?: AppOptions) {
|
||||
NotFoundErrorPage: DefaultNotFoundPage,
|
||||
BootErrorPage: DefaultBootErrorPage,
|
||||
Progress: Progress,
|
||||
Router: BrowserRouter,
|
||||
...options?.components,
|
||||
};
|
||||
const themes = options?.themes ?? [
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
import { hot } from 'react-hot-loader/root';
|
||||
import React, { FC, ComponentType, ReactNode } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import BookmarkIcon from '@material-ui/icons/Bookmark';
|
||||
import {
|
||||
createApp,
|
||||
@@ -94,12 +93,10 @@ class DevAppBuilder {
|
||||
<AlertDisplay />
|
||||
<OAuthRequestDialog />
|
||||
{this.rootChildren}
|
||||
<BrowserRouter>
|
||||
<SidebarPage>
|
||||
{sidebar}
|
||||
<AppComponent />
|
||||
</SidebarPage>
|
||||
</BrowserRouter>
|
||||
<SidebarPage>
|
||||
{sidebar}
|
||||
<AppComponent />
|
||||
</SidebarPage>
|
||||
</AppProvider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -55,6 +55,9 @@ export function wrapInTestApp(
|
||||
NotFoundErrorPage,
|
||||
BootErrorPage,
|
||||
Progress,
|
||||
Router: ({ children }) => (
|
||||
<MemoryRouter initialEntries={routeEntries} children={children} />
|
||||
),
|
||||
},
|
||||
icons: defaultSystemIcons,
|
||||
plugins: [],
|
||||
@@ -79,9 +82,7 @@ export function wrapInTestApp(
|
||||
|
||||
return (
|
||||
<AppProvider>
|
||||
<MemoryRouter initialEntries={routeEntries}>
|
||||
<Route component={Wrapper} />
|
||||
</MemoryRouter>
|
||||
<Route component={Wrapper} />
|
||||
</AppProvider>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user