Incorporated the feedback.

Signed-off-by: bnechyporenko <bnechyporenko@bol.com>
This commit is contained in:
bnechyporenko
2022-07-06 17:22:57 +02:00
parent 7925bdf109
commit ec7c578c79
13 changed files with 76 additions and 37 deletions
+1 -1
View File
@@ -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,
});
}
+6 -6
View File
@@ -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>>,
);
}
+2 -2
View File
@@ -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;
}
+25 -9
View File
@@ -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);
}
+2 -2
View File
@@ -18,8 +18,8 @@ export { createPlugin } from './Plugin';
export type {
AnyExternalRoutes,
PluginOptions,
PluginInputOptions,
AnyPluginOptions,
AnyPluginInputOptions,
AnyRoutes,
BackstagePlugin,
Extension,
+6 -3
View File
@@ -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,
> = {
+4
View File
@@ -20,5 +20,9 @@ export type CatalogPluginOptions = {
createButtonTitle: string;
};
export type CatalogInputPluginOptions = {
createButtonTitle: string;
};
export const useCatalogPluginOptions = () =>
usePluginOptions<CatalogPluginOptions>();
+4 -3
View File
@@ -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',
};