diff --git a/packages/app/package.json b/packages/app/package.json
index 8ef8a54221..c27540f63e 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -45,7 +45,6 @@
"@backstage/frontend-app-api": "workspace:^",
"@backstage/integration-react": "workspace:^",
"@backstage/plugin-api-docs": "workspace:^",
- "@backstage/plugin-app": "^0.0.0",
"@backstage/plugin-auth-react": "workspace:^",
"@backstage/plugin-catalog": "workspace:^",
"@backstage/plugin-catalog-common": "workspace:^",
diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx
index cc7512464a..ba556e8616 100644
--- a/packages/app/src/App.tsx
+++ b/packages/app/src/App.tsx
@@ -82,7 +82,6 @@ import { customDevToolsPage } from './components/devtools/CustomDevToolsPage';
import { DevToolsPage } from '@backstage/plugin-devtools';
import { CatalogUnprocessedEntitiesPage } from '@backstage/plugin-catalog-unprocessed-entities';
import { NotificationsPage } from '@backstage/plugin-notifications';
-import { AppPage } from '@backstage/plugin-app';
const app = createApp({
apis,
@@ -209,7 +208,6 @@ const routes = (
{customDevToolsPage}
} />
- } />
);
diff --git a/packages/frontend-app-api/package.json b/packages/frontend-app-api/package.json
index 3f13b4ad93..43cd9e53dd 100644
--- a/packages/frontend-app-api/package.json
+++ b/packages/frontend-app-api/package.json
@@ -48,6 +48,7 @@
},
"devDependencies": {
"@backstage/cli": "workspace:^",
+ "@backstage/plugin-app": "workspace:^",
"@backstage/test-utils": "workspace:^",
"@testing-library/jest-dom": "^6.0.0",
"@testing-library/react": "^15.0.0"
diff --git a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts
index 4d450f0ae4..4e1c37e9a0 100644
--- a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts
+++ b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.test.ts
@@ -29,12 +29,15 @@ import {
createRouteRef,
} from '@backstage/frontend-plugin-api';
import { MockConfigApi, TestApiRegistry } from '@backstage/test-utils';
+import appPlugin from '@backstage/plugin-app';
-import { builtinExtensions } from '../wiring/createApp';
import { readAppExtensionsConfig } from '../tree/readAppExtensionsConfig';
import { resolveAppNodeSpecs } from '../tree/resolveAppNodeSpecs';
import { resolveAppTree } from '../tree/resolveAppTree';
import { instantiateAppNodeTree } from '../tree/instantiateAppNodeTree';
+import { Root } from '../extensions/Root';
+// eslint-disable-next-line @backstage/no-relative-monorepo-imports
+import { resolveExtensionDefinition } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';
const ref1 = createRouteRef();
const ref2 = createRouteRef();
@@ -83,12 +86,12 @@ function routeInfoFromExtensions(extensions: ExtensionDefinition[]) {
});
const tree = resolveAppTree(
- 'app',
+ 'root',
resolveAppNodeSpecs({
- features: [plugin],
- builtinExtensions,
+ features: [appPlugin, plugin],
+ builtinExtensions: [resolveExtensionDefinition(Root)],
parameters: readAppExtensionsConfig(new MockConfigApi({})),
- forbidden: new Set(['app']),
+ forbidden: new Set(['root']),
}),
);
diff --git a/packages/frontend-app-api/src/wiring/createApp.test.tsx b/packages/frontend-app-api/src/wiring/createApp.test.tsx
index e29a3afe94..2e54aadf58 100644
--- a/packages/frontend-app-api/src/wiring/createApp.test.tsx
+++ b/packages/frontend-app-api/src/wiring/createApp.test.tsx
@@ -29,6 +29,7 @@ import { CreateAppFeatureLoader, createApp } from './createApp';
import { MockConfigApi, renderWithEffects } from '@backstage/test-utils';
import React from 'react';
import { featureFlagsApiRef, useApi } from '@backstage/core-plugin-api';
+import appPlugin from '@backstage/plugin-app';
describe('createApp', () => {
it('should allow themes to be installed', async () => {
@@ -44,6 +45,7 @@ describe('createApp', () => {
}),
}),
features: [
+ appPlugin,
createFrontendPlugin({
id: 'test',
extensions: [
@@ -73,6 +75,7 @@ describe('createApp', () => {
const app = createApp({
configLoader: async () => ({ config: new MockConfigApi({}) }),
features: [
+ appPlugin,
createFrontendPlugin({
id: duplicatedFeatureId,
extensions: [
@@ -136,7 +139,7 @@ describe('createApp', () => {
configLoader: async () => ({
config: new MockConfigApi({ key: 'config-value' }),
}),
- features: [loader],
+ features: [appPlugin, loader],
});
await renderWithEffects(app.createRoot());
@@ -174,6 +177,7 @@ describe('createApp', () => {
const app = createApp({
configLoader: async () => ({ config: new MockConfigApi({}) }),
features: [
+ appPlugin,
createFrontendPlugin({
id: 'test',
featureFlags: [{ name: 'test-1' }],
@@ -229,6 +233,7 @@ describe('createApp', () => {
const app = createApp({
configLoader: async () => ({ config: new MockConfigApi({}) }),
features: [
+ appPlugin,
createFrontendPlugin({
id: 'my-plugin',
extensions: [
@@ -255,13 +260,53 @@ describe('createApp', () => {
const { tree } = appTreeApi!.getTree();
expect(String(tree.root)).toMatchInlineSnapshot(`
- "
+ "
+ apis [
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ themes [
+
+
+ ]
+
+
+ components [
+
+
+
+ ]
+
+
+
+
+ ]
app [
root [
children [
+ nav [
+
+ ]
content [
routes [
@@ -269,9 +314,6 @@ describe('createApp', () => {
]
]
- nav [
-
- ]
]
elements [
@@ -282,43 +324,6 @@ describe('createApp', () => {
]
]
- apis [
-
- themes [
-
-
- ]
-
-
-
-
-
- components [
-
-
-
- ]
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ]
"
`);
});
diff --git a/packages/frontend-plugin-api/package.json b/packages/frontend-plugin-api/package.json
index c76bae094e..1983ed54d2 100644
--- a/packages/frontend-plugin-api/package.json
+++ b/packages/frontend-plugin-api/package.json
@@ -45,6 +45,7 @@
"@backstage/cli": "workspace:^",
"@backstage/frontend-app-api": "workspace:^",
"@backstage/frontend-test-utils": "workspace:^",
+ "@backstage/plugin-app": "workspace:^",
"@backstage/test-utils": "workspace:^",
"@testing-library/jest-dom": "^6.0.0",
"@testing-library/react": "^15.0.0",
diff --git a/packages/frontend-plugin-api/src/blueprints/RouterBlueprint.test.tsx b/packages/frontend-plugin-api/src/blueprints/RouterBlueprint.test.tsx
index 405c673d60..62b55ec4a6 100644
--- a/packages/frontend-plugin-api/src/blueprints/RouterBlueprint.test.tsx
+++ b/packages/frontend-plugin-api/src/blueprints/RouterBlueprint.test.tsx
@@ -26,6 +26,7 @@ import {
} from '../wiring';
import { MockConfigApi } from '@backstage/test-utils';
import { PageBlueprint } from './PageBlueprint';
+import appPlugin from '@backstage/plugin-app';
describe('RouterBlueprint', () => {
it('should return an extension when calling make with sensible defaults', () => {
@@ -74,6 +75,7 @@ describe('RouterBlueprint', () => {
const app = createSpecializedApp({
features: [
+ appPlugin,
createExtensionOverrides({
extensions: [
extension,
@@ -126,6 +128,7 @@ describe('RouterBlueprint', () => {
const app = createSpecializedApp({
features: [
+ appPlugin,
createExtensionOverrides({
extensions: [
extension,
diff --git a/packages/frontend-plugin-api/src/blueprints/ThemeBlueprint.test.ts b/packages/frontend-plugin-api/src/blueprints/ThemeBlueprint.test.ts
index 71c5f9b918..6d3f6280a3 100644
--- a/packages/frontend-plugin-api/src/blueprints/ThemeBlueprint.test.ts
+++ b/packages/frontend-plugin-api/src/blueprints/ThemeBlueprint.test.ts
@@ -33,7 +33,7 @@ describe('ThemeBlueprint', () => {
"$$type": "@backstage/ExtensionDefinition",
"T": undefined,
"attachTo": {
- "id": "api:app-theme",
+ "id": "api:app/app-theme",
"input": "themes",
},
"configSchema": undefined,
diff --git a/packages/frontend-plugin-api/src/blueprints/TranslationBlueprint.test.ts b/packages/frontend-plugin-api/src/blueprints/TranslationBlueprint.test.ts
index 7d045b5f6c..6bccd68c53 100644
--- a/packages/frontend-plugin-api/src/blueprints/TranslationBlueprint.test.ts
+++ b/packages/frontend-plugin-api/src/blueprints/TranslationBlueprint.test.ts
@@ -48,7 +48,7 @@ describe('TranslationBlueprint', () => {
"$$type": "@backstage/ExtensionDefinition",
"T": undefined,
"attachTo": {
- "id": "api:translations",
+ "id": "api:app/translations",
"input": "translations",
},
"configSchema": undefined,
diff --git a/packages/frontend-plugin-api/src/wiring/createFrontendPlugin.test.ts b/packages/frontend-plugin-api/src/wiring/createFrontendPlugin.test.ts
index 63256d9a3a..df393b9807 100644
--- a/packages/frontend-plugin-api/src/wiring/createFrontendPlugin.test.ts
+++ b/packages/frontend-plugin-api/src/wiring/createFrontendPlugin.test.ts
@@ -25,6 +25,7 @@ import { coreExtensionData } from './coreExtensionData';
import { MockConfigApi, renderWithEffects } from '@backstage/test-utils';
import { createExtensionInput } from './createExtensionInput';
import { BackstagePlugin } from './types';
+import appPlugin from '@backstage/plugin-app';
const nameExtensionDataRef = createExtensionDataRef().with({
id: 'name',
@@ -127,7 +128,7 @@ function createTestAppRoot({
config: JsonObject;
}) {
return createApp({
- features,
+ features: [...features, appPlugin],
configLoader: async () => ({ config: new MockConfigApi(config) }),
}).createRoot();
}
diff --git a/packages/frontend-test-utils/package.json b/packages/frontend-test-utils/package.json
index 526e8b1713..ed53d7c1f8 100644
--- a/packages/frontend-test-utils/package.json
+++ b/packages/frontend-test-utils/package.json
@@ -34,6 +34,7 @@
"@backstage/config": "workspace:^",
"@backstage/frontend-app-api": "workspace:^",
"@backstage/frontend-plugin-api": "workspace:^",
+ "@backstage/plugin-app": "workspace:^",
"@backstage/test-utils": "workspace:^",
"@backstage/types": "workspace:^"
},
diff --git a/packages/frontend-test-utils/src/app/renderInTestApp.tsx b/packages/frontend-test-utils/src/app/renderInTestApp.tsx
index cc919f3f3d..7923050050 100644
--- a/packages/frontend-test-utils/src/app/renderInTestApp.tsx
+++ b/packages/frontend-test-utils/src/app/renderInTestApp.tsx
@@ -27,12 +27,12 @@ import {
coreExtensionData,
RouteRef,
useRouteRef,
- createExtensionInput,
IconComponent,
RouterBlueprint,
NavItemBlueprint,
FrontendFeature,
} from '@backstage/frontend-plugin-api';
+import appPlugin from '@backstage/plugin-app';
/**
* Options to customize the behavior of the test app.
@@ -92,38 +92,36 @@ const NavItem = (props: {
);
};
-export const TestAppNavExtension = createExtension({
- namespace: 'app',
- name: 'nav',
- attachTo: { id: 'app/layout', input: 'nav' },
- inputs: {
- items: createExtensionInput([NavItemBlueprint.dataRefs.target]),
- },
- output: [coreExtensionData.reactElement],
- factory({ inputs }) {
- return [
- coreExtensionData.reactElement(
- ,
+ ),
+ ];
+ },
+ }),
+ ],
});
/**
@@ -152,7 +150,6 @@ export function renderInTestApp(
Component: ({ children }) => {children},
},
}),
- TestAppNavExtension,
];
if (options?.mountedRoutes) {
@@ -183,6 +180,7 @@ export function renderInTestApp(
}
const features: FrontendFeature[] = [
+ appPluginOverride,
createExtensionOverrides({
extensions,
}),
diff --git a/plugins/app/src/extensions/AppRoot.tsx b/plugins/app/src/extensions/AppRoot.tsx
index 9906480ad6..bd786765f9 100644
--- a/plugins/app/src/extensions/AppRoot.tsx
+++ b/plugins/app/src/extensions/AppRoot.tsx
@@ -75,16 +75,12 @@ export const AppRoot = createExtension({
},
output: [coreExtensionData.reactElement],
factory({ inputs, apis }) {
- const identityApi = apis.get(identityApiRef);
- if (!identityApi) {
- throw new Error('App requires an Identity API implementation');
- }
- if (!('enableCookieAuth' in identityApi)) {
- throw new Error('Unexpected Identity API implementation');
- }
- const appIdentityProxy = identityApi as AppIdentityProxy;
-
if (isProtectedApp()) {
+ const identityApi = apis.get(identityApiRef);
+ if (!identityApi) {
+ throw new Error('App requires an Identity API implementation');
+ }
+ const appIdentityProxy = toAppIdentityProxy(identityApi);
const discoveryApi = apis.get(discoveryApiRef);
const errorApi = apis.get(errorApiRef);
const fetchApi = apis.get(fetchApiRef);
@@ -119,7 +115,6 @@ export const AppRoot = createExtension({
return [
coreExtensionData.reactElement(
;
RouterComponent?: ComponentType>;
}
@@ -208,12 +209,12 @@ function DefaultRouter(props: PropsWithChildren<{}>) {
export function AppRouter(props: AppRouterProps) {
const {
children,
- appIdentityProxy,
SignInPageComponent,
RouterComponent = DefaultRouter,
} = props;
const configApi = useApi(configApiRef);
+ const appIdentityProxy = toAppIdentityProxy(useApi(identityApiRef));
const routeResolutionsApi = useApi(routeResolutionApiRef);
const basePath = getBasePath(configApi);