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);