Incorporated the feedback.
Signed-off-by: bnechyporenko <bnechyporenko@bol.com>
This commit is contained in:
@@ -50,7 +50,7 @@ export function createApp(
|
||||
...icons,
|
||||
...options?.icons,
|
||||
},
|
||||
plugins: (options?.plugins as BackstagePlugin<any, any>[]) ?? [],
|
||||
plugins: (options?.plugins as BackstagePlugin<any, any, any>[]) ?? [],
|
||||
themes: options?.themes ?? themes,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -82,8 +82,8 @@ import { resolveRouteBindings } from './resolveRouteBindings';
|
||||
import { BackstageRouteObject } from '../routing/types';
|
||||
|
||||
type CompatiblePlugin =
|
||||
| BackstagePlugin<any, any>
|
||||
| (Omit<BackstagePlugin<any, any>, 'getFeatureFlags'> & {
|
||||
| BackstagePlugin<any, any, any>
|
||||
| (Omit<BackstagePlugin<any, any, any>, 'getFeatureFlags'> & {
|
||||
output(): Array<{ type: 'feature-flag'; name: string }>;
|
||||
});
|
||||
|
||||
@@ -145,7 +145,7 @@ function useConfigLoader(
|
||||
class AppContextImpl implements AppContext {
|
||||
constructor(private readonly app: AppManager) {}
|
||||
|
||||
getPlugins(): BackstagePlugin<any, any>[] {
|
||||
getPlugins(): BackstagePlugin<any, any, any>[] {
|
||||
return this.app.getPlugins();
|
||||
}
|
||||
|
||||
@@ -186,8 +186,8 @@ export class AppManager implements BackstageApp {
|
||||
this.apiFactoryRegistry = new ApiFactoryRegistry();
|
||||
}
|
||||
|
||||
getPlugins(): BackstagePlugin<any, any>[] {
|
||||
return Array.from(this.plugins) as BackstagePlugin<any, any>[];
|
||||
getPlugins(): BackstagePlugin<any, any, any>[] {
|
||||
return Array.from(this.plugins) as BackstagePlugin<any, any, any>[];
|
||||
}
|
||||
|
||||
getSystemIcon(key: string): IconComponent | undefined {
|
||||
@@ -241,7 +241,7 @@ export class AppManager implements BackstageApp {
|
||||
validateRouteParameters(routing.paths, routing.parents);
|
||||
validateRouteBindings(
|
||||
routeBindings,
|
||||
this.plugins as Iterable<BackstagePlugin<any, any>>,
|
||||
this.plugins as Iterable<BackstagePlugin<any, any, any>>,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -291,7 +291,7 @@ export type BackstageApp = {
|
||||
/**
|
||||
* Returns all plugins registered for the app.
|
||||
*/
|
||||
getPlugins(): BackstagePlugin<any, any>[];
|
||||
getPlugins(): BackstagePlugin<any, any, any>[];
|
||||
|
||||
/**
|
||||
* Get a common or custom icon for this app.
|
||||
@@ -321,7 +321,7 @@ export type AppContext = {
|
||||
/**
|
||||
* Get a list of all plugins that are installed in the app.
|
||||
*/
|
||||
getPlugins(): BackstagePlugin<any, any>[];
|
||||
getPlugins(): BackstagePlugin<any, any, any>[];
|
||||
|
||||
/**
|
||||
* Get a common or custom icon for this app.
|
||||
|
||||
@@ -18,9 +18,9 @@ import { BackstagePlugin, getComponentData } from '@backstage/core-plugin-api';
|
||||
import { createCollector } from '../extensions/traversal';
|
||||
|
||||
export const pluginCollector = createCollector(
|
||||
() => new Set<BackstagePlugin<any, any>>(),
|
||||
() => new Set<BackstagePlugin<any, any, any>>(),
|
||||
(acc, node) => {
|
||||
const plugin = getComponentData<BackstagePlugin<any, any>>(
|
||||
const plugin = getComponentData<BackstagePlugin<any, any, any>>(
|
||||
node,
|
||||
'core.plugin',
|
||||
);
|
||||
|
||||
@@ -65,7 +65,7 @@ export function validateRouteParameters(
|
||||
// Validates that all non-optional external routes have been bound
|
||||
export function validateRouteBindings(
|
||||
routeBindings: Map<ExternalRouteRef, RouteRef | SubRouteRef>,
|
||||
plugins: Iterable<BackstagePlugin<{}, Record<string, ExternalRouteRef>>>,
|
||||
plugins: Iterable<BackstagePlugin<{}, {}, Record<string, ExternalRouteRef>>>,
|
||||
) {
|
||||
for (const plugin of plugins) {
|
||||
if (!plugin.externalRoutes) {
|
||||
|
||||
@@ -226,7 +226,7 @@ export function createReactExtension<
|
||||
'Component';
|
||||
|
||||
return {
|
||||
expose(plugin: BackstagePlugin<any, any>) {
|
||||
expose(plugin: BackstagePlugin<any, any, any>) {
|
||||
const Result: any = (props: any) => {
|
||||
const app = useApp();
|
||||
const { Progress } = app.getComponents();
|
||||
|
||||
@@ -17,13 +17,22 @@
|
||||
import React from 'react';
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { usePluginOptions, PluginProvider } from './usePluginOptions';
|
||||
import { createPlugin, PluginInputOptions, PluginOptions } from '../plugin';
|
||||
import { createPlugin } from '../plugin';
|
||||
|
||||
describe('usePluginOptions', () => {
|
||||
it('should provide a versioned value to hook', () => {
|
||||
type TestInputPluginOptions = {
|
||||
'key-1': string;
|
||||
};
|
||||
|
||||
type TestPluginOptions = {
|
||||
'key-1': string;
|
||||
'key-2': string;
|
||||
};
|
||||
|
||||
const plugin = createPlugin({
|
||||
id: 'my-plugin',
|
||||
__experimentalConfigure(_: PluginInputOptions): PluginOptions {
|
||||
__experimentalConfigure(_: TestInputPluginOptions): TestPluginOptions {
|
||||
return { 'key-1': 'value-1', 'key-2': 'value-2' };
|
||||
},
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
createVersionedValueMap,
|
||||
useVersionedContext,
|
||||
} from '@backstage/version-bridge';
|
||||
import { BackstagePlugin, PluginOptions } from '../plugin';
|
||||
import { BackstagePlugin, AnyPluginOptions } from '../plugin';
|
||||
import React, { ReactNode } from 'react';
|
||||
|
||||
const contextKey: string = 'plugin-context';
|
||||
@@ -38,12 +38,14 @@ export const PluginProvider = ({
|
||||
children,
|
||||
plugin,
|
||||
}: PluginOptionsProviderProps): JSX.Element => {
|
||||
const { Provider } = createVersionedContext<{ 1: PluginOptions }>(contextKey);
|
||||
const { Provider } = createVersionedContext<{ 1: AnyPluginOptions }>(
|
||||
contextKey,
|
||||
);
|
||||
return (
|
||||
<Provider
|
||||
value={createVersionedValueMap({
|
||||
1: plugin as unknown as {
|
||||
getPluginOptions(): PluginOptions;
|
||||
getPluginOptions(): AnyPluginOptions;
|
||||
},
|
||||
})}
|
||||
>
|
||||
@@ -59,7 +61,7 @@ export const PluginProvider = ({
|
||||
* @alpha
|
||||
*/
|
||||
export function usePluginOptions<
|
||||
TPluginOptions extends PluginOptions = PluginOptions,
|
||||
TPluginOptions extends AnyPluginOptions = AnyPluginOptions,
|
||||
>(): TPluginOptions {
|
||||
const versionedHolder = useVersionedContext<{ 1: TPluginOptions }>(
|
||||
contextKey,
|
||||
@@ -74,5 +76,9 @@ export function usePluginOptions<
|
||||
throw new Error('Plugin Options v1 is not available');
|
||||
}
|
||||
|
||||
return value.options as TPluginOptions;
|
||||
return (
|
||||
value as unknown as {
|
||||
getPluginOptions(): AnyPluginOptions;
|
||||
}
|
||||
).getPluginOptions() as TPluginOptions;
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ import {
|
||||
Extension,
|
||||
AnyRoutes,
|
||||
AnyExternalRoutes,
|
||||
PluginOptions,
|
||||
PluginInputOptions,
|
||||
AnyPluginOptions,
|
||||
AnyPluginInputOptions,
|
||||
PluginFeatureFlagConfig,
|
||||
} from './types';
|
||||
import { AnyApiFactory } from '../apis';
|
||||
@@ -30,13 +30,22 @@ import { AnyApiFactory } from '../apis';
|
||||
* @internal
|
||||
*/
|
||||
export class PluginImpl<
|
||||
PluginInputOptions extends AnyPluginInputOptions,
|
||||
PluginOptions extends AnyPluginOptions,
|
||||
Routes extends AnyRoutes,
|
||||
ExternalRoutes extends AnyExternalRoutes,
|
||||
> implements BackstagePlugin<Routes, ExternalRoutes>
|
||||
> implements BackstagePlugin<PluginInputOptions, Routes, ExternalRoutes>
|
||||
{
|
||||
constructor(private readonly config: PluginConfig<Routes, ExternalRoutes>) {}
|
||||
constructor(
|
||||
private readonly config: PluginConfig<
|
||||
PluginInputOptions,
|
||||
PluginOptions,
|
||||
Routes,
|
||||
ExternalRoutes
|
||||
>,
|
||||
) {}
|
||||
|
||||
options: PluginOptions | undefined = undefined;
|
||||
options: AnyPluginOptions | undefined = undefined;
|
||||
|
||||
getId(): string {
|
||||
return this.config.id;
|
||||
@@ -68,11 +77,11 @@ export class PluginImpl<
|
||||
}
|
||||
}
|
||||
|
||||
getPluginOptions(): PluginOptions {
|
||||
getPluginOptions(): AnyPluginOptions {
|
||||
if (this.config.__experimentalConfigure && !this.options) {
|
||||
this.options = this.config.__experimentalConfigure();
|
||||
}
|
||||
return this.options ?? ({} as PluginOptions);
|
||||
return this.options ?? ({} as AnyPluginOptions);
|
||||
}
|
||||
|
||||
toString() {
|
||||
@@ -87,10 +96,17 @@ export class PluginImpl<
|
||||
* @public
|
||||
*/
|
||||
export function createPlugin<
|
||||
PluginInputOptions extends AnyPluginInputOptions = {},
|
||||
PluginOptions extends AnyPluginInputOptions = {},
|
||||
Routes extends AnyRoutes = {},
|
||||
ExternalRoutes extends AnyExternalRoutes = {},
|
||||
>(
|
||||
config: PluginConfig<Routes, ExternalRoutes>,
|
||||
): BackstagePlugin<Routes, ExternalRoutes> {
|
||||
config: PluginConfig<
|
||||
PluginInputOptions,
|
||||
PluginOptions,
|
||||
Routes,
|
||||
ExternalRoutes
|
||||
>,
|
||||
): BackstagePlugin<PluginInputOptions, Routes, ExternalRoutes> {
|
||||
return new PluginImpl(config);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ export { createPlugin } from './Plugin';
|
||||
|
||||
export type {
|
||||
AnyExternalRoutes,
|
||||
PluginOptions,
|
||||
PluginInputOptions,
|
||||
AnyPluginOptions,
|
||||
AnyPluginInputOptions,
|
||||
AnyRoutes,
|
||||
BackstagePlugin,
|
||||
Extension,
|
||||
|
||||
@@ -27,7 +27,7 @@ import { AnyApiFactory } from '../apis';
|
||||
* @public
|
||||
*/
|
||||
export type Extension<T> = {
|
||||
expose(plugin: BackstagePlugin<any, any>): T;
|
||||
expose(plugin: BackstagePlugin<any, any, any>): T;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -49,8 +49,8 @@ export type AnyExternalRoutes = { [name: string]: ExternalRouteRef };
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type PluginOptions = { [name: string]: unknown };
|
||||
export type PluginInputOptions = { [name: string]: unknown };
|
||||
export type AnyPluginOptions = { [name: string]: unknown };
|
||||
export type AnyPluginInputOptions = { [name: string]: unknown };
|
||||
|
||||
/**
|
||||
* Plugin type.
|
||||
@@ -58,6 +58,7 @@ export type PluginInputOptions = { [name: string]: unknown };
|
||||
* @public
|
||||
*/
|
||||
export type BackstagePlugin<
|
||||
PluginInputOptions extends AnyPluginInputOptions = {},
|
||||
Routes extends AnyRoutes = {},
|
||||
ExternalRoutes extends AnyExternalRoutes = {},
|
||||
> = {
|
||||
@@ -89,6 +90,8 @@ export type PluginFeatureFlagConfig = {
|
||||
* @public
|
||||
*/
|
||||
export type PluginConfig<
|
||||
PluginInputOptions extends AnyPluginInputOptions,
|
||||
PluginOptions extends AnyPluginOptions,
|
||||
Routes extends AnyRoutes,
|
||||
ExternalRoutes extends AnyExternalRoutes,
|
||||
> = {
|
||||
|
||||
@@ -20,5 +20,9 @@ export type CatalogPluginOptions = {
|
||||
createButtonTitle: string;
|
||||
};
|
||||
|
||||
export type CatalogInputPluginOptions = {
|
||||
createButtonTitle: string;
|
||||
};
|
||||
|
||||
export const useCatalogPluginOptions = () =>
|
||||
usePluginOptions<CatalogPluginOptions>();
|
||||
|
||||
@@ -30,8 +30,6 @@ import {
|
||||
discoveryApiRef,
|
||||
fetchApiRef,
|
||||
storageApiRef,
|
||||
PluginOptions,
|
||||
PluginInputOptions,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { DefaultStarredEntitiesApi } from './apis';
|
||||
import { AboutCardProps } from './components/AboutCard';
|
||||
@@ -45,6 +43,7 @@ import { HasSubcomponentsCardProps } from './components/HasSubcomponentsCard';
|
||||
import { HasSystemsCardProps } from './components/HasSystemsCard';
|
||||
import { RelatedEntitiesCardProps } from './components/RelatedEntitiesCard';
|
||||
import { rootRouteRef } from './routes';
|
||||
import { CatalogInputPluginOptions, CatalogPluginOptions } from './options';
|
||||
|
||||
/** @public */
|
||||
export const catalogPlugin = createPlugin({
|
||||
@@ -74,7 +73,9 @@ export const catalogPlugin = createPlugin({
|
||||
createComponent: createComponentRouteRef,
|
||||
viewTechDoc: viewTechDocRouteRef,
|
||||
},
|
||||
__experimentalConfigure(options?: PluginInputOptions): PluginOptions {
|
||||
__experimentalConfigure(
|
||||
options?: CatalogInputPluginOptions,
|
||||
): CatalogPluginOptions {
|
||||
const defaultOptions = {
|
||||
createButtonTitle: 'Create',
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user