packages/core-api: split AppComponent into AppRouter and AppRoutes

This commit is contained in:
Patrik Oldsberg
2020-06-16 00:46:39 +02:00
parent b943eb065e
commit 9a37995151
6 changed files with 76 additions and 42 deletions
+7 -4
View File
@@ -27,15 +27,18 @@ const app = createApp({
});
const AppProvider = app.getProvider();
const AppComponent = app.getRootComponent();
const AppRouter = app.getRouter();
const AppRoutes = app.getRoutes();
const App: FC<{}> = () => (
<AppProvider>
<AlertDisplay />
<OAuthRequestDialog />
<Root>
<AppComponent />
</Root>
<AppRouter>
<Root>
<AppRoutes />
</Root>
</AppRouter>
</AppProvider>
);
@@ -26,13 +26,16 @@ const app = createApp({
});
const AppProvider = app.getProvider();
const AppComponent = app.getRootComponent();
const AppRouter = app.getRouter();
const AppRoutes = app.getRoutes();
const App: FC<{}> = () => {
useStyles();
return (
<AppProvider>
<AppComponent />
<AppRouter>
<AppRoutes />
</AppRouter>
</AppProvider>
);
};
+35 -20
View File
@@ -19,7 +19,11 @@ import { AppContextProvider } from './AppContext';
import { BackstageApp, AppComponents, AppConfigLoader, Apis } from './types';
import { BackstagePlugin } from '../plugin';
import { FeatureFlagsRegistryItem } from './FeatureFlags';
import { featureFlagsApiRef } from '../apis/definitions';
import {
featureFlagsApiRef,
AppThemeApi,
ConfigApi,
} from '../apis/definitions';
import { AppThemeProvider } from './AppThemeProvider';
import { IconComponent, SystemIcons, SystemIconKey } from '../icons';
@@ -32,6 +36,7 @@ import {
appThemeApiRef,
configApiRef,
ConfigReader,
useApi,
} from '../apis';
import { ApiAggregator } from '../apis/ApiAggregator';
import { useAsync } from 'react-use';
@@ -114,7 +119,7 @@ export class PrivateAppImpl implements BackstageApp {
return this.icons[key];
}
getRootComponent(): ComponentType<{}> {
getRoutes(): ComponentType<{}> {
const routes = new Array<JSX.Element>();
const registeredFeatureFlags = new Array<FeatureFlagsRegistryItem>();
@@ -195,26 +200,42 @@ export class PrivateAppImpl implements BackstageApp {
if ('node' in loadedConfig) {
return loadedConfig.node;
}
const configReader = loadedConfig.api;
const configApi = loadedConfig.api;
const appApis = ApiRegistry.from([
[appThemeApiRef, AppThemeSelector.createWithStorage(this.themes)],
[configApiRef, configReader],
[appThemeApiRef, appThemeApi],
[configApiRef, configApi],
]);
if (!this.apis) {
if ('get' in this.apisOrFactory) {
this.apis = this.apisOrFactory;
} else {
this.apis = this.apisOrFactory(configReader);
this.apis = this.apisOrFactory(configApi);
}
}
const apis = new ApiAggregator(this.apis, appApis);
const { Router } = this.components;
return (
<ApiProvider apis={apis}>
<AppContextProvider app={this}>
<AppThemeProvider>{children}</AppThemeProvider>
</AppContextProvider>
</ApiProvider>
);
};
return Provider;
}
getRouter(): ComponentType<{}> {
const { Router: RouterComponent } = this.components;
const AppRouter: FC<{}> = ({ children }) => {
const configApi = useApi(configApiRef);
let { pathname } = new URL(
configReader.getString('app.baseUrl') ?? '/',
configApi.getString('app.baseUrl') ?? '/',
'http://dummy.dev', // baseUrl can be specified as just a path
);
if (pathname.endsWith('/')) {
@@ -222,20 +243,14 @@ export class PrivateAppImpl implements BackstageApp {
}
return (
<ApiProvider apis={apis}>
<AppContextProvider app={this}>
<AppThemeProvider>
<Router>
<Routes>
<Route path={`${pathname}/*`} element={<>{children}</>} />
</Routes>
</Router>
</AppThemeProvider>
</AppContextProvider>
</ApiProvider>
<RouterComponent>
<Routes>
<Route path={`${pathname}/*`} element={<>{children}</>} />
</Routes>
</RouterComponent>
);
};
return Provider;
return AppRouter;
}
verify() {
+13 -8
View File
@@ -117,14 +117,19 @@ export type BackstageApp = {
getSystemIcon(key: SystemIconKey): IconComponent;
/**
* Creates a root component for this app, including the App chrome
* and routes to all plugins.
*/
getRootComponent(): ComponentType<{}>;
/**
* Provider component that should wrap the App's RootComponent and
* any other components that need to be within the app context.
* Provider component that should wrap the Router created with getRouter()
* and any other components that need to be within the app context.
*/
getProvider(): ComponentType<{}>;
/**
* Router component that should wrap the App Routes create with getRoutes()
* and any other components that should only be available while signed in.
*/
getRouter(): ComponentType<{}>;
/**
* Routes component that contains all routes for plugin pages in the app.
*/
getRoutes(): ComponentType<{}>;
};
+10 -5
View File
@@ -82,8 +82,10 @@ class DevAppBuilder {
apis: this.setupApiRegistry(this.factories),
plugins: this.plugins,
});
const AppProvider = app.getProvider();
const AppComponent = app.getRootComponent();
const AppRouter = app.getRouter();
const AppRoutes = app.getRoutes();
const sidebar = this.setupSidebar(this.plugins);
@@ -93,10 +95,13 @@ class DevAppBuilder {
<AlertDisplay />
<OAuthRequestDialog />
{this.rootChildren}
<SidebarPage>
{sidebar}
<AppComponent />
</SidebarPage>
<AppRouter>
<SidebarPage>
{sidebar}
<AppRoutes />
</SidebarPage>
</AppRouter>
</AppProvider>
);
};
@@ -89,12 +89,15 @@ export function wrapInTestApp(
}
const AppProvider = app.getProvider();
const AppRouter = app.getRouter();
return (
<AppProvider>
{/* The path of * here is needed to be set as a catch all, so it will render the wrapper element
* and work with nested routes if they exist too */}
<Route path="*" element={<Wrapper />} />
<AppRouter>
{/* The path of * here is needed to be set as a catch all, so it will render the wrapper element
* and work with nested routes if they exist too */}
<Route path="*" element={<Wrapper />} />
</AppRouter>
</AppProvider>
);
}