core-api: add routes and externalRoutes to plugin interface
Co-authored-by: blam <ben@blam.sh>
This commit is contained in:
@@ -59,7 +59,7 @@ import { ApiResolver, ApiFactoryRegistry } from '../apis/system';
|
||||
type FullAppOptions = {
|
||||
apis: Iterable<AnyApiFactory>;
|
||||
icons: SystemIcons;
|
||||
plugins: BackstagePlugin[];
|
||||
plugins: BackstagePlugin<any, any>[];
|
||||
components: AppComponents;
|
||||
themes: AppTheme[];
|
||||
configLoader?: AppConfigLoader;
|
||||
@@ -107,7 +107,7 @@ export class PrivateAppImpl implements BackstageApp {
|
||||
|
||||
private readonly apis: Iterable<AnyApiFactory>;
|
||||
private readonly icons: SystemIcons;
|
||||
private readonly plugins: BackstagePlugin[];
|
||||
private readonly plugins: BackstagePlugin<any, any>[];
|
||||
private readonly components: AppComponents;
|
||||
private readonly themes: AppTheme[];
|
||||
private readonly configLoader?: AppConfigLoader;
|
||||
@@ -125,7 +125,7 @@ export class PrivateAppImpl implements BackstageApp {
|
||||
this.defaultApis = options.defaultApis;
|
||||
}
|
||||
|
||||
getPlugins(): BackstagePlugin[] {
|
||||
getPlugins(): BackstagePlugin<any, any>[] {
|
||||
return this.plugins;
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ export type AppOptions = {
|
||||
/**
|
||||
* A list of all plugins to include in the app.
|
||||
*/
|
||||
plugins?: BackstagePlugin[];
|
||||
plugins?: BackstagePlugin<any, any>[];
|
||||
|
||||
/**
|
||||
* Supply components to the app to override the default ones.
|
||||
@@ -140,7 +140,7 @@ export type BackstageApp = {
|
||||
/**
|
||||
* Returns all plugins registered for the app.
|
||||
*/
|
||||
getPlugins(): BackstagePlugin[];
|
||||
getPlugins(): BackstagePlugin<any, any>[];
|
||||
|
||||
/**
|
||||
* Get a common icon for this app.
|
||||
|
||||
@@ -54,7 +54,7 @@ export function createReactExtension<Props extends {}>(options: {
|
||||
}): Extension<NamedExoticComponent<Props>> {
|
||||
const { component: Component, data = {} } = options;
|
||||
return {
|
||||
expose(plugin: BackstagePlugin): NamedExoticComponent<Props> {
|
||||
expose(plugin: BackstagePlugin<any, any>): NamedExoticComponent<Props> {
|
||||
const Result = (props: Props) => <Component {...props} />;
|
||||
|
||||
attachComponentData(Result, 'core.plugin', plugin);
|
||||
|
||||
@@ -19,13 +19,18 @@ import {
|
||||
PluginOutput,
|
||||
BackstagePlugin,
|
||||
Extension,
|
||||
AnyRoutes,
|
||||
AnyExternalRoutes,
|
||||
} from './types';
|
||||
import { AnyApiFactory } from '../apis';
|
||||
|
||||
export class PluginImpl implements BackstagePlugin {
|
||||
export class PluginImpl<
|
||||
Routes extends AnyRoutes,
|
||||
ExternalRoutes extends AnyExternalRoutes
|
||||
> implements BackstagePlugin<Routes, ExternalRoutes> {
|
||||
private storedOutput?: PluginOutput[];
|
||||
|
||||
constructor(private readonly config: PluginConfig) {}
|
||||
constructor(private readonly config: PluginConfig<Routes, ExternalRoutes>) {}
|
||||
|
||||
getId(): string {
|
||||
return this.config.id;
|
||||
@@ -35,6 +40,14 @@ export class PluginImpl implements BackstagePlugin {
|
||||
return this.config.apis ?? [];
|
||||
}
|
||||
|
||||
get routes(): Routes {
|
||||
return this.config.routes ?? ({} as Routes);
|
||||
}
|
||||
|
||||
get externalRoutes(): ExternalRoutes {
|
||||
return this.config.externalRoutes ?? ({} as ExternalRoutes);
|
||||
}
|
||||
|
||||
output(): PluginOutput[] {
|
||||
if (this.storedOutput) {
|
||||
return this.storedOutput;
|
||||
@@ -79,6 +92,11 @@ export class PluginImpl implements BackstagePlugin {
|
||||
}
|
||||
}
|
||||
|
||||
export function createPlugin(config: PluginConfig): BackstagePlugin {
|
||||
export function createPlugin<
|
||||
Routes extends AnyRoutes,
|
||||
ExternalRoutes extends AnyExternalRoutes
|
||||
>(
|
||||
config: PluginConfig<Routes, ExternalRoutes>,
|
||||
): BackstagePlugin<Routes, ExternalRoutes> {
|
||||
return new PluginImpl(config);
|
||||
}
|
||||
|
||||
@@ -34,9 +34,12 @@ import { getComponentData } from '../extensions';
|
||||
import { createCollector } from '../extensions/traversal';
|
||||
|
||||
export const pluginCollector = createCollector(
|
||||
() => new Set<BackstagePlugin>(),
|
||||
() => new Set<BackstagePlugin<any, any>>(),
|
||||
(acc, node) => {
|
||||
const plugin = getComponentData<BackstagePlugin>(node, 'core.plugin');
|
||||
const plugin = getComponentData<BackstagePlugin<any, any>>(
|
||||
node,
|
||||
'core.plugin',
|
||||
);
|
||||
if (plugin) {
|
||||
acc.add(plugin);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
import { ComponentType } from 'react';
|
||||
import { RouteRef } from '../routing';
|
||||
import { AnyApiFactory } from '../apis/system';
|
||||
import { ExternalRouteRef } from '../routing/RouteRef';
|
||||
|
||||
export type RouteOptions = {
|
||||
// Whether the route path must match exactly, defaults to true.
|
||||
@@ -67,20 +68,34 @@ export type PluginOutput =
|
||||
| FeatureFlagOutput;
|
||||
|
||||
export type Extension<T> = {
|
||||
expose(plugin: BackstagePlugin): T;
|
||||
expose(plugin: BackstagePlugin<any, any>): T;
|
||||
};
|
||||
|
||||
export type BackstagePlugin = {
|
||||
export type AnyRoutes = { [name: string]: RouteRef<any> };
|
||||
|
||||
export type AnyExternalRoutes = { [name: string]: ExternalRouteRef };
|
||||
|
||||
export type BackstagePlugin<
|
||||
Routes extends AnyRoutes,
|
||||
ExternalRoutes extends AnyExternalRoutes
|
||||
> = {
|
||||
getId(): string;
|
||||
output(): PluginOutput[];
|
||||
getApis(): Iterable<AnyApiFactory>;
|
||||
provide<T>(extension: Extension<T>): T;
|
||||
routes: Routes;
|
||||
externalRoutes: ExternalRoutes;
|
||||
};
|
||||
|
||||
export type PluginConfig = {
|
||||
export type PluginConfig<
|
||||
Routes extends AnyRoutes,
|
||||
ExternalRoutes extends AnyExternalRoutes
|
||||
> = {
|
||||
id: string;
|
||||
apis?: Iterable<AnyApiFactory>;
|
||||
register?(hooks: PluginHooks): void;
|
||||
routes?: Routes;
|
||||
externalRoutes?: ExternalRoutes;
|
||||
};
|
||||
|
||||
export type PluginHooks = {
|
||||
|
||||
Reference in New Issue
Block a user