From 24985f51cea46e58fd08a96118c644aaa7bdc3a8 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Tue, 12 Sep 2023 13:59:15 +0200 Subject: [PATCH] frontend-app-api: Add Extension utilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Patrik Oldsberg Co-authored-by: Fredrik Adelöw Co-authored-by: Camila Belo Signed-off-by: Johan Haals --- packages/frontend-app-api/api-report.md | 33 ++++++++ .../frontend-app-api/src/wiring/createApp.tsx | 78 +++++++++++++++---- .../src/wiring/createExtensionInstance.ts | 2 +- packages/frontend-app-api/src/wiring/index.ts | 8 +- 4 files changed, 106 insertions(+), 15 deletions(-) diff --git a/packages/frontend-app-api/api-report.md b/packages/frontend-app-api/api-report.md index 5c003e8129..fe0ceecbc6 100644 --- a/packages/frontend-app-api/api-report.md +++ b/packages/frontend-app-api/api-report.md @@ -5,7 +5,11 @@ ```ts import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { ConfigApi } from '@backstage/core-plugin-api'; +<<<<<<< HEAD import { JSX as JSX_2 } from 'react'; +======= +import { ExtensionDataRef } from '@backstage/frontend-plugin-api'; +>>>>>>> ed3fd70bda19 (frontend-app-api: Add Extension utilities) // @public (undocumented) export function createApp(options: { @@ -14,4 +18,33 @@ export function createApp(options: { }): { createRoot(): JSX_2.Element; }; + +// @public (undocumented) +export function createExtensionTree(): ExtensionTree; + +// @public (undocumented) +export interface ExtensionInstance { + // (undocumented) + readonly $$type: '@backstage/ExtensionInstance'; + readonly attachments: Map; + getData(ref: ExtensionDataRef): T | undefined; + // (undocumented) + readonly id: string; +} + +// @public (undocumented) +export interface ExtensionTree { + // (undocumented) + getExtension(id: string): ExtensionInstance | undefined; + // (undocumented) + getExtensionAttachments(id: string, inputName: string): ExtensionInstance[]; +} + +// @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..e5dc1db847 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -19,6 +19,7 @@ import { ConfigReader } 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): ExtensionInstance | undefined; + getExtensionAttachments(id: string, inputName: string): ExtensionInstance[]; +} + +/** @public */ +export function createExtensionTree(): ExtensionTree { + const plugins = getAvailablePlugins(); + const { instances } = createInstances({ + plugins, + config: ConfigReader.fromConfigs( + overrideBaseUrlConfigs(defaultConfigLoaderSync()), + ), + }); + + return { + getExtension(id: string): ExtensionInstance | undefined { + return instances.get(id); + }, + getExtensionAttachments( + id: string, + inputName: string, + ): ExtensionInstance[] { + return this.getExtension(id)?.attachments.get(inputName) ?? []; + }, + }; +} + +/** + * @internal + */ +export function createInstances(options: { + plugins: BackstagePlugin[]; + config: ConfigApi; +}) { 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/createExtensionInstance.ts b/packages/frontend-app-api/src/wiring/createExtensionInstance.ts index 52afe95121..0823f4e6e0 100644 --- a/packages/frontend-app-api/src/wiring/createExtensionInstance.ts +++ b/packages/frontend-app-api/src/wiring/createExtensionInstance.ts @@ -21,7 +21,7 @@ import { } from '@backstage/frontend-plugin-api'; import mapValues from 'lodash/mapValues'; -/** @internal */ +/** @public */ export interface ExtensionInstance { readonly $$type: '@backstage/ExtensionInstance'; diff --git a/packages/frontend-app-api/src/wiring/index.ts b/packages/frontend-app-api/src/wiring/index.ts index a43cd73df2..7eb1cc2de7 100644 --- a/packages/frontend-app-api/src/wiring/index.ts +++ b/packages/frontend-app-api/src/wiring/index.ts @@ -14,4 +14,10 @@ * limitations under the License. */ -export { createApp } from './createApp'; +export type { ExtensionInstance } from './createExtensionInstance'; +export { + createApp, + createExtensionTree, + type ExtensionTreeNode, + type ExtensionTree, +} from './createApp';