From 6be0e38b5621394c137d509dc439f1cbdc1072ce Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Mon, 9 May 2022 13:22:50 +0200 Subject: [PATCH 01/54] Draft(WIP): Add reconfigure to plugin Signed-off-by: bnechyporenko --- .../core-plugin-api/src/plugin/Plugin.tsx | 22 +++++++++++++++---- packages/core-plugin-api/src/plugin/types.ts | 11 ++++++++++ .../CatalogPage/DefaultCatalogPage.tsx | 12 +++++++--- plugins/catalog/src/plugin.ts | 6 +++++ 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index d97554b27b..fdf4585462 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -20,6 +20,7 @@ import { Extension, AnyRoutes, AnyExternalRoutes, + AnyMetadata, PluginFeatureFlagConfig, } from './types'; import { AnyApiFactory } from '../apis'; @@ -30,9 +31,16 @@ import { AnyApiFactory } from '../apis'; export class PluginImpl< Routes extends AnyRoutes, ExternalRoutes extends AnyExternalRoutes, -> implements BackstagePlugin + PluginMetadata extends AnyMetadata, +> implements BackstagePlugin { - constructor(private readonly config: PluginConfig) {} + constructor( + private readonly config: PluginConfig< + Routes, + ExternalRoutes, + PluginMetadata + >, + ) {} getId(): string { return this.config.id; @@ -58,6 +66,11 @@ export class PluginImpl< return extension.expose(this); } + reconfigure(metadata: PluginMetadata): BackstagePlugin { + this.config.metadata = metadata; + return this; + } + toString() { return `plugin{${this.config.id}}`; } @@ -72,8 +85,9 @@ export class PluginImpl< export function createPlugin< Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, + PluginMetadata extends AnyMetadata = {}, >( - config: PluginConfig, -): BackstagePlugin { + config: PluginConfig, +): BackstagePlugin { return new PluginImpl(config); } diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index d639327838..5a56d775b2 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -44,6 +44,13 @@ export type AnyRoutes = { [name: string]: RouteRef | SubRouteRef }; */ export type AnyExternalRoutes = { [name: string]: ExternalRouteRef }; +/** + * Catch-all metadata type. + * + * @public + */ +export type AnyMetadata = { [name: string]: any }; + /** * Plugin type. * @@ -52,6 +59,7 @@ export type AnyExternalRoutes = { [name: string]: ExternalRouteRef }; export type BackstagePlugin< Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, + PluginMetadata extends AnyMetadata = {}, > = { getId(): string; getApis(): Iterable; @@ -60,6 +68,7 @@ export type BackstagePlugin< */ getFeatureFlags(): Iterable; provide(extension: Extension): T; + reconfigure(metadata: PluginMetadata): BackstagePlugin; routes: Routes; externalRoutes: ExternalRoutes; }; @@ -82,12 +91,14 @@ export type PluginFeatureFlagConfig = { export type PluginConfig< Routes extends AnyRoutes, ExternalRoutes extends AnyExternalRoutes, + PluginMetadata extends AnyMetadata, > = { id: string; apis?: Iterable; routes?: Routes; externalRoutes?: ExternalRoutes; featureFlags?: PluginFeatureFlagConfig[]; + metadata?: PluginMetadata; }; /** diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx index 5250dcec0d..f4a31e815a 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -19,7 +19,6 @@ import { ContentHeader, CreateButton, PageWithHeader, - SupportButton, TableColumn, TableProps, } from '@backstage/core-components'; @@ -39,6 +38,12 @@ import { createComponentRouteRef } from '../../routes'; import { CatalogTable, CatalogTableRow } from '../CatalogTable'; import { CatalogKindHeader } from '../CatalogKindHeader'; +export type DefaultCatalogMetadataProps = { + createComponentTitle: string; + supportButtonText: string; + supportButton: () => JSX.Element; +}; + /** * Props for root catalog pages. * @@ -50,6 +55,7 @@ export interface DefaultCatalogPageProps { actions?: TableProps['actions']; initialKind?: string; tableOptions?: TableProps['options']; + metadata?: DefaultCatalogMetadataProps; } export function DefaultCatalogPage(props: DefaultCatalogPageProps) { @@ -72,10 +78,10 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { titleComponent={} > - All your software catalog entities + {props.metadata?.supportButton()} diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index 1b9083e7ca..9e5a335d5f 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -72,6 +72,12 @@ export const catalogPlugin = createPlugin({ createComponent: createComponentRouteRef, viewTechDoc: viewTechDocRouteRef, }, + metadata: { + createComponentTitle: 'Create Component', + supportButton: () => + import('@backstage/core-components').then(m => m.SupportButton), + supportButtonText: 'All your software catalog entities', + }, }); /** @public */ From f45d3da189534f0b6fe708dc2c0918b25b14f2e3 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Mon, 9 May 2022 16:49:36 +0200 Subject: [PATCH 02/54] Draft(WIP): Add reconfigure to plugin Signed-off-by: bnechyporenko --- .../src/extensions/extensions.tsx | 11 +++++++--- packages/core-plugin-api/src/plugin/index.ts | 1 + .../CatalogPage/DefaultCatalogPage.tsx | 9 ++------ plugins/catalog/src/plugin.ts | 22 ++++++++++++++----- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/packages/core-plugin-api/src/extensions/extensions.tsx b/packages/core-plugin-api/src/extensions/extensions.tsx index 19da082ee1..b4b5c0bdfc 100644 --- a/packages/core-plugin-api/src/extensions/extensions.tsx +++ b/packages/core-plugin-api/src/extensions/extensions.tsx @@ -19,7 +19,7 @@ import { AnalyticsContext } from '../analytics/AnalyticsContext'; import { useApp } from '../app'; import { RouteRef, useRouteRef } from '../routing'; import { attachComponentData } from './componentData'; -import { Extension, BackstagePlugin } from '../plugin/types'; +import { Extension, BackstagePlugin, AnyMetadata } from '../plugin/types'; import { PluginErrorBoundary } from './PluginErrorBoundary'; /** @@ -73,8 +73,13 @@ export function createRoutableExtension< * variable for this extension. */ name?: string; + + /** + * + */ + metadata?: AnyMetadata; }): Extension { - const { component, mountPoint, name } = options; + const { component, mountPoint, name, metadata } = options; return createReactExtension({ component: { lazy: () => @@ -100,7 +105,7 @@ export function createRoutableExtension< } throw error; } - return ; + return ; }; const componentName = diff --git a/packages/core-plugin-api/src/plugin/index.ts b/packages/core-plugin-api/src/plugin/index.ts index 95f5a6b219..1ebe1b3446 100644 --- a/packages/core-plugin-api/src/plugin/index.ts +++ b/packages/core-plugin-api/src/plugin/index.ts @@ -17,6 +17,7 @@ export { createPlugin } from './Plugin'; export type { AnyExternalRoutes, + AnyMetadata, AnyRoutes, BackstagePlugin, Extension, diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx index f4a31e815a..d74b413dbe 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -37,12 +37,7 @@ import React from 'react'; import { createComponentRouteRef } from '../../routes'; import { CatalogTable, CatalogTableRow } from '../CatalogTable'; import { CatalogKindHeader } from '../CatalogKindHeader'; - -export type DefaultCatalogMetadataProps = { - createComponentTitle: string; - supportButtonText: string; - supportButton: () => JSX.Element; -}; +import { CatalogPluginMetadata } from '../../plugin'; /** * Props for root catalog pages. @@ -55,7 +50,7 @@ export interface DefaultCatalogPageProps { actions?: TableProps['actions']; initialKind?: string; tableOptions?: TableProps['options']; - metadata?: DefaultCatalogMetadataProps; + metadata?: CatalogPluginMetadata; } export function DefaultCatalogPage(props: DefaultCatalogPageProps) { diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index 9e5a335d5f..a8a0951b5d 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -30,6 +30,7 @@ import { discoveryApiRef, fetchApiRef, storageApiRef, + AnyMetadata, } from '@backstage/core-plugin-api'; import { DefaultStarredEntitiesApi } from './apis'; import { AboutCardProps } from './components/AboutCard'; @@ -44,6 +45,19 @@ import { HasSystemsCardProps } from './components/HasSystemsCard'; import { RelatedEntitiesCardProps } from './components/RelatedEntitiesCard'; import { rootRouteRef } from './routes'; +export interface CatalogPluginMetadata extends AnyMetadata { + createComponentTitle: string; + supportButton: () => Promise; + supportButtonText: string; +} + +const metadata = { + createComponentTitle: 'Create Component', + supportButton: () => + import('@backstage/core-components').then(m => m.SupportButton), + supportButtonText: 'All your software catalog entities', +} as CatalogPluginMetadata; + /** @public */ export const catalogPlugin = createPlugin({ id: 'catalog', @@ -72,12 +86,7 @@ export const catalogPlugin = createPlugin({ createComponent: createComponentRouteRef, viewTechDoc: viewTechDocRouteRef, }, - metadata: { - createComponentTitle: 'Create Component', - supportButton: () => - import('@backstage/core-components').then(m => m.SupportButton), - supportButtonText: 'All your software catalog entities', - }, + metadata, }); /** @public */ @@ -87,6 +96,7 @@ export const CatalogIndexPage: (props: DefaultCatalogPageProps) => JSX.Element = name: 'CatalogIndexPage', component: () => import('./components/CatalogPage').then(m => m.CatalogPage), + metadata, mountPoint: rootRouteRef, }), ); From 889e393f5214bd636f2c18f0bb7a3bf5fb407f84 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Mon, 9 May 2022 20:35:49 +0200 Subject: [PATCH 03/54] Draft(WIP): Add reconfigure to plugin Signed-off-by: bnechyporenko --- packages/app/src/App.tsx | 6 ++++++ .../src/extensions/extensions.tsx | 18 +++++++++--------- packages/core-plugin-api/src/plugin/Plugin.tsx | 6 +++++- packages/core-plugin-api/src/plugin/types.ts | 1 + plugins/catalog/src/index.ts | 1 + plugins/catalog/src/plugin.ts | 8 ++++---- 6 files changed, 26 insertions(+), 14 deletions(-) diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 4cf2c02e55..4c2d8aabcb 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -94,6 +94,7 @@ import { techDocsPage } from './components/techdocs/TechDocsPage'; import { ApacheAirflowPage } from '@backstage/plugin-apache-airflow'; import { PermissionedRoute } from '@backstage/plugin-permission-react'; import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common'; +import { CatalogPluginMetadata } from '@backstage/plugin-catalog'; const app = createApp({ apis, @@ -134,6 +135,11 @@ const app = createApp({ const AppProvider = app.getProvider(); const AppRouter = app.getRouter(); +catalogPlugin.reconfigure({ + createComponentTitle: 'Create!!', + supportButton: () =>
Contact Support
, +} as CatalogPluginMetadata); + const routes = ( diff --git a/packages/core-plugin-api/src/extensions/extensions.tsx b/packages/core-plugin-api/src/extensions/extensions.tsx index b4b5c0bdfc..408cf054e2 100644 --- a/packages/core-plugin-api/src/extensions/extensions.tsx +++ b/packages/core-plugin-api/src/extensions/extensions.tsx @@ -19,7 +19,7 @@ import { AnalyticsContext } from '../analytics/AnalyticsContext'; import { useApp } from '../app'; import { RouteRef, useRouteRef } from '../routing'; import { attachComponentData } from './componentData'; -import { Extension, BackstagePlugin, AnyMetadata } from '../plugin/types'; +import { Extension, BackstagePlugin } from '../plugin/types'; import { PluginErrorBoundary } from './PluginErrorBoundary'; /** @@ -73,13 +73,8 @@ export function createRoutableExtension< * variable for this extension. */ name?: string; - - /** - * - */ - metadata?: AnyMetadata; }): Extension { - const { component, mountPoint, name, metadata } = options; + const { component, mountPoint, name } = options; return createReactExtension({ component: { lazy: () => @@ -105,7 +100,7 @@ export function createRoutableExtension< } throw error; } - return ; + return ; }; const componentName = @@ -240,6 +235,11 @@ export function createReactExtension< | { id?: string } | undefined; + const metadata = plugin.getMetadata(); + const componentProperties = metadata + ? { ...props, metadata } + : { ...props }; + return ( }> @@ -250,7 +250,7 @@ export function createReactExtension< ...(mountPoint && { routeRef: mountPoint.id }), }} > - + diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index fdf4585462..6c4c77f58b 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -54,6 +54,10 @@ export class PluginImpl< return this.config.featureFlags?.slice() ?? []; } + getMetadata(): PluginMetadata { + return this.config.metadata!!; + } + get routes(): Routes { return this.config.routes ?? ({} as Routes); } @@ -67,7 +71,7 @@ export class PluginImpl< } reconfigure(metadata: PluginMetadata): BackstagePlugin { - this.config.metadata = metadata; + this.config.metadata = { ...this.config.metadata, ...metadata }; return this; } diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index 5a56d775b2..a640013c47 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -67,6 +67,7 @@ export type BackstagePlugin< * Returns all registered feature flags for this plugin. */ getFeatureFlags(): Iterable; + getMetadata(): PluginMetadata; provide(extension: Extension): T; reconfigure(metadata: PluginMetadata): BackstagePlugin; routes: Routes; diff --git a/plugins/catalog/src/index.ts b/plugins/catalog/src/index.ts index cfe4851d09..ca55bac335 100644 --- a/plugins/catalog/src/index.ts +++ b/plugins/catalog/src/index.ts @@ -53,6 +53,7 @@ export { RelatedEntitiesCard, } from './plugin'; +export type { CatalogPluginMetadata } from './plugin'; export type { DependencyOfComponentsCardProps } from './components/DependencyOfComponentsCard'; export type { DependsOnComponentsCardProps } from './components/DependsOnComponentsCard'; export type { DependsOnResourcesCardProps } from './components/DependsOnResourcesCard'; diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index a8a0951b5d..264b3bdaf9 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -32,6 +32,7 @@ import { storageApiRef, AnyMetadata, } from '@backstage/core-plugin-api'; +import { SupportButton } from '@backstage/core-components'; import { DefaultStarredEntitiesApi } from './apis'; import { AboutCardProps } from './components/AboutCard'; import { DefaultCatalogPageProps } from './components/CatalogPage'; @@ -47,14 +48,14 @@ import { rootRouteRef } from './routes'; export interface CatalogPluginMetadata extends AnyMetadata { createComponentTitle: string; - supportButton: () => Promise; + supportButton: () => JSX.Element; supportButtonText: string; } const metadata = { createComponentTitle: 'Create Component', - supportButton: () => - import('@backstage/core-components').then(m => m.SupportButton), + // eslint-disable-next-line new-cap + supportButton: () => SupportButton({}), supportButtonText: 'All your software catalog entities', } as CatalogPluginMetadata; @@ -96,7 +97,6 @@ export const CatalogIndexPage: (props: DefaultCatalogPageProps) => JSX.Element = name: 'CatalogIndexPage', component: () => import('./components/CatalogPage').then(m => m.CatalogPage), - metadata, mountPoint: rootRouteRef, }), ); From 69c590b0ff9682580e48fff049a7a52f0151d6da Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 10 May 2022 08:54:04 +0200 Subject: [PATCH 04/54] Removed testing code Signed-off-by: bnechyporenko --- packages/app/src/App.tsx | 6 ------ .../src/extensions/extensions.tsx | 7 +------ packages/core-plugin-api/src/plugin/Plugin.tsx | 2 +- .../CatalogPage/DefaultCatalogPage.tsx | 7 +++---- plugins/catalog/src/index.ts | 1 - plugins/catalog/src/plugin.ts | 16 ---------------- 6 files changed, 5 insertions(+), 34 deletions(-) diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 4c2d8aabcb..4cf2c02e55 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -94,7 +94,6 @@ import { techDocsPage } from './components/techdocs/TechDocsPage'; import { ApacheAirflowPage } from '@backstage/plugin-apache-airflow'; import { PermissionedRoute } from '@backstage/plugin-permission-react'; import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common'; -import { CatalogPluginMetadata } from '@backstage/plugin-catalog'; const app = createApp({ apis, @@ -135,11 +134,6 @@ const app = createApp({ const AppProvider = app.getProvider(); const AppRouter = app.getRouter(); -catalogPlugin.reconfigure({ - createComponentTitle: 'Create!!', - supportButton: () =>
Contact Support
, -} as CatalogPluginMetadata); - const routes = ( diff --git a/packages/core-plugin-api/src/extensions/extensions.tsx b/packages/core-plugin-api/src/extensions/extensions.tsx index 408cf054e2..8f1efe3b65 100644 --- a/packages/core-plugin-api/src/extensions/extensions.tsx +++ b/packages/core-plugin-api/src/extensions/extensions.tsx @@ -235,11 +235,6 @@ export function createReactExtension< | { id?: string } | undefined; - const metadata = plugin.getMetadata(); - const componentProperties = metadata - ? { ...props, metadata } - : { ...props }; - return ( }> @@ -250,7 +245,7 @@ export function createReactExtension< ...(mountPoint && { routeRef: mountPoint.id }), }} > - + diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index 6c4c77f58b..61b8a5db8c 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -55,7 +55,7 @@ export class PluginImpl< } getMetadata(): PluginMetadata { - return this.config.metadata!!; + return this.config.metadata ?? ({} as PluginMetadata); } get routes(): Routes { diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx index d74b413dbe..5250dcec0d 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -19,6 +19,7 @@ import { ContentHeader, CreateButton, PageWithHeader, + SupportButton, TableColumn, TableProps, } from '@backstage/core-components'; @@ -37,7 +38,6 @@ import React from 'react'; import { createComponentRouteRef } from '../../routes'; import { CatalogTable, CatalogTableRow } from '../CatalogTable'; import { CatalogKindHeader } from '../CatalogKindHeader'; -import { CatalogPluginMetadata } from '../../plugin'; /** * Props for root catalog pages. @@ -50,7 +50,6 @@ export interface DefaultCatalogPageProps { actions?: TableProps['actions']; initialKind?: string; tableOptions?: TableProps['options']; - metadata?: CatalogPluginMetadata; } export function DefaultCatalogPage(props: DefaultCatalogPageProps) { @@ -73,10 +72,10 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { titleComponent={} > - {props.metadata?.supportButton()} + All your software catalog entities diff --git a/plugins/catalog/src/index.ts b/plugins/catalog/src/index.ts index ca55bac335..cfe4851d09 100644 --- a/plugins/catalog/src/index.ts +++ b/plugins/catalog/src/index.ts @@ -53,7 +53,6 @@ export { RelatedEntitiesCard, } from './plugin'; -export type { CatalogPluginMetadata } from './plugin'; export type { DependencyOfComponentsCardProps } from './components/DependencyOfComponentsCard'; export type { DependsOnComponentsCardProps } from './components/DependsOnComponentsCard'; export type { DependsOnResourcesCardProps } from './components/DependsOnResourcesCard'; diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index 264b3bdaf9..1b9083e7ca 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -30,9 +30,7 @@ import { discoveryApiRef, fetchApiRef, storageApiRef, - AnyMetadata, } from '@backstage/core-plugin-api'; -import { SupportButton } from '@backstage/core-components'; import { DefaultStarredEntitiesApi } from './apis'; import { AboutCardProps } from './components/AboutCard'; import { DefaultCatalogPageProps } from './components/CatalogPage'; @@ -46,19 +44,6 @@ import { HasSystemsCardProps } from './components/HasSystemsCard'; import { RelatedEntitiesCardProps } from './components/RelatedEntitiesCard'; import { rootRouteRef } from './routes'; -export interface CatalogPluginMetadata extends AnyMetadata { - createComponentTitle: string; - supportButton: () => JSX.Element; - supportButtonText: string; -} - -const metadata = { - createComponentTitle: 'Create Component', - // eslint-disable-next-line new-cap - supportButton: () => SupportButton({}), - supportButtonText: 'All your software catalog entities', -} as CatalogPluginMetadata; - /** @public */ export const catalogPlugin = createPlugin({ id: 'catalog', @@ -87,7 +72,6 @@ export const catalogPlugin = createPlugin({ createComponent: createComponentRouteRef, viewTechDoc: viewTechDocRouteRef, }, - metadata, }); /** @public */ From 82996af90b16eb17410f2d9385bdcdb842a37cd0 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 10 May 2022 09:14:12 +0200 Subject: [PATCH 05/54] created a change set Signed-off-by: bnechyporenko --- .changeset/fast-walls-carry.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fast-walls-carry.md diff --git a/.changeset/fast-walls-carry.md b/.changeset/fast-walls-carry.md new file mode 100644 index 0000000000..dcbe53ff29 --- /dev/null +++ b/.changeset/fast-walls-carry.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-plugin-api': patch +--- + +Introduced an optional metadata for the components, which can contain a configurable data. The author of the component might define the cofnigurable places of the component, and the user of this component can reconfigure it if necessary. From d2d41c6f139920c785395d52439eb27be244df7d Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 10 May 2022 09:34:52 +0200 Subject: [PATCH 06/54] Added a unit test Signed-off-by: bnechyporenko --- .../src/plugin/Plugin.test.tsx | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/packages/core-plugin-api/src/plugin/Plugin.test.tsx b/packages/core-plugin-api/src/plugin/Plugin.test.tsx index b66235e210..26c704517f 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.test.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.test.tsx @@ -32,3 +32,35 @@ describe('Plugin Feature Flag', () => { ).toEqual([]); }); }); + +describe('Plugin metadata', () => { + it('should be able to define metadata', () => { + expect( + createPlugin({ + id: 'test', + metadata: { + key: 'value', + }, + }).getMetadata(), + ).toEqual({ + key: 'value', + }); + }); + + it('should be able to reconfigure metadata', () => { + const plugin = createPlugin({ + id: 'test', + metadata: { + key: 'original-value', + }, + }); + + plugin.reconfigure({ + key: 'modified-value', + }); + + expect(plugin.getMetadata()).toEqual({ + key: 'modified-value', + }); + }); +}); From 44f422e2090a106d64f81fa3c44cd8fe18caf7c6 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 10 May 2022 10:39:13 +0200 Subject: [PATCH 07/54] Added a unit test Signed-off-by: bnechyporenko --- .../src/extensions/extensions.test.tsx | 65 ++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/packages/core-plugin-api/src/extensions/extensions.test.tsx b/packages/core-plugin-api/src/extensions/extensions.test.tsx index dcc92d9d47..5cb223cc31 100644 --- a/packages/core-plugin-api/src/extensions/extensions.test.tsx +++ b/packages/core-plugin-api/src/extensions/extensions.test.tsx @@ -19,7 +19,7 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; import { useAnalyticsContext } from '../analytics/AnalyticsContext'; import { useApp, ErrorBoundaryFallbackProps } from '../app'; -import { createPlugin } from '../plugin'; +import { AnyMetadata, createPlugin } from '../plugin'; import { createRouteRef } from '../routing'; import { getComponentData } from './componentData'; import { @@ -36,6 +36,17 @@ const plugin = createPlugin({ id: 'my-plugin', }); +type Props = { + metadata?: AnyMetadata; +}; + +const customPlugin = createPlugin({ + id: 'custom-plugin', + metadata: { + pluginLabel: 'initial label', + }, +}); + describe('extensions', () => { it('should create a react extension with component data', () => { const Component = () =>
; @@ -139,4 +150,56 @@ describe('extensions', () => { expect(result.getByTestId('route-ref')).toHaveTextContent('some-ref'); expect(result.getByTestId('extension')).toHaveTextContent('AnalyticsSpy'); }); + + it('should allow for the plugin to define default labels via metadata', async () => { + const CustomPluginExtension = customPlugin.provide( + createReactExtension({ + name: 'CustomPlugin', + component: { + sync: (props: Props) => { + return ( + <> +
+ {props.metadata?.pluginLabel} +
+ + ); + }, + }, + }), + ); + + const initialComponent = render(); + expect(initialComponent.getByTestId('plugin-label')).toHaveTextContent( + 'initial label', + ); + }); + + it('should allow for the plugin to redefine default labels', async () => { + customPlugin.reconfigure({ + pluginLabel: 'new label', + }); + + const CustomPluginExtension = customPlugin.provide( + createReactExtension({ + name: 'CustomPlugin', + component: { + sync: (props: Props) => { + return ( + <> +
+ {props.metadata?.pluginLabel} +
+ + ); + }, + }, + }), + ); + + const updatedComponent = render(); + expect(updatedComponent.getByTestId('plugin-label')).toHaveTextContent( + 'new label', + ); + }); }); From a79c6f427fef29d3e4c11ca64445f60c4948ad41 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 10 May 2022 11:39:02 +0200 Subject: [PATCH 08/54] Added a documentation how to use it Signed-off-by: bnechyporenko --- docs/plugins/customization.md | 55 +++++++++++++++++++++++++++++++++++ microsite/sidebars.json | 1 + 2 files changed, 56 insertions(+) create mode 100644 docs/plugins/customization.md diff --git a/docs/plugins/customization.md b/docs/plugins/customization.md new file mode 100644 index 0000000000..799cff3480 --- /dev/null +++ b/docs/plugins/customization.md @@ -0,0 +1,55 @@ +--- +id: customization +title: Customization +description: Documentation on adding a customization logic to the plugin +--- + +## Overview + +The Backstage core logic provides a possibility to make the component customizable in such a way that the application +developer can redefine the labels, icons, elements or even completely replace the component. It's up to each plugin +to decide what can be customized. + +## For a plugin developer + +When you are creating your plugin, you have a possibility to use a metadata field and define there all +customizable elements. For example + +```typescript jsx +const plugin = createPlugin({ + id: 'myPlugin', + metadata: { + mainHeaderText: 'Welcome to my plugin', + submitButton: () => , + }, +}); +``` + +And the rendering part of the exposed component can retrieve that metadata as: + +```typescript jsx +export function DefaultMyPluginWelcomePage(props: DefaultMyPluginWelcomeProps) { + const { mainHeaderText, submitButton } = this.props.metadata; + + return ( +
+

{mainHeaderText}

+
{submitButton}
+
+ ); +} +``` + +## For an application developer using the plugin + +The way to reconfigure the default values provided by the plugin you can do it via reconfigure method, defined on the +plugin. Example: + +```typescript jsx +import { myPlugin } from '@backstage/my-plugin'; + +myPlugin.reconfigure({ + mainHeaderText: 'Custom header', + submitButton: () => , +}); +``` diff --git a/microsite/sidebars.json b/microsite/sidebars.json index f96747f0ca..2d55b40a2a 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -198,6 +198,7 @@ "plugins/plugin-development", "plugins/structure-of-a-plugin", "plugins/integrating-plugin-into-software-catalog", + "plugins/customization", "plugins/composability", "plugins/analytics", { From 9a64f4a54a5892626f2f075fd51ec550902b8e54 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 10 May 2022 12:03:29 +0200 Subject: [PATCH 09/54] Updated to use deep merge instead of shallow merge. Signed-off-by: bnechyporenko --- packages/core-plugin-api/package.json | 1 + .../src/extensions/extensions.test.tsx | 11 ++++++++++- packages/core-plugin-api/src/plugin/Plugin.tsx | 3 ++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 03ecdfab74..7c8e7dc1fa 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -37,6 +37,7 @@ "@backstage/types": "^1.0.0", "@backstage/version-bridge": "^1.0.1", "history": "^5.0.0", + "lodash": "^4.17.21", "prop-types": "^15.7.2", "react-router-dom": "6.0.0-beta.0", "zen-observable": "^0.8.15" diff --git a/packages/core-plugin-api/src/extensions/extensions.test.tsx b/packages/core-plugin-api/src/extensions/extensions.test.tsx index 5cb223cc31..28d84cae3e 100644 --- a/packages/core-plugin-api/src/extensions/extensions.test.tsx +++ b/packages/core-plugin-api/src/extensions/extensions.test.tsx @@ -44,6 +44,9 @@ const customPlugin = createPlugin({ id: 'custom-plugin', metadata: { pluginLabel: 'initial label', + table: { + tableHeader: 'table header', + }, }, }); @@ -178,7 +181,7 @@ describe('extensions', () => { it('should allow for the plugin to redefine default labels', async () => { customPlugin.reconfigure({ pluginLabel: 'new label', - }); + } as any); const CustomPluginExtension = customPlugin.provide( createReactExtension({ @@ -189,6 +192,9 @@ describe('extensions', () => { <>
{props.metadata?.pluginLabel} +
+

{props.metadata?.table.tableHeader}

+
); @@ -201,5 +207,8 @@ describe('extensions', () => { expect(updatedComponent.getByTestId('plugin-label')).toHaveTextContent( 'new label', ); + expect( + updatedComponent.getByTestId('plugin-table-summary'), + ).toHaveTextContent('table header'); }); }); diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index 61b8a5db8c..29eacde6ae 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -23,6 +23,7 @@ import { AnyMetadata, PluginFeatureFlagConfig, } from './types'; +import { merge } from 'lodash'; import { AnyApiFactory } from '../apis'; /** @@ -71,7 +72,7 @@ export class PluginImpl< } reconfigure(metadata: PluginMetadata): BackstagePlugin { - this.config.metadata = { ...this.config.metadata, ...metadata }; + this.config.metadata = merge(this.config.metadata, metadata); return this; } From b17260213eb0307aba71b3ce777273c123ce178c Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 10 May 2022 12:05:10 +0200 Subject: [PATCH 10/54] Fixed the typo in fast-walls-carry.md Signed-off-by: bnechyporenko --- .changeset/fast-walls-carry.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.changeset/fast-walls-carry.md b/.changeset/fast-walls-carry.md index dcbe53ff29..edf03a9c60 100644 --- a/.changeset/fast-walls-carry.md +++ b/.changeset/fast-walls-carry.md @@ -2,4 +2,6 @@ '@backstage/core-plugin-api': patch --- -Introduced an optional metadata for the components, which can contain a configurable data. The author of the component might define the cofnigurable places of the component, and the user of this component can reconfigure it if necessary. +Introduced an optional metadata for the components, which can contain a configurable data. +The author of the component might define the configurable places of the component, and the user of this +component can reconfigure it if necessary. From 7294a7ea920a10248412285cbad7303bfb9f9717 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Fri, 13 May 2022 09:10:39 +0200 Subject: [PATCH 11/54] =?UTF-8?q?Based=20on=20feedback=20from=20Gustaf=20R?= =?UTF-8?q?=C3=A4ntil=C3=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: bnechyporenko --- .../core-app-api/src/app/AppManager.test.tsx | 175 ++++++++++++++++++ packages/core-app-api/src/app/AppManager.tsx | 54 ++++-- packages/core-app-api/src/index.ts | 1 + packages/core-app-api/src/metadata/index.ts | 17 ++ .../system/MetadataAggregator.test.ts | 45 +++++ .../src/metadata/system/MetadataAggregator.ts | 39 ++++ .../metadata/system/MetadataProvider.test.tsx | 129 +++++++++++++ .../src/metadata/system/MetadataProvider.tsx | 66 +++++++ .../metadata/system/MetadataRegistry.test.ts | 39 ++++ .../src/metadata/system/MetadataRegistry.ts | 40 ++++ .../core-app-api/src/metadata/system/index.ts | 19 ++ .../src/extensions/extensions.test.tsx | 74 +------- .../src/extensions/extensions.tsx | 2 +- packages/core-plugin-api/src/index.ts | 1 + .../src/metadata/MetadataRef.ts | 50 +++++ .../core-plugin-api/src/metadata/index.ts | 19 ++ .../core-plugin-api/src/metadata/types.ts | 34 ++++ .../src/metadata/useMetadata.tsx | 54 ++++++ .../src/plugin/Plugin.test.tsx | 32 ---- .../core-plugin-api/src/plugin/Plugin.tsx | 15 +- packages/core-plugin-api/src/plugin/types.ts | 8 +- 21 files changed, 781 insertions(+), 132 deletions(-) create mode 100644 packages/core-app-api/src/metadata/index.ts create mode 100644 packages/core-app-api/src/metadata/system/MetadataAggregator.test.ts create mode 100644 packages/core-app-api/src/metadata/system/MetadataAggregator.ts create mode 100644 packages/core-app-api/src/metadata/system/MetadataProvider.test.tsx create mode 100644 packages/core-app-api/src/metadata/system/MetadataProvider.tsx create mode 100644 packages/core-app-api/src/metadata/system/MetadataRegistry.test.ts create mode 100644 packages/core-app-api/src/metadata/system/MetadataRegistry.ts create mode 100644 packages/core-app-api/src/metadata/system/index.ts create mode 100644 packages/core-plugin-api/src/metadata/MetadataRef.ts create mode 100644 packages/core-plugin-api/src/metadata/index.ts create mode 100644 packages/core-plugin-api/src/metadata/types.ts create mode 100644 packages/core-plugin-api/src/metadata/useMetadata.tsx diff --git a/packages/core-app-api/src/app/AppManager.test.tsx b/packages/core-app-api/src/app/AppManager.test.tsx index 467145acfc..1b518ad0a4 100644 --- a/packages/core-app-api/src/app/AppManager.test.tsx +++ b/packages/core-app-api/src/app/AppManager.test.tsx @@ -34,6 +34,8 @@ import { createSubRouteRef, createRoutableExtension, analyticsApiRef, + createMetadataRef, + useMetadata, } from '@backstage/core-plugin-api'; import { AppManager } from './AppManager'; import { AppComponents, AppIcons } from './types'; @@ -165,6 +167,179 @@ describe('Integration Test', () => { const icons = {} as AppIcons; + it('should be possible to define customizable values via metadata', async () => { + type CustomPluginMetadataProps = { + pluginLabel: string; + }; + + const customPluginMetadataRef = + createMetadataRef({ + id: 'custom.plugin.provider', + }); + + const customPluginMetadata = { + [customPluginMetadataRef.id]: { + pluginLabel: 'Default Label', + }, + }; + + const extRouteCustomRef = createExternalRouteRef({ + id: 'extRouteCustomRef', + params: ['x'], + }); + + const customPlugin = createPlugin({ + id: 'custom-plugin', + externalRoutes: { + extRouteCustomRef, + }, + metadata: [customPluginMetadata], + }); + + const customPluginRef = createRouteRef({ id: 'custom-ref', params: ['x'] }); + + const CustomPlugin = () => { + const { pluginLabel } = useMetadata( + customPluginMetadataRef, + ); + + return ( + <> +
{pluginLabel}
+ + ); + }; + + const CustomComponent = customPlugin.provide( + createRoutableExtension({ + name: 'CustomComponent', + component: () => Promise.resolve(() => ), + mountPoint: customPluginRef, + }), + ); + + const app = new AppManager({ + apis: [], + defaultApis: [], + themes: [], + icons, + plugins: [customPlugin], + components, + configLoader: async () => [], + bindRoutes: ({ bind }) => { + bind(customPlugin.externalRoutes, { + extRouteCustomRef: customPluginRef, + }); + }, + }); + + const Provider = app.getProvider(); + const Router = app.getRouter(); + + await renderWithEffects( + + + + } /> + + + , + ); + + expect(await screen.getByText('Default Label')).toBeInTheDocument(); + }); + + it('should be possible to reconfigure customizable values via metadata', async () => { + type CustomPluginMetadataProps = { + pluginLabel: string; + }; + + const customPluginMetadataRef = + createMetadataRef({ + id: 'custom.plugin.provider', + }); + + const customPluginMetadata = { + [customPluginMetadataRef.id]: { + pluginLabel: 'Default Label', + }, + }; + + const extRouteCustomRef = createExternalRouteRef({ + id: 'extRouteCustomRef', + params: ['x'], + }); + + const customPlugin = createPlugin({ + id: 'custom-plugin', + externalRoutes: { + extRouteCustomRef, + }, + metadata: [customPluginMetadata], + }); + + customPlugin.reconfigure({ + [customPluginMetadataRef.id]: { + pluginLabel: 'Custom Label', + }, + }); + + const customPluginRef = createRouteRef({ + id: 'custom-ref-2', + params: ['x'], + }); + + const RedefinedCustom = () => { + const { pluginLabel } = useMetadata( + customPluginMetadataRef, + ); + + return ( + <> +
{pluginLabel}
+ + ); + }; + + const RedefinedCustomPlugin = customPlugin.provide( + createRoutableExtension({ + name: 'RedefinedCustomPlugin', + component: () => Promise.resolve(() => ), + mountPoint: customPluginRef, + }), + ); + + const app = new AppManager({ + apis: [], + defaultApis: [], + themes: [], + icons, + plugins: [customPlugin], + components, + configLoader: async () => [], + bindRoutes: ({ bind }) => { + bind(customPlugin.externalRoutes, { + extRouteCustomRef: customPluginRef, + }); + }, + }); + + const Provider = app.getProvider(); + const Router = app.getRouter(); + + await renderWithEffects( + + + + } /> + + + , + ); + + expect(screen.getByText('Custom Label')).toBeInTheDocument(); + }); + it('runs happy paths', async () => { const app = new AppManager({ apis: [noOpAnalyticsApi], diff --git a/packages/core-app-api/src/app/AppManager.tsx b/packages/core-app-api/src/app/AppManager.tsx index 75bab5c2df..20b8161a8b 100644 --- a/packages/core-app-api/src/app/AppManager.tsx +++ b/packages/core-app-api/src/app/AppManager.tsx @@ -47,6 +47,7 @@ import { IdentityApi, identityApiRef, BackstagePlugin, + MetadataHolder, } from '@backstage/core-plugin-api'; import { ApiFactoryRegistry, ApiResolver } from '../apis/system'; import { @@ -80,6 +81,7 @@ import { defaultConfigLoader } from './defaultConfigLoader'; import { ApiRegistry } from '../apis/system/ApiRegistry'; import { resolveRouteBindings } from './resolveRouteBindings'; import { BackstageRouteObject } from '../routing/types'; +import { MetadataProvider, MetadataRegistry } from '../metadata'; type CompatiblePlugin = | BackstagePlugin @@ -173,6 +175,7 @@ export class AppManager implements BackstageApp { private readonly appIdentityProxy = new AppIdentityProxy(); private readonly apiFactoryRegistry: ApiFactoryRegistry; + private readonly metadataRegistry: MetadataRegistry; constructor(options: AppOptions) { this.apis = options.apis ?? []; @@ -184,6 +187,7 @@ export class AppManager implements BackstageApp { this.defaultApis = options.defaultApis ?? []; this.bindRoutes = options.bindRoutes; this.apiFactoryRegistry = new ApiFactoryRegistry(); + this.metadataRegistry = new MetadataRegistry(); } getPlugins(): BackstagePlugin[] { @@ -298,23 +302,25 @@ export class AppManager implements BackstageApp { return ( - - - - + + + - {children} - - - - + + {children} + + + + + ); }; @@ -395,6 +401,22 @@ export class AppManager implements BackstageApp { return AppRouter; } + private getMetadataHolder(): MetadataHolder { + for (const plugin of this.plugins) { + if (plugin.getMetadata) { + for (const entry of plugin.getMetadata()) { + for (const entryKey in entry) { + if (entry.hasOwnProperty(entryKey)) { + this.metadataRegistry.register(entryKey, entry[entryKey]); + } + } + } + } + } + + return this.metadataRegistry; + } + private getApiHolder(): ApiHolder { if (this.apiHolder) { // Register additional plugins if they have been added. diff --git a/packages/core-app-api/src/index.ts b/packages/core-app-api/src/index.ts index a5e6b649e9..d7b24dbf28 100644 --- a/packages/core-app-api/src/index.ts +++ b/packages/core-app-api/src/index.ts @@ -21,5 +21,6 @@ */ export * from './apis'; +export * from './metadata'; export * from './app'; export * from './routing'; diff --git a/packages/core-app-api/src/metadata/index.ts b/packages/core-app-api/src/metadata/index.ts new file mode 100644 index 0000000000..59aa474fee --- /dev/null +++ b/packages/core-app-api/src/metadata/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './system'; diff --git a/packages/core-app-api/src/metadata/system/MetadataAggregator.test.ts b/packages/core-app-api/src/metadata/system/MetadataAggregator.test.ts new file mode 100644 index 0000000000..ba6aa05c6f --- /dev/null +++ b/packages/core-app-api/src/metadata/system/MetadataAggregator.test.ts @@ -0,0 +1,45 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createMetadataRef } from '@backstage/core-plugin-api'; +import { MetadataAggregator } from './MetadataAggregator'; +import { MetadataRegistry } from './MetadataRegistry'; + +describe('MetadataAggregator', () => { + const apiARef = createMetadataRef({ id: '1' }); + const apiBRef = createMetadataRef({ id: '2' }); + + it('should forward implementations', () => { + const holder1 = new MetadataRegistry(); + holder1.register(apiARef.id, { label: 'label 1' }); + const holder2 = new MetadataRegistry(); + holder2.register(apiBRef.id, { label: 'label 2' }); + + const agg = new MetadataAggregator(holder1, holder2); + expect(agg.get(apiARef)).toEqual({ label: 'label 1' }); + expect(agg.get(apiBRef)).toEqual({ label: 'label 2' }); + }); + + it('should return the first implementation', () => { + const holder1 = new MetadataRegistry(); + holder1.register(apiARef.id, { label: 'label 1' }); + const holder2 = new MetadataRegistry(); + holder2.register(apiARef.id, { label: 'label 2' }); + + const agg = new MetadataAggregator(holder1, holder2); + expect(agg.get(apiARef)).toEqual({ label: 'label 1' }); + }); +}); diff --git a/packages/core-app-api/src/metadata/system/MetadataAggregator.ts b/packages/core-app-api/src/metadata/system/MetadataAggregator.ts new file mode 100644 index 0000000000..ebc26961c1 --- /dev/null +++ b/packages/core-app-api/src/metadata/system/MetadataAggregator.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { MetadataRef, MetadataHolder } from '@backstage/core-plugin-api'; + +/** + * An MetadataHolder that queries multiple other holders from for + * an metadata implementation, returning the first one encountered.. + */ +export class MetadataAggregator implements MetadataHolder { + private readonly holders: MetadataHolder[]; + + constructor(...holders: MetadataHolder[]) { + this.holders = holders; + } + + get(ref: MetadataRef): T | undefined { + for (const holder of this.holders) { + const metadata = holder.get(ref); + if (metadata) { + return metadata; + } + } + return undefined; + } +} diff --git a/packages/core-app-api/src/metadata/system/MetadataProvider.test.tsx b/packages/core-app-api/src/metadata/system/MetadataProvider.test.tsx new file mode 100644 index 0000000000..dfbd96eb31 --- /dev/null +++ b/packages/core-app-api/src/metadata/system/MetadataProvider.test.tsx @@ -0,0 +1,129 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { + useMetadata, + createMetadataRef, + MetadataRef, + MetadataHolder, +} from '@backstage/core-plugin-api'; +import { MetadataProvider } from './MetadataProvider'; +import { MetadataRegistry } from './MetadataRegistry'; +import { render } from '@testing-library/react'; +import { withLogCollector } from '@backstage/test-utils'; +import { useVersionedContext } from '@backstage/version-bridge'; + +describe('MetadataProvider', () => { + type Metadata = () => string; + const metadataRef = createMetadataRef({ id: 'x' }); + + const MyHookConsumer = () => { + const payload = useMetadata(metadataRef); + return

hook message: {payload}

; + }; + + it('should provide apis', () => { + const renderedHook = render( + + + , + ); + renderedHook.getByText('hook message: hello'); + }); + + it('should provide nested access to apis', () => { + const aRef = createMetadataRef({ id: 'a' }); + const bRef = createMetadataRef({ id: 'b' }); + + const MyComponent = () => { + const a = useMetadata(aRef); + const b = useMetadata(bRef); + return ( +
+ a={a} b={b} +
+ ); + }; + + const renderedHook = render( + + + + + , + ); + renderedHook.getByText('a=z b=y'); + }); + + it('should error if metadata is not available', () => { + expect( + withLogCollector(['error'], () => { + expect(() => { + render( + + + , + ); + }).toThrow('No implementation available for metadataRef{x}'); + }).error, + ).toEqual([ + expect.stringMatching( + /^Error: Uncaught \[Error: No implementation available for metadataRef{x}\]/, + ), + expect.stringMatching( + /^The above error occurred in the component/, + ), + ]); + }); +}); + +describe('v1 consumer', () => { + function useMockApiV1(apiRef: MetadataRef): T { + const impl = useVersionedContext<{ 1: MetadataHolder }>('metadata-context') + ?.atVersion(1) + ?.get(apiRef); + if (!impl) { + throw new Error('no impl'); + } + return impl; + } + + type Api = () => string; + const apiRef = createMetadataRef({ id: 'x' }); + const registry = MetadataRegistry.from([[apiRef, () => 'hello']]); + + const MyHookConsumerV1 = () => { + const api = useMockApiV1(apiRef); + return

hook message: {api()}

; + }; + + it('should provide apis', () => { + const renderedHook = render( + + + , + ); + renderedHook.getByText('hook message: hello'); + }); +}); diff --git a/packages/core-app-api/src/metadata/system/MetadataProvider.tsx b/packages/core-app-api/src/metadata/system/MetadataProvider.tsx new file mode 100644 index 0000000000..a072f0a84a --- /dev/null +++ b/packages/core-app-api/src/metadata/system/MetadataProvider.tsx @@ -0,0 +1,66 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { useContext, ReactNode, PropsWithChildren } from 'react'; +import PropTypes from 'prop-types'; +import { MetadataHolder } from '@backstage/core-plugin-api'; +import { + createVersionedValueMap, + createVersionedContext, +} from '@backstage/version-bridge'; +import { MetadataAggregator } from './MetadataAggregator'; + +/** + * Prop types for the MetadataProvider component. + * + * @public + */ +export type MetadataProviderProps = { + metadata: MetadataHolder; + children: ReactNode; +}; + +const MetadataContext = createVersionedContext<{ 1: MetadataHolder }>( + 'metadata-context', +); + +/** + * Provides an {@link @backstage/core-plugin-api#MetadataHolder} for consumption in + * the React tree. + * + * @public + */ +export const MetadataProvider = ( + props: PropsWithChildren, +) => { + const { children, metadata } = props; + const parentHolder = useContext(MetadataContext)?.atVersion(1); + const holder = parentHolder + ? new MetadataAggregator(metadata, parentHolder) + : metadata; + + return ( + + ); +}; + +MetadataProvider.propTypes = { + metadata: PropTypes.shape({ get: PropTypes.func.isRequired }).isRequired, + children: PropTypes.node, +}; diff --git a/packages/core-app-api/src/metadata/system/MetadataRegistry.test.ts b/packages/core-app-api/src/metadata/system/MetadataRegistry.test.ts new file mode 100644 index 0000000000..4acac8565a --- /dev/null +++ b/packages/core-app-api/src/metadata/system/MetadataRegistry.test.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createMetadataRef } from '@backstage/core-plugin-api'; +import { MetadataRegistry } from './MetadataRegistry'; + +describe('MetadataRegistry', () => { + const x1Ref = createMetadataRef({ id: 'x1' }); + const x1DuplicateRef = createMetadataRef({ id: 'x1' }); + const x2Ref = createMetadataRef({ id: 'x2' }); + + it('should be created', () => { + const registry = MetadataRegistry.from([]); + expect(registry.get(x1Ref)).toBe(undefined); + }); + + it('should be created with metadata', () => { + const registry = MetadataRegistry.from([ + [x1Ref, 3], + [x2Ref, 'y'], + ]); + expect(registry.get(x1Ref)).toBe(3); + expect(registry.get(x1DuplicateRef)).toBe(3); + expect(registry.get(x2Ref)).toBe('y'); + }); +}); diff --git a/packages/core-app-api/src/metadata/system/MetadataRegistry.ts b/packages/core-app-api/src/metadata/system/MetadataRegistry.ts new file mode 100644 index 0000000000..053a52b5f6 --- /dev/null +++ b/packages/core-app-api/src/metadata/system/MetadataRegistry.ts @@ -0,0 +1,40 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { MetadataRef, MetadataHolder } from '@backstage/core-plugin-api'; + +type MetadataImpl = readonly [MetadataRef, T]; + +export class MetadataRegistry implements MetadataHolder { + private readonly registry = new Map(); + + register(id: string, payload: any): boolean { + this.registry.set(id, payload); + return true; + } + + get(ref: MetadataRef): T | undefined { + return this.registry.get(ref.id); + } + + static from(entries: MetadataImpl[]) { + const registry = new MetadataRegistry(); + for (const entry of entries) { + registry.register(entry[0].id, entry[1]); + } + return registry; + } +} diff --git a/packages/core-app-api/src/metadata/system/index.ts b/packages/core-app-api/src/metadata/system/index.ts new file mode 100644 index 0000000000..faa7c814c8 --- /dev/null +++ b/packages/core-app-api/src/metadata/system/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { MetadataRegistry } from './MetadataRegistry'; +export { MetadataProvider } from './MetadataProvider'; +export { MetadataAggregator } from './MetadataAggregator'; diff --git a/packages/core-plugin-api/src/extensions/extensions.test.tsx b/packages/core-plugin-api/src/extensions/extensions.test.tsx index 28d84cae3e..dcc92d9d47 100644 --- a/packages/core-plugin-api/src/extensions/extensions.test.tsx +++ b/packages/core-plugin-api/src/extensions/extensions.test.tsx @@ -19,7 +19,7 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; import { useAnalyticsContext } from '../analytics/AnalyticsContext'; import { useApp, ErrorBoundaryFallbackProps } from '../app'; -import { AnyMetadata, createPlugin } from '../plugin'; +import { createPlugin } from '../plugin'; import { createRouteRef } from '../routing'; import { getComponentData } from './componentData'; import { @@ -36,20 +36,6 @@ const plugin = createPlugin({ id: 'my-plugin', }); -type Props = { - metadata?: AnyMetadata; -}; - -const customPlugin = createPlugin({ - id: 'custom-plugin', - metadata: { - pluginLabel: 'initial label', - table: { - tableHeader: 'table header', - }, - }, -}); - describe('extensions', () => { it('should create a react extension with component data', () => { const Component = () =>
; @@ -153,62 +139,4 @@ describe('extensions', () => { expect(result.getByTestId('route-ref')).toHaveTextContent('some-ref'); expect(result.getByTestId('extension')).toHaveTextContent('AnalyticsSpy'); }); - - it('should allow for the plugin to define default labels via metadata', async () => { - const CustomPluginExtension = customPlugin.provide( - createReactExtension({ - name: 'CustomPlugin', - component: { - sync: (props: Props) => { - return ( - <> -
- {props.metadata?.pluginLabel} -
- - ); - }, - }, - }), - ); - - const initialComponent = render(); - expect(initialComponent.getByTestId('plugin-label')).toHaveTextContent( - 'initial label', - ); - }); - - it('should allow for the plugin to redefine default labels', async () => { - customPlugin.reconfigure({ - pluginLabel: 'new label', - } as any); - - const CustomPluginExtension = customPlugin.provide( - createReactExtension({ - name: 'CustomPlugin', - component: { - sync: (props: Props) => { - return ( - <> -
- {props.metadata?.pluginLabel} -
-

{props.metadata?.table.tableHeader}

-
-
- - ); - }, - }, - }), - ); - - const updatedComponent = render(); - expect(updatedComponent.getByTestId('plugin-label')).toHaveTextContent( - 'new label', - ); - expect( - updatedComponent.getByTestId('plugin-table-summary'), - ).toHaveTextContent('table header'); - }); }); diff --git a/packages/core-plugin-api/src/extensions/extensions.tsx b/packages/core-plugin-api/src/extensions/extensions.tsx index 8f1efe3b65..19da082ee1 100644 --- a/packages/core-plugin-api/src/extensions/extensions.tsx +++ b/packages/core-plugin-api/src/extensions/extensions.tsx @@ -245,7 +245,7 @@ export function createReactExtension< ...(mountPoint && { routeRef: mountPoint.id }), }} > - + diff --git a/packages/core-plugin-api/src/index.ts b/packages/core-plugin-api/src/index.ts index 30fc35b62a..172f00295b 100644 --- a/packages/core-plugin-api/src/index.ts +++ b/packages/core-plugin-api/src/index.ts @@ -22,6 +22,7 @@ export * from './analytics'; export * from './apis'; +export * from './metadata'; export * from './app'; export * from './extensions'; export * from './icons'; diff --git a/packages/core-plugin-api/src/metadata/MetadataRef.ts b/packages/core-plugin-api/src/metadata/MetadataRef.ts new file mode 100644 index 0000000000..f261fb5352 --- /dev/null +++ b/packages/core-plugin-api/src/metadata/MetadataRef.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { MetadataRef } from './types'; + +export type MetadataRefConfig = { + id: string; +}; + +class MetadataRefImpl implements MetadataRef { + constructor(private readonly config: MetadataRefConfig) {} + + get id(): string { + return this.config.id; + } + + get T(): T { + throw new Error(`tried to read MetadataRef.T of ${this}`); + } + + toString() { + return `metadataRef{${this.config.id}}`; + } +} + +/** + * Creates a reference to a metadata. + * + * @param config - The descriptor of the metadata to reference. + * @returns A metadata reference. + * @public + */ +export function createMetadataRef( + config: MetadataRefConfig, +): MetadataRef { + return new MetadataRefImpl(config); +} diff --git a/packages/core-plugin-api/src/metadata/index.ts b/packages/core-plugin-api/src/metadata/index.ts new file mode 100644 index 0000000000..29d5532edd --- /dev/null +++ b/packages/core-plugin-api/src/metadata/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { useMetadata, useMetadataHolder } from './useMetadata'; +export { createMetadataRef } from './MetadataRef'; +export * from './types'; diff --git a/packages/core-plugin-api/src/metadata/types.ts b/packages/core-plugin-api/src/metadata/types.ts new file mode 100644 index 0000000000..5b721b5b55 --- /dev/null +++ b/packages/core-plugin-api/src/metadata/types.ts @@ -0,0 +1,34 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Metadata reference. + * + * @public + */ +export type MetadataRef = { + id: string; + T: T; +}; + +/** + * Provides lookup of metadata through their {@link MetadataRef}s. + * + * @public + */ +export type MetadataHolder = { + get(key: MetadataRef): T | undefined; +}; diff --git a/packages/core-plugin-api/src/metadata/useMetadata.tsx b/packages/core-plugin-api/src/metadata/useMetadata.tsx new file mode 100644 index 0000000000..99ce68f1e4 --- /dev/null +++ b/packages/core-plugin-api/src/metadata/useMetadata.tsx @@ -0,0 +1,54 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { MetadataHolder, MetadataRef } from './types'; +import { useVersionedContext } from '@backstage/version-bridge'; + +/** + * React hook for retrieving {@link MetadataHolder} + * + * @public + */ +export function useMetadataHolder(): MetadataHolder { + const versionedHolder = useVersionedContext<{ 1: MetadataHolder }>( + 'metadata-context', + ); + if (!versionedHolder) { + throw new Error('Metadata context is not available'); + } + + const metadataHolder = versionedHolder.atVersion(1); + if (!metadataHolder) { + throw new Error('Metadata context v1 not available'); + } + return metadataHolder; +} + +/** + * React hook for retrieving metadata. + * + * @param metadataRef - Reference of the metadata to use. + * @public + */ +export function useMetadata(metadataRef: MetadataRef): T { + const metadataHolder = useMetadataHolder(); + + const metadata = metadataHolder.get(metadataRef); + if (!metadata) { + throw new Error(`No implementation available for ${metadataRef}`); + } + return metadata; +} diff --git a/packages/core-plugin-api/src/plugin/Plugin.test.tsx b/packages/core-plugin-api/src/plugin/Plugin.test.tsx index 26c704517f..b66235e210 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.test.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.test.tsx @@ -32,35 +32,3 @@ describe('Plugin Feature Flag', () => { ).toEqual([]); }); }); - -describe('Plugin metadata', () => { - it('should be able to define metadata', () => { - expect( - createPlugin({ - id: 'test', - metadata: { - key: 'value', - }, - }).getMetadata(), - ).toEqual({ - key: 'value', - }); - }); - - it('should be able to reconfigure metadata', () => { - const plugin = createPlugin({ - id: 'test', - metadata: { - key: 'original-value', - }, - }); - - plugin.reconfigure({ - key: 'modified-value', - }); - - expect(plugin.getMetadata()).toEqual({ - key: 'modified-value', - }); - }); -}); diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index 29eacde6ae..999d154166 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -23,7 +23,6 @@ import { AnyMetadata, PluginFeatureFlagConfig, } from './types'; -import { merge } from 'lodash'; import { AnyApiFactory } from '../apis'; /** @@ -43,6 +42,8 @@ export class PluginImpl< >, ) {} + private reconfiguredMetadata: Array = []; + getId(): string { return this.config.id; } @@ -55,8 +56,11 @@ export class PluginImpl< return this.config.featureFlags?.slice() ?? []; } - getMetadata(): PluginMetadata { - return this.config.metadata ?? ({} as PluginMetadata); + getMetadata(): Iterable { + return [ + ...Array.from(this.config.metadata ?? []), + ...this.reconfiguredMetadata, + ]; } get routes(): Routes { @@ -71,9 +75,8 @@ export class PluginImpl< return extension.expose(this); } - reconfigure(metadata: PluginMetadata): BackstagePlugin { - this.config.metadata = merge(this.config.metadata, metadata); - return this; + reconfigure(metadata: PluginMetadata): void { + this.reconfiguredMetadata.push(metadata); } toString() { diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index a640013c47..8aadac36bc 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -59,7 +59,7 @@ export type AnyMetadata = { [name: string]: any }; export type BackstagePlugin< Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, - PluginMetadata extends AnyMetadata = {}, + PluginMetadata extends AnyMetadata = { [name: string]: any }, > = { getId(): string; getApis(): Iterable; @@ -67,9 +67,9 @@ export type BackstagePlugin< * Returns all registered feature flags for this plugin. */ getFeatureFlags(): Iterable; - getMetadata(): PluginMetadata; + getMetadata(): Iterable; provide(extension: Extension): T; - reconfigure(metadata: PluginMetadata): BackstagePlugin; + reconfigure(metadata: PluginMetadata): void; routes: Routes; externalRoutes: ExternalRoutes; }; @@ -99,7 +99,7 @@ export type PluginConfig< routes?: Routes; externalRoutes?: ExternalRoutes; featureFlags?: PluginFeatureFlagConfig[]; - metadata?: PluginMetadata; + metadata?: Iterable; }; /** From 0a3f105bb459d23afac719b739a18eca063fd637 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Fri, 13 May 2022 09:19:23 +0200 Subject: [PATCH 12/54] Updated a doc reflected the changes Signed-off-by: bnechyporenko --- docs/plugins/customization.md | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/docs/plugins/customization.md b/docs/plugins/customization.md index 799cff3480..88d7d4bad6 100644 --- a/docs/plugins/customization.md +++ b/docs/plugins/customization.md @@ -16,12 +16,24 @@ When you are creating your plugin, you have a possibility to use a metadata fiel customizable elements. For example ```typescript jsx +export type MyPluginMetadataProps = { + createButtonTitle: string; +}; + +export const myPluginMetadataRef = createMetadataRef({ + id: 'MyPluginMetadataProvider', +}); + +export const myPluginMetadata = { + MyPluginMetadataProvider: { + // or [myPluginMetadataRef.id] + createButtonTitle: 'Create Component', + }, +}; + const plugin = createPlugin({ id: 'myPlugin', - metadata: { - mainHeaderText: 'Welcome to my plugin', - submitButton: () => , - }, + metadata: [myPluginMetadata], }); ``` @@ -29,12 +41,12 @@ And the rendering part of the exposed component can retrieve that metadata as: ```typescript jsx export function DefaultMyPluginWelcomePage(props: DefaultMyPluginWelcomeProps) { - const { mainHeaderText, submitButton } = this.props.metadata; + const { createButtonTitle } = + useMetadata(myPluginMetadataRef); return (
-

{mainHeaderText}

-
{submitButton}
+
); } @@ -49,7 +61,9 @@ plugin. Example: import { myPlugin } from '@backstage/my-plugin'; myPlugin.reconfigure({ - mainHeaderText: 'Custom header', - submitButton: () => , + MyPluginMetadataProvider: { + // or [myPluginMetadataRef.id] + createButtonTitle: 'Make Component', + }, }); ``` From 1e6c6bd627393bb3b0403174d6730fb7a9cd2216 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Fri, 13 May 2022 09:31:58 +0200 Subject: [PATCH 13/54] Removed lodash from dependencies in core-plugin-api, as it is not used anymore Signed-off-by: bnechyporenko --- packages/core-plugin-api/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 7c8e7dc1fa..03ecdfab74 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -37,7 +37,6 @@ "@backstage/types": "^1.0.0", "@backstage/version-bridge": "^1.0.1", "history": "^5.0.0", - "lodash": "^4.17.21", "prop-types": "^15.7.2", "react-router-dom": "6.0.0-beta.0", "zen-observable": "^0.8.15" From 08d2b2a0319cee953b9b1208d62c7d0fa49eeaec Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Fri, 20 May 2022 16:05:13 +0200 Subject: [PATCH 14/54] WIP changes, still have to be implemented `pluginOptions`, as default values are not stored anywhere yet, only `reconfigure` defines it. Docs and tests have to be updated too Signed-off-by: bnechyporenko --- packages/app/src/App.tsx | 5 + .../core-app-api/src/app/AppManager.test.tsx | 175 ------------------ packages/core-app-api/src/app/AppManager.tsx | 54 ++---- packages/core-app-api/src/index.ts | 1 - .../system/MetadataAggregator.test.ts | 45 ----- .../src/metadata/system/MetadataAggregator.ts | 39 ---- .../metadata/system/MetadataProvider.test.tsx | 129 ------------- .../src/metadata/system/MetadataProvider.tsx | 66 ------- .../metadata/system/MetadataRegistry.test.ts | 39 ---- .../src/metadata/system/MetadataRegistry.ts | 40 ---- .../core-app-api/src/metadata/system/index.ts | 19 -- packages/core-plugin-api/package.json | 1 + .../src/extensions/extensions.tsx | 12 +- packages/core-plugin-api/src/index.ts | 2 +- .../src/metadata/MetadataRef.ts | 50 ----- .../core-plugin-api/src/metadata/index.ts | 19 -- .../core-plugin-api/src/metadata/types.ts | 34 ---- .../src/metadata/useMetadata.tsx | 54 ------ .../src/plugin-options}/index.ts | 2 +- .../src/plugin-options/usePluginOptions.tsx | 75 ++++++++ .../core-plugin-api/src/plugin/Plugin.tsx | 31 ++-- packages/core-plugin-api/src/plugin/index.ts | 2 +- packages/core-plugin-api/src/plugin/types.ts | 20 +- .../CatalogPage/DefaultCatalogPage.tsx | 15 +- plugins/catalog/src/plugin.ts | 5 + 25 files changed, 156 insertions(+), 778 deletions(-) delete mode 100644 packages/core-app-api/src/metadata/system/MetadataAggregator.test.ts delete mode 100644 packages/core-app-api/src/metadata/system/MetadataAggregator.ts delete mode 100644 packages/core-app-api/src/metadata/system/MetadataProvider.test.tsx delete mode 100644 packages/core-app-api/src/metadata/system/MetadataProvider.tsx delete mode 100644 packages/core-app-api/src/metadata/system/MetadataRegistry.test.ts delete mode 100644 packages/core-app-api/src/metadata/system/MetadataRegistry.ts delete mode 100644 packages/core-app-api/src/metadata/system/index.ts delete mode 100644 packages/core-plugin-api/src/metadata/MetadataRef.ts delete mode 100644 packages/core-plugin-api/src/metadata/index.ts delete mode 100644 packages/core-plugin-api/src/metadata/types.ts delete mode 100644 packages/core-plugin-api/src/metadata/useMetadata.tsx rename packages/{core-app-api/src/metadata => core-plugin-api/src/plugin-options}/index.ts (88%) create mode 100644 packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 35c61f2f16..aa3cafc2c9 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -138,6 +138,11 @@ const app = createApp({ const AppProvider = app.getProvider(); const AppRouter = app.getRouter(); +catalogPlugin.reconfigure({ + // TODO: remove it, only for testing here + createButtonTitle: 'Maybe Create Component', +}); + const routes = ( diff --git a/packages/core-app-api/src/app/AppManager.test.tsx b/packages/core-app-api/src/app/AppManager.test.tsx index 1b518ad0a4..467145acfc 100644 --- a/packages/core-app-api/src/app/AppManager.test.tsx +++ b/packages/core-app-api/src/app/AppManager.test.tsx @@ -34,8 +34,6 @@ import { createSubRouteRef, createRoutableExtension, analyticsApiRef, - createMetadataRef, - useMetadata, } from '@backstage/core-plugin-api'; import { AppManager } from './AppManager'; import { AppComponents, AppIcons } from './types'; @@ -167,179 +165,6 @@ describe('Integration Test', () => { const icons = {} as AppIcons; - it('should be possible to define customizable values via metadata', async () => { - type CustomPluginMetadataProps = { - pluginLabel: string; - }; - - const customPluginMetadataRef = - createMetadataRef({ - id: 'custom.plugin.provider', - }); - - const customPluginMetadata = { - [customPluginMetadataRef.id]: { - pluginLabel: 'Default Label', - }, - }; - - const extRouteCustomRef = createExternalRouteRef({ - id: 'extRouteCustomRef', - params: ['x'], - }); - - const customPlugin = createPlugin({ - id: 'custom-plugin', - externalRoutes: { - extRouteCustomRef, - }, - metadata: [customPluginMetadata], - }); - - const customPluginRef = createRouteRef({ id: 'custom-ref', params: ['x'] }); - - const CustomPlugin = () => { - const { pluginLabel } = useMetadata( - customPluginMetadataRef, - ); - - return ( - <> -
{pluginLabel}
- - ); - }; - - const CustomComponent = customPlugin.provide( - createRoutableExtension({ - name: 'CustomComponent', - component: () => Promise.resolve(() => ), - mountPoint: customPluginRef, - }), - ); - - const app = new AppManager({ - apis: [], - defaultApis: [], - themes: [], - icons, - plugins: [customPlugin], - components, - configLoader: async () => [], - bindRoutes: ({ bind }) => { - bind(customPlugin.externalRoutes, { - extRouteCustomRef: customPluginRef, - }); - }, - }); - - const Provider = app.getProvider(); - const Router = app.getRouter(); - - await renderWithEffects( - - - - } /> - - - , - ); - - expect(await screen.getByText('Default Label')).toBeInTheDocument(); - }); - - it('should be possible to reconfigure customizable values via metadata', async () => { - type CustomPluginMetadataProps = { - pluginLabel: string; - }; - - const customPluginMetadataRef = - createMetadataRef({ - id: 'custom.plugin.provider', - }); - - const customPluginMetadata = { - [customPluginMetadataRef.id]: { - pluginLabel: 'Default Label', - }, - }; - - const extRouteCustomRef = createExternalRouteRef({ - id: 'extRouteCustomRef', - params: ['x'], - }); - - const customPlugin = createPlugin({ - id: 'custom-plugin', - externalRoutes: { - extRouteCustomRef, - }, - metadata: [customPluginMetadata], - }); - - customPlugin.reconfigure({ - [customPluginMetadataRef.id]: { - pluginLabel: 'Custom Label', - }, - }); - - const customPluginRef = createRouteRef({ - id: 'custom-ref-2', - params: ['x'], - }); - - const RedefinedCustom = () => { - const { pluginLabel } = useMetadata( - customPluginMetadataRef, - ); - - return ( - <> -
{pluginLabel}
- - ); - }; - - const RedefinedCustomPlugin = customPlugin.provide( - createRoutableExtension({ - name: 'RedefinedCustomPlugin', - component: () => Promise.resolve(() => ), - mountPoint: customPluginRef, - }), - ); - - const app = new AppManager({ - apis: [], - defaultApis: [], - themes: [], - icons, - plugins: [customPlugin], - components, - configLoader: async () => [], - bindRoutes: ({ bind }) => { - bind(customPlugin.externalRoutes, { - extRouteCustomRef: customPluginRef, - }); - }, - }); - - const Provider = app.getProvider(); - const Router = app.getRouter(); - - await renderWithEffects( - - - - } /> - - - , - ); - - expect(screen.getByText('Custom Label')).toBeInTheDocument(); - }); - it('runs happy paths', async () => { const app = new AppManager({ apis: [noOpAnalyticsApi], diff --git a/packages/core-app-api/src/app/AppManager.tsx b/packages/core-app-api/src/app/AppManager.tsx index 20b8161a8b..75bab5c2df 100644 --- a/packages/core-app-api/src/app/AppManager.tsx +++ b/packages/core-app-api/src/app/AppManager.tsx @@ -47,7 +47,6 @@ import { IdentityApi, identityApiRef, BackstagePlugin, - MetadataHolder, } from '@backstage/core-plugin-api'; import { ApiFactoryRegistry, ApiResolver } from '../apis/system'; import { @@ -81,7 +80,6 @@ import { defaultConfigLoader } from './defaultConfigLoader'; import { ApiRegistry } from '../apis/system/ApiRegistry'; import { resolveRouteBindings } from './resolveRouteBindings'; import { BackstageRouteObject } from '../routing/types'; -import { MetadataProvider, MetadataRegistry } from '../metadata'; type CompatiblePlugin = | BackstagePlugin @@ -175,7 +173,6 @@ export class AppManager implements BackstageApp { private readonly appIdentityProxy = new AppIdentityProxy(); private readonly apiFactoryRegistry: ApiFactoryRegistry; - private readonly metadataRegistry: MetadataRegistry; constructor(options: AppOptions) { this.apis = options.apis ?? []; @@ -187,7 +184,6 @@ export class AppManager implements BackstageApp { this.defaultApis = options.defaultApis ?? []; this.bindRoutes = options.bindRoutes; this.apiFactoryRegistry = new ApiFactoryRegistry(); - this.metadataRegistry = new MetadataRegistry(); } getPlugins(): BackstagePlugin[] { @@ -302,25 +298,23 @@ export class AppManager implements BackstageApp { return ( - - - - + + + - - {children} - - - - - + {children} + + + + ); }; @@ -401,22 +395,6 @@ export class AppManager implements BackstageApp { return AppRouter; } - private getMetadataHolder(): MetadataHolder { - for (const plugin of this.plugins) { - if (plugin.getMetadata) { - for (const entry of plugin.getMetadata()) { - for (const entryKey in entry) { - if (entry.hasOwnProperty(entryKey)) { - this.metadataRegistry.register(entryKey, entry[entryKey]); - } - } - } - } - } - - return this.metadataRegistry; - } - private getApiHolder(): ApiHolder { if (this.apiHolder) { // Register additional plugins if they have been added. diff --git a/packages/core-app-api/src/index.ts b/packages/core-app-api/src/index.ts index d7b24dbf28..a5e6b649e9 100644 --- a/packages/core-app-api/src/index.ts +++ b/packages/core-app-api/src/index.ts @@ -21,6 +21,5 @@ */ export * from './apis'; -export * from './metadata'; export * from './app'; export * from './routing'; diff --git a/packages/core-app-api/src/metadata/system/MetadataAggregator.test.ts b/packages/core-app-api/src/metadata/system/MetadataAggregator.test.ts deleted file mode 100644 index ba6aa05c6f..0000000000 --- a/packages/core-app-api/src/metadata/system/MetadataAggregator.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { createMetadataRef } from '@backstage/core-plugin-api'; -import { MetadataAggregator } from './MetadataAggregator'; -import { MetadataRegistry } from './MetadataRegistry'; - -describe('MetadataAggregator', () => { - const apiARef = createMetadataRef({ id: '1' }); - const apiBRef = createMetadataRef({ id: '2' }); - - it('should forward implementations', () => { - const holder1 = new MetadataRegistry(); - holder1.register(apiARef.id, { label: 'label 1' }); - const holder2 = new MetadataRegistry(); - holder2.register(apiBRef.id, { label: 'label 2' }); - - const agg = new MetadataAggregator(holder1, holder2); - expect(agg.get(apiARef)).toEqual({ label: 'label 1' }); - expect(agg.get(apiBRef)).toEqual({ label: 'label 2' }); - }); - - it('should return the first implementation', () => { - const holder1 = new MetadataRegistry(); - holder1.register(apiARef.id, { label: 'label 1' }); - const holder2 = new MetadataRegistry(); - holder2.register(apiARef.id, { label: 'label 2' }); - - const agg = new MetadataAggregator(holder1, holder2); - expect(agg.get(apiARef)).toEqual({ label: 'label 1' }); - }); -}); diff --git a/packages/core-app-api/src/metadata/system/MetadataAggregator.ts b/packages/core-app-api/src/metadata/system/MetadataAggregator.ts deleted file mode 100644 index ebc26961c1..0000000000 --- a/packages/core-app-api/src/metadata/system/MetadataAggregator.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { MetadataRef, MetadataHolder } from '@backstage/core-plugin-api'; - -/** - * An MetadataHolder that queries multiple other holders from for - * an metadata implementation, returning the first one encountered.. - */ -export class MetadataAggregator implements MetadataHolder { - private readonly holders: MetadataHolder[]; - - constructor(...holders: MetadataHolder[]) { - this.holders = holders; - } - - get(ref: MetadataRef): T | undefined { - for (const holder of this.holders) { - const metadata = holder.get(ref); - if (metadata) { - return metadata; - } - } - return undefined; - } -} diff --git a/packages/core-app-api/src/metadata/system/MetadataProvider.test.tsx b/packages/core-app-api/src/metadata/system/MetadataProvider.test.tsx deleted file mode 100644 index dfbd96eb31..0000000000 --- a/packages/core-app-api/src/metadata/system/MetadataProvider.test.tsx +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React from 'react'; -import { - useMetadata, - createMetadataRef, - MetadataRef, - MetadataHolder, -} from '@backstage/core-plugin-api'; -import { MetadataProvider } from './MetadataProvider'; -import { MetadataRegistry } from './MetadataRegistry'; -import { render } from '@testing-library/react'; -import { withLogCollector } from '@backstage/test-utils'; -import { useVersionedContext } from '@backstage/version-bridge'; - -describe('MetadataProvider', () => { - type Metadata = () => string; - const metadataRef = createMetadataRef({ id: 'x' }); - - const MyHookConsumer = () => { - const payload = useMetadata(metadataRef); - return

hook message: {payload}

; - }; - - it('should provide apis', () => { - const renderedHook = render( - - - , - ); - renderedHook.getByText('hook message: hello'); - }); - - it('should provide nested access to apis', () => { - const aRef = createMetadataRef({ id: 'a' }); - const bRef = createMetadataRef({ id: 'b' }); - - const MyComponent = () => { - const a = useMetadata(aRef); - const b = useMetadata(bRef); - return ( -
- a={a} b={b} -
- ); - }; - - const renderedHook = render( - - - - - , - ); - renderedHook.getByText('a=z b=y'); - }); - - it('should error if metadata is not available', () => { - expect( - withLogCollector(['error'], () => { - expect(() => { - render( - - - , - ); - }).toThrow('No implementation available for metadataRef{x}'); - }).error, - ).toEqual([ - expect.stringMatching( - /^Error: Uncaught \[Error: No implementation available for metadataRef{x}\]/, - ), - expect.stringMatching( - /^The above error occurred in the component/, - ), - ]); - }); -}); - -describe('v1 consumer', () => { - function useMockApiV1(apiRef: MetadataRef): T { - const impl = useVersionedContext<{ 1: MetadataHolder }>('metadata-context') - ?.atVersion(1) - ?.get(apiRef); - if (!impl) { - throw new Error('no impl'); - } - return impl; - } - - type Api = () => string; - const apiRef = createMetadataRef({ id: 'x' }); - const registry = MetadataRegistry.from([[apiRef, () => 'hello']]); - - const MyHookConsumerV1 = () => { - const api = useMockApiV1(apiRef); - return

hook message: {api()}

; - }; - - it('should provide apis', () => { - const renderedHook = render( - - - , - ); - renderedHook.getByText('hook message: hello'); - }); -}); diff --git a/packages/core-app-api/src/metadata/system/MetadataProvider.tsx b/packages/core-app-api/src/metadata/system/MetadataProvider.tsx deleted file mode 100644 index a072f0a84a..0000000000 --- a/packages/core-app-api/src/metadata/system/MetadataProvider.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React, { useContext, ReactNode, PropsWithChildren } from 'react'; -import PropTypes from 'prop-types'; -import { MetadataHolder } from '@backstage/core-plugin-api'; -import { - createVersionedValueMap, - createVersionedContext, -} from '@backstage/version-bridge'; -import { MetadataAggregator } from './MetadataAggregator'; - -/** - * Prop types for the MetadataProvider component. - * - * @public - */ -export type MetadataProviderProps = { - metadata: MetadataHolder; - children: ReactNode; -}; - -const MetadataContext = createVersionedContext<{ 1: MetadataHolder }>( - 'metadata-context', -); - -/** - * Provides an {@link @backstage/core-plugin-api#MetadataHolder} for consumption in - * the React tree. - * - * @public - */ -export const MetadataProvider = ( - props: PropsWithChildren, -) => { - const { children, metadata } = props; - const parentHolder = useContext(MetadataContext)?.atVersion(1); - const holder = parentHolder - ? new MetadataAggregator(metadata, parentHolder) - : metadata; - - return ( - - ); -}; - -MetadataProvider.propTypes = { - metadata: PropTypes.shape({ get: PropTypes.func.isRequired }).isRequired, - children: PropTypes.node, -}; diff --git a/packages/core-app-api/src/metadata/system/MetadataRegistry.test.ts b/packages/core-app-api/src/metadata/system/MetadataRegistry.test.ts deleted file mode 100644 index 4acac8565a..0000000000 --- a/packages/core-app-api/src/metadata/system/MetadataRegistry.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { createMetadataRef } from '@backstage/core-plugin-api'; -import { MetadataRegistry } from './MetadataRegistry'; - -describe('MetadataRegistry', () => { - const x1Ref = createMetadataRef({ id: 'x1' }); - const x1DuplicateRef = createMetadataRef({ id: 'x1' }); - const x2Ref = createMetadataRef({ id: 'x2' }); - - it('should be created', () => { - const registry = MetadataRegistry.from([]); - expect(registry.get(x1Ref)).toBe(undefined); - }); - - it('should be created with metadata', () => { - const registry = MetadataRegistry.from([ - [x1Ref, 3], - [x2Ref, 'y'], - ]); - expect(registry.get(x1Ref)).toBe(3); - expect(registry.get(x1DuplicateRef)).toBe(3); - expect(registry.get(x2Ref)).toBe('y'); - }); -}); diff --git a/packages/core-app-api/src/metadata/system/MetadataRegistry.ts b/packages/core-app-api/src/metadata/system/MetadataRegistry.ts deleted file mode 100644 index 053a52b5f6..0000000000 --- a/packages/core-app-api/src/metadata/system/MetadataRegistry.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { MetadataRef, MetadataHolder } from '@backstage/core-plugin-api'; - -type MetadataImpl = readonly [MetadataRef, T]; - -export class MetadataRegistry implements MetadataHolder { - private readonly registry = new Map(); - - register(id: string, payload: any): boolean { - this.registry.set(id, payload); - return true; - } - - get(ref: MetadataRef): T | undefined { - return this.registry.get(ref.id); - } - - static from(entries: MetadataImpl[]) { - const registry = new MetadataRegistry(); - for (const entry of entries) { - registry.register(entry[0].id, entry[1]); - } - return registry; - } -} diff --git a/packages/core-app-api/src/metadata/system/index.ts b/packages/core-app-api/src/metadata/system/index.ts deleted file mode 100644 index faa7c814c8..0000000000 --- a/packages/core-app-api/src/metadata/system/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export { MetadataRegistry } from './MetadataRegistry'; -export { MetadataProvider } from './MetadataProvider'; -export { MetadataAggregator } from './MetadataAggregator'; diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 4377761d89..124dbc8966 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -37,6 +37,7 @@ "@backstage/types": "^1.0.0", "@backstage/version-bridge": "^1.0.1", "history": "^5.0.0", + "lodash": "^4.17.21", "prop-types": "^15.7.2", "react-router-dom": "6.0.0-beta.0", "zen-observable": "^0.8.15" diff --git a/packages/core-plugin-api/src/extensions/extensions.tsx b/packages/core-plugin-api/src/extensions/extensions.tsx index 19da082ee1..c648214c22 100644 --- a/packages/core-plugin-api/src/extensions/extensions.tsx +++ b/packages/core-plugin-api/src/extensions/extensions.tsx @@ -21,6 +21,7 @@ import { RouteRef, useRouteRef } from '../routing'; import { attachComponentData } from './componentData'; import { Extension, BackstagePlugin } from '../plugin/types'; import { PluginErrorBoundary } from './PluginErrorBoundary'; +import { PluginOptionsProvider } from '../plugin-options'; /** * Lazy or synchronous retrieving of extension components. @@ -235,6 +236,15 @@ export function createReactExtension< | { id?: string } | undefined; + const renderComponent = () => + plugin.getPluginOptions() ? ( + + + + ) : ( + + ); + return ( }> @@ -245,7 +255,7 @@ export function createReactExtension< ...(mountPoint && { routeRef: mountPoint.id }), }} > - + {renderComponent()} diff --git a/packages/core-plugin-api/src/index.ts b/packages/core-plugin-api/src/index.ts index 172f00295b..e8edd38ff3 100644 --- a/packages/core-plugin-api/src/index.ts +++ b/packages/core-plugin-api/src/index.ts @@ -22,7 +22,7 @@ export * from './analytics'; export * from './apis'; -export * from './metadata'; +export * from './plugin-options'; export * from './app'; export * from './extensions'; export * from './icons'; diff --git a/packages/core-plugin-api/src/metadata/MetadataRef.ts b/packages/core-plugin-api/src/metadata/MetadataRef.ts deleted file mode 100644 index f261fb5352..0000000000 --- a/packages/core-plugin-api/src/metadata/MetadataRef.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { MetadataRef } from './types'; - -export type MetadataRefConfig = { - id: string; -}; - -class MetadataRefImpl implements MetadataRef { - constructor(private readonly config: MetadataRefConfig) {} - - get id(): string { - return this.config.id; - } - - get T(): T { - throw new Error(`tried to read MetadataRef.T of ${this}`); - } - - toString() { - return `metadataRef{${this.config.id}}`; - } -} - -/** - * Creates a reference to a metadata. - * - * @param config - The descriptor of the metadata to reference. - * @returns A metadata reference. - * @public - */ -export function createMetadataRef( - config: MetadataRefConfig, -): MetadataRef { - return new MetadataRefImpl(config); -} diff --git a/packages/core-plugin-api/src/metadata/index.ts b/packages/core-plugin-api/src/metadata/index.ts deleted file mode 100644 index 29d5532edd..0000000000 --- a/packages/core-plugin-api/src/metadata/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export { useMetadata, useMetadataHolder } from './useMetadata'; -export { createMetadataRef } from './MetadataRef'; -export * from './types'; diff --git a/packages/core-plugin-api/src/metadata/types.ts b/packages/core-plugin-api/src/metadata/types.ts deleted file mode 100644 index 5b721b5b55..0000000000 --- a/packages/core-plugin-api/src/metadata/types.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Metadata reference. - * - * @public - */ -export type MetadataRef = { - id: string; - T: T; -}; - -/** - * Provides lookup of metadata through their {@link MetadataRef}s. - * - * @public - */ -export type MetadataHolder = { - get(key: MetadataRef): T | undefined; -}; diff --git a/packages/core-plugin-api/src/metadata/useMetadata.tsx b/packages/core-plugin-api/src/metadata/useMetadata.tsx deleted file mode 100644 index 99ce68f1e4..0000000000 --- a/packages/core-plugin-api/src/metadata/useMetadata.tsx +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { MetadataHolder, MetadataRef } from './types'; -import { useVersionedContext } from '@backstage/version-bridge'; - -/** - * React hook for retrieving {@link MetadataHolder} - * - * @public - */ -export function useMetadataHolder(): MetadataHolder { - const versionedHolder = useVersionedContext<{ 1: MetadataHolder }>( - 'metadata-context', - ); - if (!versionedHolder) { - throw new Error('Metadata context is not available'); - } - - const metadataHolder = versionedHolder.atVersion(1); - if (!metadataHolder) { - throw new Error('Metadata context v1 not available'); - } - return metadataHolder; -} - -/** - * React hook for retrieving metadata. - * - * @param metadataRef - Reference of the metadata to use. - * @public - */ -export function useMetadata(metadataRef: MetadataRef): T { - const metadataHolder = useMetadataHolder(); - - const metadata = metadataHolder.get(metadataRef); - if (!metadata) { - throw new Error(`No implementation available for ${metadataRef}`); - } - return metadata; -} diff --git a/packages/core-app-api/src/metadata/index.ts b/packages/core-plugin-api/src/plugin-options/index.ts similarity index 88% rename from packages/core-app-api/src/metadata/index.ts rename to packages/core-plugin-api/src/plugin-options/index.ts index 59aa474fee..83901f526a 100644 --- a/packages/core-app-api/src/metadata/index.ts +++ b/packages/core-plugin-api/src/plugin-options/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export * from './system'; +export { usePluginOptions, PluginOptionsProvider } from './usePluginOptions'; diff --git a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx new file mode 100644 index 0000000000..5e8952ee76 --- /dev/null +++ b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx @@ -0,0 +1,75 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createVersionedContext, + createVersionedValueMap, + useVersionedContext, +} from '@backstage/version-bridge'; +import { AnyPluginOptions } from '../plugin'; +import React, { ReactNode } from 'react'; + +const contextKey: string = 'pluginOptions-context'; + +/** + * Properties for the AsyncEntityProvider component. + * + * @public + */ +export interface PluginOptionsProviderProps { + children: ReactNode; + pluginOptions?: AnyPluginOptions; +} + +export const PluginOptionsProvider = ({ + children, + pluginOptions, +}: PluginOptionsProviderProps) => { + const value = { pluginOptions }; + const { Provider } = createVersionedContext<{ 1: AnyPluginOptions }>( + contextKey, + ); + return ( + + {children} + + ); +}; + +/** + * Grab the current entity from the context, throws if the entity has not yet been loaded + * or is not available. + * + * @public + */ +export function usePluginOptions< + TPluginOptions extends AnyPluginOptions = AnyPluginOptions, +>(): TPluginOptions { + const versionedHolder = useVersionedContext<{ 1: TPluginOptions }>( + contextKey, + ); + + if (!versionedHolder) { + throw new Error('Plugin Options context is not available'); + } + + const value = versionedHolder.atVersion(1); + if (!value) { + throw new Error('Plugin Options v1 is not available'); + } + + return value.pluginOptions; +} diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index 999d154166..6565289542 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -20,7 +20,7 @@ import { Extension, AnyRoutes, AnyExternalRoutes, - AnyMetadata, + AnyPluginOptions, PluginFeatureFlagConfig, } from './types'; import { AnyApiFactory } from '../apis'; @@ -31,19 +31,17 @@ import { AnyApiFactory } from '../apis'; export class PluginImpl< Routes extends AnyRoutes, ExternalRoutes extends AnyExternalRoutes, - PluginMetadata extends AnyMetadata, -> implements BackstagePlugin + PluginOptions extends AnyPluginOptions, +> implements BackstagePlugin { constructor( private readonly config: PluginConfig< Routes, ExternalRoutes, - PluginMetadata + PluginOptions >, ) {} - private reconfiguredMetadata: Array = []; - getId(): string { return this.config.id; } @@ -56,13 +54,6 @@ export class PluginImpl< return this.config.featureFlags?.slice() ?? []; } - getMetadata(): Iterable { - return [ - ...Array.from(this.config.metadata ?? []), - ...this.reconfiguredMetadata, - ]; - } - get routes(): Routes { return this.config.routes ?? ({} as Routes); } @@ -75,8 +66,12 @@ export class PluginImpl< return extension.expose(this); } - reconfigure(metadata: PluginMetadata): void { - this.reconfiguredMetadata.push(metadata); + reconfigure(pluginOptions: PluginOptions): void { + this.config.options = pluginOptions; + } + + getPluginOptions(): PluginOptions { + return this.config.options ?? ({} as PluginOptions); } toString() { @@ -93,9 +88,9 @@ export class PluginImpl< export function createPlugin< Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, - PluginMetadata extends AnyMetadata = {}, + PluginOptions extends AnyPluginOptions = {}, >( - config: PluginConfig, -): BackstagePlugin { + config: PluginConfig, +): BackstagePlugin { return new PluginImpl(config); } diff --git a/packages/core-plugin-api/src/plugin/index.ts b/packages/core-plugin-api/src/plugin/index.ts index 1ebe1b3446..5885fb1bc6 100644 --- a/packages/core-plugin-api/src/plugin/index.ts +++ b/packages/core-plugin-api/src/plugin/index.ts @@ -17,7 +17,7 @@ export { createPlugin } from './Plugin'; export type { AnyExternalRoutes, - AnyMetadata, + AnyPluginOptions, AnyRoutes, BackstagePlugin, Extension, diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index 8aadac36bc..953a55a9ee 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -49,7 +49,7 @@ export type AnyExternalRoutes = { [name: string]: ExternalRouteRef }; * * @public */ -export type AnyMetadata = { [name: string]: any }; +export type AnyPluginOptions = { [name: string]: any }; /** * Plugin type. @@ -59,7 +59,7 @@ export type AnyMetadata = { [name: string]: any }; export type BackstagePlugin< Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, - PluginMetadata extends AnyMetadata = { [name: string]: any }, + PluginOptions extends AnyPluginOptions = { [name: string]: any }, > = { getId(): string; getApis(): Iterable; @@ -67,9 +67,9 @@ export type BackstagePlugin< * Returns all registered feature flags for this plugin. */ getFeatureFlags(): Iterable; - getMetadata(): Iterable; provide(extension: Extension): T; - reconfigure(metadata: PluginMetadata): void; + getPluginOptions(): PluginOptions; + reconfigure(pluginOptions: PluginOptions): void; routes: Routes; externalRoutes: ExternalRoutes; }; @@ -92,14 +92,22 @@ export type PluginFeatureFlagConfig = { export type PluginConfig< Routes extends AnyRoutes, ExternalRoutes extends AnyExternalRoutes, - PluginMetadata extends AnyMetadata, + PluginOptions extends AnyPluginOptions, > = { id: string; apis?: Iterable; routes?: Routes; externalRoutes?: ExternalRoutes; featureFlags?: PluginFeatureFlagConfig[]; - metadata?: Iterable; + options?: PluginOptions; + /** + * TODO: Not clear yet does it make sense to do it as a function. + * As for me it makes more sense to provide it as an object with default values. + * And keep only reconfigure as a function to update default values. + * Otherwise it looks like we have 2 places where it is possible to override default values. + * @param inputOptions + */ + pluginOptions(inputOptions: AnyPluginOptions): PluginOptions; }; /** diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx index 5250dcec0d..35e4aa5753 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -23,7 +23,12 @@ import { TableColumn, TableProps, } from '@backstage/core-components'; -import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; +import { + configApiRef, + useApi, + usePluginOptions, + useRouteRef, +} from '@backstage/core-plugin-api'; import { CatalogFilterLayout, EntityLifecyclePicker, @@ -52,6 +57,10 @@ export interface DefaultCatalogPageProps { tableOptions?: TableProps['options']; } +export type CatalogPageMetadataProps = { + createButtonTitle: string; +}; + export function DefaultCatalogPage(props: DefaultCatalogPageProps) { const { columns, @@ -64,6 +73,8 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { useApi(configApiRef).getOptionalString('organization.name') ?? 'Backstage'; const createComponentLink = useRouteRef(createComponentRouteRef); + const { createButtonTitle } = usePluginOptions(); + return ( @@ -72,7 +83,7 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { titleComponent={} > All your software catalog entities diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index 1b9083e7ca..e1bf10e186 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -23,6 +23,7 @@ import { } from '@backstage/plugin-catalog-react'; import { createComponentRouteRef, viewTechDocRouteRef } from './routes'; import { + AnyPluginOptions, createApiFactory, createComponentExtension, createPlugin, @@ -72,6 +73,10 @@ export const catalogPlugin = createPlugin({ createComponent: createComponentRouteRef, viewTechDoc: viewTechDocRouteRef, }, + pluginOptions: (inputOptions: AnyPluginOptions) => ({ + // TODO: remove it, only for testing here + createButtonTitle: inputOptions.createButtonTitle || 'Create', + }), }); /** @public */ From 71f5f4c5597c0dc9d7d22dcc919bc71cc58e0326 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Fri, 20 May 2022 20:26:48 +0200 Subject: [PATCH 15/54] A bit changed the structure Signed-off-by: bnechyporenko --- packages/app/src/App.tsx | 10 ++++++---- .../src/extensions/extensions.tsx | 4 ++-- packages/core-plugin-api/src/plugin/Plugin.tsx | 7 +++++-- packages/core-plugin-api/src/plugin/types.ts | 16 ++++++---------- plugins/catalog/src/plugin.ts | 8 +++----- 5 files changed, 22 insertions(+), 23 deletions(-) diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index aa3cafc2c9..d55b3afca7 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -97,6 +97,7 @@ import * as plugins from './plugins'; import { techDocsPage } from './components/techdocs/TechDocsPage'; import { ApacheAirflowPage } from '@backstage/plugin-apache-airflow'; import { PermissionedRoute } from '@backstage/plugin-permission-react'; +import { AnyPluginOptions } from '@backstage/core-plugin-api'; import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common'; const app = createApp({ @@ -138,10 +139,11 @@ const app = createApp({ const AppProvider = app.getProvider(); const AppRouter = app.getRouter(); -catalogPlugin.reconfigure({ - // TODO: remove it, only for testing here - createButtonTitle: 'Maybe Create Component', -}); +// TODO: remove it, only for testing here +catalogPlugin.reconfigure((options: AnyPluginOptions) => ({ + ...options, + createButtonTitle: 'Maybe Create', +})); const routes = ( diff --git a/packages/core-plugin-api/src/extensions/extensions.tsx b/packages/core-plugin-api/src/extensions/extensions.tsx index c648214c22..654ec8f710 100644 --- a/packages/core-plugin-api/src/extensions/extensions.tsx +++ b/packages/core-plugin-api/src/extensions/extensions.tsx @@ -15,11 +15,11 @@ */ import React, { lazy, Suspense } from 'react'; -import { AnalyticsContext } from '../analytics/AnalyticsContext'; +import { AnalyticsContext } from '../analytics'; import { useApp } from '../app'; import { RouteRef, useRouteRef } from '../routing'; import { attachComponentData } from './componentData'; -import { Extension, BackstagePlugin } from '../plugin/types'; +import { Extension, BackstagePlugin } from '../plugin'; import { PluginErrorBoundary } from './PluginErrorBoundary'; import { PluginOptionsProvider } from '../plugin-options'; diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index 6565289542..07d3cf64cd 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -22,6 +22,7 @@ import { AnyExternalRoutes, AnyPluginOptions, PluginFeatureFlagConfig, + ReconfigureFunction, } from './types'; import { AnyApiFactory } from '../apis'; @@ -66,8 +67,10 @@ export class PluginImpl< return extension.expose(this); } - reconfigure(pluginOptions: PluginOptions): void { - this.config.options = pluginOptions; + reconfigure(fn: ReconfigureFunction): void { + if (this.config.options) { + this.config.options = fn(this.config.options) as PluginOptions; + } } getPluginOptions(): PluginOptions { diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index 953a55a9ee..8b6573c17b 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -15,7 +15,7 @@ */ import { RouteRef, SubRouteRef, ExternalRouteRef } from '../routing'; -import { AnyApiFactory } from '../apis/system'; +import { AnyApiFactory } from '../apis'; /** * Plugin extension type. @@ -51,6 +51,10 @@ export type AnyExternalRoutes = { [name: string]: ExternalRouteRef }; */ export type AnyPluginOptions = { [name: string]: any }; +export type ReconfigureFunction = ( + options: AnyPluginOptions, +) => AnyPluginOptions; + /** * Plugin type. * @@ -69,7 +73,7 @@ export type BackstagePlugin< getFeatureFlags(): Iterable; provide(extension: Extension): T; getPluginOptions(): PluginOptions; - reconfigure(pluginOptions: PluginOptions): void; + reconfigure(fn: ReconfigureFunction): void; routes: Routes; externalRoutes: ExternalRoutes; }; @@ -100,14 +104,6 @@ export type PluginConfig< externalRoutes?: ExternalRoutes; featureFlags?: PluginFeatureFlagConfig[]; options?: PluginOptions; - /** - * TODO: Not clear yet does it make sense to do it as a function. - * As for me it makes more sense to provide it as an object with default values. - * And keep only reconfigure as a function to update default values. - * Otherwise it looks like we have 2 places where it is possible to override default values. - * @param inputOptions - */ - pluginOptions(inputOptions: AnyPluginOptions): PluginOptions; }; /** diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index e1bf10e186..6b441acbdc 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -23,7 +23,6 @@ import { } from '@backstage/plugin-catalog-react'; import { createComponentRouteRef, viewTechDocRouteRef } from './routes'; import { - AnyPluginOptions, createApiFactory, createComponentExtension, createPlugin, @@ -73,10 +72,9 @@ export const catalogPlugin = createPlugin({ createComponent: createComponentRouteRef, viewTechDoc: viewTechDocRouteRef, }, - pluginOptions: (inputOptions: AnyPluginOptions) => ({ - // TODO: remove it, only for testing here - createButtonTitle: inputOptions.createButtonTitle || 'Create', - }), + options: { + createButtonTitle: 'Create', + }, }); /** @public */ From dab3abbec470a828facd2d356e769f03a36e8133 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 31 May 2022 13:35:00 +0200 Subject: [PATCH 16/54] Cleaned up the code and added a test Signed-off-by: bnechyporenko --- docs/plugins/customization.md | 40 +++++++------------ packages/app/src/App.tsx | 6 --- .../plugin-options/usePluginOptions.test.tsx | 38 ++++++++++++++++++ .../src/plugin-options/usePluginOptions.tsx | 2 +- .../CatalogPage/DefaultCatalogPage.tsx | 4 +- plugins/catalog/src/plugin.ts | 3 -- tsconfig.json | 3 +- 7 files changed, 57 insertions(+), 39 deletions(-) create mode 100644 packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx diff --git a/docs/plugins/customization.md b/docs/plugins/customization.md index 88d7d4bad6..566b843def 100644 --- a/docs/plugins/customization.md +++ b/docs/plugins/customization.md @@ -16,33 +16,23 @@ When you are creating your plugin, you have a possibility to use a metadata fiel customizable elements. For example ```typescript jsx -export type MyPluginMetadataProps = { - createButtonTitle: string; -}; - -export const myPluginMetadataRef = createMetadataRef({ - id: 'MyPluginMetadataProvider', -}); - -export const myPluginMetadata = { - MyPluginMetadataProvider: { - // or [myPluginMetadataRef.id] - createButtonTitle: 'Create Component', - }, -}; - const plugin = createPlugin({ - id: 'myPlugin', - metadata: [myPluginMetadata], + id: 'my-plugin', + options: { + createButtonTitle: 'Create', + }, }); ``` And the rendering part of the exposed component can retrieve that metadata as: ```typescript jsx -export function DefaultMyPluginWelcomePage(props: DefaultMyPluginWelcomeProps) { - const { createButtonTitle } = - useMetadata(myPluginMetadataRef); +export type CatalogPageOptionsProps = { + createButtonTitle: string; +}; + +export function DefaultMyPluginWelcomePage() { + const { createButtonTitle } = usePluginOptions(); return (
@@ -60,10 +50,8 @@ plugin. Example: ```typescript jsx import { myPlugin } from '@backstage/my-plugin'; -myPlugin.reconfigure({ - MyPluginMetadataProvider: { - // or [myPluginMetadataRef.id] - createButtonTitle: 'Make Component', - }, -}); +myPlugin.reconfigure((options: CatalogPageOptionsProps) => ({ + ...options, + createButtonTitle: 'Maybe Create', +})); ``` diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index d55b3afca7..2499055e7d 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -139,12 +139,6 @@ const app = createApp({ const AppProvider = app.getProvider(); const AppRouter = app.getRouter(); -// TODO: remove it, only for testing here -catalogPlugin.reconfigure((options: AnyPluginOptions) => ({ - ...options, - createButtonTitle: 'Maybe Create', -})); - const routes = ( diff --git a/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx b/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx new file mode 100644 index 0000000000..ea4c1d383e --- /dev/null +++ b/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx @@ -0,0 +1,38 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { renderHook } from '@testing-library/react-hooks'; +import { usePluginOptions, PluginOptionsProvider } from './usePluginOptions'; + +describe('usePluginOptions', () => { + it('should provide a versioned value to hook', () => { + const rendered = renderHook(() => usePluginOptions(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + expect(rendered.result.current).toEqual({ + 'key-1': 'value-1', + 'key-2': 'value-2', + }); + }); +}); diff --git a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx index 5e8952ee76..bc1e4d7d3d 100644 --- a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx +++ b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx @@ -37,7 +37,7 @@ export interface PluginOptionsProviderProps { export const PluginOptionsProvider = ({ children, pluginOptions, -}: PluginOptionsProviderProps) => { +}: PluginOptionsProviderProps): JSX.Element => { const value = { pluginOptions }; const { Provider } = createVersionedContext<{ 1: AnyPluginOptions }>( contextKey, diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx index 35e4aa5753..4318fc242f 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -57,7 +57,7 @@ export interface DefaultCatalogPageProps { tableOptions?: TableProps['options']; } -export type CatalogPageMetadataProps = { +export type CatalogPageOptionsProps = { createButtonTitle: string; }; @@ -73,7 +73,7 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { useApi(configApiRef).getOptionalString('organization.name') ?? 'Backstage'; const createComponentLink = useRouteRef(createComponentRouteRef); - const { createButtonTitle } = usePluginOptions(); + const { createButtonTitle } = usePluginOptions(); return ( diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index 6b441acbdc..1b9083e7ca 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -72,9 +72,6 @@ export const catalogPlugin = createPlugin({ createComponent: createComponentRouteRef, viewTechDoc: viewTechDocRouteRef, }, - options: { - createButtonTitle: 'Create', - }, }); /** @public */ diff --git a/tsconfig.json b/tsconfig.json index 789743363d..5ad2749f19 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,6 +9,7 @@ "compilerOptions": { "outDir": "dist-types", "rootDir": ".", - "useUnknownInCatchVariables": false + "useUnknownInCatchVariables": false, + "jsx": "react" } } From 516e30404cb4887b54fda5d46894665f80c142d4 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 31 May 2022 13:37:41 +0200 Subject: [PATCH 17/54] Cleaned up the code and added a test Signed-off-by: bnechyporenko --- .../components/CatalogPage/DefaultCatalogPage.tsx | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx index 4318fc242f..5250dcec0d 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -23,12 +23,7 @@ import { TableColumn, TableProps, } from '@backstage/core-components'; -import { - configApiRef, - useApi, - usePluginOptions, - useRouteRef, -} from '@backstage/core-plugin-api'; +import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; import { CatalogFilterLayout, EntityLifecyclePicker, @@ -57,10 +52,6 @@ export interface DefaultCatalogPageProps { tableOptions?: TableProps['options']; } -export type CatalogPageOptionsProps = { - createButtonTitle: string; -}; - export function DefaultCatalogPage(props: DefaultCatalogPageProps) { const { columns, @@ -73,8 +64,6 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { useApi(configApiRef).getOptionalString('organization.name') ?? 'Backstage'; const createComponentLink = useRouteRef(createComponentRouteRef); - const { createButtonTitle } = usePluginOptions(); - return ( @@ -83,7 +72,7 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { titleComponent={} > All your software catalog entities From 720de25f582bd79051318ed4e7cd8439ff6310cb Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Thu, 2 Jun 2022 16:18:56 +0200 Subject: [PATCH 18/54] Incorporated the feedback Signed-off-by: bnechyporenko --- .../core-plugin-api/src/extensions/extensions.tsx | 11 ++++------- .../src/plugin-options/usePluginOptions.tsx | 2 +- packages/core-plugin-api/src/plugin/types.ts | 2 +- tsconfig.json | 3 +-- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/packages/core-plugin-api/src/extensions/extensions.tsx b/packages/core-plugin-api/src/extensions/extensions.tsx index 654ec8f710..af883b428e 100644 --- a/packages/core-plugin-api/src/extensions/extensions.tsx +++ b/packages/core-plugin-api/src/extensions/extensions.tsx @@ -236,14 +236,11 @@ export function createReactExtension< | { id?: string } | undefined; - const renderComponent = () => - plugin.getPluginOptions() ? ( - - - - ) : ( + const renderComponent = () => ( + - ); + + ); return ( }> diff --git a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx index bc1e4d7d3d..629d0d290c 100644 --- a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx +++ b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx @@ -22,7 +22,7 @@ import { import { AnyPluginOptions } from '../plugin'; import React, { ReactNode } from 'react'; -const contextKey: string = 'pluginOptions-context'; +const contextKey: string = 'plugin-options-context'; /** * Properties for the AsyncEntityProvider component. diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index 8b6573c17b..5e5e650a2a 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -49,7 +49,7 @@ export type AnyExternalRoutes = { [name: string]: ExternalRouteRef }; * * @public */ -export type AnyPluginOptions = { [name: string]: any }; +export type AnyPluginOptions = { [name: string]: unknown }; export type ReconfigureFunction = ( options: AnyPluginOptions, diff --git a/tsconfig.json b/tsconfig.json index 5ad2749f19..789743363d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,6 @@ "compilerOptions": { "outDir": "dist-types", "rootDir": ".", - "useUnknownInCatchVariables": false, - "jsx": "react" + "useUnknownInCatchVariables": false } } From ecb2c3104db0bf5e3f5b7a87de7e0750710c09e3 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Wed, 8 Jun 2022 10:27:27 +0200 Subject: [PATCH 19/54] Incorporated the feedback. Made input options type for `reconfigure` different from default options Signed-off-by: bnechyporenko --- packages/core-plugin-api/src/plugin/types.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index 5e5e650a2a..51cd00b2b0 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -50,9 +50,10 @@ export type AnyExternalRoutes = { [name: string]: ExternalRouteRef }; * @public */ export type AnyPluginOptions = { [name: string]: unknown }; +export type AnyPluginInputOptions = { [name: string]: unknown }; export type ReconfigureFunction = ( - options: AnyPluginOptions, + options: AnyPluginInputOptions, ) => AnyPluginOptions; /** From abf96994eebde87a67891c40be15bb75941dc43b Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Wed, 8 Jun 2022 15:42:05 +0200 Subject: [PATCH 20/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- docs/plugins/customization.md | 13 +++++---- packages/app/src/App.tsx | 1 - .../src/extensions/extensions.tsx | 12 ++++---- .../core-plugin-api/src/plugin/Plugin.tsx | 29 ++++++++----------- packages/core-plugin-api/src/plugin/index.ts | 3 +- packages/core-plugin-api/src/plugin/types.ts | 13 +++------ plugins/catalog/src/plugin.ts | 9 ++++++ 7 files changed, 40 insertions(+), 40 deletions(-) diff --git a/docs/plugins/customization.md b/docs/plugins/customization.md index 566b843def..e9a92d1021 100644 --- a/docs/plugins/customization.md +++ b/docs/plugins/customization.md @@ -18,8 +18,12 @@ customizable elements. For example ```typescript jsx const plugin = createPlugin({ id: 'my-plugin', - options: { - createButtonTitle: 'Create', + configure(options?: PluginInputOptions): PluginOptions { + const defaultOptions = { createButtonTitle: 'Create' }; + if (!options) { + return defaultOptions; + } + return { ...defaultOptions, ...options }; }, }); ``` @@ -50,8 +54,7 @@ plugin. Example: ```typescript jsx import { myPlugin } from '@backstage/my-plugin'; -myPlugin.reconfigure((options: CatalogPageOptionsProps) => ({ - ...options, +myPlugin.reconfigure({ createButtonTitle: 'Maybe Create', -})); +}); ``` diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 2499055e7d..35c61f2f16 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -97,7 +97,6 @@ import * as plugins from './plugins'; import { techDocsPage } from './components/techdocs/TechDocsPage'; import { ApacheAirflowPage } from '@backstage/plugin-apache-airflow'; import { PermissionedRoute } from '@backstage/plugin-permission-react'; -import { AnyPluginOptions } from '@backstage/core-plugin-api'; import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common'; const app = createApp({ diff --git a/packages/core-plugin-api/src/extensions/extensions.tsx b/packages/core-plugin-api/src/extensions/extensions.tsx index af883b428e..c0d54af2c1 100644 --- a/packages/core-plugin-api/src/extensions/extensions.tsx +++ b/packages/core-plugin-api/src/extensions/extensions.tsx @@ -236,12 +236,6 @@ export function createReactExtension< | { id?: string } | undefined; - const renderComponent = () => ( - - - - ); - return ( }> @@ -252,7 +246,11 @@ export function createReactExtension< ...(mountPoint && { routeRef: mountPoint.id }), }} > - {renderComponent()} + + + diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index 07d3cf64cd..fb2f304b46 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -20,9 +20,9 @@ import { Extension, AnyRoutes, AnyExternalRoutes, - AnyPluginOptions, + PluginOptions, + PluginInputOptions, PluginFeatureFlagConfig, - ReconfigureFunction, } from './types'; import { AnyApiFactory } from '../apis'; @@ -32,16 +32,9 @@ import { AnyApiFactory } from '../apis'; export class PluginImpl< Routes extends AnyRoutes, ExternalRoutes extends AnyExternalRoutes, - PluginOptions extends AnyPluginOptions, -> implements BackstagePlugin +> implements BackstagePlugin { - constructor( - private readonly config: PluginConfig< - Routes, - ExternalRoutes, - PluginOptions - >, - ) {} + constructor(private readonly config: PluginConfig) {} getId(): string { return this.config.id; @@ -67,13 +60,16 @@ export class PluginImpl< return extension.expose(this); } - reconfigure(fn: ReconfigureFunction): void { - if (this.config.options) { - this.config.options = fn(this.config.options) as PluginOptions; + reconfigure(options: PluginInputOptions): void { + if (this.config.configure) { + this.config.options = this.config.configure(options); } } getPluginOptions(): PluginOptions { + if (this.config.configure && !this.config.options) { + this.config.options = this.config.configure(); + } return this.config.options ?? ({} as PluginOptions); } @@ -91,9 +87,8 @@ export class PluginImpl< export function createPlugin< Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, - PluginOptions extends AnyPluginOptions = {}, >( - config: PluginConfig, -): BackstagePlugin { + config: PluginConfig, +): BackstagePlugin { return new PluginImpl(config); } diff --git a/packages/core-plugin-api/src/plugin/index.ts b/packages/core-plugin-api/src/plugin/index.ts index 5885fb1bc6..6826ba37c6 100644 --- a/packages/core-plugin-api/src/plugin/index.ts +++ b/packages/core-plugin-api/src/plugin/index.ts @@ -17,7 +17,8 @@ export { createPlugin } from './Plugin'; export type { AnyExternalRoutes, - AnyPluginOptions, + PluginOptions, + PluginInputOptions, AnyRoutes, BackstagePlugin, Extension, diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index 51cd00b2b0..fa8778ce93 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -49,12 +49,8 @@ export type AnyExternalRoutes = { [name: string]: ExternalRouteRef }; * * @public */ -export type AnyPluginOptions = { [name: string]: unknown }; -export type AnyPluginInputOptions = { [name: string]: unknown }; - -export type ReconfigureFunction = ( - options: AnyPluginInputOptions, -) => AnyPluginOptions; +export type PluginOptions = { [name: string]: unknown }; +export type PluginInputOptions = { [name: string]: unknown }; /** * Plugin type. @@ -64,7 +60,6 @@ export type ReconfigureFunction = ( export type BackstagePlugin< Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, - PluginOptions extends AnyPluginOptions = { [name: string]: any }, > = { getId(): string; getApis(): Iterable; @@ -74,7 +69,7 @@ export type BackstagePlugin< getFeatureFlags(): Iterable; provide(extension: Extension): T; getPluginOptions(): PluginOptions; - reconfigure(fn: ReconfigureFunction): void; + reconfigure(options: PluginInputOptions): void; routes: Routes; externalRoutes: ExternalRoutes; }; @@ -97,7 +92,6 @@ export type PluginFeatureFlagConfig = { export type PluginConfig< Routes extends AnyRoutes, ExternalRoutes extends AnyExternalRoutes, - PluginOptions extends AnyPluginOptions, > = { id: string; apis?: Iterable; @@ -105,6 +99,7 @@ export type PluginConfig< externalRoutes?: ExternalRoutes; featureFlags?: PluginFeatureFlagConfig[]; options?: PluginOptions; + configure?(options?: PluginInputOptions): PluginOptions; }; /** diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index 1b9083e7ca..61612c404b 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -30,6 +30,8 @@ import { discoveryApiRef, fetchApiRef, storageApiRef, + PluginOptions, + PluginInputOptions, } from '@backstage/core-plugin-api'; import { DefaultStarredEntitiesApi } from './apis'; import { AboutCardProps } from './components/AboutCard'; @@ -72,6 +74,13 @@ export const catalogPlugin = createPlugin({ createComponent: createComponentRouteRef, viewTechDoc: viewTechDocRouteRef, }, + configure(options?: PluginInputOptions): PluginOptions { + const defaultOptions = { createButtonTitle: 'Create' }; + if (!options) { + return defaultOptions; + } + return { ...defaultOptions, ...options }; + }, }); /** @public */ From 6f0ce1202b8e52574e7d133aa37b2fdc05ed3572 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 28 Jun 2022 14:28:19 +0200 Subject: [PATCH 21/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- packages/app/package.json | 1 + packages/app/src/App.tsx | 4 ++ .../src/plugin-options/usePluginOptions.tsx | 12 ++-- packages/core-plugin-api/src/plugin/index.ts | 1 + plugins/catalog-customized/.eslintrc.js | 1 + plugins/catalog-customized/README.md | 57 +++++++++++++++++++ plugins/catalog-customized/package.json | 47 +++++++++++++++ plugins/catalog-customized/src/components.tsx | 33 +++++++++++ plugins/catalog-customized/src/index.ts | 17 ++++++ plugins/catalog-customized/src/plugin.ts | 33 +++++++++++ .../CatalogPage/DefaultCatalogPage.tsx | 23 ++++++-- plugins/catalog/src/plugin.ts | 14 ++++- plugins/catalog/src/types.ts | 28 +++++++++ 13 files changed, 256 insertions(+), 15 deletions(-) create mode 100644 plugins/catalog-customized/.eslintrc.js create mode 100644 plugins/catalog-customized/README.md create mode 100644 plugins/catalog-customized/package.json create mode 100644 plugins/catalog-customized/src/components.tsx create mode 100644 plugins/catalog-customized/src/index.ts create mode 100644 plugins/catalog-customized/src/plugin.ts create mode 100644 plugins/catalog/src/types.ts diff --git a/packages/app/package.json b/packages/app/package.json index 9c43f03f49..68fed34421 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -70,6 +70,7 @@ "@roadiehq/backstage-plugin-github-insights": "^2.0.0", "@roadiehq/backstage-plugin-github-pull-requests": "^2.0.0", "@roadiehq/backstage-plugin-travis-ci": "^2.0.0", + "@internal/plugin-catalog-customized": "1.2.1-next.1", "history": "^5.0.0", "prop-types": "^15.7.2", "react": "^17.0.2", diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 35c61f2f16..dc004ef2fd 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -40,6 +40,10 @@ import { CatalogIndexPage, catalogPlugin, } from '@backstage/plugin-catalog'; + +/* Uncomment this import to enable a customized version of a catalog */ +// import '@internal/plugin-catalog-customized'; + import { CatalogGraphPage } from '@backstage/plugin-catalog-graph'; import { CatalogImportPage, diff --git a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx index 629d0d290c..1e667e09ea 100644 --- a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx +++ b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx @@ -19,7 +19,7 @@ import { createVersionedValueMap, useVersionedContext, } from '@backstage/version-bridge'; -import { AnyPluginOptions } from '../plugin'; +import { PluginOptions } from '../plugin'; import React, { ReactNode } from 'react'; const contextKey: string = 'plugin-options-context'; @@ -31,7 +31,7 @@ const contextKey: string = 'plugin-options-context'; */ export interface PluginOptionsProviderProps { children: ReactNode; - pluginOptions?: AnyPluginOptions; + pluginOptions?: PluginOptions; } export const PluginOptionsProvider = ({ @@ -39,9 +39,7 @@ export const PluginOptionsProvider = ({ pluginOptions, }: PluginOptionsProviderProps): JSX.Element => { const value = { pluginOptions }; - const { Provider } = createVersionedContext<{ 1: AnyPluginOptions }>( - contextKey, - ); + const { Provider } = createVersionedContext<{ 1: PluginOptions }>(contextKey); return ( {children} @@ -56,7 +54,7 @@ export const PluginOptionsProvider = ({ * @public */ export function usePluginOptions< - TPluginOptions extends AnyPluginOptions = AnyPluginOptions, + TPluginOptions extends PluginOptions = PluginOptions, >(): TPluginOptions { const versionedHolder = useVersionedContext<{ 1: TPluginOptions }>( contextKey, @@ -71,5 +69,5 @@ export function usePluginOptions< throw new Error('Plugin Options v1 is not available'); } - return value.pluginOptions; + return value.pluginOptions as TPluginOptions; } diff --git a/packages/core-plugin-api/src/plugin/index.ts b/packages/core-plugin-api/src/plugin/index.ts index 6826ba37c6..e433e5cc86 100644 --- a/packages/core-plugin-api/src/plugin/index.ts +++ b/packages/core-plugin-api/src/plugin/index.ts @@ -15,6 +15,7 @@ */ export { createPlugin } from './Plugin'; + export type { AnyExternalRoutes, PluginOptions, diff --git a/plugins/catalog-customized/.eslintrc.js b/plugins/catalog-customized/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/catalog-customized/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/catalog-customized/README.md b/plugins/catalog-customized/README.md new file mode 100644 index 0000000000..129d70ad58 --- /dev/null +++ b/plugins/catalog-customized/README.md @@ -0,0 +1,57 @@ +# Backstage Catalog Frontend + +This is the React frontend to customize Backstage [software +catalog](http://backstage.io/docs/features/software-catalog/software-catalog-overview). +This package supplies the example how it can be achieved. + +## Installation + +This `@internal/plugin-catalog-customized` package comes installed by default in example application of +Backstage application. + +To check if you already have the package, look under +`packages/app/package.json`, in the `dependencies` block, for +`@internal/plugin-catalog-customized`. The instructions below walk through restoring the +plugin, if you previously removed it. + +### Install the package + +```bash +# From your Backstage root directory +yarn add --cwd packages/app @internal/plugin-catalog-customized +``` + +### Add the plugin to your `packages/app` + +Add the import to a file where is your plugin catalog is defined: + +```diff +// packages/app/src/App.tsx + +import from '@internal/plugin-catalog-customized'; + +... + +import { + CatalogIndexPage, + CatalogEntityPage, +} from '@backstage/plugin-catalog'; + +... +``` + +## Development + +This frontend plugin can be started in a standalone mode from directly in this +package with `yarn start`. However, it will have limited functionality and that +process is most convenient when developing the catalog frontend plugin itself. + +To evaluate the catalog and have a greater amount of functionality available, +run the entire Backstage example application from the root folder: + +```bash +yarn dev +``` + +This will launch both frontend and backend in the same window, populated with +some example entities. diff --git a/plugins/catalog-customized/package.json b/plugins/catalog-customized/package.json new file mode 100644 index 0000000000..4ffc82c2b0 --- /dev/null +++ b/plugins/catalog-customized/package.json @@ -0,0 +1,47 @@ +{ + "name": "@internal/plugin-catalog-customized", + "description": "The internal Backstage Customizable plugin for browsing the Backstage catalog", + "version": "1.2.1-next.1", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "private": false, + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "frontend-plugin" + }, + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/catalog-customized" + }, + "keywords": [ + "backstage" + ], + "scripts": { + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "diff": "backstage-cli plugin:diff", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" + }, + "dependencies": { + "@backstage/plugin-catalog": "^1.3.1-next.0", + "@backstage/plugin-catalog-react": "^1.1.2-next.0" + }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", + "react": "^16.13.1 || ^17.0.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/catalog-customized/src/components.tsx b/plugins/catalog-customized/src/components.tsx new file mode 100644 index 0000000000..9c9bd2e187 --- /dev/null +++ b/plugins/catalog-customized/src/components.tsx @@ -0,0 +1,33 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { + EntityTypePickerProps, + UserListPickerProps, +} from '@backstage/plugin-catalog-react'; + +export const EntityOwnerPicker = () => { + return
Customized entity owner picker
; +}; + +export const EntityTypePicker = (_: EntityTypePickerProps) => { + return
Customized entity type picker
; +}; + +export const UserListPicker = (_: UserListPickerProps) => { + return
Customized user lis picker
; +}; diff --git a/plugins/catalog-customized/src/index.ts b/plugins/catalog-customized/src/index.ts new file mode 100644 index 0000000000..0ad4c9ff68 --- /dev/null +++ b/plugins/catalog-customized/src/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { customizedCatalog } from './plugin'; diff --git a/plugins/catalog-customized/src/plugin.ts b/plugins/catalog-customized/src/plugin.ts new file mode 100644 index 0000000000..e46eb17192 --- /dev/null +++ b/plugins/catalog-customized/src/plugin.ts @@ -0,0 +1,33 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { catalogPlugin } from '@backstage/plugin-catalog'; + +import { + EntityOwnerPicker, + EntityTypePicker, + UserListPicker, +} from './components'; + +catalogPlugin.reconfigure({ + EntityOwnerPicker, + EntityTypePicker, + UserListPicker, + createButtonTitle: 'Maybe Create', + showButtonText: 'Mine catalog entities', +}); + +export const customizedCatalog = catalogPlugin; diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx index 5250dcec0d..a02623118f 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -23,21 +23,24 @@ import { TableColumn, TableProps, } from '@backstage/core-components'; -import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; +import { + configApiRef, + useApi, + usePluginOptions, + useRouteRef, +} from '@backstage/core-plugin-api'; import { CatalogFilterLayout, EntityLifecyclePicker, EntityListProvider, - EntityOwnerPicker, EntityTagPicker, - EntityTypePicker, UserListFilterKind, - UserListPicker, } from '@backstage/plugin-catalog-react'; import React from 'react'; import { createComponentRouteRef } from '../../routes'; import { CatalogTable, CatalogTableRow } from '../CatalogTable'; import { CatalogKindHeader } from '../CatalogKindHeader'; +import { CatalogPageOptionsProps } from '../../types'; /** * Props for root catalog pages. @@ -64,6 +67,14 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { useApi(configApiRef).getOptionalString('organization.name') ?? 'Backstage'; const createComponentLink = useRouteRef(createComponentRouteRef); + const { + EntityOwnerPicker, + EntityTypePicker, + UserListPicker, + createButtonTitle, + showButtonText, + } = usePluginOptions(); + return ( @@ -72,10 +83,10 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { titleComponent={} > - All your software catalog entities + ${showButtonText} diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index 61612c404b..ce68fafcbc 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -18,7 +18,10 @@ import { CatalogClient } from '@backstage/catalog-client'; import { Entity } from '@backstage/catalog-model'; import { catalogApiRef, + EntityOwnerPicker, entityRouteRef, + EntityTypePicker, + UserListPicker, starredEntitiesApiRef, } from '@backstage/plugin-catalog-react'; import { createComponentRouteRef, viewTechDocRouteRef } from './routes'; @@ -31,7 +34,6 @@ import { fetchApiRef, storageApiRef, PluginOptions, - PluginInputOptions, } from '@backstage/core-plugin-api'; import { DefaultStarredEntitiesApi } from './apis'; import { AboutCardProps } from './components/AboutCard'; @@ -46,6 +48,8 @@ import { HasSystemsCardProps } from './components/HasSystemsCard'; import { RelatedEntitiesCardProps } from './components/RelatedEntitiesCard'; import { rootRouteRef } from './routes'; +export interface PluginInputOptions {} + /** @public */ export const catalogPlugin = createPlugin({ id: 'catalog', @@ -75,7 +79,13 @@ export const catalogPlugin = createPlugin({ viewTechDoc: viewTechDocRouteRef, }, configure(options?: PluginInputOptions): PluginOptions { - const defaultOptions = { createButtonTitle: 'Create' }; + const defaultOptions = { + EntityOwnerPicker, + EntityTypePicker, + UserListPicker, + createButtonTitle: 'Create', + showButtonText: 'All your software catalog entities', + }; if (!options) { return defaultOptions; } diff --git a/plugins/catalog/src/types.ts b/plugins/catalog/src/types.ts new file mode 100644 index 0000000000..29997d1368 --- /dev/null +++ b/plugins/catalog/src/types.ts @@ -0,0 +1,28 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + EntityTypePickerProps, + UserListPickerProps, +} from '@backstage/plugin-catalog-react'; + +export type CatalogPageOptionsProps = { + EntityOwnerPicker: () => JSX.Element | null; + EntityTypePicker: (props: EntityTypePickerProps) => JSX.Element | null; + UserListPicker: (props: UserListPickerProps) => JSX.Element | null; + createButtonTitle: string; + showButtonText: string; +}; From a66aabe733106450d590f8ef2502ad33083c0b36 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Wed, 6 Jul 2022 11:46:41 +0200 Subject: [PATCH 22/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- microsite/sidebars.json | 1 - packages/core-plugin-api/package.json | 2 +- .../src/extensions/extensions.tsx | 8 +- .../src/plugin-options/index.ts | 2 +- .../plugin-options/usePluginOptions.test.tsx | 20 +++-- .../src/plugin-options/usePluginOptions.tsx | 15 ++-- .../core-plugin-api/src/plugin/Plugin.tsx | 10 +-- packages/core-plugin-api/src/plugin/types.ts | 5 +- plugins/catalog-customized/package.json | 2 +- plugins/catalog-customized/src/plugin.ts | 12 +-- .../CatalogPage/DefaultCatalogPage.tsx | 15 ++-- plugins/catalog/src/{types.ts => options.ts} | 11 +-- plugins/catalog/src/plugin.ts | 12 +-- yarn.lock | 73 +++++++++++++++++++ 14 files changed, 118 insertions(+), 70 deletions(-) rename plugins/catalog/src/{types.ts => options.ts} (64%) diff --git a/microsite/sidebars.json b/microsite/sidebars.json index bfe1b9c6e9..29fb3a0534 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -212,7 +212,6 @@ "plugins/structure-of-a-plugin", "plugins/integrating-plugin-into-software-catalog", "plugins/integrating-search-into-plugins", - "plugins/customization", "plugins/composability", "plugins/analytics", { diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 7a5d7f2138..148020b409 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -24,7 +24,7 @@ "main": "src/index.ts", "types": "src/index.ts", "scripts": { - "build": "backstage-cli package build", + "build": "backstage-cli package build --experimental-type-build", "lint": "backstage-cli package lint", "test": "backstage-cli package test", "prepack": "backstage-cli package prepack", diff --git a/packages/core-plugin-api/src/extensions/extensions.tsx b/packages/core-plugin-api/src/extensions/extensions.tsx index c0d54af2c1..149ea1f520 100644 --- a/packages/core-plugin-api/src/extensions/extensions.tsx +++ b/packages/core-plugin-api/src/extensions/extensions.tsx @@ -21,7 +21,7 @@ import { RouteRef, useRouteRef } from '../routing'; import { attachComponentData } from './componentData'; import { Extension, BackstagePlugin } from '../plugin'; import { PluginErrorBoundary } from './PluginErrorBoundary'; -import { PluginOptionsProvider } from '../plugin-options'; +import { PluginProvider } from '../plugin-options'; /** * Lazy or synchronous retrieving of extension components. @@ -246,11 +246,9 @@ export function createReactExtension< ...(mountPoint && { routeRef: mountPoint.id }), }} > - + - +
diff --git a/packages/core-plugin-api/src/plugin-options/index.ts b/packages/core-plugin-api/src/plugin-options/index.ts index 83901f526a..937cf49032 100644 --- a/packages/core-plugin-api/src/plugin-options/index.ts +++ b/packages/core-plugin-api/src/plugin-options/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { usePluginOptions, PluginOptionsProvider } from './usePluginOptions'; +export { usePluginOptions, PluginProvider } from './usePluginOptions'; diff --git a/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx b/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx index ea4c1d383e..268e191cec 100644 --- a/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx +++ b/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx @@ -16,21 +16,27 @@ import React from 'react'; import { renderHook } from '@testing-library/react-hooks'; -import { usePluginOptions, PluginOptionsProvider } from './usePluginOptions'; +import { usePluginOptions, PluginProvider } from './usePluginOptions'; +import { createPlugin, PluginOptions } from '../plugin'; describe('usePluginOptions', () => { it('should provide a versioned value to hook', () => { + const plugin = createPlugin({ + id: 'my-plugin', + options: { 'key-1': 'value-1', 'key-2': 'value-2' }, + }); + const rendered = renderHook(() => usePluginOptions(), { wrapper: ({ children }) => ( - - {children} - + {children} ), }); - expect(rendered.result.current).toEqual({ + const config = rendered.result.current.config as unknown as { + options: PluginOptions; + }; + + expect(config.options).toEqual({ 'key-1': 'value-1', 'key-2': 'value-2', }); diff --git a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx index 1e667e09ea..fc136e960d 100644 --- a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx +++ b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx @@ -19,7 +19,7 @@ import { createVersionedValueMap, useVersionedContext, } from '@backstage/version-bridge'; -import { PluginOptions } from '../plugin'; +import { BackstagePlugin, PluginOptions } from '../plugin'; import React, { ReactNode } from 'react'; const contextKey: string = 'plugin-options-context'; @@ -31,14 +31,17 @@ const contextKey: string = 'plugin-options-context'; */ export interface PluginOptionsProviderProps { children: ReactNode; - pluginOptions?: PluginOptions; + plugin?: BackstagePlugin; } -export const PluginOptionsProvider = ({ +export const PluginProvider = ({ children, - pluginOptions, + plugin, }: PluginOptionsProviderProps): JSX.Element => { - const value = { pluginOptions }; + const providerPlugin = plugin as unknown as { + getPluginOptions(): PluginOptions; + }; + const value = { pluginOptions: providerPlugin.getPluginOptions() }; const { Provider } = createVersionedContext<{ 1: PluginOptions }>(contextKey); return ( @@ -51,7 +54,7 @@ export const PluginOptionsProvider = ({ * Grab the current entity from the context, throws if the entity has not yet been loaded * or is not available. * - * @public + * @alpha */ export function usePluginOptions< TPluginOptions extends PluginOptions = PluginOptions, diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index fb2f304b46..a99885cfe8 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -60,15 +60,15 @@ export class PluginImpl< return extension.expose(this); } - reconfigure(options: PluginInputOptions): void { - if (this.config.configure) { - this.config.options = this.config.configure(options); + __experimentalReconfigure(options: PluginInputOptions): void { + if (this.config.__experimentalConfigure) { + this.config.options = this.config.__experimentalConfigure(options); } } getPluginOptions(): PluginOptions { - if (this.config.configure && !this.config.options) { - this.config.options = this.config.configure(); + if (this.config.__experimentalConfigure && !this.config.options) { + this.config.options = this.config.__experimentalConfigure(); } return this.config.options ?? ({} as PluginOptions); } diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index fa8778ce93..4dbb9e0e41 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -68,10 +68,9 @@ export type BackstagePlugin< */ getFeatureFlags(): Iterable; provide(extension: Extension): T; - getPluginOptions(): PluginOptions; - reconfigure(options: PluginInputOptions): void; routes: Routes; externalRoutes: ExternalRoutes; + __experimentalReconfigure(options: PluginInputOptions): void; }; /** @@ -99,7 +98,7 @@ export type PluginConfig< externalRoutes?: ExternalRoutes; featureFlags?: PluginFeatureFlagConfig[]; options?: PluginOptions; - configure?(options?: PluginInputOptions): PluginOptions; + __experimentalConfigure?(options?: PluginInputOptions): PluginOptions; }; /** diff --git a/plugins/catalog-customized/package.json b/plugins/catalog-customized/package.json index 4ffc82c2b0..1e1c2c14b5 100644 --- a/plugins/catalog-customized/package.json +++ b/plugins/catalog-customized/package.json @@ -34,7 +34,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/plugin-catalog": "^1.3.1-next.0", + "@backstage/plugin-catalog": "1.4.0-next.2", "@backstage/plugin-catalog-react": "^1.1.2-next.0" }, "peerDependencies": { diff --git a/plugins/catalog-customized/src/plugin.ts b/plugins/catalog-customized/src/plugin.ts index e46eb17192..e3830ee31c 100644 --- a/plugins/catalog-customized/src/plugin.ts +++ b/plugins/catalog-customized/src/plugin.ts @@ -16,18 +16,8 @@ import { catalogPlugin } from '@backstage/plugin-catalog'; -import { - EntityOwnerPicker, - EntityTypePicker, - UserListPicker, -} from './components'; - -catalogPlugin.reconfigure({ - EntityOwnerPicker, - EntityTypePicker, - UserListPicker, +catalogPlugin.__experimentalReconfigure({ createButtonTitle: 'Maybe Create', - showButtonText: 'Mine catalog entities', }); export const customizedCatalog = catalogPlugin; diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx index da31fa6726..f06bbc8acd 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -34,14 +34,17 @@ import { EntityLifecyclePicker, EntityListProvider, EntityProcessingStatusPicker, + EntityOwnerPicker, EntityTagPicker, + EntityTypePicker, UserListFilterKind, + UserListPicker, } from '@backstage/plugin-catalog-react'; import React from 'react'; import { createComponentRouteRef } from '../../routes'; import { CatalogTable, CatalogTableRow } from '../CatalogTable'; import { CatalogKindHeader } from '../CatalogKindHeader'; -import { CatalogPageOptionsProps } from '../../types'; +import { CatalogPluginOptions } from '../../options'; /** * Props for root catalog pages. @@ -68,13 +71,7 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { useApi(configApiRef).getOptionalString('organization.name') ?? 'Backstage'; const createComponentLink = useRouteRef(createComponentRouteRef); - const { - EntityOwnerPicker, - EntityTypePicker, - UserListPicker, - createButtonTitle, - showButtonText, - } = usePluginOptions(); + const { createButtonTitle } = usePluginOptions(); return ( @@ -87,7 +84,7 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { title={createButtonTitle} to={createComponentLink && createComponentLink()} /> - ${showButtonText} + All your software catalog entities diff --git a/plugins/catalog/src/types.ts b/plugins/catalog/src/options.ts similarity index 64% rename from plugins/catalog/src/types.ts rename to plugins/catalog/src/options.ts index 29997d1368..5b0e0767e3 100644 --- a/plugins/catalog/src/types.ts +++ b/plugins/catalog/src/options.ts @@ -14,15 +14,6 @@ * limitations under the License. */ -import { - EntityTypePickerProps, - UserListPickerProps, -} from '@backstage/plugin-catalog-react'; - -export type CatalogPageOptionsProps = { - EntityOwnerPicker: () => JSX.Element | null; - EntityTypePicker: (props: EntityTypePickerProps) => JSX.Element | null; - UserListPicker: (props: UserListPickerProps) => JSX.Element | null; +export type CatalogPluginOptions = { createButtonTitle: string; - showButtonText: string; }; diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index ce68fafcbc..1fd52a82a8 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -18,10 +18,7 @@ import { CatalogClient } from '@backstage/catalog-client'; import { Entity } from '@backstage/catalog-model'; import { catalogApiRef, - EntityOwnerPicker, entityRouteRef, - EntityTypePicker, - UserListPicker, starredEntitiesApiRef, } from '@backstage/plugin-catalog-react'; import { createComponentRouteRef, viewTechDocRouteRef } from './routes'; @@ -34,6 +31,7 @@ import { fetchApiRef, storageApiRef, PluginOptions, + PluginInputOptions, } from '@backstage/core-plugin-api'; import { DefaultStarredEntitiesApi } from './apis'; import { AboutCardProps } from './components/AboutCard'; @@ -48,8 +46,6 @@ import { HasSystemsCardProps } from './components/HasSystemsCard'; import { RelatedEntitiesCardProps } from './components/RelatedEntitiesCard'; import { rootRouteRef } from './routes'; -export interface PluginInputOptions {} - /** @public */ export const catalogPlugin = createPlugin({ id: 'catalog', @@ -78,13 +74,9 @@ export const catalogPlugin = createPlugin({ createComponent: createComponentRouteRef, viewTechDoc: viewTechDocRouteRef, }, - configure(options?: PluginInputOptions): PluginOptions { + __experimentalConfigure(options?: PluginInputOptions): PluginOptions { const defaultOptions = { - EntityOwnerPicker, - EntityTypePicker, - UserListPicker, createButtonTitle: 'Create', - showButtonText: 'All your software catalog entities', }; if (!options) { return defaultOptions; diff --git a/yarn.lock b/yarn.lock index 4393aedfb8..68e9a56a40 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1602,6 +1602,51 @@ zen-observable "^0.8.15" zod "^3.11.6" +"@backstage/core-components@^0.9.6-next.1": + version "0.9.6-next.1" + resolved "https://registry.npmjs.org/@backstage/core-components/-/core-components-0.9.6-next.1.tgz#52fc93339ee9f9adf11833fb6f54a6a2c7f6526e" + integrity sha512-TTNGzypjcDI7xAqSz+d3SLN7W2duHiOAebCiyoi38MHzHeQGjga7feBu0HuxEcXxfn8i6E0j3cdmZIlCIlcUXA== + dependencies: + "@backstage/config" "^1.0.1" + "@backstage/core-plugin-api" "^1.0.3" + "@backstage/errors" "^1.1.0-next.0" + "@backstage/theme" "^0.2.16-next.0" + "@backstage/version-bridge" "^1.0.1" + "@material-table/core" "^3.1.0" + "@material-ui/core" "^4.12.2" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.57" + "@react-hookz/web" "^14.0.0" + "@types/react-sparklines" "^1.7.0" + "@types/react-text-truncate" "^0.14.0" + ansi-regex "^6.0.1" + classnames "^2.2.6" + d3-selection "^3.0.0" + d3-shape "^3.0.0" + d3-zoom "^3.0.0" + dagre "^0.8.5" + history "^5.0.0" + immer "^9.0.1" + lodash "^4.17.21" + pluralize "^8.0.0" + prop-types "^15.7.2" + qs "^6.9.4" + rc-progress "3.3.3" + react-helmet "6.1.0" + react-hook-form "^7.12.2" + react-markdown "^8.0.0" + react-router "6.0.0-beta.0" + react-router-dom "6.0.0-beta.0" + react-sparklines "^1.7.0" + react-syntax-highlighter "^15.4.5" + react-text-truncate "^0.19.0" + react-use "^17.3.2" + react-virtualized-auto-sizer "^1.0.6" + react-window "^1.8.6" + remark-gfm "^3.0.1" + zen-observable "^0.8.15" + zod "^3.11.6" + "@backstage/errors@^1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@backstage/errors/-/errors-1.0.0.tgz#08ebf53afdeaca32362955ea8551e8ffa0bb3cd7" @@ -1677,6 +1722,33 @@ yaml "^1.10.0" zen-observable "^0.8.15" +"@backstage/plugin-catalog@^1.3.1-next.0": + version "1.3.1-next.1" + resolved "https://registry.npmjs.org/@backstage/plugin-catalog/-/plugin-catalog-1.3.1-next.1.tgz#c191a6bc8bbef485a40dffe0a1d0ab9114497be2" + integrity sha512-aPSpX33ZHdok0ruJg5k7BPQd28k4ARjPHwEQCNvAVXLRJHIeU63ZOgsQPQ/iWSutRJE/6seELnZ1a4tWSGYe6Q== + dependencies: + "@backstage/catalog-client" "^1.0.4-next.1" + "@backstage/catalog-model" "^1.1.0-next.1" + "@backstage/core-components" "^0.9.6-next.1" + "@backstage/core-plugin-api" "^1.0.3" + "@backstage/errors" "^1.1.0-next.0" + "@backstage/integration-react" "^1.1.2-next.1" + "@backstage/plugin-catalog-common" "^1.0.4-next.0" + "@backstage/plugin-catalog-react" "^1.1.2-next.1" + "@backstage/plugin-search-common" "^0.3.6-next.0" + "@backstage/plugin-search-react" "^0.2.2-next.1" + "@backstage/theme" "^0.2.16-next.0" + "@backstage/types" "^1.0.0" + "@material-ui/core" "^4.12.2" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.57" + history "^5.0.0" + lodash "^4.17.21" + react-helmet "6.1.0" + react-router "6.0.0-beta.0" + react-use "^17.2.4" + zen-observable "^0.8.15" + "@backstage/plugin-home@^0.4.19", "@backstage/plugin-home@^0.4.22": version "0.4.22" resolved "https://registry.npmjs.org/@backstage/plugin-home/-/plugin-home-0.4.22.tgz#efc54ebffb83a2a36dcd43e65142c30be5d8559d" @@ -12690,6 +12762,7 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: "@backstage/plugin-todo" "^0.2.9-next.2" "@backstage/plugin-user-settings" "^0.4.6-next.2" "@backstage/theme" "^0.2.16-next.1" + "@internal/plugin-catalog-customized" "1.2.1-next.1" "@material-ui/core" "^4.12.2" "@material-ui/icons" "^4.9.1" "@material-ui/lab" "4.0.0-alpha.57" From 5c782900e3ab95a3e79db61b39fc6a991274c991 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Wed, 6 Jul 2022 13:16:49 +0200 Subject: [PATCH 23/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- .../src/plugin-options/usePluginOptions.test.tsx | 12 ++++++------ packages/core-plugin-api/src/plugin/Plugin.tsx | 10 ++++++---- packages/core-plugin-api/src/plugin/types.ts | 1 - 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx b/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx index 268e191cec..f9f1b6c67e 100644 --- a/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx +++ b/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx @@ -17,13 +17,15 @@ import React from 'react'; import { renderHook } from '@testing-library/react-hooks'; import { usePluginOptions, PluginProvider } from './usePluginOptions'; -import { createPlugin, PluginOptions } from '../plugin'; +import { createPlugin, PluginInputOptions, PluginOptions } from '../plugin'; describe('usePluginOptions', () => { it('should provide a versioned value to hook', () => { const plugin = createPlugin({ id: 'my-plugin', - options: { 'key-1': 'value-1', 'key-2': 'value-2' }, + __experimentalConfigure(_: PluginInputOptions): PluginOptions { + return { 'key-1': 'value-1', 'key-2': 'value-2' }; + }, }); const rendered = renderHook(() => usePluginOptions(), { @@ -32,11 +34,9 @@ describe('usePluginOptions', () => { ), }); - const config = rendered.result.current.config as unknown as { - options: PluginOptions; - }; + const config = rendered.result.current; - expect(config.options).toEqual({ + expect(config).toEqual({ 'key-1': 'value-1', 'key-2': 'value-2', }); diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index a99885cfe8..e78b6be01e 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -36,6 +36,8 @@ export class PluginImpl< { constructor(private readonly config: PluginConfig) {} + options: PluginOptions | undefined = undefined; + getId(): string { return this.config.id; } @@ -62,15 +64,15 @@ export class PluginImpl< __experimentalReconfigure(options: PluginInputOptions): void { if (this.config.__experimentalConfigure) { - this.config.options = this.config.__experimentalConfigure(options); + this.options = this.config.__experimentalConfigure(options); } } getPluginOptions(): PluginOptions { - if (this.config.__experimentalConfigure && !this.config.options) { - this.config.options = this.config.__experimentalConfigure(); + if (this.config.__experimentalConfigure && !this.options) { + this.options = this.config.__experimentalConfigure(); } - return this.config.options ?? ({} as PluginOptions); + return this.options ?? ({} as PluginOptions); } toString() { diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index 4dbb9e0e41..5daaa3e9f9 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -97,7 +97,6 @@ export type PluginConfig< routes?: Routes; externalRoutes?: ExternalRoutes; featureFlags?: PluginFeatureFlagConfig[]; - options?: PluginOptions; __experimentalConfigure?(options?: PluginInputOptions): PluginOptions; }; From 67550c6b99f50c795bc72ca28866397a0bce0616 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Wed, 6 Jul 2022 13:21:41 +0200 Subject: [PATCH 24/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- .../src/components/CatalogPage/DefaultCatalogPage.tsx | 11 +++-------- plugins/catalog/src/options.ts | 5 +++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx index f06bbc8acd..39c19d717a 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -23,12 +23,7 @@ import { TableColumn, TableProps, } from '@backstage/core-components'; -import { - configApiRef, - useApi, - usePluginOptions, - useRouteRef, -} from '@backstage/core-plugin-api'; +import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; import { CatalogFilterLayout, EntityLifecyclePicker, @@ -44,7 +39,7 @@ import React from 'react'; import { createComponentRouteRef } from '../../routes'; import { CatalogTable, CatalogTableRow } from '../CatalogTable'; import { CatalogKindHeader } from '../CatalogKindHeader'; -import { CatalogPluginOptions } from '../../options'; +import { useCatalogPluginOptions } from '../../options'; /** * Props for root catalog pages. @@ -71,7 +66,7 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { useApi(configApiRef).getOptionalString('organization.name') ?? 'Backstage'; const createComponentLink = useRouteRef(createComponentRouteRef); - const { createButtonTitle } = usePluginOptions(); + const { createButtonTitle } = useCatalogPluginOptions(); return ( diff --git a/plugins/catalog/src/options.ts b/plugins/catalog/src/options.ts index 5b0e0767e3..edf702ee0b 100644 --- a/plugins/catalog/src/options.ts +++ b/plugins/catalog/src/options.ts @@ -14,6 +14,11 @@ * limitations under the License. */ +import { usePluginOptions } from '@backstage/core-plugin-api'; + export type CatalogPluginOptions = { createButtonTitle: string; }; + +export const useCatalogPluginOptions = () => + usePluginOptions(); From c768e53c305ffb2625c3371219ba9b5b980360c6 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Wed, 6 Jul 2022 14:03:09 +0200 Subject: [PATCH 25/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- packages/app/src/App.tsx | 6 +- packages/core-plugin-api/package.json | 1 - .../src/plugin-options/usePluginOptions.tsx | 2 +- plugins/catalog-customized/src/components.tsx | 33 ---------- plugins/catalog-customized/src/index.ts | 63 +++++++++++++++++++ plugins/catalog-customized/src/plugin.ts | 2 +- 6 files changed, 67 insertions(+), 40 deletions(-) delete mode 100644 plugins/catalog-customized/src/components.tsx diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index dc004ef2fd..289af8d40f 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -35,14 +35,12 @@ import { } from '@backstage/core-components'; import { apiDocsPlugin, ApiExplorerPage } from '@backstage/plugin-api-docs'; import { AzurePullRequestsPage } from '@backstage/plugin-azure-devops'; + import { CatalogEntityPage, CatalogIndexPage, catalogPlugin, -} from '@backstage/plugin-catalog'; - -/* Uncomment this import to enable a customized version of a catalog */ -// import '@internal/plugin-catalog-customized'; +} from '@internal/plugin-catalog-customized'; import { CatalogGraphPage } from '@backstage/plugin-catalog-graph'; import { diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 148020b409..2203954f1b 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -37,7 +37,6 @@ "@backstage/types": "^1.0.0", "@backstage/version-bridge": "^1.0.1", "history": "^5.0.0", - "lodash": "^4.17.21", "prop-types": "^15.7.2", "react-router-dom": "6.0.0-beta.0", "zen-observable": "^0.8.15" diff --git a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx index fc136e960d..3970c8c133 100644 --- a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx +++ b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx @@ -22,7 +22,7 @@ import { import { BackstagePlugin, PluginOptions } from '../plugin'; import React, { ReactNode } from 'react'; -const contextKey: string = 'plugin-options-context'; +const contextKey: string = 'plugin-context'; /** * Properties for the AsyncEntityProvider component. diff --git a/plugins/catalog-customized/src/components.tsx b/plugins/catalog-customized/src/components.tsx deleted file mode 100644 index 9c9bd2e187..0000000000 --- a/plugins/catalog-customized/src/components.tsx +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React from 'react'; -import { - EntityTypePickerProps, - UserListPickerProps, -} from '@backstage/plugin-catalog-react'; - -export const EntityOwnerPicker = () => { - return
Customized entity owner picker
; -}; - -export const EntityTypePicker = (_: EntityTypePickerProps) => { - return
Customized entity type picker
; -}; - -export const UserListPicker = (_: UserListPickerProps) => { - return
Customized user lis picker
; -}; diff --git a/plugins/catalog-customized/src/index.ts b/plugins/catalog-customized/src/index.ts index 0ad4c9ff68..05678fc562 100644 --- a/plugins/catalog-customized/src/index.ts +++ b/plugins/catalog-customized/src/index.ts @@ -15,3 +15,66 @@ */ export { customizedCatalog } from './plugin'; + +export type { + AboutCardProps, + AboutContentProps, + AboutFieldProps, + BackstageOverrides, + CatalogTable, + CatalogTableProps, + CatalogTableRow, + CatalogKindHeaderProps, + CatalogSearchResultListItemProps, + DefaultCatalogPageProps, + DefaultStarredEntitiesApi, + DependencyOfComponentsCardProps, + DependsOnComponentsCardProps, + DependsOnResourcesCardProps, + EntityContextMenuClassKey, + EntityLayoutProps, + EntityLayoutRouteProps, + EntityLinksEmptyStateClassKey, + EntityListContainer, + EntityLinksCardProps, + EntityOrphanWarning, + EntityProcessingErrorsPanel, + EntitySwitch, + EntitySwitchCaseProps, + EntitySwitchProps, + hasCatalogProcessingErrors, + HasComponentsCardProps, + HasResourcesCardProps, + isKind, + isNamespace, + isComponentType, + isOrphan, + FilterContainer, + FilteredEntityLayout, + HasSubcomponentsCardProps, + HasSystemsCardProps, + PluginCatalogComponentsNameToClassKey, + RelatedEntitiesCardProps, + SystemDiagramCardClassKey, +} from '@backstage/plugin-catalog'; + +export { + AboutContent, + AboutField, + catalogPlugin, + CatalogEntityPage, + CatalogIndexPage, + CatalogKindHeader, + CatalogSearchResultListItem, + EntityAboutCard, + EntityDependencyOfComponentsCard, + EntityDependsOnComponentsCard, + EntityDependsOnResourcesCard, + EntityHasComponentsCard, + EntityHasResourcesCard, + EntityHasSubcomponentsCard, + EntityHasSystemsCard, + EntityLayout, + EntityLinksCard, + RelatedEntitiesCard, +} from '@backstage/plugin-catalog'; diff --git a/plugins/catalog-customized/src/plugin.ts b/plugins/catalog-customized/src/plugin.ts index e3830ee31c..82d89251a0 100644 --- a/plugins/catalog-customized/src/plugin.ts +++ b/plugins/catalog-customized/src/plugin.ts @@ -17,7 +17,7 @@ import { catalogPlugin } from '@backstage/plugin-catalog'; catalogPlugin.__experimentalReconfigure({ - createButtonTitle: 'Maybe Create', + createButtonTitle: 'New', }); export const customizedCatalog = catalogPlugin; From 7925bdf1098fd67fdd5fcbf4c2283a269a8a8d1c Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Wed, 6 Jul 2022 14:22:56 +0200 Subject: [PATCH 26/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- .../src/plugin-options/usePluginOptions.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx index 3970c8c133..499c4f10d3 100644 --- a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx +++ b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx @@ -38,13 +38,15 @@ export const PluginProvider = ({ children, plugin, }: PluginOptionsProviderProps): JSX.Element => { - const providerPlugin = plugin as unknown as { - getPluginOptions(): PluginOptions; - }; - const value = { pluginOptions: providerPlugin.getPluginOptions() }; const { Provider } = createVersionedContext<{ 1: PluginOptions }>(contextKey); return ( - + {children} ); @@ -72,5 +74,5 @@ export function usePluginOptions< throw new Error('Plugin Options v1 is not available'); } - return value.pluginOptions as TPluginOptions; + return value.options as TPluginOptions; } From ec7c578c795bf40901e5169e6dec3c6ee6a44ae0 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Wed, 6 Jul 2022 17:22:57 +0200 Subject: [PATCH 27/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- packages/app-defaults/src/createApp.tsx | 2 +- packages/core-app-api/src/app/AppManager.tsx | 12 +++---- packages/core-app-api/src/app/types.ts | 4 +-- .../core-app-api/src/plugins/collectors.ts | 4 +-- .../core-app-api/src/routing/validation.ts | 2 +- .../src/extensions/extensions.tsx | 2 +- .../plugin-options/usePluginOptions.test.tsx | 13 +++++-- .../src/plugin-options/usePluginOptions.tsx | 16 ++++++--- .../core-plugin-api/src/plugin/Plugin.tsx | 34 ++++++++++++++----- packages/core-plugin-api/src/plugin/index.ts | 4 +-- packages/core-plugin-api/src/plugin/types.ts | 9 +++-- plugins/catalog/src/options.ts | 4 +++ plugins/catalog/src/plugin.ts | 7 ++-- 13 files changed, 76 insertions(+), 37 deletions(-) diff --git a/packages/app-defaults/src/createApp.tsx b/packages/app-defaults/src/createApp.tsx index d85dfa04eb..05e048ffca 100644 --- a/packages/app-defaults/src/createApp.tsx +++ b/packages/app-defaults/src/createApp.tsx @@ -50,7 +50,7 @@ export function createApp( ...icons, ...options?.icons, }, - plugins: (options?.plugins as BackstagePlugin[]) ?? [], + plugins: (options?.plugins as BackstagePlugin[]) ?? [], themes: options?.themes ?? themes, }); } diff --git a/packages/core-app-api/src/app/AppManager.tsx b/packages/core-app-api/src/app/AppManager.tsx index f47ddf676a..130d961312 100644 --- a/packages/core-app-api/src/app/AppManager.tsx +++ b/packages/core-app-api/src/app/AppManager.tsx @@ -82,8 +82,8 @@ import { resolveRouteBindings } from './resolveRouteBindings'; import { BackstageRouteObject } from '../routing/types'; type CompatiblePlugin = - | BackstagePlugin - | (Omit, 'getFeatureFlags'> & { + | BackstagePlugin + | (Omit, '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[] { + getPlugins(): BackstagePlugin[] { return this.app.getPlugins(); } @@ -186,8 +186,8 @@ export class AppManager implements BackstageApp { this.apiFactoryRegistry = new ApiFactoryRegistry(); } - getPlugins(): BackstagePlugin[] { - return Array.from(this.plugins) as BackstagePlugin[]; + getPlugins(): BackstagePlugin[] { + return Array.from(this.plugins) as BackstagePlugin[]; } 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>, + this.plugins as Iterable>, ); } diff --git a/packages/core-app-api/src/app/types.ts b/packages/core-app-api/src/app/types.ts index ff7a43d0eb..e7436dbf0a 100644 --- a/packages/core-app-api/src/app/types.ts +++ b/packages/core-app-api/src/app/types.ts @@ -291,7 +291,7 @@ export type BackstageApp = { /** * Returns all plugins registered for the app. */ - getPlugins(): BackstagePlugin[]; + getPlugins(): BackstagePlugin[]; /** * 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[]; + getPlugins(): BackstagePlugin[]; /** * Get a common or custom icon for this app. diff --git a/packages/core-app-api/src/plugins/collectors.ts b/packages/core-app-api/src/plugins/collectors.ts index 0f8b65ad62..376a8b709c 100644 --- a/packages/core-app-api/src/plugins/collectors.ts +++ b/packages/core-app-api/src/plugins/collectors.ts @@ -18,9 +18,9 @@ import { BackstagePlugin, getComponentData } from '@backstage/core-plugin-api'; import { createCollector } from '../extensions/traversal'; export const pluginCollector = createCollector( - () => new Set>(), + () => new Set>(), (acc, node) => { - const plugin = getComponentData>( + const plugin = getComponentData>( node, 'core.plugin', ); diff --git a/packages/core-app-api/src/routing/validation.ts b/packages/core-app-api/src/routing/validation.ts index c5d3e4aca9..2e0093eaab 100644 --- a/packages/core-app-api/src/routing/validation.ts +++ b/packages/core-app-api/src/routing/validation.ts @@ -65,7 +65,7 @@ export function validateRouteParameters( // Validates that all non-optional external routes have been bound export function validateRouteBindings( routeBindings: Map, - plugins: Iterable>>, + plugins: Iterable>>, ) { for (const plugin of plugins) { if (!plugin.externalRoutes) { diff --git a/packages/core-plugin-api/src/extensions/extensions.tsx b/packages/core-plugin-api/src/extensions/extensions.tsx index 149ea1f520..1d84d55442 100644 --- a/packages/core-plugin-api/src/extensions/extensions.tsx +++ b/packages/core-plugin-api/src/extensions/extensions.tsx @@ -226,7 +226,7 @@ export function createReactExtension< 'Component'; return { - expose(plugin: BackstagePlugin) { + expose(plugin: BackstagePlugin) { const Result: any = (props: any) => { const app = useApp(); const { Progress } = app.getComponents(); diff --git a/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx b/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx index f9f1b6c67e..11bf85aafa 100644 --- a/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx +++ b/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx @@ -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' }; }, }); diff --git a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx index 499c4f10d3..5feda8234b 100644 --- a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx +++ b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx @@ -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 ( @@ -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; } diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index e78b6be01e..8c5153da99 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -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 +> implements BackstagePlugin { - constructor(private readonly config: PluginConfig) {} + 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, -): BackstagePlugin { + config: PluginConfig< + PluginInputOptions, + PluginOptions, + Routes, + ExternalRoutes + >, +): BackstagePlugin { return new PluginImpl(config); } diff --git a/packages/core-plugin-api/src/plugin/index.ts b/packages/core-plugin-api/src/plugin/index.ts index e433e5cc86..58fcec03aa 100644 --- a/packages/core-plugin-api/src/plugin/index.ts +++ b/packages/core-plugin-api/src/plugin/index.ts @@ -18,8 +18,8 @@ export { createPlugin } from './Plugin'; export type { AnyExternalRoutes, - PluginOptions, - PluginInputOptions, + AnyPluginOptions, + AnyPluginInputOptions, AnyRoutes, BackstagePlugin, Extension, diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index 5daaa3e9f9..56e0845706 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -27,7 +27,7 @@ import { AnyApiFactory } from '../apis'; * @public */ export type Extension = { - expose(plugin: BackstagePlugin): T; + expose(plugin: BackstagePlugin): 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, > = { diff --git a/plugins/catalog/src/options.ts b/plugins/catalog/src/options.ts index edf702ee0b..1d8b972ec2 100644 --- a/plugins/catalog/src/options.ts +++ b/plugins/catalog/src/options.ts @@ -20,5 +20,9 @@ export type CatalogPluginOptions = { createButtonTitle: string; }; +export type CatalogInputPluginOptions = { + createButtonTitle: string; +}; + export const useCatalogPluginOptions = () => usePluginOptions(); diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index 1fd52a82a8..ec4a1b52e1 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -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', }; From a12f6189477c52209b0abf0da8a2576f9136dc90 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Wed, 6 Jul 2022 17:26:11 +0200 Subject: [PATCH 28/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- packages/app/src/App.tsx | 6 +-- plugins/catalog-customized/src/index.ts | 63 +------------------------ 2 files changed, 4 insertions(+), 65 deletions(-) diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 289af8d40f..2a6e542c75 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -39,7 +39,7 @@ import { AzurePullRequestsPage } from '@backstage/plugin-azure-devops'; import { CatalogEntityPage, CatalogIndexPage, - catalogPlugin, + customizedCatalog, } from '@internal/plugin-catalog-customized'; import { CatalogGraphPage } from '@backstage/plugin-catalog-graph'; @@ -121,7 +121,7 @@ const app = createApp({ }, }, bindRoutes({ bind }) { - bind(catalogPlugin.externalRoutes, { + bind(customizedCatalog.externalRoutes, { createComponent: scaffolderPlugin.routes.root, viewTechDoc: techdocsPlugin.routes.docRoot, }); @@ -132,7 +132,7 @@ const app = createApp({ registerComponent: catalogImportPlugin.routes.importPage, }); bind(orgPlugin.externalRoutes, { - catalogIndex: catalogPlugin.routes.catalogIndex, + catalogIndex: customizedCatalog.routes.catalogIndex, }); }, }); diff --git a/plugins/catalog-customized/src/index.ts b/plugins/catalog-customized/src/index.ts index 05678fc562..9c828cacfc 100644 --- a/plugins/catalog-customized/src/index.ts +++ b/plugins/catalog-customized/src/index.ts @@ -16,65 +16,4 @@ export { customizedCatalog } from './plugin'; -export type { - AboutCardProps, - AboutContentProps, - AboutFieldProps, - BackstageOverrides, - CatalogTable, - CatalogTableProps, - CatalogTableRow, - CatalogKindHeaderProps, - CatalogSearchResultListItemProps, - DefaultCatalogPageProps, - DefaultStarredEntitiesApi, - DependencyOfComponentsCardProps, - DependsOnComponentsCardProps, - DependsOnResourcesCardProps, - EntityContextMenuClassKey, - EntityLayoutProps, - EntityLayoutRouteProps, - EntityLinksEmptyStateClassKey, - EntityListContainer, - EntityLinksCardProps, - EntityOrphanWarning, - EntityProcessingErrorsPanel, - EntitySwitch, - EntitySwitchCaseProps, - EntitySwitchProps, - hasCatalogProcessingErrors, - HasComponentsCardProps, - HasResourcesCardProps, - isKind, - isNamespace, - isComponentType, - isOrphan, - FilterContainer, - FilteredEntityLayout, - HasSubcomponentsCardProps, - HasSystemsCardProps, - PluginCatalogComponentsNameToClassKey, - RelatedEntitiesCardProps, - SystemDiagramCardClassKey, -} from '@backstage/plugin-catalog'; - -export { - AboutContent, - AboutField, - catalogPlugin, - CatalogEntityPage, - CatalogIndexPage, - CatalogKindHeader, - CatalogSearchResultListItem, - EntityAboutCard, - EntityDependencyOfComponentsCard, - EntityDependsOnComponentsCard, - EntityDependsOnResourcesCard, - EntityHasComponentsCard, - EntityHasResourcesCard, - EntityHasSubcomponentsCard, - EntityHasSystemsCard, - EntityLayout, - EntityLinksCard, - RelatedEntitiesCard, -} from '@backstage/plugin-catalog'; +export { CatalogEntityPage, CatalogIndexPage } from '@backstage/plugin-catalog'; From c3837441c83b595dc3f352de4239acf97be1530c Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Wed, 6 Jul 2022 20:01:09 +0200 Subject: [PATCH 29/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- .../src/plugin-options/usePluginOptions.tsx | 23 +++++++++++-------- .../core-plugin-api/src/plugin/Plugin.tsx | 16 ++++++------- packages/core-plugin-api/src/plugin/index.ts | 2 -- packages/core-plugin-api/src/plugin/types.ts | 14 +++-------- 4 files changed, 23 insertions(+), 32 deletions(-) diff --git a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx index 5feda8234b..55e2c28701 100644 --- a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx +++ b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx @@ -19,13 +19,13 @@ import { createVersionedValueMap, useVersionedContext, } from '@backstage/version-bridge'; -import { BackstagePlugin, AnyPluginOptions } from '../plugin'; +import { BackstagePlugin } from '../plugin'; import React, { ReactNode } from 'react'; const contextKey: string = 'plugin-context'; /** - * Properties for the AsyncEntityProvider component. + * Properties for the PluginProvider component. * * @public */ @@ -38,14 +38,15 @@ export const PluginProvider = ({ children, plugin, }: PluginOptionsProviderProps): JSX.Element => { - const { Provider } = createVersionedContext<{ 1: AnyPluginOptions }>( - contextKey, - ); + const { Provider } = createVersionedContext<{ + 1: { plugin: BackstagePlugin | undefined }; + }>(contextKey); + return ( @@ -61,7 +62,7 @@ export const PluginProvider = ({ * @alpha */ export function usePluginOptions< - TPluginOptions extends AnyPluginOptions = AnyPluginOptions, + TPluginOptions extends {} = {}, >(): TPluginOptions { const versionedHolder = useVersionedContext<{ 1: TPluginOptions }>( contextKey, @@ -78,7 +79,9 @@ export function usePluginOptions< return ( value as unknown as { - getPluginOptions(): AnyPluginOptions; + plugin: { + getPluginOptions(): {}; + }; } - ).getPluginOptions() as TPluginOptions; + ).plugin.getPluginOptions() as TPluginOptions; } diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index 8c5153da99..6c5963d3f0 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -20,8 +20,6 @@ import { Extension, AnyRoutes, AnyExternalRoutes, - AnyPluginOptions, - AnyPluginInputOptions, PluginFeatureFlagConfig, } from './types'; import { AnyApiFactory } from '../apis'; @@ -30,8 +28,8 @@ import { AnyApiFactory } from '../apis'; * @internal */ export class PluginImpl< - PluginInputOptions extends AnyPluginInputOptions, - PluginOptions extends AnyPluginOptions, + PluginInputOptions extends {}, + PluginOptions extends {}, Routes extends AnyRoutes, ExternalRoutes extends AnyExternalRoutes, > implements BackstagePlugin @@ -45,7 +43,7 @@ export class PluginImpl< >, ) {} - options: AnyPluginOptions | undefined = undefined; + options: {} | undefined = undefined; getId(): string { return this.config.id; @@ -77,11 +75,11 @@ export class PluginImpl< } } - getPluginOptions(): AnyPluginOptions { + getPluginOptions(): {} { if (this.config.__experimentalConfigure && !this.options) { this.options = this.config.__experimentalConfigure(); } - return this.options ?? ({} as AnyPluginOptions); + return this.options ?? {}; } toString() { @@ -96,8 +94,8 @@ export class PluginImpl< * @public */ export function createPlugin< - PluginInputOptions extends AnyPluginInputOptions = {}, - PluginOptions extends AnyPluginInputOptions = {}, + PluginInputOptions extends {}, + PluginOptions extends {}, Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, >( diff --git a/packages/core-plugin-api/src/plugin/index.ts b/packages/core-plugin-api/src/plugin/index.ts index 58fcec03aa..7d088ef823 100644 --- a/packages/core-plugin-api/src/plugin/index.ts +++ b/packages/core-plugin-api/src/plugin/index.ts @@ -18,8 +18,6 @@ export { createPlugin } from './Plugin'; export type { AnyExternalRoutes, - AnyPluginOptions, - AnyPluginInputOptions, AnyRoutes, BackstagePlugin, Extension, diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index 56e0845706..51e75ff416 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -44,21 +44,13 @@ export type AnyRoutes = { [name: string]: RouteRef | SubRouteRef }; */ export type AnyExternalRoutes = { [name: string]: ExternalRouteRef }; -/** - * Catch-all metadata type. - * - * @public - */ -export type AnyPluginOptions = { [name: string]: unknown }; -export type AnyPluginInputOptions = { [name: string]: unknown }; - /** * Plugin type. * * @public */ export type BackstagePlugin< - PluginInputOptions extends AnyPluginInputOptions = {}, + PluginInputOptions extends {} = {}, Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, > = { @@ -90,8 +82,8 @@ export type PluginFeatureFlagConfig = { * @public */ export type PluginConfig< - PluginInputOptions extends AnyPluginInputOptions, - PluginOptions extends AnyPluginOptions, + PluginInputOptions extends {}, + PluginOptions extends {}, Routes extends AnyRoutes, ExternalRoutes extends AnyExternalRoutes, > = { From 7bdb043b970f176b8feea92f5ee2ac920090579c Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Wed, 6 Jul 2022 21:05:54 +0200 Subject: [PATCH 30/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- plugins/catalog/src/plugin.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index ec4a1b52e1..5419854cb6 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -79,9 +79,6 @@ export const catalogPlugin = createPlugin({ const defaultOptions = { createButtonTitle: 'Create', }; - if (!options) { - return defaultOptions; - } return { ...defaultOptions, ...options }; }, }); From 923b72c0ff60a1b146af12571de3a32cfb7bffe9 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Wed, 6 Jul 2022 21:11:49 +0200 Subject: [PATCH 31/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- packages/app/src/App.tsx | 6 +++--- plugins/catalog-customized/src/index.ts | 4 +--- plugins/catalog-customized/src/plugin.ts | 2 -- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 2a6e542c75..289af8d40f 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -39,7 +39,7 @@ import { AzurePullRequestsPage } from '@backstage/plugin-azure-devops'; import { CatalogEntityPage, CatalogIndexPage, - customizedCatalog, + catalogPlugin, } from '@internal/plugin-catalog-customized'; import { CatalogGraphPage } from '@backstage/plugin-catalog-graph'; @@ -121,7 +121,7 @@ const app = createApp({ }, }, bindRoutes({ bind }) { - bind(customizedCatalog.externalRoutes, { + bind(catalogPlugin.externalRoutes, { createComponent: scaffolderPlugin.routes.root, viewTechDoc: techdocsPlugin.routes.docRoot, }); @@ -132,7 +132,7 @@ const app = createApp({ registerComponent: catalogImportPlugin.routes.importPage, }); bind(orgPlugin.externalRoutes, { - catalogIndex: customizedCatalog.routes.catalogIndex, + catalogIndex: catalogPlugin.routes.catalogIndex, }); }, }); diff --git a/plugins/catalog-customized/src/index.ts b/plugins/catalog-customized/src/index.ts index 9c828cacfc..095842e9ac 100644 --- a/plugins/catalog-customized/src/index.ts +++ b/plugins/catalog-customized/src/index.ts @@ -14,6 +14,4 @@ * limitations under the License. */ -export { customizedCatalog } from './plugin'; - -export { CatalogEntityPage, CatalogIndexPage } from '@backstage/plugin-catalog'; +export * from '@backstage/plugin-catalog'; diff --git a/plugins/catalog-customized/src/plugin.ts b/plugins/catalog-customized/src/plugin.ts index 82d89251a0..bc11fc64d1 100644 --- a/plugins/catalog-customized/src/plugin.ts +++ b/plugins/catalog-customized/src/plugin.ts @@ -19,5 +19,3 @@ import { catalogPlugin } from '@backstage/plugin-catalog'; catalogPlugin.__experimentalReconfigure({ createButtonTitle: 'New', }); - -export const customizedCatalog = catalogPlugin; From 4c638cf05bb905cde395b71a9529c9b44edc56dd Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Thu, 7 Jul 2022 09:37:10 +0200 Subject: [PATCH 32/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- packages/core-plugin-api/src/plugin/Plugin.tsx | 10 +--------- packages/core-plugin-api/src/plugin/types.ts | 3 +-- plugins/catalog-customized/src/index.ts | 1 + 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index 6c5963d3f0..f081d03fa5 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -29,7 +29,6 @@ import { AnyApiFactory } from '../apis'; */ export class PluginImpl< PluginInputOptions extends {}, - PluginOptions extends {}, Routes extends AnyRoutes, ExternalRoutes extends AnyExternalRoutes, > implements BackstagePlugin @@ -37,7 +36,6 @@ export class PluginImpl< constructor( private readonly config: PluginConfig< PluginInputOptions, - PluginOptions, Routes, ExternalRoutes >, @@ -95,16 +93,10 @@ export class PluginImpl< */ export function createPlugin< PluginInputOptions extends {}, - PluginOptions extends {}, Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, >( - config: PluginConfig< - PluginInputOptions, - PluginOptions, - Routes, - ExternalRoutes - >, + config: PluginConfig, ): BackstagePlugin { return new PluginImpl(config); } diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index 51e75ff416..eee38465cc 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -83,7 +83,6 @@ export type PluginFeatureFlagConfig = { */ export type PluginConfig< PluginInputOptions extends {}, - PluginOptions extends {}, Routes extends AnyRoutes, ExternalRoutes extends AnyExternalRoutes, > = { @@ -92,7 +91,7 @@ export type PluginConfig< routes?: Routes; externalRoutes?: ExternalRoutes; featureFlags?: PluginFeatureFlagConfig[]; - __experimentalConfigure?(options?: PluginInputOptions): PluginOptions; + __experimentalConfigure?(options?: PluginInputOptions): {}; }; /** diff --git a/plugins/catalog-customized/src/index.ts b/plugins/catalog-customized/src/index.ts index 095842e9ac..cc8aefeaa6 100644 --- a/plugins/catalog-customized/src/index.ts +++ b/plugins/catalog-customized/src/index.ts @@ -13,5 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import './plugin'; export * from '@backstage/plugin-catalog'; From 6f4678a285304f596153ed20c79615f29155aa09 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Thu, 7 Jul 2022 10:10:22 +0200 Subject: [PATCH 33/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- packages/core-app-api/src/routing/validation.ts | 2 +- packages/core-plugin-api/src/plugin/Plugin.tsx | 14 +++++++------- packages/core-plugin-api/src/plugin/types.ts | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/core-app-api/src/routing/validation.ts b/packages/core-app-api/src/routing/validation.ts index 2e0093eaab..c5d3e4aca9 100644 --- a/packages/core-app-api/src/routing/validation.ts +++ b/packages/core-app-api/src/routing/validation.ts @@ -65,7 +65,7 @@ export function validateRouteParameters( // Validates that all non-optional external routes have been bound export function validateRouteBindings( routeBindings: Map, - plugins: Iterable>>, + plugins: Iterable>>, ) { for (const plugin of plugins) { if (!plugin.externalRoutes) { diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index f081d03fa5..4e042ab0ba 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -28,16 +28,16 @@ import { AnyApiFactory } from '../apis'; * @internal */ export class PluginImpl< - PluginInputOptions extends {}, Routes extends AnyRoutes, ExternalRoutes extends AnyExternalRoutes, -> implements BackstagePlugin + PluginInputOptions extends {}, +> implements BackstagePlugin { constructor( private readonly config: PluginConfig< - PluginInputOptions, Routes, - ExternalRoutes + ExternalRoutes, + PluginInputOptions >, ) {} @@ -92,11 +92,11 @@ export class PluginImpl< * @public */ export function createPlugin< - PluginInputOptions extends {}, Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, + PluginInputOptions extends {} = {}, >( - config: PluginConfig, -): BackstagePlugin { + config: PluginConfig, +): BackstagePlugin { return new PluginImpl(config); } diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index eee38465cc..5d5362ad07 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -50,9 +50,9 @@ export type AnyExternalRoutes = { [name: string]: ExternalRouteRef }; * @public */ export type BackstagePlugin< - PluginInputOptions extends {} = {}, Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, + PluginInputOptions extends {} = {}, > = { getId(): string; getApis(): Iterable; @@ -82,9 +82,9 @@ export type PluginFeatureFlagConfig = { * @public */ export type PluginConfig< - PluginInputOptions extends {}, Routes extends AnyRoutes, ExternalRoutes extends AnyExternalRoutes, + PluginInputOptions extends {}, > = { id: string; apis?: Iterable; From 68209b33fd219104e1d559280d95cb0edea8c483 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Thu, 7 Jul 2022 10:38:37 +0200 Subject: [PATCH 34/54] Updated the customization.md Signed-off-by: bnechyporenko --- docs/plugins/customization.md | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/docs/plugins/customization.md b/docs/plugins/customization.md index e9a92d1021..0477ba18a7 100644 --- a/docs/plugins/customization.md +++ b/docs/plugins/customization.md @@ -18,11 +18,12 @@ customizable elements. For example ```typescript jsx const plugin = createPlugin({ id: 'my-plugin', - configure(options?: PluginInputOptions): PluginOptions { - const defaultOptions = { createButtonTitle: 'Create' }; - if (!options) { - return defaultOptions; - } + __experimentalConfigure( + options?: CatalogInputPluginOptions, + ): CatalogPluginOptions { + const defaultOptions = { + createButtonTitle: 'Create', + }; return { ...defaultOptions, ...options }; }, }); @@ -31,12 +32,19 @@ const plugin = createPlugin({ And the rendering part of the exposed component can retrieve that metadata as: ```typescript jsx -export type CatalogPageOptionsProps = { +export type CatalogPluginOptions = { createButtonTitle: string; }; +export type CatalogInputPluginOptions = { + createButtonTitle: string; +}; + +export const useCatalogPluginOptions = () => + usePluginOptions(); + export function DefaultMyPluginWelcomePage() { - const { createButtonTitle } = usePluginOptions(); + const { createButtonTitle } = useCatalogPluginOptions(); return (
@@ -54,7 +62,7 @@ plugin. Example: ```typescript jsx import { myPlugin } from '@backstage/my-plugin'; -myPlugin.reconfigure({ - createButtonTitle: 'Maybe Create', +myPlugin.__experimentalReconfigure({ + createButtonTitle: 'New', }); ``` From dddcedbf2e3a9f143dabe1bc59ee91ae780ef862 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Thu, 7 Jul 2022 12:47:47 +0200 Subject: [PATCH 35/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- .changeset/fast-walls-carry.md | 4 +- packages/app/package.json | 3 +- .../core-plugin-api/src/plugin/Plugin.tsx | 2 +- plugins/catalog-customized/package.json | 6 +- yarn.lock | 75 +------------------ 5 files changed, 8 insertions(+), 82 deletions(-) diff --git a/.changeset/fast-walls-carry.md b/.changeset/fast-walls-carry.md index edf03a9c60..4126bf3d2d 100644 --- a/.changeset/fast-walls-carry.md +++ b/.changeset/fast-walls-carry.md @@ -1,7 +1,7 @@ --- -'@backstage/core-plugin-api': patch +'@internal/plugin-catalog-customized': patch --- -Introduced an optional metadata for the components, which can contain a configurable data. +Introduced plugin options for the components, to be able to customise existing components. The author of the component might define the configurable places of the component, and the user of this component can reconfigure it if necessary. diff --git a/packages/app/package.json b/packages/app/package.json index 35f3925d54..7a308cc129 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -20,7 +20,6 @@ "@backstage/plugin-azure-devops": "^0.1.23-next.2", "@backstage/plugin-apache-airflow": "^0.2.0-next.2", "@backstage/plugin-badges": "^0.2.31-next.2", - "@backstage/plugin-catalog": "^1.4.0-next.2", "@backstage/plugin-catalog-common": "^1.0.4-next.0", "@backstage/plugin-catalog-graph": "^0.2.19-next.2", "@backstage/plugin-catalog-import": "^0.8.10-next.2", @@ -70,7 +69,7 @@ "@roadiehq/backstage-plugin-github-insights": "^2.0.0", "@roadiehq/backstage-plugin-github-pull-requests": "^2.0.0", "@roadiehq/backstage-plugin-travis-ci": "^2.0.0", - "@internal/plugin-catalog-customized": "1.2.1-next.1", + "@internal/plugin-catalog-customized": "0.0.0", "history": "^5.0.0", "prop-types": "^15.7.2", "react": "^17.0.2", diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index 4e042ab0ba..da26cd4db0 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -41,7 +41,7 @@ export class PluginImpl< >, ) {} - options: {} | undefined = undefined; + private options: {} | undefined = undefined; getId(): string { return this.config.id; diff --git a/plugins/catalog-customized/package.json b/plugins/catalog-customized/package.json index 1e1c2c14b5..b6cc66b3b1 100644 --- a/plugins/catalog-customized/package.json +++ b/plugins/catalog-customized/package.json @@ -1,11 +1,11 @@ { "name": "@internal/plugin-catalog-customized", "description": "The internal Backstage Customizable plugin for browsing the Backstage catalog", - "version": "1.2.1-next.1", + "version": "0.0.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", - "private": false, + "private": true, "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -35,7 +35,7 @@ }, "dependencies": { "@backstage/plugin-catalog": "1.4.0-next.2", - "@backstage/plugin-catalog-react": "^1.1.2-next.0" + "@backstage/plugin-catalog-react": "^1.1.2-next.2" }, "peerDependencies": { "@types/react": "^16.13.1 || ^17.0.0", diff --git a/yarn.lock b/yarn.lock index 68e9a56a40..fa5d2c0620 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1602,51 +1602,6 @@ zen-observable "^0.8.15" zod "^3.11.6" -"@backstage/core-components@^0.9.6-next.1": - version "0.9.6-next.1" - resolved "https://registry.npmjs.org/@backstage/core-components/-/core-components-0.9.6-next.1.tgz#52fc93339ee9f9adf11833fb6f54a6a2c7f6526e" - integrity sha512-TTNGzypjcDI7xAqSz+d3SLN7W2duHiOAebCiyoi38MHzHeQGjga7feBu0HuxEcXxfn8i6E0j3cdmZIlCIlcUXA== - dependencies: - "@backstage/config" "^1.0.1" - "@backstage/core-plugin-api" "^1.0.3" - "@backstage/errors" "^1.1.0-next.0" - "@backstage/theme" "^0.2.16-next.0" - "@backstage/version-bridge" "^1.0.1" - "@material-table/core" "^3.1.0" - "@material-ui/core" "^4.12.2" - "@material-ui/icons" "^4.9.1" - "@material-ui/lab" "4.0.0-alpha.57" - "@react-hookz/web" "^14.0.0" - "@types/react-sparklines" "^1.7.0" - "@types/react-text-truncate" "^0.14.0" - ansi-regex "^6.0.1" - classnames "^2.2.6" - d3-selection "^3.0.0" - d3-shape "^3.0.0" - d3-zoom "^3.0.0" - dagre "^0.8.5" - history "^5.0.0" - immer "^9.0.1" - lodash "^4.17.21" - pluralize "^8.0.0" - prop-types "^15.7.2" - qs "^6.9.4" - rc-progress "3.3.3" - react-helmet "6.1.0" - react-hook-form "^7.12.2" - react-markdown "^8.0.0" - react-router "6.0.0-beta.0" - react-router-dom "6.0.0-beta.0" - react-sparklines "^1.7.0" - react-syntax-highlighter "^15.4.5" - react-text-truncate "^0.19.0" - react-use "^17.3.2" - react-virtualized-auto-sizer "^1.0.6" - react-window "^1.8.6" - remark-gfm "^3.0.1" - zen-observable "^0.8.15" - zod "^3.11.6" - "@backstage/errors@^1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@backstage/errors/-/errors-1.0.0.tgz#08ebf53afdeaca32362955ea8551e8ffa0bb3cd7" @@ -1722,33 +1677,6 @@ yaml "^1.10.0" zen-observable "^0.8.15" -"@backstage/plugin-catalog@^1.3.1-next.0": - version "1.3.1-next.1" - resolved "https://registry.npmjs.org/@backstage/plugin-catalog/-/plugin-catalog-1.3.1-next.1.tgz#c191a6bc8bbef485a40dffe0a1d0ab9114497be2" - integrity sha512-aPSpX33ZHdok0ruJg5k7BPQd28k4ARjPHwEQCNvAVXLRJHIeU63ZOgsQPQ/iWSutRJE/6seELnZ1a4tWSGYe6Q== - dependencies: - "@backstage/catalog-client" "^1.0.4-next.1" - "@backstage/catalog-model" "^1.1.0-next.1" - "@backstage/core-components" "^0.9.6-next.1" - "@backstage/core-plugin-api" "^1.0.3" - "@backstage/errors" "^1.1.0-next.0" - "@backstage/integration-react" "^1.1.2-next.1" - "@backstage/plugin-catalog-common" "^1.0.4-next.0" - "@backstage/plugin-catalog-react" "^1.1.2-next.1" - "@backstage/plugin-search-common" "^0.3.6-next.0" - "@backstage/plugin-search-react" "^0.2.2-next.1" - "@backstage/theme" "^0.2.16-next.0" - "@backstage/types" "^1.0.0" - "@material-ui/core" "^4.12.2" - "@material-ui/icons" "^4.9.1" - "@material-ui/lab" "4.0.0-alpha.57" - history "^5.0.0" - lodash "^4.17.21" - react-helmet "6.1.0" - react-router "6.0.0-beta.0" - react-use "^17.2.4" - zen-observable "^0.8.15" - "@backstage/plugin-home@^0.4.19", "@backstage/plugin-home@^0.4.22": version "0.4.22" resolved "https://registry.npmjs.org/@backstage/plugin-home/-/plugin-home-0.4.22.tgz#efc54ebffb83a2a36dcd43e65142c30be5d8559d" @@ -12720,7 +12648,6 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: "@backstage/plugin-api-docs" "^0.8.7-next.2" "@backstage/plugin-azure-devops" "^0.1.23-next.2" "@backstage/plugin-badges" "^0.2.31-next.2" - "@backstage/plugin-catalog" "^1.4.0-next.2" "@backstage/plugin-catalog-common" "^1.0.4-next.0" "@backstage/plugin-catalog-graph" "^0.2.19-next.2" "@backstage/plugin-catalog-import" "^0.8.10-next.2" @@ -12762,7 +12689,7 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: "@backstage/plugin-todo" "^0.2.9-next.2" "@backstage/plugin-user-settings" "^0.4.6-next.2" "@backstage/theme" "^0.2.16-next.1" - "@internal/plugin-catalog-customized" "1.2.1-next.1" + "@internal/plugin-catalog-customized" "0.0.0" "@material-ui/core" "^4.12.2" "@material-ui/icons" "^4.9.1" "@material-ui/lab" "4.0.0-alpha.57" From 15a815276fa752aa114e2f2cbb1ce39241a47949 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Thu, 7 Jul 2022 13:22:45 +0200 Subject: [PATCH 36/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- .changeset/fast-walls-carry.md | 45 ++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/.changeset/fast-walls-carry.md b/.changeset/fast-walls-carry.md index 4126bf3d2d..fe8e81f4a0 100644 --- a/.changeset/fast-walls-carry.md +++ b/.changeset/fast-walls-carry.md @@ -5,3 +5,48 @@ Introduced plugin options for the components, to be able to customise existing components. The author of the component might define the configurable places of the component, and the user of this component can reconfigure it if necessary. + +--- + +## @backstage/app-defaults + +Introduced an extra parameter in BackstagePlugin. +This optional parameter is responsible for providing a type for input options for the plugin. + +--- + +## @backstage/core-app-api + +Introduced an extra parameter in BackstagePlugin. +This optional parameter is responsible for providing a type for input options for the plugin. + +--- + +## @backstage/core-plugin-api + +Introduced plugin options for the components, to be able to customise existing components. +Those customizations are stored in React context of the plugin. +The configurable options could be defined during the creation of the plugin via `__experimentalConfigure` method. +And the user of the plugin can redefine it with + +``` +myPlugin.__experimentalReconfigure({ +... +}); +``` + +--- + +## @backstage/plugin-catalog + +Plugin catalog has been modified to use an experimental feature where you can customize the title of the create button. + +You can modify it by doing next: + +```typescript jsx +import { catalogPlugin } from '@backstage/plugin-catalog'; + +catalogPlugin.__experimentalReconfigure({ + createButtonTitle: 'New', +}); +``` From a165e3cf89b3e25575622ebc1781e4131fd21350 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Thu, 7 Jul 2022 13:23:21 +0200 Subject: [PATCH 37/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- .changeset/fast-walls-carry.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.changeset/fast-walls-carry.md b/.changeset/fast-walls-carry.md index fe8e81f4a0..8c31d96326 100644 --- a/.changeset/fast-walls-carry.md +++ b/.changeset/fast-walls-carry.md @@ -10,6 +10,8 @@ component can reconfigure it if necessary. ## @backstage/app-defaults +--- + Introduced an extra parameter in BackstagePlugin. This optional parameter is responsible for providing a type for input options for the plugin. @@ -17,6 +19,8 @@ This optional parameter is responsible for providing a type for input options fo ## @backstage/core-app-api +--- + Introduced an extra parameter in BackstagePlugin. This optional parameter is responsible for providing a type for input options for the plugin. @@ -24,6 +28,8 @@ This optional parameter is responsible for providing a type for input options fo ## @backstage/core-plugin-api +--- + Introduced plugin options for the components, to be able to customise existing components. Those customizations are stored in React context of the plugin. The configurable options could be defined during the creation of the plugin via `__experimentalConfigure` method. @@ -39,6 +45,8 @@ myPlugin.__experimentalReconfigure({ ## @backstage/plugin-catalog +--- + Plugin catalog has been modified to use an experimental feature where you can customize the title of the create button. You can modify it by doing next: From 2102452e721d208673889ec3130afb1020300e7d Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Fri, 8 Jul 2022 10:45:19 +0200 Subject: [PATCH 38/54] Updated fast-walls-carry.md Signed-off-by: bnechyporenko --- .changeset/fast-walls-carry.md | 50 +++++----------------------------- 1 file changed, 7 insertions(+), 43 deletions(-) diff --git a/.changeset/fast-walls-carry.md b/.changeset/fast-walls-carry.md index 8c31d96326..1da91b4ef8 100644 --- a/.changeset/fast-walls-carry.md +++ b/.changeset/fast-walls-carry.md @@ -1,56 +1,17 @@ --- -'@internal/plugin-catalog-customized': patch +'@backstage/app-defaults': none +'@backstage/core-app-api': none +'@backstage/core-plugin-api': none +'@backstage/plugin-catalog': none --- Introduced plugin options for the components, to be able to customise existing components. The author of the component might define the configurable places of the component, and the user of this component can reconfigure it if necessary. ---- - -## @backstage/app-defaults - ---- - -Introduced an extra parameter in BackstagePlugin. -This optional parameter is responsible for providing a type for input options for the plugin. - ---- - -## @backstage/core-app-api - ---- - -Introduced an extra parameter in BackstagePlugin. -This optional parameter is responsible for providing a type for input options for the plugin. - ---- - -## @backstage/core-plugin-api - ---- - -Introduced plugin options for the components, to be able to customise existing components. -Those customizations are stored in React context of the plugin. The configurable options could be defined during the creation of the plugin via `__experimentalConfigure` method. And the user of the plugin can redefine it with -``` -myPlugin.__experimentalReconfigure({ -... -}); -``` - ---- - -## @backstage/plugin-catalog - ---- - -Plugin catalog has been modified to use an experimental feature where you can customize the title of the create button. - -You can modify it by doing next: - ```typescript jsx import { catalogPlugin } from '@backstage/plugin-catalog'; @@ -58,3 +19,6 @@ catalogPlugin.__experimentalReconfigure({ createButtonTitle: 'New', }); ``` + +Also introduced an extra parameter in BackstagePlugin. +This optional parameter is responsible for providing a type for input options for the plugin. From a8f439c724cf496269614ff3f797749d3dcc86d5 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Fri, 8 Jul 2022 11:17:24 +0200 Subject: [PATCH 39/54] wip Signed-off-by: bnechyporenko --- packages/app/src/components/catalog/EntityPage.test.tsx | 2 +- packages/app/src/components/catalog/EntityPage.tsx | 2 +- packages/app/src/components/search/SearchModal.tsx | 2 +- packages/app/src/components/search/SearchPage.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/app/src/components/catalog/EntityPage.test.tsx b/packages/app/src/components/catalog/EntityPage.test.tsx index 68ce5fb497..f9d23247c6 100644 --- a/packages/app/src/components/catalog/EntityPage.test.tsx +++ b/packages/app/src/components/catalog/EntityPage.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { EntityLayout } from '@backstage/plugin-catalog'; +import { EntityLayout } from '@internal/plugin-catalog-customized'; import { EntityProvider, starredEntitiesApiRef, diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index 155dc071ff..288196266e 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -59,7 +59,7 @@ import { isComponentType, isKind, isOrphan, -} from '@backstage/plugin-catalog'; +} from '@internal/plugin-catalog-customized'; import { Direction, EntityCatalogGraphCard, diff --git a/packages/app/src/components/search/SearchModal.tsx b/packages/app/src/components/search/SearchModal.tsx index 99fc964cb2..218ead9b82 100644 --- a/packages/app/src/components/search/SearchModal.tsx +++ b/packages/app/src/components/search/SearchModal.tsx @@ -33,7 +33,7 @@ import { useContent, } from '@backstage/core-components'; import { useApi, useRouteRef } from '@backstage/core-plugin-api'; -import { CatalogSearchResultListItem } from '@backstage/plugin-catalog'; +import { CatalogSearchResultListItem } from '@internal/plugin-catalog-customized'; import { catalogApiRef, CATALOG_FILTER_EXISTS, diff --git a/packages/app/src/components/search/SearchPage.tsx b/packages/app/src/components/search/SearchPage.tsx index 053fa81da8..99814130c2 100644 --- a/packages/app/src/components/search/SearchPage.tsx +++ b/packages/app/src/components/search/SearchPage.tsx @@ -24,7 +24,7 @@ import { useSidebarPinState, } from '@backstage/core-components'; import { useApi } from '@backstage/core-plugin-api'; -import { CatalogSearchResultListItem } from '@backstage/plugin-catalog'; +import { CatalogSearchResultListItem } from '@internal/plugin-catalog-customized'; import { catalogApiRef, CATALOG_FILTER_EXISTS, From 50423a30ba40158c72619c12f3a1b9e96837043c Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Fri, 8 Jul 2022 11:22:17 +0200 Subject: [PATCH 40/54] wip Signed-off-by: bnechyporenko --- .changeset/fast-walls-carry.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.changeset/fast-walls-carry.md b/.changeset/fast-walls-carry.md index 1da91b4ef8..4f903c2dd8 100644 --- a/.changeset/fast-walls-carry.md +++ b/.changeset/fast-walls-carry.md @@ -1,8 +1,8 @@ --- -'@backstage/app-defaults': none -'@backstage/core-app-api': none -'@backstage/core-plugin-api': none -'@backstage/plugin-catalog': none +'@backstage/app-defaults': patch +'@backstage/core-app-api': patch +'@backstage/core-plugin-api': patch +'@backstage/plugin-catalog': patch --- Introduced plugin options for the components, to be able to customise existing components. From 5bb73faa54f0daa4222be0210ef8433af8607a13 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Fri, 8 Jul 2022 11:57:49 +0200 Subject: [PATCH 41/54] wip Signed-off-by: bnechyporenko --- packages/core-plugin-api/api-report.md | 27 ++++++++++++++++--- plugins/adr/api-report.md | 1 + plugins/airbrake/api-report.md | 1 + plugins/allure/api-report.md | 1 + plugins/analytics-module-ga/api-report.md | 2 +- plugins/apache-airflow/api-report.md | 5 ++-- plugins/api-docs/api-report.md | 3 ++- plugins/azure-devops/api-report.md | 2 +- plugins/badges/api-report.md | 2 +- plugins/bazaar/api-report.md | 1 + plugins/bitrise/api-report.md | 2 +- plugins/catalog-customized/api-report.md | 9 +++++++ plugins/catalog-graph/api-report.md | 3 ++- plugins/catalog-import/api-report.md | 1 + plugins/catalog/api-report.md | 5 +++- plugins/cicd-statistics/api-report.md | 1 + plugins/circleci/api-report.md | 2 +- plugins/cloudbuild/api-report.md | 1 + plugins/code-climate/api-report.md | 1 + plugins/code-coverage/api-report.md | 1 + plugins/codescene/api-report.md | 1 + plugins/config-schema/api-report.md | 1 + plugins/cost-insights/api-report.md | 1 + plugins/dynatrace/api-report.md | 2 +- plugins/example-todo-list/api-report.md | 1 + plugins/explore/api-report.md | 3 ++- plugins/firehydrant/api-report.md | 1 + plugins/fossa/api-report.md | 1 + plugins/gcalendar/api-report.md | 1 + plugins/gcp-projects/api-report.md | 1 + plugins/git-release-manager/api-report.md | 1 + plugins/github-actions/api-report.md | 1 + plugins/github-deployments/api-report.md | 2 +- plugins/gitops-profiles/api-report.md | 1 + plugins/gocd/api-report.md | 2 +- plugins/graphiql/api-report.md | 2 +- plugins/home/api-report.md | 1 + plugins/ilert/api-report.md | 1 + plugins/jenkins/api-report.md | 1 + plugins/kafka/api-report.md | 1 + plugins/kubernetes/api-report.md | 1 + plugins/lighthouse/api-report.md | 1 + plugins/newrelic-dashboard/api-report.md | 1 + plugins/newrelic/api-report.md | 1 + plugins/org/api-report.md | 3 ++- plugins/pagerduty/api-report.md | 2 +- plugins/periskop/api-report.md | 2 +- plugins/rollbar/api-report.md | 1 + plugins/scaffolder/api-report.md | 3 ++- plugins/search/api-report.md | 1 + plugins/sentry/api-report.md | 1 + plugins/shortcuts/api-report.md | 2 +- plugins/sonarqube/api-report.md | 2 +- plugins/splunk-on-call/api-report.md | 1 + plugins/stack-overflow/api-report.md | 2 +- plugins/tech-insights/api-report.md | 1 + plugins/tech-radar/api-report.md | 1 + .../api-report.md | 2 +- plugins/techdocs/api-report.md | 1 + plugins/todo/api-report.md | 1 + plugins/user-settings/api-report.md | 1 + plugins/vault/api-report.md | 2 +- plugins/xcmetrics/api-report.md | 1 + 63 files changed, 103 insertions(+), 28 deletions(-) create mode 100644 plugins/catalog-customized/api-report.md diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index 8289e863e0..5bddd891cd 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -147,7 +147,7 @@ export type AppComponents = { // @public export type AppContext = { - getPlugins(): BackstagePlugin_2[]; + getPlugins(): BackstagePlugin_2[]; getSystemIcon(key: string): IconComponent_2 | undefined; getComponents(): AppComponents; }; @@ -214,6 +214,7 @@ export type BackstageIdentityResponse = { export type BackstagePlugin< Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, + PluginInputOptions extends {} = {}, > = { getId(): string; getApis(): Iterable; @@ -221,6 +222,7 @@ export type BackstagePlugin< provide(extension: Extension): T; routes: Routes; externalRoutes: ExternalRoutes; + __experimentalReconfigure(options: PluginInputOptions): void; }; // @public @@ -303,9 +305,10 @@ export function createExternalRouteRef< export function createPlugin< Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, + PluginInputOptions extends {} = {}, >( - config: PluginConfig, -): BackstagePlugin; + config: PluginConfig, +): BackstagePlugin; // @public export function createReactExtension< @@ -401,7 +404,7 @@ export type ErrorBoundaryFallbackProps = { // @public export type Extension = { - expose(plugin: BackstagePlugin): T; + expose(plugin: BackstagePlugin): T; }; // @public @@ -621,12 +624,14 @@ export type PendingOAuthRequest = { export type PluginConfig< Routes extends AnyRoutes, ExternalRoutes extends AnyExternalRoutes, + PluginInputOptions extends {}, > = { id: string; apis?: Iterable; routes?: Routes; externalRoutes?: ExternalRoutes; featureFlags?: PluginFeatureFlagConfig[]; + __experimentalConfigure?(options?: PluginInputOptions): {}; }; // @public @@ -634,6 +639,15 @@ export type PluginFeatureFlagConfig = { name: string; }; +// Warning: (ae-forgotten-export) The symbol "PluginOptionsProviderProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "PluginProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const PluginProvider: ({ + children, + plugin, +}: PluginOptionsProviderProps) => JSX.Element; + // @public export type ProfileInfo = { email?: string; @@ -734,6 +748,11 @@ export function useElementFilter( dependencies?: any[], ): T; +// @alpha +export function usePluginOptions< + TPluginOptions extends {} = {}, +>(): TPluginOptions; + // @public export function useRouteRef( routeRef: ExternalRouteRef, diff --git a/plugins/adr/api-report.md b/plugins/adr/api-report.md index fbe04b1dc4..5059d51023 100644 --- a/plugins/adr/api-report.md +++ b/plugins/adr/api-report.md @@ -25,6 +25,7 @@ export const adrPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; diff --git a/plugins/airbrake/api-report.md b/plugins/airbrake/api-report.md index bd274e604d..e48fbf9cde 100644 --- a/plugins/airbrake/api-report.md +++ b/plugins/airbrake/api-report.md @@ -13,6 +13,7 @@ export const airbrakePlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; diff --git a/plugins/allure/api-report.md b/plugins/allure/api-report.md index c5c4253cd4..e6f5d2aa67 100644 --- a/plugins/allure/api-report.md +++ b/plugins/allure/api-report.md @@ -21,6 +21,7 @@ export const allurePlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; diff --git a/plugins/analytics-module-ga/api-report.md b/plugins/analytics-module-ga/api-report.md index 9a359f81e9..557f472f71 100644 --- a/plugins/analytics-module-ga/api-report.md +++ b/plugins/analytics-module-ga/api-report.md @@ -10,7 +10,7 @@ import { Config } from '@backstage/config'; import { IdentityApi } from '@backstage/core-plugin-api'; // @public @deprecated (undocumented) -export const analyticsModuleGA: BackstagePlugin<{}, {}>; +export const analyticsModuleGA: BackstagePlugin<{}, {}, {}>; // @public export class GoogleAnalytics implements AnalyticsApi { diff --git a/plugins/apache-airflow/api-report.md b/plugins/apache-airflow/api-report.md index 333e4543cf..428f3238e8 100644 --- a/plugins/apache-airflow/api-report.md +++ b/plugins/apache-airflow/api-report.md @@ -10,8 +10,8 @@ import { RouteRef } from '@backstage/core-plugin-api'; // @public export const ApacheAirflowDagTable: ({ - dagIds, - }: { + dagIds, +}: { dagIds?: string[] | undefined; }) => JSX.Element; @@ -27,6 +27,7 @@ export const apacheAirflowPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; ``` diff --git a/plugins/api-docs/api-report.md b/plugins/api-docs/api-report.md index 991c73d4ab..e32a529df2 100644 --- a/plugins/api-docs/api-report.md +++ b/plugins/api-docs/api-report.md @@ -47,7 +47,8 @@ const apiDocsPlugin: BackstagePlugin< }, { registerApi: ExternalRouteRef; - } + }, + {} >; export { apiDocsPlugin }; export { apiDocsPlugin as plugin }; diff --git a/plugins/azure-devops/api-report.md b/plugins/azure-devops/api-report.md index b366166d95..0fe600f15d 100644 --- a/plugins/azure-devops/api-report.md +++ b/plugins/azure-devops/api-report.md @@ -170,7 +170,7 @@ export class AzureDevOpsClient implements AzureDevOpsApi { // Warning: (ae-missing-release-tag) "azureDevOpsPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const azureDevOpsPlugin: BackstagePlugin<{}, {}>; +export const azureDevOpsPlugin: BackstagePlugin<{}, {}, {}>; // Warning: (ae-missing-release-tag) "AzurePullRequestsIcon" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // diff --git a/plugins/badges/api-report.md b/plugins/badges/api-report.md index f4ba97cabc..e3af0857a4 100644 --- a/plugins/badges/api-report.md +++ b/plugins/badges/api-report.md @@ -10,7 +10,7 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; // Warning: (ae-missing-release-tag) "badgesPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const badgesPlugin: BackstagePlugin<{}, {}>; +export const badgesPlugin: BackstagePlugin<{}, {}, {}>; // Warning: (ae-missing-release-tag) "EntityBadgesDialog" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // diff --git a/plugins/bazaar/api-report.md b/plugins/bazaar/api-report.md index e7816757b3..801f75a04c 100644 --- a/plugins/bazaar/api-report.md +++ b/plugins/bazaar/api-report.md @@ -20,6 +20,7 @@ export const bazaarPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; diff --git a/plugins/bitrise/api-report.md b/plugins/bitrise/api-report.md index 293ea5fe40..f8421a532a 100644 --- a/plugins/bitrise/api-report.md +++ b/plugins/bitrise/api-report.md @@ -11,7 +11,7 @@ import { Entity } from '@backstage/catalog-model'; // Warning: (ae-missing-release-tag) "bitrisePlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const bitrisePlugin: BackstagePlugin<{}, {}>; +export const bitrisePlugin: BackstagePlugin<{}, {}, {}>; // Warning: (ae-missing-release-tag) "EntityBitriseContent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // diff --git a/plugins/catalog-customized/api-report.md b/plugins/catalog-customized/api-report.md new file mode 100644 index 0000000000..5cf6eefde1 --- /dev/null +++ b/plugins/catalog-customized/api-report.md @@ -0,0 +1,9 @@ +## API Report File for "@internal/plugin-catalog-customized" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +export * from '@backstage/plugin-catalog'; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/catalog-graph/api-report.md b/plugins/catalog-graph/api-report.md index 1a2b03a292..ed4ca2a2c9 100644 --- a/plugins/catalog-graph/api-report.md +++ b/plugins/catalog-graph/api-report.md @@ -48,7 +48,8 @@ export const catalogGraphPlugin: BackstagePlugin< }, true >; - } + }, + {} >; // @public diff --git a/plugins/catalog-import/api-report.md b/plugins/catalog-import/api-report.md index 5a9e8f03fd..90c01255b0 100644 --- a/plugins/catalog-import/api-report.md +++ b/plugins/catalog-import/api-report.md @@ -133,6 +133,7 @@ const catalogImportPlugin: BackstagePlugin< { importPage: RouteRef; }, + {}, {} >; export { catalogImportPlugin }; diff --git a/plugins/catalog/api-report.md b/plugins/catalog/api-report.md index bfdf62bdb0..306a01b9ad 100644 --- a/plugins/catalog/api-report.md +++ b/plugins/catalog/api-report.md @@ -79,6 +79,8 @@ export interface CatalogKindHeaderProps { initialFilter?: string; } +// Warning: (ae-forgotten-export) The symbol "CatalogInputPluginOptions" needs to be exported by the entry point index.d.ts +// // @public (undocumented) export const catalogPlugin: BackstagePlugin< { @@ -99,7 +101,8 @@ export const catalogPlugin: BackstagePlugin< }, true >; - } + }, + CatalogInputPluginOptions >; // @public (undocumented) diff --git a/plugins/cicd-statistics/api-report.md b/plugins/cicd-statistics/api-report.md index 3c7a52cdad..e49c6b27dc 100644 --- a/plugins/cicd-statistics/api-report.md +++ b/plugins/cicd-statistics/api-report.md @@ -107,6 +107,7 @@ export const cicdStatisticsPlugin: BackstagePlugin< { entityContent: RouteRef; }, + {}, {} >; diff --git a/plugins/circleci/api-report.md b/plugins/circleci/api-report.md index 5cdf916514..e8640ec78b 100644 --- a/plugins/circleci/api-report.md +++ b/plugins/circleci/api-report.md @@ -75,7 +75,7 @@ export const circleCIBuildRouteRef: SubRouteRef>; // Warning: (ae-missing-release-tag) "circleCIPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -const circleCIPlugin: BackstagePlugin<{}, {}>; +const circleCIPlugin: BackstagePlugin<{}, {}, {}>; export { circleCIPlugin }; export { circleCIPlugin as plugin }; diff --git a/plugins/cloudbuild/api-report.md b/plugins/cloudbuild/api-report.md index 4077a8991a..ecc6d7b460 100644 --- a/plugins/cloudbuild/api-report.md +++ b/plugins/cloudbuild/api-report.md @@ -141,6 +141,7 @@ const cloudbuildPlugin: BackstagePlugin< { entityContent: RouteRef; }, + {}, {} >; export { cloudbuildPlugin }; diff --git a/plugins/code-climate/api-report.md b/plugins/code-climate/api-report.md index 11366384d3..b0cc3e1450 100644 --- a/plugins/code-climate/api-report.md +++ b/plugins/code-climate/api-report.md @@ -48,6 +48,7 @@ export const codeClimatePlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; diff --git a/plugins/code-coverage/api-report.md b/plugins/code-coverage/api-report.md index 152cc93103..5dcb5fcfd1 100644 --- a/plugins/code-coverage/api-report.md +++ b/plugins/code-coverage/api-report.md @@ -14,6 +14,7 @@ export const codeCoveragePlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; diff --git a/plugins/codescene/api-report.md b/plugins/codescene/api-report.md index 962a20a618..75dfddd09e 100644 --- a/plugins/codescene/api-report.md +++ b/plugins/codescene/api-report.md @@ -23,6 +23,7 @@ export const codescenePlugin: BackstagePlugin< projectId: string; }>; }, + {}, {} >; diff --git a/plugins/config-schema/api-report.md b/plugins/config-schema/api-report.md index f3b620738f..4b9f47c950 100644 --- a/plugins/config-schema/api-report.md +++ b/plugins/config-schema/api-report.md @@ -38,6 +38,7 @@ export const configSchemaPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; diff --git a/plugins/cost-insights/api-report.md b/plugins/cost-insights/api-report.md index 5a9024de5a..94cab949c7 100644 --- a/plugins/cost-insights/api-report.md +++ b/plugins/cost-insights/api-report.md @@ -382,6 +382,7 @@ const costInsightsPlugin: BackstagePlugin< growthAlerts: RouteRef; unlabeledDataflowAlerts: RouteRef; }, + {}, {} >; export { costInsightsPlugin }; diff --git a/plugins/dynatrace/api-report.md b/plugins/dynatrace/api-report.md index 026df62189..59fd145250 100644 --- a/plugins/dynatrace/api-report.md +++ b/plugins/dynatrace/api-report.md @@ -9,7 +9,7 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; import { Entity } from '@backstage/catalog-model'; // @public -export const dynatracePlugin: BackstagePlugin<{}, {}>; +export const dynatracePlugin: BackstagePlugin<{}, {}, {}>; // @public export const DynatraceTab: () => JSX.Element; diff --git a/plugins/example-todo-list/api-report.md b/plugins/example-todo-list/api-report.md index 534c33200e..68b3ffd73e 100644 --- a/plugins/example-todo-list/api-report.md +++ b/plugins/example-todo-list/api-report.md @@ -16,6 +16,7 @@ export const todoListPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; diff --git a/plugins/explore/api-report.md b/plugins/explore/api-report.md index 412c0cc54b..c7181af19d 100644 --- a/plugins/explore/api-report.md +++ b/plugins/explore/api-report.md @@ -68,7 +68,8 @@ const explorePlugin: BackstagePlugin< }, true >; - } + }, + {} >; export { explorePlugin }; export { explorePlugin as plugin }; diff --git a/plugins/firehydrant/api-report.md b/plugins/firehydrant/api-report.md index 86f090c34d..c12048e81f 100644 --- a/plugins/firehydrant/api-report.md +++ b/plugins/firehydrant/api-report.md @@ -20,6 +20,7 @@ export const firehydrantPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; ``` diff --git a/plugins/fossa/api-report.md b/plugins/fossa/api-report.md index d6e229d3d6..ca9610b992 100644 --- a/plugins/fossa/api-report.md +++ b/plugins/fossa/api-report.md @@ -40,6 +40,7 @@ export const fossaPlugin: BackstagePlugin< { fossaOverview: RouteRef; }, + {}, {} >; ``` diff --git a/plugins/gcalendar/api-report.md b/plugins/gcalendar/api-report.md index b4aebf1ff3..61c39aaf2a 100644 --- a/plugins/gcalendar/api-report.md +++ b/plugins/gcalendar/api-report.md @@ -65,6 +65,7 @@ export const gcalendarPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; diff --git a/plugins/gcp-projects/api-report.md b/plugins/gcp-projects/api-report.md index 8049441b1f..46c8dd2c2f 100644 --- a/plugins/gcp-projects/api-report.md +++ b/plugins/gcp-projects/api-report.md @@ -57,6 +57,7 @@ const gcpProjectsPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; export { gcpProjectsPlugin }; diff --git a/plugins/git-release-manager/api-report.md b/plugins/git-release-manager/api-report.md index 743ea4e0f9..24207de991 100644 --- a/plugins/git-release-manager/api-report.md +++ b/plugins/git-release-manager/api-report.md @@ -203,6 +203,7 @@ export const gitReleaseManagerPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; diff --git a/plugins/github-actions/api-report.md b/plugins/github-actions/api-report.md index 08761bad56..8100cb6c7a 100644 --- a/plugins/github-actions/api-report.md +++ b/plugins/github-actions/api-report.md @@ -198,6 +198,7 @@ const githubActionsPlugin: BackstagePlugin< { entityContent: RouteRef; }, + {}, {} >; export { githubActionsPlugin }; diff --git a/plugins/github-deployments/api-report.md b/plugins/github-deployments/api-report.md index 36680cb020..3e75b2f9bc 100644 --- a/plugins/github-deployments/api-report.md +++ b/plugins/github-deployments/api-report.md @@ -47,7 +47,7 @@ export const EntityGithubDeploymentsCard: (props: { // Warning: (ae-missing-release-tag) "githubDeploymentsPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const githubDeploymentsPlugin: BackstagePlugin<{}, {}>; +export const githubDeploymentsPlugin: BackstagePlugin<{}, {}, {}>; // Warning: (ae-forgotten-export) The symbol "GithubDeploymentsTableProps" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "GithubDeploymentsTable" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) diff --git a/plugins/gitops-profiles/api-report.md b/plugins/gitops-profiles/api-report.md index 3c77d0301b..245a1fb30b 100644 --- a/plugins/gitops-profiles/api-report.md +++ b/plugins/gitops-profiles/api-report.md @@ -149,6 +149,7 @@ const gitopsProfilesPlugin: BackstagePlugin< }>; createPage: RouteRef; }, + {}, {} >; export { gitopsProfilesPlugin }; diff --git a/plugins/gocd/api-report.md b/plugins/gocd/api-report.md index de2c76e06b..df93b5f2eb 100644 --- a/plugins/gocd/api-report.md +++ b/plugins/gocd/api-report.md @@ -15,7 +15,7 @@ export const EntityGoCdContent: () => JSX.Element; export const GOCD_PIPELINES_ANNOTATION = 'gocd.org/pipelines'; // @public -export const gocdPlugin: BackstagePlugin<{}, {}>; +export const gocdPlugin: BackstagePlugin<{}, {}, {}>; // @public export const isGoCdAvailable: (entity: Entity) => boolean; diff --git a/plugins/graphiql/api-report.md b/plugins/graphiql/api-report.md index 5c613b1f57..c96966c585 100644 --- a/plugins/graphiql/api-report.md +++ b/plugins/graphiql/api-report.md @@ -39,7 +39,7 @@ export const GraphiQLIcon: IconComponent; export const GraphiQLPage: () => JSX.Element; // @public (undocumented) -const graphiqlPlugin: BackstagePlugin<{}, {}>; +const graphiqlPlugin: BackstagePlugin<{}, {}, {}>; export { graphiqlPlugin }; export { graphiqlPlugin as plugin }; diff --git a/plugins/home/api-report.md b/plugins/home/api-report.md index 452b3e1685..0870a23ba7 100644 --- a/plugins/home/api-report.md +++ b/plugins/home/api-report.md @@ -107,6 +107,7 @@ export const homePlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; diff --git a/plugins/ilert/api-report.md b/plugins/ilert/api-report.md index 3c6965b2c4..a4e6a7a76c 100644 --- a/plugins/ilert/api-report.md +++ b/plugins/ilert/api-report.md @@ -249,6 +249,7 @@ const ilertPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; export { ilertPlugin }; diff --git a/plugins/jenkins/api-report.md b/plugins/jenkins/api-report.md index fc9de04a7a..33072ecf49 100644 --- a/plugins/jenkins/api-report.md +++ b/plugins/jenkins/api-report.md @@ -108,6 +108,7 @@ const jenkinsPlugin: BackstagePlugin< { entityContent: RouteRef; }, + {}, {} >; export { jenkinsPlugin }; diff --git a/plugins/kafka/api-report.md b/plugins/kafka/api-report.md index 95eed1dc13..844082764e 100644 --- a/plugins/kafka/api-report.md +++ b/plugins/kafka/api-report.md @@ -34,6 +34,7 @@ const kafkaPlugin: BackstagePlugin< { entityContent: RouteRef; }, + {}, {} >; export { kafkaPlugin }; diff --git a/plugins/kubernetes/api-report.md b/plugins/kubernetes/api-report.md index 1a95446e5f..4dea506473 100644 --- a/plugins/kubernetes/api-report.md +++ b/plugins/kubernetes/api-report.md @@ -322,6 +322,7 @@ const kubernetesPlugin: BackstagePlugin< { entityContent: RouteRef; }, + {}, {} >; export { kubernetesPlugin }; diff --git a/plugins/lighthouse/api-report.md b/plugins/lighthouse/api-report.md index 26db053ef0..a53bef3cb0 100644 --- a/plugins/lighthouse/api-report.md +++ b/plugins/lighthouse/api-report.md @@ -175,6 +175,7 @@ const lighthousePlugin: BackstagePlugin< root: RouteRef; entityContent: RouteRef; }, + {}, {} >; export { lighthousePlugin }; diff --git a/plugins/newrelic-dashboard/api-report.md b/plugins/newrelic-dashboard/api-report.md index fd0846bc4e..d74d69cad6 100644 --- a/plugins/newrelic-dashboard/api-report.md +++ b/plugins/newrelic-dashboard/api-report.md @@ -42,6 +42,7 @@ export const newRelicDashboardPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; diff --git a/plugins/newrelic/api-report.md b/plugins/newrelic/api-report.md index 43beb3807f..fbf639ee9d 100644 --- a/plugins/newrelic/api-report.md +++ b/plugins/newrelic/api-report.md @@ -20,6 +20,7 @@ const newRelicPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; export { newRelicPlugin }; diff --git a/plugins/org/api-report.md b/plugins/org/api-report.md index d020dfb438..f8cf8afe22 100644 --- a/plugins/org/api-report.md +++ b/plugins/org/api-report.md @@ -58,7 +58,8 @@ const orgPlugin: BackstagePlugin< {}, { catalogIndex: ExternalRouteRef; - } + }, + {} >; export { orgPlugin }; export { orgPlugin as plugin }; diff --git a/plugins/pagerduty/api-report.md b/plugins/pagerduty/api-report.md index be3fa9fa23..c81da24454 100644 --- a/plugins/pagerduty/api-report.md +++ b/plugins/pagerduty/api-report.md @@ -166,7 +166,7 @@ export type PagerDutyOnCallsResponse = { // Warning: (ae-missing-release-tag) "pagerDutyPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -const pagerDutyPlugin: BackstagePlugin<{}, {}>; +const pagerDutyPlugin: BackstagePlugin<{}, {}, {}>; export { pagerDutyPlugin }; export { pagerDutyPlugin as plugin }; diff --git a/plugins/periskop/api-report.md b/plugins/periskop/api-report.md index 2cf84faccf..3332dd9edb 100644 --- a/plugins/periskop/api-report.md +++ b/plugins/periskop/api-report.md @@ -119,7 +119,7 @@ export class PeriskopClient implements PeriskopApi { } // @public (undocumented) -export const periskopPlugin: BackstagePlugin<{}, {}>; +export const periskopPlugin: BackstagePlugin<{}, {}, {}>; // @public (undocumented) export interface RequestHeaders { diff --git a/plugins/rollbar/api-report.md b/plugins/rollbar/api-report.md index f666ade34c..27f0e4641b 100644 --- a/plugins/rollbar/api-report.md +++ b/plugins/rollbar/api-report.md @@ -91,6 +91,7 @@ const rollbarPlugin: BackstagePlugin< { entityContent: RouteRef; }, + {}, {} >; export { rollbarPlugin as plugin }; diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index 3fa623b5b9..fe04327afd 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -365,7 +365,8 @@ export const scaffolderPlugin: BackstagePlugin< }, { registerComponent: ExternalRouteRef; - } + }, + {} >; // @public diff --git a/plugins/search/api-report.md b/plugins/search/api-report.md index 800fa7e7fc..4ff684b6ea 100644 --- a/plugins/search/api-report.md +++ b/plugins/search/api-report.md @@ -194,6 +194,7 @@ const searchPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; export { searchPlugin as plugin }; diff --git a/plugins/sentry/api-report.md b/plugins/sentry/api-report.md index 625db39959..e752eb2110 100644 --- a/plugins/sentry/api-report.md +++ b/plugins/sentry/api-report.md @@ -145,6 +145,7 @@ const sentryPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; export { sentryPlugin as plugin }; diff --git a/plugins/shortcuts/api-report.md b/plugins/shortcuts/api-report.md index 4b5a8e74df..537ce972ab 100644 --- a/plugins/shortcuts/api-report.md +++ b/plugins/shortcuts/api-report.md @@ -62,7 +62,7 @@ export const shortcutsApiRef: ApiRef; // Warning: (ae-missing-release-tag) "shortcutsPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const shortcutsPlugin: BackstagePlugin<{}, {}>; +export const shortcutsPlugin: BackstagePlugin<{}, {}, {}>; // @public export interface ShortcutsProps { diff --git a/plugins/sonarqube/api-report.md b/plugins/sonarqube/api-report.md index a7549a689c..06e4b8578e 100644 --- a/plugins/sonarqube/api-report.md +++ b/plugins/sonarqube/api-report.md @@ -44,7 +44,7 @@ export const SonarQubeCard: ({ // Warning: (ae-missing-release-tag) "sonarQubePlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -const sonarQubePlugin: BackstagePlugin<{}, {}>; +const sonarQubePlugin: BackstagePlugin<{}, {}, {}>; export { sonarQubePlugin as plugin }; export { sonarQubePlugin }; diff --git a/plugins/splunk-on-call/api-report.md b/plugins/splunk-on-call/api-report.md index 60ec38ca6d..b24a68e07a 100644 --- a/plugins/splunk-on-call/api-report.md +++ b/plugins/splunk-on-call/api-report.md @@ -98,6 +98,7 @@ const splunkOnCallPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; export { splunkOnCallPlugin as plugin }; diff --git a/plugins/stack-overflow/api-report.md b/plugins/stack-overflow/api-report.md index e4912fcd18..9404c74700 100644 --- a/plugins/stack-overflow/api-report.md +++ b/plugins/stack-overflow/api-report.md @@ -20,7 +20,7 @@ export const HomePageStackOverflowQuestions: ( export const StackOverflowIcon: () => JSX.Element; // @public -export const stackOverflowPlugin: BackstagePlugin<{}, {}>; +export const stackOverflowPlugin: BackstagePlugin<{}, {}, {}>; // @public export type StackOverflowQuestion = { diff --git a/plugins/tech-insights/api-report.md b/plugins/tech-insights/api-report.md index 54884f12ea..694fb583d2 100644 --- a/plugins/tech-insights/api-report.md +++ b/plugins/tech-insights/api-report.md @@ -112,6 +112,7 @@ export const techInsightsPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; diff --git a/plugins/tech-radar/api-report.md b/plugins/tech-radar/api-report.md index 75824f0509..a55cf79f28 100644 --- a/plugins/tech-radar/api-report.md +++ b/plugins/tech-radar/api-report.md @@ -126,6 +126,7 @@ const techRadarPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; export { techRadarPlugin as plugin }; diff --git a/plugins/techdocs-module-addons-contrib/api-report.md b/plugins/techdocs-module-addons-contrib/api-report.md index efe88e2d5c..f787e0678c 100644 --- a/plugins/techdocs-module-addons-contrib/api-report.md +++ b/plugins/techdocs-module-addons-contrib/api-report.md @@ -33,7 +33,7 @@ export type ReportIssueTemplateBuilder = ({ }) => ReportIssueTemplate; // @public -export const techdocsModuleAddonsContribPlugin: BackstagePlugin<{}, {}>; +export const techdocsModuleAddonsContribPlugin: BackstagePlugin<{}, {}, {}>; // @public export const TextSize: () => JSX.Element | null; diff --git a/plugins/techdocs/api-report.md b/plugins/techdocs/api-report.md index d4ec65ed53..fa7c3c0f3d 100644 --- a/plugins/techdocs/api-report.md +++ b/plugins/techdocs/api-report.md @@ -288,6 +288,7 @@ const techdocsPlugin: BackstagePlugin< }>; entityContent: RouteRef; }, + {}, {} >; export { techdocsPlugin as plugin }; diff --git a/plugins/todo/api-report.md b/plugins/todo/api-report.md index c1667f1111..09356cd48f 100644 --- a/plugins/todo/api-report.md +++ b/plugins/todo/api-report.md @@ -84,6 +84,7 @@ export const todoPlugin: BackstagePlugin< { entityContent: RouteRef; }, + {}, {} >; ``` diff --git a/plugins/user-settings/api-report.md b/plugins/user-settings/api-report.md index a38b37846a..914f8b2385 100644 --- a/plugins/user-settings/api-report.md +++ b/plugins/user-settings/api-report.md @@ -102,6 +102,7 @@ const userSettingsPlugin: BackstagePlugin< { settingsPage: RouteRef; }, + {}, {} >; export { userSettingsPlugin as plugin }; diff --git a/plugins/vault/api-report.md b/plugins/vault/api-report.md index b347989800..8c4e5da829 100644 --- a/plugins/vault/api-report.md +++ b/plugins/vault/api-report.md @@ -27,7 +27,7 @@ export interface VaultApi { export const vaultApiRef: ApiRef; // @public -export const vaultPlugin: BackstagePlugin<{}, {}>; +export const vaultPlugin: BackstagePlugin<{}, {}, {}>; // @public export type VaultSecret = { diff --git a/plugins/xcmetrics/api-report.md b/plugins/xcmetrics/api-report.md index 3e2aa23451..373748e9e2 100644 --- a/plugins/xcmetrics/api-report.md +++ b/plugins/xcmetrics/api-report.md @@ -20,6 +20,7 @@ export const xcmetricsPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >; ``` From 80da5162c72569b7a2716be1375952ebfeabc01e Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Fri, 8 Jul 2022 12:33:02 +0200 Subject: [PATCH 42/54] wip Signed-off-by: bnechyporenko --- .changeset/famous-bikes-brush.md | 8 +++++++ .changeset/fast-walls-carry.md | 24 ------------------- .changeset/few-berries-deny.md | 15 ++++++++++++ .changeset/gentle-games-count.md | 12 ++++++++++ .changeset/hungry-hotels-flow.md | 6 +++++ packages/core-app-api/api-report.md | 4 ++-- packages/core-plugin-api/api-report.md | 13 ++++++---- .../src/plugin-options/index.ts | 1 + .../src/plugin-options/usePluginOptions.tsx | 5 ++++ 9 files changed, 58 insertions(+), 30 deletions(-) create mode 100644 .changeset/famous-bikes-brush.md delete mode 100644 .changeset/fast-walls-carry.md create mode 100644 .changeset/few-berries-deny.md create mode 100644 .changeset/gentle-games-count.md create mode 100644 .changeset/hungry-hotels-flow.md diff --git a/.changeset/famous-bikes-brush.md b/.changeset/famous-bikes-brush.md new file mode 100644 index 0000000000..0c4867d46a --- /dev/null +++ b/.changeset/famous-bikes-brush.md @@ -0,0 +1,8 @@ +--- +'@backstage/core-plugin-api': patch +--- + +Introduced plugin options for the components, to be able to customise existing components. +Those customizations are stored in React context of the plugin. +The configurable options could be defined during the creation of the plugin via `__experimentalConfigure` method. +And the user of the plugin can redefine it with. diff --git a/.changeset/fast-walls-carry.md b/.changeset/fast-walls-carry.md deleted file mode 100644 index 4f903c2dd8..0000000000 --- a/.changeset/fast-walls-carry.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@backstage/app-defaults': patch -'@backstage/core-app-api': patch -'@backstage/core-plugin-api': patch -'@backstage/plugin-catalog': patch ---- - -Introduced plugin options for the components, to be able to customise existing components. -The author of the component might define the configurable places of the component, and the user of this -component can reconfigure it if necessary. - -The configurable options could be defined during the creation of the plugin via `__experimentalConfigure` method. -And the user of the plugin can redefine it with - -```typescript jsx -import { catalogPlugin } from '@backstage/plugin-catalog'; - -catalogPlugin.__experimentalReconfigure({ - createButtonTitle: 'New', -}); -``` - -Also introduced an extra parameter in BackstagePlugin. -This optional parameter is responsible for providing a type for input options for the plugin. diff --git a/.changeset/few-berries-deny.md b/.changeset/few-berries-deny.md new file mode 100644 index 0000000000..0cbed15f81 --- /dev/null +++ b/.changeset/few-berries-deny.md @@ -0,0 +1,15 @@ +--- +'@backstage/plugin-catalog': minor +--- + +Plugin catalog has been modified to use an experimental feature where you can customize the title of the create button. + +You can modify it by doing next: + +```typescript jsx +import { catalogPlugin } from '@backstage/plugin-catalog'; + +catalogPlugin.__experimentalReconfigure({ + createButtonTitle: 'New', +}); +``` diff --git a/.changeset/gentle-games-count.md b/.changeset/gentle-games-count.md new file mode 100644 index 0000000000..fd7b586803 --- /dev/null +++ b/.changeset/gentle-games-count.md @@ -0,0 +1,12 @@ +--- +'@backstage/app-defaults': patch +--- + +Introduced an extra parameter in BackstagePlugin. +This optional parameter is responsible for providing a type for input options for the plugin. + +``` +myPlugin.__experimentalReconfigure({ +... +}); +``` diff --git a/.changeset/hungry-hotels-flow.md b/.changeset/hungry-hotels-flow.md new file mode 100644 index 0000000000..0fef92bd90 --- /dev/null +++ b/.changeset/hungry-hotels-flow.md @@ -0,0 +1,6 @@ +--- +'@backstage/core-app-api': patch +--- + +Introduced an extra parameter in BackstagePlugin. +This optional parameter is responsible for providing a type for input options for the plugin. diff --git a/packages/core-app-api/api-report.md b/packages/core-app-api/api-report.md index 116b33c598..4792453af1 100644 --- a/packages/core-app-api/api-report.md +++ b/packages/core-app-api/api-report.md @@ -155,7 +155,7 @@ export type AppConfigLoader = () => Promise; // @public export type AppContext = { - getPlugins(): BackstagePlugin[]; + getPlugins(): BackstagePlugin[]; getSystemIcon(key: string): IconComponent | undefined; getComponents(): AppComponents; }; @@ -254,7 +254,7 @@ export type AuthApiCreateOptions = { // @public export type BackstageApp = { - getPlugins(): BackstagePlugin[]; + getPlugins(): BackstagePlugin[]; getSystemIcon(key: string): IconComponent | undefined; getProvider(): ComponentType<{}>; getRouter(): ComponentType<{}>; diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index 5bddd891cd..490d58a267 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -639,10 +639,15 @@ export type PluginFeatureFlagConfig = { name: string; }; -// Warning: (ae-forgotten-export) The symbol "PluginOptionsProviderProps" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "PluginProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @public +export interface PluginOptionsProviderProps { + // (undocumented) + children: ReactNode; + // (undocumented) + plugin?: BackstagePlugin; +} + +// @alpha export const PluginProvider: ({ children, plugin, diff --git a/packages/core-plugin-api/src/plugin-options/index.ts b/packages/core-plugin-api/src/plugin-options/index.ts index 937cf49032..1737a1c836 100644 --- a/packages/core-plugin-api/src/plugin-options/index.ts +++ b/packages/core-plugin-api/src/plugin-options/index.ts @@ -15,3 +15,4 @@ */ export { usePluginOptions, PluginProvider } from './usePluginOptions'; +export type { PluginOptionsProviderProps } from './usePluginOptions'; diff --git a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx index 55e2c28701..f5cbb72fcd 100644 --- a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx +++ b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx @@ -34,6 +34,11 @@ export interface PluginOptionsProviderProps { plugin?: BackstagePlugin; } +/** + * Contains the plugin configuration. + * + * @alpha + */ export const PluginProvider = ({ children, plugin, From f68f205d732d2cb87b82d282e8adb620120738d8 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Fri, 8 Jul 2022 13:26:00 +0200 Subject: [PATCH 43/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- .changeset/famous-bikes-brush.md | 8 ++++---- .changeset/few-berries-deny.md | 2 +- .changeset/gentle-games-count.md | 3 +-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.changeset/famous-bikes-brush.md b/.changeset/famous-bikes-brush.md index 0c4867d46a..0008a9145c 100644 --- a/.changeset/famous-bikes-brush.md +++ b/.changeset/famous-bikes-brush.md @@ -2,7 +2,7 @@ '@backstage/core-plugin-api': patch --- -Introduced plugin options for the components, to be able to customise existing components. -Those customizations are stored in React context of the plugin. -The configurable options could be defined during the creation of the plugin via `__experimentalConfigure` method. -And the user of the plugin can redefine it with. +Introduced a new experimental feature that allows you to declare plugin-wide options for your plugin by defining +`__experimentalConfigure` in your `createPlugin` options. See https://backstage.io/docs/plugins/customization.md for more information. + +This is an experimental feature and it will have breaking changes in the future. diff --git a/.changeset/few-berries-deny.md b/.changeset/few-berries-deny.md index 0cbed15f81..d5e14a807c 100644 --- a/.changeset/few-berries-deny.md +++ b/.changeset/few-berries-deny.md @@ -4,7 +4,7 @@ Plugin catalog has been modified to use an experimental feature where you can customize the title of the create button. -You can modify it by doing next: +You can modify it by doing: ```typescript jsx import { catalogPlugin } from '@backstage/plugin-catalog'; diff --git a/.changeset/gentle-games-count.md b/.changeset/gentle-games-count.md index fd7b586803..99f62a4506 100644 --- a/.changeset/gentle-games-count.md +++ b/.changeset/gentle-games-count.md @@ -2,8 +2,7 @@ '@backstage/app-defaults': patch --- -Introduced an extra parameter in BackstagePlugin. -This optional parameter is responsible for providing a type for input options for the plugin. +Updated usage of the `BackstagePlugin` type. ``` myPlugin.__experimentalReconfigure({ From 5ce1ca34479cc1d1f199a2e3dda4cec13edad33f Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Fri, 8 Jul 2022 23:44:56 +0200 Subject: [PATCH 44/54] Fixing broken CI pipeline Signed-off-by: bnechyporenko --- packages/core-components/package.json | 3 ++- plugins/catalog-customized/package.json | 4 +++- plugins/permission-react/package.json | 3 ++- yarn.lock | 22 ++++++++++++++++++++++ 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/packages/core-components/package.json b/packages/core-components/package.json index a6dff88333..5fb8999c1b 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -71,7 +71,8 @@ "react-window": "^1.8.6", "remark-gfm": "^3.0.1", "zen-observable": "^0.8.15", - "zod": "^3.11.6" + "zod": "^3.11.6", + "@types/react-router-dom": "^5.3.3" }, "peerDependencies": { "@types/react": "^16.13.1 || ^17.0.0", diff --git a/plugins/catalog-customized/package.json b/plugins/catalog-customized/package.json index b6cc66b3b1..3d01044474 100644 --- a/plugins/catalog-customized/package.json +++ b/plugins/catalog-customized/package.json @@ -37,8 +37,10 @@ "@backstage/plugin-catalog": "1.4.0-next.2", "@backstage/plugin-catalog-react": "^1.1.2-next.2" }, + "devDependencies": { + "@types/react": "^16.13.1 || ^17.0.0" + }, "peerDependencies": { - "@types/react": "^16.13.1 || ^17.0.0", "react": "^16.13.1 || ^17.0.0" }, "files": [ diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index f0dcc88de0..dc4dc5e96f 100644 --- a/plugins/permission-react/package.json +++ b/plugins/permission-react/package.json @@ -37,7 +37,8 @@ "cross-fetch": "^3.1.5", "react-router": "6.0.0-beta.0", "react-use": "^17.2.4", - "swr": "^1.1.2" + "swr": "^1.1.2", + "@types/react-router": "^5.1.18" }, "peerDependencies": { "@types/react": "^16.13.1 || ^17.0.0", diff --git a/yarn.lock b/yarn.lock index 7df8542a63..db9d6240f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6379,6 +6379,11 @@ dependencies: highlight.js "^10.1.0" +"@types/history@^4.7.11": + version "4.7.11" + resolved "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64" + integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA== + "@types/hoist-non-react-statics@^3.3.0": version "3.3.1" resolved "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" @@ -6865,6 +6870,23 @@ hoist-non-react-statics "^3.3.0" redux "^4.0.0" +"@types/react-router-dom@^5.3.3": + version "5.3.3" + resolved "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83" + integrity sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw== + dependencies: + "@types/history" "^4.7.11" + "@types/react" "*" + "@types/react-router" "*" + +"@types/react-router@*", "@types/react-router@^5.1.18": + version "5.1.18" + resolved "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.18.tgz#c8851884b60bc23733500d86c1266e1cfbbd9ef3" + integrity sha512-YYknwy0D0iOwKQgz9v8nOzt2J6l4gouBmDnWqUUznltOTaon+r8US8ky8HvN0tXvc38U9m6z/t2RsVsnd1zM0g== + dependencies: + "@types/history" "^4.7.11" + "@types/react" "*" + "@types/react-sparklines@^1.7.0": version "1.7.2" resolved "https://registry.npmjs.org/@types/react-sparklines/-/react-sparklines-1.7.2.tgz#c14e80623abd3669a10f18d13f6fb9fbdc322f70" From 0bc9dff8ad7300c8bc8dda183a4dd592b8a44008 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Sat, 9 Jul 2022 10:55:01 +0200 Subject: [PATCH 45/54] Fixing broken CI pipeline Signed-off-by: bnechyporenko --- plugins/catalog-customized/src/plugin.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/catalog-customized/src/plugin.ts b/plugins/catalog-customized/src/plugin.ts index bc11fc64d1..ce729d5226 100644 --- a/plugins/catalog-customized/src/plugin.ts +++ b/plugins/catalog-customized/src/plugin.ts @@ -16,6 +16,7 @@ import { catalogPlugin } from '@backstage/plugin-catalog'; +// id: 'catalog-customized' catalogPlugin.__experimentalReconfigure({ createButtonTitle: 'New', }); From 2e81cc2258c0101167e009657fefcdbdd59ea133 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Sat, 9 Jul 2022 13:10:52 +0200 Subject: [PATCH 46/54] Fixing broken CI pipeline Signed-off-by: bnechyporenko --- .../CatalogPage/DefaultCatalogPage.test.tsx | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx index c3135e5697..cc00a57314 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx @@ -23,8 +23,10 @@ import { } from '@backstage/catalog-model'; import { TableColumn, TableProps } from '@backstage/core-components'; import { + createPlugin, IdentityApi, identityApiRef, + PluginProvider, ProfileInfo, storageApiRef, } from '@backstage/core-plugin-api'; @@ -133,6 +135,22 @@ describe('DefaultCatalogPage', () => { }; const storageApi = MockStorageApi.create(); + type TestInputPluginOptions = { + 'key-1': string; + }; + + type TestPluginOptions = { + 'key-1': string; + 'key-2': string; + }; + + const plugin = createPlugin({ + id: 'my-plugin', + __experimentalConfigure(_: TestInputPluginOptions): TestPluginOptions { + return { 'key-1': 'value-1', 'key-2': 'value-2' }; + }, + }); + const renderWrapped = (children: React.ReactNode) => renderWithEffects( wrapInTestApp( @@ -144,7 +162,7 @@ describe('DefaultCatalogPage', () => { [starredEntitiesApiRef, new MockStarredEntitiesApi()], ]} > - {children} + {children} , { mountedRoutes: { From 6f362dba4da6b6f0a6864a142b0e316a42051f91 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 12 Jul 2022 11:14:52 +0200 Subject: [PATCH 47/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- packages/app-defaults/src/createApp.tsx | 2 +- packages/core-app-api/api-report.md | 4 ++-- packages/core-app-api/src/app/AppManager.tsx | 12 ++++++------ packages/core-app-api/src/app/types.ts | 4 ++-- packages/core-app-api/src/plugins/collectors.ts | 7 ++----- packages/core-plugin-api/api-report.md | 6 +++--- .../core-plugin-api/src/extensions/extensions.tsx | 2 +- .../src/plugin-options/usePluginOptions.tsx | 4 ++-- packages/core-plugin-api/src/plugin/types.ts | 2 +- 9 files changed, 20 insertions(+), 23 deletions(-) diff --git a/packages/app-defaults/src/createApp.tsx b/packages/app-defaults/src/createApp.tsx index 05e048ffca..9d0c01c633 100644 --- a/packages/app-defaults/src/createApp.tsx +++ b/packages/app-defaults/src/createApp.tsx @@ -50,7 +50,7 @@ export function createApp( ...icons, ...options?.icons, }, - plugins: (options?.plugins as BackstagePlugin[]) ?? [], + plugins: (options?.plugins as BackstagePlugin[]) ?? [], themes: options?.themes ?? themes, }); } diff --git a/packages/core-app-api/api-report.md b/packages/core-app-api/api-report.md index 4792453af1..800699d179 100644 --- a/packages/core-app-api/api-report.md +++ b/packages/core-app-api/api-report.md @@ -155,7 +155,7 @@ export type AppConfigLoader = () => Promise; // @public export type AppContext = { - getPlugins(): BackstagePlugin[]; + getPlugins(): BackstagePlugin[]; getSystemIcon(key: string): IconComponent | undefined; getComponents(): AppComponents; }; @@ -254,7 +254,7 @@ export type AuthApiCreateOptions = { // @public export type BackstageApp = { - getPlugins(): BackstagePlugin[]; + getPlugins(): BackstagePlugin[]; getSystemIcon(key: string): IconComponent | undefined; getProvider(): ComponentType<{}>; getRouter(): ComponentType<{}>; diff --git a/packages/core-app-api/src/app/AppManager.tsx b/packages/core-app-api/src/app/AppManager.tsx index 130d961312..72c69f7da4 100644 --- a/packages/core-app-api/src/app/AppManager.tsx +++ b/packages/core-app-api/src/app/AppManager.tsx @@ -82,8 +82,8 @@ import { resolveRouteBindings } from './resolveRouteBindings'; import { BackstageRouteObject } from '../routing/types'; type CompatiblePlugin = - | BackstagePlugin - | (Omit, 'getFeatureFlags'> & { + | BackstagePlugin + | (Omit & { output(): Array<{ type: 'feature-flag'; name: string }>; }); @@ -145,7 +145,7 @@ function useConfigLoader( class AppContextImpl implements AppContext { constructor(private readonly app: AppManager) {} - getPlugins(): BackstagePlugin[] { + getPlugins(): BackstagePlugin[] { return this.app.getPlugins(); } @@ -186,8 +186,8 @@ export class AppManager implements BackstageApp { this.apiFactoryRegistry = new ApiFactoryRegistry(); } - getPlugins(): BackstagePlugin[] { - return Array.from(this.plugins) as BackstagePlugin[]; + getPlugins(): BackstagePlugin[] { + return Array.from(this.plugins) as BackstagePlugin[]; } 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>, + this.plugins as Iterable, ); } diff --git a/packages/core-app-api/src/app/types.ts b/packages/core-app-api/src/app/types.ts index e7436dbf0a..3bf2354e27 100644 --- a/packages/core-app-api/src/app/types.ts +++ b/packages/core-app-api/src/app/types.ts @@ -291,7 +291,7 @@ export type BackstageApp = { /** * Returns all plugins registered for the app. */ - getPlugins(): BackstagePlugin[]; + getPlugins(): BackstagePlugin[]; /** * 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[]; + getPlugins(): BackstagePlugin[]; /** * Get a common or custom icon for this app. diff --git a/packages/core-app-api/src/plugins/collectors.ts b/packages/core-app-api/src/plugins/collectors.ts index 376a8b709c..41b4b00ea3 100644 --- a/packages/core-app-api/src/plugins/collectors.ts +++ b/packages/core-app-api/src/plugins/collectors.ts @@ -18,12 +18,9 @@ import { BackstagePlugin, getComponentData } from '@backstage/core-plugin-api'; import { createCollector } from '../extensions/traversal'; export const pluginCollector = createCollector( - () => new Set>(), + () => new Set(), (acc, node) => { - const plugin = getComponentData>( - node, - 'core.plugin', - ); + const plugin = getComponentData(node, 'core.plugin'); if (plugin) { acc.add(plugin); } diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index 7a8b0c06f3..49e0be3800 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -147,7 +147,7 @@ export type AppComponents = { // @public export type AppContext = { - getPlugins(): BackstagePlugin_2[]; + getPlugins(): BackstagePlugin_2[]; getSystemIcon(key: string): IconComponent_2 | undefined; getComponents(): AppComponents; }; @@ -404,7 +404,7 @@ export type ErrorBoundaryFallbackProps = { // @public export type Extension = { - expose(plugin: BackstagePlugin): T; + expose(plugin: BackstagePlugin): T; }; // @public @@ -639,7 +639,7 @@ export type PluginFeatureFlagConfig = { name: string; }; -// @public +// @alpha export interface PluginOptionsProviderProps { // (undocumented) children: ReactNode; diff --git a/packages/core-plugin-api/src/extensions/extensions.tsx b/packages/core-plugin-api/src/extensions/extensions.tsx index 1d84d55442..18b815debf 100644 --- a/packages/core-plugin-api/src/extensions/extensions.tsx +++ b/packages/core-plugin-api/src/extensions/extensions.tsx @@ -226,7 +226,7 @@ export function createReactExtension< 'Component'; return { - expose(plugin: BackstagePlugin) { + expose(plugin: BackstagePlugin) { const Result: any = (props: any) => { const app = useApp(); const { Progress } = app.getComponents(); diff --git a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx index f5cbb72fcd..82684636d6 100644 --- a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx +++ b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx @@ -27,7 +27,7 @@ const contextKey: string = 'plugin-context'; /** * Properties for the PluginProvider component. * - * @public + * @alpha */ export interface PluginOptionsProviderProps { children: ReactNode; @@ -44,7 +44,7 @@ export const PluginProvider = ({ plugin, }: PluginOptionsProviderProps): JSX.Element => { const { Provider } = createVersionedContext<{ - 1: { plugin: BackstagePlugin | undefined }; + 1: { plugin: BackstagePlugin | undefined }; }>(contextKey); return ( diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index 5d5362ad07..37ce6c9e7c 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -27,7 +27,7 @@ import { AnyApiFactory } from '../apis'; * @public */ export type Extension = { - expose(plugin: BackstagePlugin): T; + expose(plugin: BackstagePlugin): T; }; /** From 2b3e5fecd6338bf9ca89d1f780b37d15d751231a Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 12 Jul 2022 14:10:19 +0200 Subject: [PATCH 48/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- packages/core-components/package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 5fb8999c1b..a6dff88333 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -71,8 +71,7 @@ "react-window": "^1.8.6", "remark-gfm": "^3.0.1", "zen-observable": "^0.8.15", - "zod": "^3.11.6", - "@types/react-router-dom": "^5.3.3" + "zod": "^3.11.6" }, "peerDependencies": { "@types/react": "^16.13.1 || ^17.0.0", From fe1fb67df265b33046894cdb1021e007b46ff48f Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 12 Jul 2022 14:51:23 +0200 Subject: [PATCH 49/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- packages/core-app-api/src/app/types.ts | 2 +- yarn.lock | 11 +---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/core-app-api/src/app/types.ts b/packages/core-app-api/src/app/types.ts index 3bf2354e27..979fb0496e 100644 --- a/packages/core-app-api/src/app/types.ts +++ b/packages/core-app-api/src/app/types.ts @@ -206,7 +206,7 @@ export type AppOptions = { * A list of all plugins to include in the app. */ plugins?: Array< - BackstagePlugin & { + BackstagePlugin & { output?(): Array< { type: 'feature-flag'; name: string } | { type: string } >; // support for old plugins diff --git a/yarn.lock b/yarn.lock index e082fc6920..da18a0980a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6930,16 +6930,7 @@ hoist-non-react-statics "^3.3.0" redux "^4.0.0" -"@types/react-router-dom@^5.3.3": - version "5.3.3" - resolved "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83" - integrity sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw== - dependencies: - "@types/history" "^4.7.11" - "@types/react" "*" - "@types/react-router" "*" - -"@types/react-router@*", "@types/react-router@^5.1.18": +"@types/react-router@^5.1.18": version "5.1.18" resolved "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.18.tgz#c8851884b60bc23733500d86c1266e1cfbbd9ef3" integrity sha512-YYknwy0D0iOwKQgz9v8nOzt2J6l4gouBmDnWqUUznltOTaon+r8US8ky8HvN0tXvc38U9m6z/t2RsVsnd1zM0g== From 3f15ec4116d8868404d34e416826957d66f7416a Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Wed, 13 Jul 2022 10:58:51 +0200 Subject: [PATCH 50/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- plugins/permission-react/package.json | 3 +-- yarn.lock | 29 ++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index b298bf3657..2356c9a344 100644 --- a/plugins/permission-react/package.json +++ b/plugins/permission-react/package.json @@ -37,8 +37,7 @@ "cross-fetch": "^3.1.5", "react-router": "6.0.0-beta.0", "react-use": "^17.2.4", - "swr": "^1.1.2", - "@types/react-router": "^5.1.18" + "swr": "^1.1.2" }, "peerDependencies": { "@types/react": "^16.13.1 || ^17.0.0", diff --git a/yarn.lock b/yarn.lock index 1847591659..e301c74476 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1695,6 +1695,33 @@ yaml "^1.10.0" zen-observable "^0.8.15" +"@backstage/plugin-catalog@1.4.0-next.2": + version "1.4.0-next.2" + resolved "https://registry.npmjs.org/@backstage/plugin-catalog/-/plugin-catalog-1.4.0-next.2.tgz#57d32877f0b4bf255384053f8a58c2865efd5fa8" + integrity sha512-pLdEnlggXmYZQYPdG4m2ZqfiQlrKPnZ9MVVQmvKtd7FGVrguif7Wr5jPiP4DBOPlWQZoyeqqDu5+AWuNvcq/MQ== + dependencies: + "@backstage/catalog-client" "^1.0.4-next.1" + "@backstage/catalog-model" "^1.1.0-next.2" + "@backstage/core-components" "^0.10.0-next.2" + "@backstage/core-plugin-api" "^1.0.3" + "@backstage/errors" "^1.1.0-next.0" + "@backstage/integration-react" "^1.1.2-next.2" + "@backstage/plugin-catalog-common" "^1.0.4-next.0" + "@backstage/plugin-catalog-react" "^1.1.2-next.2" + "@backstage/plugin-search-common" "^0.3.6-next.0" + "@backstage/plugin-search-react" "^0.2.2-next.2" + "@backstage/theme" "^0.2.16-next.1" + "@backstage/types" "^1.0.0" + "@material-ui/core" "^4.12.2" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.57" + history "^5.0.0" + lodash "^4.17.21" + react-helmet "6.1.0" + react-router "6.0.0-beta.0" + react-use "^17.2.4" + zen-observable "^0.8.15" + "@backstage/plugin-home@^0.4.19", "@backstage/plugin-home@^0.4.22": version "0.4.22" resolved "https://registry.npmjs.org/@backstage/plugin-home/-/plugin-home-0.4.22.tgz#efc54ebffb83a2a36dcd43e65142c30be5d8559d" @@ -12614,7 +12641,6 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: "@backstage/plugin-api-docs" "^0.8.7-next.3" "@backstage/plugin-azure-devops" "^0.1.23-next.3" "@backstage/plugin-badges" "^0.2.31-next.3" - "@backstage/plugin-catalog" "^1.4.0-next.3" "@backstage/plugin-catalog-common" "^1.0.4-next.0" "@backstage/plugin-catalog-graph" "^0.2.19-next.3" "@backstage/plugin-catalog-import" "^0.8.10-next.3" @@ -12656,6 +12682,7 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: "@backstage/plugin-todo" "^0.2.9-next.3" "@backstage/plugin-user-settings" "^0.4.6-next.3" "@backstage/theme" "^0.2.16-next.1" + "@internal/plugin-catalog-customized" "0.0.0" "@material-ui/core" "^4.12.2" "@material-ui/icons" "^4.9.1" "@material-ui/lab" "4.0.0-alpha.57" From 62c368bae24221e8738b5be0c0791c8b208a235d Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Wed, 13 Jul 2022 11:32:58 +0200 Subject: [PATCH 51/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- packages/app/package.json | 2 +- plugins/catalog-customized/package.json | 4 +- yarn.lock | 66 ++++++++++++++----------- 3 files changed, 41 insertions(+), 31 deletions(-) diff --git a/packages/app/package.json b/packages/app/package.json index 54e5c8f366..9187acf775 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -64,7 +64,7 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "@octokit/rest": "^18.5.3", + "@octokit/rest": "^19.0.3", "@roadiehq/backstage-plugin-buildkite": "^2.0.0", "@roadiehq/backstage-plugin-github-insights": "^2.0.0", "@roadiehq/backstage-plugin-github-pull-requests": "^2.0.0", diff --git a/plugins/catalog-customized/package.json b/plugins/catalog-customized/package.json index 3d01044474..ccedc46683 100644 --- a/plugins/catalog-customized/package.json +++ b/plugins/catalog-customized/package.json @@ -34,8 +34,8 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/plugin-catalog": "1.4.0-next.2", - "@backstage/plugin-catalog-react": "^1.1.2-next.2" + "@backstage/plugin-catalog": "1.4.0-next.3", + "@backstage/plugin-catalog-react": "^1.1.2-next.3" }, "devDependencies": { "@types/react": "^16.13.1 || ^17.0.0" diff --git a/yarn.lock b/yarn.lock index e301c74476..3e4daeca8f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1695,33 +1695,6 @@ yaml "^1.10.0" zen-observable "^0.8.15" -"@backstage/plugin-catalog@1.4.0-next.2": - version "1.4.0-next.2" - resolved "https://registry.npmjs.org/@backstage/plugin-catalog/-/plugin-catalog-1.4.0-next.2.tgz#57d32877f0b4bf255384053f8a58c2865efd5fa8" - integrity sha512-pLdEnlggXmYZQYPdG4m2ZqfiQlrKPnZ9MVVQmvKtd7FGVrguif7Wr5jPiP4DBOPlWQZoyeqqDu5+AWuNvcq/MQ== - dependencies: - "@backstage/catalog-client" "^1.0.4-next.1" - "@backstage/catalog-model" "^1.1.0-next.2" - "@backstage/core-components" "^0.10.0-next.2" - "@backstage/core-plugin-api" "^1.0.3" - "@backstage/errors" "^1.1.0-next.0" - "@backstage/integration-react" "^1.1.2-next.2" - "@backstage/plugin-catalog-common" "^1.0.4-next.0" - "@backstage/plugin-catalog-react" "^1.1.2-next.2" - "@backstage/plugin-search-common" "^0.3.6-next.0" - "@backstage/plugin-search-react" "^0.2.2-next.2" - "@backstage/theme" "^0.2.16-next.1" - "@backstage/types" "^1.0.0" - "@material-ui/core" "^4.12.2" - "@material-ui/icons" "^4.9.1" - "@material-ui/lab" "4.0.0-alpha.57" - history "^5.0.0" - lodash "^4.17.21" - react-helmet "6.1.0" - react-router "6.0.0-beta.0" - react-use "^17.2.4" - zen-observable "^0.8.15" - "@backstage/plugin-home@^0.4.19", "@backstage/plugin-home@^0.4.22": version "0.4.22" resolved "https://registry.npmjs.org/@backstage/plugin-home/-/plugin-home-0.4.22.tgz#efc54ebffb83a2a36dcd43e65142c30be5d8559d" @@ -5128,6 +5101,11 @@ resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.4.0.tgz#fd8bf5db72bd566c5ba2cb76754512a9ebe66e71" integrity sha512-Npcb7Pv30b33U04jvcD7l75yLU0mxhuX2Xqrn51YyZ5WTkF04bpbxLaZ6GcaTqu03WZQHoO/Gbfp95NGRueDUA== +"@octokit/openapi-types@^12.7.0": + version "12.8.0" + resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.8.0.tgz#f4708cf948724d6e8f7d878cfd91584c1c5c0523" + integrity sha512-ydcKLs2KKcxlhpdWLzJxEBDEk/U5MUeqtqkXlrtAUXXFPs6vLl1PEGghFC/BbpleosB7iXs0Z4P2DGe7ZT5ZNg== + "@octokit/openapi-types@^7.3.2": version "7.3.2" resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-7.3.2.tgz#065ce49b338043ec7f741316ce06afd4d459d944" @@ -5159,6 +5137,13 @@ dependencies: "@octokit/types" "^6.0.1" +"@octokit/plugin-paginate-rest@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-3.0.0.tgz#df779de686aeb21b5e776e4318defc33b0418566" + integrity sha512-fvw0Q5IXnn60D32sKeLIxgXCEZ7BTSAjJd8cFAE6QU5qUp0xo7LjFUjjX1J5D7HgN355CN4EXE4+Q1/96JaNUA== + dependencies: + "@octokit/types" "^6.39.0" + "@octokit/plugin-request-log@^1.0.2": version "1.0.2" resolved "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.2.tgz#394d59ec734cd2f122431fbaf05099861ece3c44" @@ -5193,6 +5178,14 @@ "@octokit/types" "^6.36.0" deprecation "^2.3.1" +"@octokit/plugin-rest-endpoint-methods@^6.0.0": + version "6.0.1" + resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.0.1.tgz#dedf1698e7970ed1fd0d9fce09a6c5bb808a896f" + integrity sha512-Ge227MjEykkRI7OYkJ0NIZexjO1kzKAPW/pFyWZAGWT9uO3bChn57+NKleK8r9iXXN4SM0JkpJxK8TdbeCTPYw== + dependencies: + "@octokit/types" "^6.39.0" + deprecation "^2.3.1" + "@octokit/plugin-retry@^3.0.9": version "3.0.9" resolved "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-3.0.9.tgz#ae625cca1e42b0253049102acd71c1d5134788fe" @@ -5271,6 +5264,16 @@ "@octokit/plugin-request-log" "^1.0.4" "@octokit/plugin-rest-endpoint-methods" "^5.12.0" +"@octokit/rest@^19.0.3": + version "19.0.3" + resolved "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.3.tgz#b9a4e8dc8d53e030d611c053153ee6045f080f02" + integrity sha512-5arkTsnnRT7/sbI4fqgSJ35KiFaN7zQm0uQiQtivNQLI8RQx8EHwJCajcTUwmaCMNDg7tdCvqAnc7uvHHPxrtQ== + dependencies: + "@octokit/core" "^4.0.0" + "@octokit/plugin-paginate-rest" "^3.0.0" + "@octokit/plugin-request-log" "^1.0.4" + "@octokit/plugin-rest-endpoint-methods" "^6.0.0" + "@octokit/types@^5.0.0", "@octokit/types@^5.0.1": version "5.5.0" resolved "https://registry.npmjs.org/@octokit/types/-/types-5.5.0.tgz#e5f06e8db21246ca102aa28444cdb13ae17a139b" @@ -5299,6 +5302,13 @@ dependencies: "@octokit/openapi-types" "^12.4.0" +"@octokit/types@^6.39.0": + version "6.39.0" + resolved "https://registry.npmjs.org/@octokit/types/-/types-6.39.0.tgz#46ce28ca59a3d4bac0e487015949008302e78eee" + integrity sha512-Mq4N9sOAYCitTsBtDdRVrBE80lIrMBhL9Jbrw0d+j96BAzlq4V+GLHFJbHokEsVvO/9tQupQdoFdgVYhD2C8UQ== + dependencies: + "@octokit/openapi-types" "^12.7.0" + "@octokit/webhooks-methods@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@octokit/webhooks-methods/-/webhooks-methods-3.0.0.tgz#4f4443605233f46abc5f85a857ba105095aa1181" @@ -12686,7 +12696,7 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: "@material-ui/core" "^4.12.2" "@material-ui/icons" "^4.9.1" "@material-ui/lab" "4.0.0-alpha.57" - "@octokit/rest" "^18.5.3" + "@octokit/rest" "^19.0.3" "@roadiehq/backstage-plugin-buildkite" "^2.0.0" "@roadiehq/backstage-plugin-github-insights" "^2.0.0" "@roadiehq/backstage-plugin-github-pull-requests" "^2.0.0" From a405ec5a9555e216f9be2b91d466115885b1de09 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Wed, 13 Jul 2022 13:56:08 +0200 Subject: [PATCH 52/54] Incorporated the feedback. Signed-off-by: bnechyporenko --- .changeset/gentle-games-count.md | 11 ----------- .changeset/hungry-hotels-flow.md | 6 ------ 2 files changed, 17 deletions(-) delete mode 100644 .changeset/gentle-games-count.md delete mode 100644 .changeset/hungry-hotels-flow.md diff --git a/.changeset/gentle-games-count.md b/.changeset/gentle-games-count.md deleted file mode 100644 index 99f62a4506..0000000000 --- a/.changeset/gentle-games-count.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/app-defaults': patch ---- - -Updated usage of the `BackstagePlugin` type. - -``` -myPlugin.__experimentalReconfigure({ -... -}); -``` diff --git a/.changeset/hungry-hotels-flow.md b/.changeset/hungry-hotels-flow.md deleted file mode 100644 index 0fef92bd90..0000000000 --- a/.changeset/hungry-hotels-flow.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/core-app-api': patch ---- - -Introduced an extra parameter in BackstagePlugin. -This optional parameter is responsible for providing a type for input options for the plugin. From fcf972fbfbed6570d4c4a3daef5d872526b101f1 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 19 Jul 2022 18:22:19 +0200 Subject: [PATCH 53/54] Updated deps Signed-off-by: bnechyporenko --- plugins/catalog-customized/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/catalog-customized/package.json b/plugins/catalog-customized/package.json index ccedc46683..537d6858c6 100644 --- a/plugins/catalog-customized/package.json +++ b/plugins/catalog-customized/package.json @@ -34,8 +34,8 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/plugin-catalog": "1.4.0-next.3", - "@backstage/plugin-catalog-react": "^1.1.2-next.3" + "@backstage/plugin-catalog": "^1.4.0", + "@backstage/plugin-catalog-react": "^1.1.2" }, "devDependencies": { "@types/react": "^16.13.1 || ^17.0.0" From c38cb38339a443b77a9fd9e2b9837cfc17dfbc66 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Tue, 19 Jul 2022 18:48:34 +0200 Subject: [PATCH 54/54] api-report.md Signed-off-by: bnechyporenko --- plugins/apollo-explorer/api-report.md | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/apollo-explorer/api-report.md b/plugins/apollo-explorer/api-report.md index 593f8f3004..80dae62e60 100644 --- a/plugins/apollo-explorer/api-report.md +++ b/plugins/apollo-explorer/api-report.md @@ -41,6 +41,7 @@ export const apolloExplorerPlugin: BackstagePlugin< { root: RouteRef; }, + {}, {} >;