frontend-app-api: Add Extension utilities

Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com>
Co-authored-by: Fredrik Adelöw <freben@gmail.com>
Co-authored-by: Camila Belo <camilaibs@gmail.com>
Signed-off-by: Johan Haals <johan.haals@gmail.com>
This commit is contained in:
Johan Haals
2023-09-12 13:59:15 +02:00
parent 68bb68b83b
commit 24985f51ce
4 changed files with 106 additions and 15 deletions
+33
View File
@@ -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<string, ExtensionInstance[]>;
getData<T>(ref: ExtensionDataRef<T>): 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<T>(ref: ExtensionDataRef<T>): T | undefined;
// (undocumented)
id: string;
}
```
@@ -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<T>(ref: ExtensionDataRef<T>): 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');
@@ -21,7 +21,7 @@ import {
} from '@backstage/frontend-plugin-api';
import mapValues from 'lodash/mapValues';
/** @internal */
/** @public */
export interface ExtensionInstance {
readonly $$type: '@backstage/ExtensionInstance';
@@ -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';