From c3f56507740906dddeeb6304216db9f77755dec6 Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 23 Jul 2024 10:32:30 +0200 Subject: [PATCH 1/3] chore: migrate the EntityCardExtension to EntityCardBlueprint Signed-off-by: blam --- plugins/catalog-react/src/alpha.tsx | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/plugins/catalog-react/src/alpha.tsx b/plugins/catalog-react/src/alpha.tsx index e81b8e5ebf..7f276b8ea6 100644 --- a/plugins/catalog-react/src/alpha.tsx +++ b/plugins/catalog-react/src/alpha.tsx @@ -22,6 +22,7 @@ import { RouteRef, coreExtensionData, createExtension, + createExtensionBlueprint, createExtensionDataRef, createSchemaFromZod, } from '@backstage/frontend-plugin-api'; @@ -47,6 +48,44 @@ export const catalogExtensionData = { }), }; +/** @alpha */ +export const EntityCardBlueprint = createExtensionBlueprint({ + kind: 'entity-card', + attachTo: { id: 'entity-content:catalog/overview', input: 'cards' }, + configSchema: createSchemaFromZod(z => + z.object({ + filter: z.string().optional(), + }), + ), + output: { + element: coreExtensionData.reactElement, + filterFunction: catalogExtensionData.entityFilterFunction.optional(), + filterExpression: catalogExtensionData.entityFilterExpression.optional(), + }, + factory( + params: { + filter?: + | typeof catalogExtensionData.entityFilterFunction.T + | typeof catalogExtensionData.entityFilterExpression.T; + loader: () => Promise; + }, + { node, config }, + ) { + const ExtensionComponent = lazy(() => + params.loader().then(element => ({ default: () => element })), + ); + + return { + element: ( + + + + ), + ...mergeFilters({ config, options: params }), + }; + }, +}); + // TODO: Figure out how to merge with provided config schema /** @alpha */ export function createEntityCardExtension< From d5bf3b1f4b7dd3f1c2ba76141c3ba972e0dcfd20 Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 23 Jul 2024 11:09:33 +0200 Subject: [PATCH 2/3] chore: rework how to define factory functions and params in blueprints Signed-off-by: blam --- .../wiring/createExtensionBlueprint.test.tsx | 13 +-- .../src/wiring/createExtensionBlueprint.ts | 110 ++++++++++-------- 2 files changed, 66 insertions(+), 57 deletions(-) diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx index 87b3cec152..d2373518a3 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx @@ -88,20 +88,17 @@ describe('createExtensionBlueprint', () => { const extension = TestExtensionBlueprint.make({ name: 'my-extension', - params: { - text: 'Hello, world!', - }, - factory(params: { text: string }) { - return { - element:

{params.text}

, - }; + factory(origFactory) { + return origFactory({ + text: 'Hello, world!', + }); }, }); expect(extension).toBeDefined(); const { container } = createExtensionTester(extension).render(); - expect(container.querySelector('h2')).toHaveTextContent('Hello, world!'); + expect(container.querySelector('h1')).toHaveTextContent('Hello, world!'); }); it('should allow exporting the dataRefs from the extension blueprint', () => { diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts index b504db5f03..fb9081f7f8 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts @@ -67,32 +67,43 @@ export interface ExtensionBlueprint< > { dataRefs: TDataRefs; - make(args: { - namespace?: string; - name?: string; - attachTo?: { id: string; input: string }; - disabled?: boolean; - inputs?: TInputs; - output?: TOutput; - configSchema?: PortableSchema; - params: TParams; - factory?( - params: TParams, - context: { - node: AppNode; - config: TConfig; - inputs: Expand>; - orignalFactory( - params?: TParams, - context?: { - node?: AppNode; - config?: TConfig; - inputs?: Expand>; - }, - ): Expand>; - }, - ): Expand>; - }): ExtensionDefinition; + /** + * Creates a new extension from the blueprint. + * + * You must either pass `params` directly, or define a `factory` that can + * optionally call the original factory with the same params. + */ + make( + args: { + namespace?: string; + name?: string; + attachTo?: { id: string; input: string }; + disabled?: boolean; + inputs?: TInputs; + output?: TOutput; + configSchema?: PortableSchema; + } & ( + | { + factory( + originalFactory: ( + params: TParams, + context?: { + config?: TConfig; + inputs?: Expand>; + }, + ) => Expand>, + context: { + node: AppNode; + config: TConfig; + inputs: Expand>; + }, + ): Expand>; + } + | { + params: TParams; + } + ), + ): ExtensionDefinition; } /** @@ -127,21 +138,19 @@ class ExtensionBlueprintImpl< inputs?: TInputs; output?: TOutput; configSchema?: PortableSchema; - params: TParams; + params?: TParams; factory?( - params: TParams, + originalFactory: ( + params: TParams, + context?: { + config?: TConfig; + inputs?: Expand>; + }, + ) => Expand>, context: { node: AppNode; config: TConfig; inputs: Expand>; - orignalFactory( - params?: TParams, - context?: { - node?: AppNode; - config?: TConfig; - inputs?: Expand>; - }, - ): Expand>; }, ): Expand>; }): ExtensionDefinition { @@ -156,30 +165,33 @@ class ExtensionBlueprintImpl< configSchema: args.configSchema ?? this.options.configSchema, // TODO: some config merging or smth factory: ({ node, config, inputs }) => { if (args.factory) { - return args.factory(args.params, { - node, - config, - inputs, - orignalFactory: ( - innerParams?: TParams, + return args.factory( + ( + innerParams: TParams, innerContext?: { config?: TConfig; inputs?: Expand>; }, ) => - this.options.factory(innerParams ?? args.params, { + this.options.factory(innerParams, { node, config: innerContext?.config ?? config, inputs: innerContext?.inputs ?? inputs, }), + { + node, + config, + inputs, + }, + ); + } else if (args.params) { + return this.options.factory(args.params, { + node, + config, + inputs, }); } - - return this.options.factory(args.params, { - node, - config, - inputs, - }); + throw new Error('Either params or factory must be provided'); }, }); } From 81ea85028c0551474f390cb32b08d4096ebdc6cf Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 23 Jul 2024 11:16:05 +0200 Subject: [PATCH 3/3] chore: fix api-reports Signed-off-by: blam --- packages/frontend-plugin-api/api-report.md | 64 ++++++++++++---------- plugins/catalog-react/src/alpha.tsx | 39 ------------- 2 files changed, 34 insertions(+), 69 deletions(-) diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 3c082a7694..d6a91c0c99 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -931,36 +931,40 @@ export interface ExtensionBlueprint< > { // (undocumented) dataRefs: TDataRefs; - // (undocumented) - make(args: { - namespace?: string; - name?: string; - attachTo?: { - id: string; - input: string; - }; - disabled?: boolean; - inputs?: TInputs; - output?: TOutput; - configSchema?: PortableSchema; - params: TParams; - factory?( - params: TParams, - context: { - node: AppNode; - config: TConfig; - inputs: Expand>; - orignalFactory( - params?: TParams, - context?: { - node?: AppNode; - config?: TConfig; - inputs?: Expand>; - }, - ): Expand>; - }, - ): Expand>; - }): ExtensionDefinition; + make( + args: { + namespace?: string; + name?: string; + attachTo?: { + id: string; + input: string; + }; + disabled?: boolean; + inputs?: TInputs; + output?: TOutput; + configSchema?: PortableSchema; + } & ( + | { + factory( + originalFactory: ( + params: TParams, + context?: { + config?: TConfig; + inputs?: Expand>; + }, + ) => Expand>, + context: { + node: AppNode; + config: TConfig; + inputs: Expand>; + }, + ): Expand>; + } + | { + params: TParams; + } + ), + ): ExtensionDefinition; } // @public (undocumented) diff --git a/plugins/catalog-react/src/alpha.tsx b/plugins/catalog-react/src/alpha.tsx index 7f276b8ea6..e81b8e5ebf 100644 --- a/plugins/catalog-react/src/alpha.tsx +++ b/plugins/catalog-react/src/alpha.tsx @@ -22,7 +22,6 @@ import { RouteRef, coreExtensionData, createExtension, - createExtensionBlueprint, createExtensionDataRef, createSchemaFromZod, } from '@backstage/frontend-plugin-api'; @@ -48,44 +47,6 @@ export const catalogExtensionData = { }), }; -/** @alpha */ -export const EntityCardBlueprint = createExtensionBlueprint({ - kind: 'entity-card', - attachTo: { id: 'entity-content:catalog/overview', input: 'cards' }, - configSchema: createSchemaFromZod(z => - z.object({ - filter: z.string().optional(), - }), - ), - output: { - element: coreExtensionData.reactElement, - filterFunction: catalogExtensionData.entityFilterFunction.optional(), - filterExpression: catalogExtensionData.entityFilterExpression.optional(), - }, - factory( - params: { - filter?: - | typeof catalogExtensionData.entityFilterFunction.T - | typeof catalogExtensionData.entityFilterExpression.T; - loader: () => Promise; - }, - { node, config }, - ) { - const ExtensionComponent = lazy(() => - params.loader().then(element => ({ default: () => element })), - ); - - return { - element: ( - - - - ), - ...mergeFilters({ config, options: params }), - }; - }, -}); - // TODO: Figure out how to merge with provided config schema /** @alpha */ export function createEntityCardExtension<