diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx
index ed0518485a..ba7fb4a8a5 100644
--- a/packages/app/src/App.tsx
+++ b/packages/app/src/App.tsx
@@ -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<{}> = () => (
-
-
-
+
+
+
+
+
);
diff --git a/packages/cli/templates/default-app/packages/app/src/App.tsx b/packages/cli/templates/default-app/packages/app/src/App.tsx
index 140d1c1660..1b58a3e5df 100644
--- a/packages/cli/templates/default-app/packages/app/src/App.tsx
+++ b/packages/cli/templates/default-app/packages/app/src/App.tsx
@@ -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 (
-
+
+
+
);
};
diff --git a/packages/core-api/src/app/App.tsx b/packages/core-api/src/app/App.tsx
index 6da2b5f1b9..8d625a3a0d 100644
--- a/packages/core-api/src/app/App.tsx
+++ b/packages/core-api/src/app/App.tsx
@@ -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();
const registeredFeatureFlags = new Array();
@@ -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 (
+
+
+ {children}
+
+
+ );
+ };
+ 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 (
-
-
-
-
-
- {children}>} />
-
-
-
-
-
+
+
+ {children}>} />
+
+
);
};
- return Provider;
+ return AppRouter;
}
verify() {
diff --git a/packages/core-api/src/app/types.ts b/packages/core-api/src/app/types.ts
index e30c79dd73..97809ca899 100644
--- a/packages/core-api/src/app/types.ts
+++ b/packages/core-api/src/app/types.ts
@@ -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<{}>;
};
diff --git a/packages/dev-utils/src/devApp/render.tsx b/packages/dev-utils/src/devApp/render.tsx
index 8900ecd54b..0e28a5bf8b 100644
--- a/packages/dev-utils/src/devApp/render.tsx
+++ b/packages/dev-utils/src/devApp/render.tsx
@@ -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 {
{this.rootChildren}
-
- {sidebar}
-
-
+
+
+
+ {sidebar}
+
+
+
);
};
diff --git a/packages/test-utils/src/testUtils/appWrappers.tsx b/packages/test-utils/src/testUtils/appWrappers.tsx
index c474678fd1..15814d918d 100644
--- a/packages/test-utils/src/testUtils/appWrappers.tsx
+++ b/packages/test-utils/src/testUtils/appWrappers.tsx
@@ -89,12 +89,15 @@ export function wrapInTestApp(
}
const AppProvider = app.getProvider();
+ const AppRouter = app.getRouter();
return (
- {/* 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 */}
- } />
+
+ {/* 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 */}
+ } />
+
);
}