diff --git a/packages/frontend-app-api/api-report.md b/packages/frontend-app-api/api-report.md index 5c003e8129..04f30c2616 100644 --- a/packages/frontend-app-api/api-report.md +++ b/packages/frontend-app-api/api-report.md @@ -4,7 +4,9 @@ ```ts import { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { Config } from '@backstage/config'; import { ConfigApi } from '@backstage/core-plugin-api'; +import { ExtensionDataRef } from '@backstage/frontend-plugin-api'; import { JSX as JSX_2 } from 'react'; // @public (undocumented) @@ -14,4 +16,23 @@ export function createApp(options: { }): { createRoot(): JSX_2.Element; }; + +// @public (undocumented) +export function createExtensionTree(options: { config: Config }): ExtensionTree; + +// @public (undocumented) +export interface ExtensionTree { + // (undocumented) + getExtension(id: string): ExtensionTreeNode | undefined; + // (undocumented) + getExtensionAttachments(id: string, inputName: string): ExtensionTreeNode[]; +} + +// @public (undocumented) +export interface ExtensionTreeNode { + // (undocumented) + getData(ref: ExtensionDataRef): T | undefined; + // (undocumented) + id: string; +} ``` diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index c65c511e55..23b7b4ca11 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -15,10 +15,11 @@ */ import React, { JSX } from 'react'; -import { ConfigReader } from '@backstage/config'; +import { ConfigReader, Config } from '@backstage/config'; import { BackstagePlugin, coreExtensionData, + ExtensionDataRef, } from '@backstage/frontend-plugin-api'; import { Core } from '../extensions/Core'; import { CoreRoutes } from '../extensions/CoreRoutes'; @@ -76,26 +77,55 @@ import { import { BrowserRouter } from 'react-router-dom'; /** @public */ -export function createApp(options: { - plugins: BackstagePlugin[]; - config?: ConfigApi; -}): { - createRoot(): JSX.Element; -} { - const appConfig = - options?.config ?? - ConfigReader.fromConfigs(overrideBaseUrlConfigs(defaultConfigLoaderSync())); +export interface ExtensionTreeNode { + id: string; + getData(ref: ExtensionDataRef): T | undefined; +} +/** @public */ +export interface ExtensionTree { + getExtension(id: string): ExtensionTreeNode | undefined; + getExtensionAttachments(id: string, inputName: string): ExtensionTreeNode[]; +} + +/** @public */ +export function createExtensionTree(options: { + config: Config; +}): ExtensionTree { + const plugins = getAvailablePlugins(); + const { instances } = createInstances({ + plugins, + config: options.config, + }); + + return { + getExtension(id: string): ExtensionTreeNode | undefined { + return instances.get(id); + }, + getExtensionAttachments( + id: string, + inputName: string, + ): ExtensionTreeNode[] { + return instances.get(id)?.attachments.get(inputName) ?? []; + }, + }; +} + +/** + * @internal + */ +export function createInstances(options: { + plugins: BackstagePlugin[]; + config: Config; +}) { const builtinExtensions = [Core, CoreRoutes, CoreNav, CoreLayout]; - const discoveredPlugins = getAvailablePlugins(); - const allPlugins = [...discoveredPlugins, ...options.plugins]; // pull in default extension instance from discovered packages // apply config to adjust default extension instances and add more const extensionParams = mergeExtensionParameters({ - sources: allPlugins, + sources: options.plugins, builtinExtensions, - parameters: readAppExtensionParameters(appConfig), + parameters: readAppExtensionParameters(options.config), }); // TODO: validate the config of all extension instances @@ -156,10 +186,32 @@ export function createApp(options: { } const rootConfigs = attachmentMap.get('root')?.get('default') ?? []; + const rootInstances = rootConfigs.map(instanceParams => createInstance(instanceParams), ); + return { instances, rootInstances }; +} + +/** @public */ +export function createApp(options: { + plugins: BackstagePlugin[]; + config?: ConfigApi; +}): { + createRoot(): JSX.Element; +} { + const discoveredPlugins = getAvailablePlugins(); + const allPlugins = [...discoveredPlugins, ...options.plugins]; + const appConfig = + options?.config ?? + ConfigReader.fromConfigs(overrideBaseUrlConfigs(defaultConfigLoaderSync())); + + const { rootInstances } = createInstances({ + plugins: allPlugins, + config: appConfig, + }); + const routePaths = extractRouteInfoFromInstanceTree(rootInstances); const coreInstance = rootInstances.find(({ id }) => id === 'core'); diff --git a/packages/frontend-app-api/src/wiring/index.ts b/packages/frontend-app-api/src/wiring/index.ts index a43cd73df2..dc1ba3bc13 100644 --- a/packages/frontend-app-api/src/wiring/index.ts +++ b/packages/frontend-app-api/src/wiring/index.ts @@ -14,4 +14,9 @@ * limitations under the License. */ -export { createApp } from './createApp'; +export { + createApp, + createExtensionTree, + type ExtensionTreeNode, + type ExtensionTree, +} from './createApp';