From e6c763f76b6d19865a320c86a361fbb3ef5035f9 Mon Sep 17 00:00:00 2001 From: blam Date: Fri, 9 Aug 2024 15:12:47 +0200 Subject: [PATCH] chore: getting the tests working MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Patrik Oldsberg Co-authored-by: Fredrik Adelöw Co-authored-by: Camila Belo Signed-off-by: blam --- packages/frontend-plugin-api/api-report.md | 410 +++++++++++++++--- .../ApiBlueprint.test.ts | 3 +- .../ApiBlueprint.ts | 4 +- .../AppRootElementBlueprint.test.tsx | 0 .../AppRootElementBlueprint.ts | 1 + .../AppRootWrapperBlueprint.test.tsx | 7 +- .../AppRootWrapperBlueprint.tsx | 3 +- .../IconBundleBlueprint.ts | 0 .../NavItemBlueprint.test.tsx | 1 - .../NavItemBlueprint.ts | 12 +- .../NavLogoBlueprint.test.tsx | 0 .../NavLogoBlueprint.ts | 3 +- .../PageBlueprint.test.tsx | 2 +- .../PageBlueprint.tsx | 5 +- .../RouterBlueprint.test.tsx | 2 +- .../RouterBlueprint.tsx | 3 +- .../SignInPageBlueprint.test.tsx | 0 .../SignInPageBlueprint.tsx | 3 +- .../ThemeBlueprint.test.ts | 3 +- .../ThemeBlueprint.ts | 4 +- .../TranslationBlueprint.test.ts | 2 +- .../TranslationBlueprint.ts | 4 +- .../src/blueprints/index.ts | 27 ++ .../src/extensions/createApiExtension.ts | 5 +- .../createAppRootElementExtension.ts | 1 + .../createAppRootWrapperExtension.tsx | 1 + .../src/extensions/createNavItemExtension.tsx | 2 + .../src/extensions/createNavLogoExtension.tsx | 2 + .../src/extensions/createPageExtension.tsx | 1 + .../src/extensions/createRouterExtension.tsx | 1 + .../extensions/createSignInPageExtension.tsx | 1 + .../src/extensions/createThemeExtension.ts | 10 +- .../extensions/createTranslationExtension.ts | 10 +- .../src/extensions/index.ts | 1 - packages/frontend-plugin-api/src/index.ts | 1 + .../wiring/createExtensionBlueprint.test.tsx | 95 +--- .../src/wiring/createExtensionBlueprint.ts | 224 +++++----- .../src/app/createExtensionTester.tsx | 5 +- 38 files changed, 578 insertions(+), 281 deletions(-) rename packages/frontend-plugin-api/src/{extensions => blueprints}/ApiBlueprint.test.ts (97%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/ApiBlueprint.ts (91%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/AppRootElementBlueprint.test.tsx (100%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/AppRootElementBlueprint.ts (98%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/AppRootWrapperBlueprint.test.tsx (95%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/AppRootWrapperBlueprint.tsx (92%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/IconBundleBlueprint.ts (100%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/NavItemBlueprint.test.tsx (98%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/NavItemBlueprint.ts (86%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/NavLogoBlueprint.test.tsx (100%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/NavLogoBlueprint.ts (92%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/PageBlueprint.test.tsx (98%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/PageBlueprint.tsx (97%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/RouterBlueprint.test.tsx (98%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/RouterBlueprint.tsx (92%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/SignInPageBlueprint.test.tsx (100%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/SignInPageBlueprint.tsx (93%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/ThemeBlueprint.test.ts (94%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/ThemeBlueprint.ts (91%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/TranslationBlueprint.test.ts (98%) rename packages/frontend-plugin-api/src/{extensions => blueprints}/TranslationBlueprint.ts (90%) create mode 100644 packages/frontend-plugin-api/src/blueprints/index.ts diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index a8f8ce591b..2d3f1d3278 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -189,6 +189,27 @@ export type AnyRoutes = { [name in string]: RouteRef | SubRouteRef; }; +// @public (undocumented) +export const ApiBlueprint: ExtensionBlueprint< + 'api', + undefined, + undefined, + { + factory: AnyApiFactory; + }, + ConfigurableExtensionDataRef, + {}, + {}, + {}, + { + factory: ConfigurableExtensionDataRef< + AnyApiFactory, + 'core.api.factory', + {} + >; + } +>; + export { ApiFactory }; export { ApiHolder }; @@ -240,6 +261,50 @@ export interface AppNodeSpec { readonly source?: BackstagePlugin; } +// @public (undocumented) +export const AppRootElementBlueprint: ExtensionBlueprint< + 'app-root-element', + undefined, + undefined, + { + element: JSX.Element | (() => JSX.Element); + }, + ConfigurableExtensionDataRef, + {}, + {}, + {}, + never +>; + +// @public (undocumented) +export const AppRootWrapperBlueprint: ExtensionBlueprint< + 'app-root-wrapper', + undefined, + undefined, + { + Component: ComponentType>; + }, + ConfigurableExtensionDataRef< + React_2.ComponentType<{ + children?: React_2.ReactNode; + }>, + 'app.root.wrapper', + {} + >, + {}, + {}, + {}, + { + component: ConfigurableExtensionDataRef< + React_2.ComponentType<{ + children?: React_2.ReactNode; + }>, + 'app.root.wrapper', + {} + >; + } +>; + export { AppTheme }; export { AppThemeApi }; @@ -381,7 +446,7 @@ export type CoreNotFoundErrorPageProps = { // @public (undocumented) export type CoreProgressProps = {}; -// @public (undocumented) +// @public @deprecated (undocumented) export function createApiExtension< TConfig extends {}, TInputs extends AnyExtensionInputMap, @@ -425,7 +490,7 @@ export { createApiFactory }; export { createApiRef }; -// @public +// @public @deprecated export function createAppRootElementExtension< TConfig extends {}, TInputs extends AnyExtensionInputMap, @@ -447,7 +512,7 @@ export function createAppRootElementExtension< }) => JSX_2.Element); }): ExtensionDefinition; -// @public +// @public @deprecated export function createAppRootWrapperExtension< TConfig extends {}, TInputs extends AnyExtensionInputMap, @@ -675,7 +740,7 @@ export type CreateExtensionBlueprintOptions< }, > = { kind: TKind; - namespace?: TNamespace | ((params: TParams) => TNamespace); + namespace?: TNamespace; attachTo: { id: string; input: string; @@ -683,9 +748,9 @@ export type CreateExtensionBlueprintOptions< disabled?: boolean; inputs?: TInputs; output: Array; - name?: TName | ((params: TParams) => TName); + name?: TName; config?: { - schema: TConfigSchema | ((params: TParams) => TConfigSchema); + schema: TConfigSchema; }; factory( params: TParams, @@ -824,7 +889,7 @@ export function createExternalRouteRef< } >; -// @public +// @public @deprecated export function createNavItemExtension(options: { namespace?: string; name?: string; @@ -859,7 +924,7 @@ export namespace createNavItemExtension { >; } -// @public +// @public @deprecated export function createNavLogoExtension(options: { name?: string; namespace?: string; @@ -888,7 +953,7 @@ export namespace createNavLogoExtension { >; } -// @public +// @public @deprecated export function createPageExtension< TConfig extends { path: string; @@ -958,7 +1023,7 @@ export function createRouteRef< } >; -// @public +// @public @deprecated export function createRouterExtension< TConfig extends {}, TInputs extends AnyExtensionInputMap, @@ -997,7 +1062,7 @@ export function createSchemaFromZod( schemaCreator: (zImpl: typeof z) => ZodSchema, ): PortableSchema; -// @public (undocumented) +// @public @deprecated (undocumented) export function createSignInPageExtension< TConfig extends {}, TInputs extends AnyExtensionInputMap, @@ -1036,7 +1101,7 @@ export function createSubRouteRef< parent: RouteRef; }): MakeSubRouteRef, ParentParams>; -// @public (undocumented) +// @public @deprecated (undocumented) export function createThemeExtension( theme: AppTheme, ): ExtensionDefinition< @@ -1049,7 +1114,7 @@ export function createThemeExtension( string | undefined >; -// @public (undocumented) +// @public @deprecated (undocumented) export namespace createThemeExtension { const // (undocumented) themeDataRef: ConfigurableExtensionDataRef< @@ -1059,7 +1124,7 @@ export namespace createThemeExtension { >; } -// @public (undocumented) +// @public @deprecated (undocumented) export function createTranslationExtension(options: { name?: string; resource: TranslationResource | TranslationMessages; @@ -1073,7 +1138,7 @@ export function createTranslationExtension(options: { string | undefined >; -// @public (undocumented) +// @public @deprecated (undocumented) export namespace createTranslationExtension { const // (undocumented) translationDataRef: ConfigurableExtensionDataRef< @@ -1153,9 +1218,31 @@ export interface ExtensionBlueprint< > { // (undocumented) dataRefs: TDataRefs; + // (undocumented) make< TNewNamespace extends string | undefined, TNewName extends string | undefined, + >(args: { + namespace?: TNewNamespace; + name?: TNewName; + attachTo?: { + id: string; + input: string; + }; + disabled?: boolean; + params: TParams; + }): ExtensionDefinition< + TConfig, + TConfigInput, + UOutput, + TInputs, + TKind, + string | undefined extends TNewNamespace ? TNamespace : TNewNamespace, + string | undefined extends TNewName ? TName : TNewName + >; + makeWithOverrides< + TNewNamespace extends string | undefined, + TNewName extends string | undefined, TExtensionConfigSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType; }, @@ -1170,55 +1257,48 @@ export interface ExtensionBlueprint< } >; }, - >( - args: { - namespace?: TNewNamespace; - name?: TNewName; - attachTo?: { - id: string; - input: string; + >(args: { + namespace?: TNewNamespace; + name?: TNewName; + attachTo?: { + id: string; + input: string; + }; + disabled?: boolean; + inputs?: TExtraInputs & { + [KName in keyof TInputs]?: `Error: Input '${KName & + string}' is already defined in parent definition`; + }; + output?: Array; + config?: { + schema: TExtensionConfigSchema & { + [KName in keyof TConfig]?: `Error: Config key '${KName & + string}' is already defined in parent schema`; }; - disabled?: boolean; - inputs?: TExtraInputs & { - [KName in keyof TInputs]?: `Error: Input '${KName & - string}' is already defined in parent definition`; - }; - output?: Array; - config?: { - schema: TExtensionConfigSchema & { - [KName in keyof TConfig]?: `Error: Config key '${KName & - string}' is already defined in parent schema`; + }; + factory( + originalFactory: ( + params: TParams, + context?: { + config?: TConfig; + inputs?: Expand>; + }, + ) => ExtensionDataContainer, + context: { + node: AppNode; + config: TConfig & { + [key in keyof TExtensionConfigSchema]: z.infer< + ReturnType + >; }; - }; - } & ( - | ({ - factory( - originalFactory: ( - params: TParams, - context?: { - config?: TConfig; - inputs?: Expand>; - }, - ) => ExtensionDataContainer, - context: { - node: AppNode; - config: TConfig & { - [key in keyof TExtensionConfigSchema]: z.infer< - ReturnType - >; - }; - inputs: Expand>; - }, - ): Iterable; - } & VerifyExtensionFactoryOutput< - AnyExtensionDataRef extends UNewOutput ? UOutput : UNewOutput, - UFactoryOutput - >) - | { - params: TParams; - } - ), - ): ExtensionDefinition< + inputs: Expand>; + }, + ): Iterable & + VerifyExtensionFactoryOutput< + AnyExtensionDataRef extends UNewOutput ? UOutput : UNewOutput, + UFactoryOutput + >; + }): ExtensionDefinition< { [key in keyof TExtensionConfigSchema]: z.infer< ReturnType @@ -1616,6 +1696,73 @@ export interface LegacyExtensionInput< export { microsoftAuthApiRef }; +// @public (undocumented) +export const NavItemBlueprint: ExtensionBlueprint< + 'nav-item', + undefined, + undefined, + { + title: string; + icon: IconComponent_2; + routeRef: RouteRef; + }, + ConfigurableExtensionDataRef< + { + title: string; + icon: IconComponent_2; + routeRef: RouteRef; + }, + 'core.nav-item.target', + {} + >, + {}, + {}, + {}, + { + target: ConfigurableExtensionDataRef< + { + title: string; + icon: IconComponent_2; + routeRef: RouteRef; + }, + 'core.nav-item.target', + {} + >; + } +>; + +// @public (undocumented) +export const NavLogoBlueprint: ExtensionBlueprint< + 'nav-logo', + undefined, + undefined, + { + logoIcon: JSX.Element; + logoFull: JSX.Element; + }, + ConfigurableExtensionDataRef< + { + logoIcon?: JSX.Element | undefined; + logoFull?: JSX.Element | undefined; + }, + 'core.nav-logo.logo-elements', + {} + >, + {}, + {}, + {}, + { + logoElements: ConfigurableExtensionDataRef< + { + logoIcon?: JSX.Element | undefined; + logoFull?: JSX.Element | undefined; + }, + 'core.nav-logo.logo-elements', + {} + >; + } +>; + export { OAuthApi }; export { OAuthRequestApi }; @@ -1634,6 +1781,35 @@ export { oneloginAuthApiRef }; export { OpenIdConnectApi }; +// @public (undocumented) +export const PageBlueprint: ExtensionBlueprint< + 'page', + undefined, + undefined, + { + defaultPath: string; + loader: () => Promise; + routeRef?: RouteRef | undefined; + }, + | ConfigurableExtensionDataRef + | ConfigurableExtensionDataRef + | ConfigurableExtensionDataRef< + RouteRef, + 'core.routing.ref', + RouteRef & { + optional: true; + } + >, + {}, + { + path: string | undefined; + }, + { + path?: string | undefined; + }, + never +>; + export { PendingOAuthRequest }; // @public (undocumented) @@ -1699,6 +1875,35 @@ export type RouteFunc = ( : readonly [params: TParams] ) => string; +// @public (undocumented) +export const RouterBlueprint: ExtensionBlueprint< + 'app-router-component', + undefined, + undefined, + { + Component: ComponentType>; + }, + ConfigurableExtensionDataRef< + ComponentType<{ + children?: ReactNode; + }>, + 'app.router.wrapper', + {} + >, + {}, + {}, + {}, + { + component: ConfigurableExtensionDataRef< + ComponentType<{ + children?: ReactNode; + }>, + 'app.router.wrapper', + {} + >; + } +>; + // @public export interface RouteRef< TParams extends AnyRouteRefParams = AnyRouteRefParams, @@ -1733,6 +1938,31 @@ export { SessionApi }; export { SessionState }; +// @public (undocumented) +export const SignInPageBlueprint: ExtensionBlueprint< + 'sign-in-page', + undefined, + undefined, + { + loader: () => Promise>; + }, + ConfigurableExtensionDataRef< + React_2.ComponentType, + 'core.sign-in-page.component', + {} + >, + {}, + {}, + {}, + { + component: ConfigurableExtensionDataRef< + React_2.ComponentType, + 'core.sign-in-page.component', + {} + >; + } +>; + export { StorageApi }; export { storageApiRef }; @@ -1751,6 +1981,62 @@ export interface SubRouteRef< readonly T: TParams; } +// @public (undocumented) +export const ThemeBlueprint: ExtensionBlueprint< + 'theme', + 'app', + undefined, + { + theme: AppTheme; + }, + ConfigurableExtensionDataRef, + {}, + {}, + {}, + { + theme: ConfigurableExtensionDataRef; + } +>; + +// @public (undocumented) +export const TranslationBlueprint: ExtensionBlueprint< + 'translation', + undefined, + undefined, + { + resource: TranslationResource | TranslationMessages; + }, + ConfigurableExtensionDataRef< + | TranslationResource + | TranslationMessages< + string, + { + [x: string]: string; + }, + boolean + >, + 'core.translation.translation', + {} + >, + {}, + {}, + {}, + { + translation: ConfigurableExtensionDataRef< + | TranslationResource + | TranslationMessages< + string, + { + [x: string]: string; + }, + boolean + >, + 'core.translation.translation', + {} + >; + } +>; + export { TranslationMessages }; export { TranslationMessagesOptions }; diff --git a/packages/frontend-plugin-api/src/extensions/ApiBlueprint.test.ts b/packages/frontend-plugin-api/src/blueprints/ApiBlueprint.test.ts similarity index 97% rename from packages/frontend-plugin-api/src/extensions/ApiBlueprint.test.ts rename to packages/frontend-plugin-api/src/blueprints/ApiBlueprint.test.ts index f070956e96..3b865a78bb 100644 --- a/packages/frontend-plugin-api/src/extensions/ApiBlueprint.test.ts +++ b/packages/frontend-plugin-api/src/blueprints/ApiBlueprint.test.ts @@ -30,6 +30,7 @@ describe('ApiBlueprint', () => { params: { factory, }, + namespace: 'test', }); expect(extension).toMatchInlineSnapshot(` @@ -60,7 +61,7 @@ describe('ApiBlueprint', () => { const api = createApiRef<{ foo: string }>({ id: 'test' }); const factory = jest.fn(() => ({ foo: 'bar' })); - const extension = ApiBlueprint.make({ + const extension = ApiBlueprint.makeWithOverrides({ config: { schema: { test: z => z.string().default('test'), diff --git a/packages/frontend-plugin-api/src/extensions/ApiBlueprint.ts b/packages/frontend-plugin-api/src/blueprints/ApiBlueprint.ts similarity index 91% rename from packages/frontend-plugin-api/src/extensions/ApiBlueprint.ts rename to packages/frontend-plugin-api/src/blueprints/ApiBlueprint.ts index 16a20b5130..da12faef1a 100644 --- a/packages/frontend-plugin-api/src/extensions/ApiBlueprint.ts +++ b/packages/frontend-plugin-api/src/blueprints/ApiBlueprint.ts @@ -14,9 +14,10 @@ * limitations under the License. */ import { createExtensionBlueprint } from '../wiring'; -import { createApiExtension } from './createApiExtension'; +import { createApiExtension } from '../extensions/createApiExtension'; import { AnyApiFactory } from '@backstage/core-plugin-api'; +/** @public */ export const ApiBlueprint = createExtensionBlueprint({ kind: 'api', attachTo: { id: 'app', input: 'apis' }, @@ -27,5 +28,4 @@ export const ApiBlueprint = createExtensionBlueprint({ *factory(params: { factory: AnyApiFactory }) { yield createApiExtension.factoryDataRef(params.factory); }, - namespace: ({ factory }) => factory.api.id, }); diff --git a/packages/frontend-plugin-api/src/extensions/AppRootElementBlueprint.test.tsx b/packages/frontend-plugin-api/src/blueprints/AppRootElementBlueprint.test.tsx similarity index 100% rename from packages/frontend-plugin-api/src/extensions/AppRootElementBlueprint.test.tsx rename to packages/frontend-plugin-api/src/blueprints/AppRootElementBlueprint.test.tsx diff --git a/packages/frontend-plugin-api/src/extensions/AppRootElementBlueprint.ts b/packages/frontend-plugin-api/src/blueprints/AppRootElementBlueprint.ts similarity index 98% rename from packages/frontend-plugin-api/src/extensions/AppRootElementBlueprint.ts rename to packages/frontend-plugin-api/src/blueprints/AppRootElementBlueprint.ts index 1048d531ab..e44942979d 100644 --- a/packages/frontend-plugin-api/src/extensions/AppRootElementBlueprint.ts +++ b/packages/frontend-plugin-api/src/blueprints/AppRootElementBlueprint.ts @@ -15,6 +15,7 @@ */ import { coreExtensionData, createExtensionBlueprint } from '../wiring'; +/** @public */ export const AppRootElementBlueprint = createExtensionBlueprint({ kind: 'app-root-element', attachTo: { id: 'app/root', input: 'elements' }, diff --git a/packages/frontend-plugin-api/src/extensions/AppRootWrapperBlueprint.test.tsx b/packages/frontend-plugin-api/src/blueprints/AppRootWrapperBlueprint.test.tsx similarity index 95% rename from packages/frontend-plugin-api/src/extensions/AppRootWrapperBlueprint.test.tsx rename to packages/frontend-plugin-api/src/blueprints/AppRootWrapperBlueprint.test.tsx index 2ff46f0785..f7feab1d46 100644 --- a/packages/frontend-plugin-api/src/extensions/AppRootWrapperBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/blueprints/AppRootWrapperBlueprint.test.tsx @@ -78,7 +78,7 @@ describe('AppRootWrapperBlueprint', () => { }); it('should render the complex component wrapper', async () => { - const extension = AppRootWrapperBlueprint.make({ + const extension = AppRootWrapperBlueprint.makeWithOverrides({ namespace: 'ns', name: 'test', config: { @@ -94,6 +94,9 @@ describe('AppRootWrapperBlueprint', () => { Component: ({ children }) => (
{children} + {inputs.children.flatMap(c => + c.get(coreExtensionData.reactElement), + )}
), }); @@ -119,9 +122,9 @@ describe('AppRootWrapperBlueprint', () => { .render(); await waitFor(() => { - expect(getByText('Its Me')).toBeInTheDocument(); expect(getByText('Hi')).toBeInTheDocument(); expect(getByTestId('Robin-1')).toBeInTheDocument(); + expect(getByText('Its Me')).toBeInTheDocument(); }); }); }); diff --git a/packages/frontend-plugin-api/src/extensions/AppRootWrapperBlueprint.tsx b/packages/frontend-plugin-api/src/blueprints/AppRootWrapperBlueprint.tsx similarity index 92% rename from packages/frontend-plugin-api/src/extensions/AppRootWrapperBlueprint.tsx rename to packages/frontend-plugin-api/src/blueprints/AppRootWrapperBlueprint.tsx index 4e8cab8f1b..db63550880 100644 --- a/packages/frontend-plugin-api/src/extensions/AppRootWrapperBlueprint.tsx +++ b/packages/frontend-plugin-api/src/blueprints/AppRootWrapperBlueprint.tsx @@ -17,8 +17,9 @@ import React from 'react'; import { ComponentType, PropsWithChildren } from 'react'; import { createExtensionBlueprint } from '../wiring'; -import { createAppRootWrapperExtension } from './createAppRootWrapperExtension'; +import { createAppRootWrapperExtension } from '../extensions/createAppRootWrapperExtension'; +/** @public */ export const AppRootWrapperBlueprint = createExtensionBlueprint({ kind: 'app-root-wrapper', attachTo: { id: 'app/root', input: 'wrappers' }, diff --git a/packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts b/packages/frontend-plugin-api/src/blueprints/IconBundleBlueprint.ts similarity index 100% rename from packages/frontend-plugin-api/src/extensions/IconBundleBlueprint.ts rename to packages/frontend-plugin-api/src/blueprints/IconBundleBlueprint.ts diff --git a/packages/frontend-plugin-api/src/extensions/NavItemBlueprint.test.tsx b/packages/frontend-plugin-api/src/blueprints/NavItemBlueprint.test.tsx similarity index 98% rename from packages/frontend-plugin-api/src/extensions/NavItemBlueprint.test.tsx rename to packages/frontend-plugin-api/src/blueprints/NavItemBlueprint.test.tsx index 90c9cdf9b4..94b9e7b8e6 100644 --- a/packages/frontend-plugin-api/src/extensions/NavItemBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/blueprints/NavItemBlueprint.test.tsx @@ -44,7 +44,6 @@ describe('NavItemBlueprint', () => { "additionalProperties": false, "properties": { "title": { - "default": "TEST", "type": "string", }, }, diff --git a/packages/frontend-plugin-api/src/extensions/NavItemBlueprint.ts b/packages/frontend-plugin-api/src/blueprints/NavItemBlueprint.ts similarity index 86% rename from packages/frontend-plugin-api/src/extensions/NavItemBlueprint.ts rename to packages/frontend-plugin-api/src/blueprints/NavItemBlueprint.ts index 568431c0f5..5391d0dec2 100644 --- a/packages/frontend-plugin-api/src/extensions/NavItemBlueprint.ts +++ b/packages/frontend-plugin-api/src/blueprints/NavItemBlueprint.ts @@ -17,8 +17,9 @@ import { IconComponent } from '@backstage/core-plugin-api'; import { RouteRef } from '../routing'; import { createExtensionBlueprint } from '../wiring'; -import { createNavItemExtension } from './createNavItemExtension'; +import { createNavItemExtension } from '../extensions/createNavItemExtension'; +/** @public */ export const NavItemBlueprint = createExtensionBlueprint({ kind: 'nav-item', attachTo: { id: 'app/nav', input: 'items' }, @@ -30,6 +31,7 @@ export const NavItemBlueprint = createExtensionBlueprint({ { icon, routeRef, + title, }: { title: string; icon: IconComponent; @@ -38,14 +40,14 @@ export const NavItemBlueprint = createExtensionBlueprint({ { config }, ) => [ createNavItemExtension.targetDataRef({ - title: config.title, + title: config.title ?? title, icon, routeRef, }), ], config: { - schema: ({ title }) => ({ - title: z => z.string().default(title), - }), + schema: { + title: z => z.string().optional(), + }, }, }); diff --git a/packages/frontend-plugin-api/src/extensions/NavLogoBlueprint.test.tsx b/packages/frontend-plugin-api/src/blueprints/NavLogoBlueprint.test.tsx similarity index 100% rename from packages/frontend-plugin-api/src/extensions/NavLogoBlueprint.test.tsx rename to packages/frontend-plugin-api/src/blueprints/NavLogoBlueprint.test.tsx diff --git a/packages/frontend-plugin-api/src/extensions/NavLogoBlueprint.ts b/packages/frontend-plugin-api/src/blueprints/NavLogoBlueprint.ts similarity index 92% rename from packages/frontend-plugin-api/src/extensions/NavLogoBlueprint.ts rename to packages/frontend-plugin-api/src/blueprints/NavLogoBlueprint.ts index d119287f29..f31b3cec9b 100644 --- a/packages/frontend-plugin-api/src/extensions/NavLogoBlueprint.ts +++ b/packages/frontend-plugin-api/src/blueprints/NavLogoBlueprint.ts @@ -15,8 +15,9 @@ */ import { createExtensionBlueprint } from '../wiring'; -import { createNavLogoExtension } from './createNavLogoExtension'; +import { createNavLogoExtension } from '../extensions/createNavLogoExtension'; +/** @public */ export const NavLogoBlueprint = createExtensionBlueprint({ kind: 'nav-logo', attachTo: { id: 'app/nav', input: 'logos' }, diff --git a/packages/frontend-plugin-api/src/extensions/PageBlueprint.test.tsx b/packages/frontend-plugin-api/src/blueprints/PageBlueprint.test.tsx similarity index 98% rename from packages/frontend-plugin-api/src/extensions/PageBlueprint.test.tsx rename to packages/frontend-plugin-api/src/blueprints/PageBlueprint.test.tsx index c1350b3ddb..c4bcb4b467 100644 --- a/packages/frontend-plugin-api/src/extensions/PageBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/blueprints/PageBlueprint.test.tsx @@ -106,7 +106,7 @@ describe('PageBlueprint', () => { }); it('should allow defining additional inputs to the extension', async () => { - const myPage = PageBlueprint.make({ + const myPage = PageBlueprint.makeWithOverrides({ name: 'test-page', inputs: { cards: createExtensionInput([coreExtensionData.reactElement], { diff --git a/packages/frontend-plugin-api/src/extensions/PageBlueprint.tsx b/packages/frontend-plugin-api/src/blueprints/PageBlueprint.tsx similarity index 97% rename from packages/frontend-plugin-api/src/extensions/PageBlueprint.tsx rename to packages/frontend-plugin-api/src/blueprints/PageBlueprint.tsx index 506301ffdf..bfcf4a7934 100644 --- a/packages/frontend-plugin-api/src/extensions/PageBlueprint.tsx +++ b/packages/frontend-plugin-api/src/blueprints/PageBlueprint.tsx @@ -18,6 +18,7 @@ import { RouteRef } from '../routing'; import { coreExtensionData, createExtensionBlueprint } from '../wiring'; import { ExtensionBoundary } from '../components'; +/** @public */ export const PageBlueprint = createExtensionBlueprint({ kind: 'page', attachTo: { id: 'app/routes', input: 'routes' }, @@ -37,7 +38,7 @@ export const PageBlueprint = createExtensionBlueprint({ loader, routeRef, }: { - defaultPath?: string; + defaultPath: string; loader: () => Promise; routeRef?: RouteRef; }, @@ -47,7 +48,7 @@ export const PageBlueprint = createExtensionBlueprint({ loader().then(element => ({ default: () => element })), ); - yield coreExtensionData.routePath(config.path ?? defaultPath!); + yield coreExtensionData.routePath(config.path ?? defaultPath); yield coreExtensionData.reactElement( diff --git a/packages/frontend-plugin-api/src/extensions/RouterBlueprint.test.tsx b/packages/frontend-plugin-api/src/blueprints/RouterBlueprint.test.tsx similarity index 98% rename from packages/frontend-plugin-api/src/extensions/RouterBlueprint.test.tsx rename to packages/frontend-plugin-api/src/blueprints/RouterBlueprint.test.tsx index 018c3fc570..fe40aaa8d7 100644 --- a/packages/frontend-plugin-api/src/extensions/RouterBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/blueprints/RouterBlueprint.test.tsx @@ -97,7 +97,7 @@ describe('RouterBlueprint', () => { }); it('should work with complex options and props', async () => { - const extension = RouterBlueprint.make({ + const extension = RouterBlueprint.makeWithOverrides({ namespace: 'test', name: 'test', config: { diff --git a/packages/frontend-plugin-api/src/extensions/RouterBlueprint.tsx b/packages/frontend-plugin-api/src/blueprints/RouterBlueprint.tsx similarity index 92% rename from packages/frontend-plugin-api/src/extensions/RouterBlueprint.tsx rename to packages/frontend-plugin-api/src/blueprints/RouterBlueprint.tsx index e584a5654c..24ee805659 100644 --- a/packages/frontend-plugin-api/src/extensions/RouterBlueprint.tsx +++ b/packages/frontend-plugin-api/src/blueprints/RouterBlueprint.tsx @@ -15,8 +15,9 @@ */ import { ComponentType, PropsWithChildren } from 'react'; import { createExtensionBlueprint } from '../wiring'; -import { createRouterExtension } from './createRouterExtension'; +import { createRouterExtension } from '../extensions/createRouterExtension'; +/** @public */ export const RouterBlueprint = createExtensionBlueprint({ kind: 'app-router-component', attachTo: { id: 'app/root', input: 'router' }, diff --git a/packages/frontend-plugin-api/src/extensions/SignInPageBlueprint.test.tsx b/packages/frontend-plugin-api/src/blueprints/SignInPageBlueprint.test.tsx similarity index 100% rename from packages/frontend-plugin-api/src/extensions/SignInPageBlueprint.test.tsx rename to packages/frontend-plugin-api/src/blueprints/SignInPageBlueprint.test.tsx diff --git a/packages/frontend-plugin-api/src/extensions/SignInPageBlueprint.tsx b/packages/frontend-plugin-api/src/blueprints/SignInPageBlueprint.tsx similarity index 93% rename from packages/frontend-plugin-api/src/extensions/SignInPageBlueprint.tsx rename to packages/frontend-plugin-api/src/blueprints/SignInPageBlueprint.tsx index fc779f58ab..2727335d8a 100644 --- a/packages/frontend-plugin-api/src/extensions/SignInPageBlueprint.tsx +++ b/packages/frontend-plugin-api/src/blueprints/SignInPageBlueprint.tsx @@ -15,10 +15,11 @@ */ import React, { ComponentType, lazy } from 'react'; import { createExtensionBlueprint } from '../wiring'; -import { createSignInPageExtension } from './createSignInPageExtension'; +import { createSignInPageExtension } from '../extensions/createSignInPageExtension'; import { SignInPageProps } from '@backstage/core-plugin-api'; import { ExtensionBoundary } from '../components'; +/** @public */ export const SignInPageBlueprint = createExtensionBlueprint({ kind: 'sign-in-page', attachTo: { id: 'app/root', input: 'signInPage' }, diff --git a/packages/frontend-plugin-api/src/extensions/ThemeBlueprint.test.ts b/packages/frontend-plugin-api/src/blueprints/ThemeBlueprint.test.ts similarity index 94% rename from packages/frontend-plugin-api/src/extensions/ThemeBlueprint.test.ts rename to packages/frontend-plugin-api/src/blueprints/ThemeBlueprint.test.ts index 92acd8eeba..40323b6a31 100644 --- a/packages/frontend-plugin-api/src/extensions/ThemeBlueprint.test.ts +++ b/packages/frontend-plugin-api/src/blueprints/ThemeBlueprint.test.ts @@ -27,7 +27,8 @@ describe('ThemeBlueprint', () => { } as AppTheme; it('should create an extension with sensible defaults', () => { - expect(ThemeBlueprint.make({ params: { theme } })).toMatchInlineSnapshot(` + expect(ThemeBlueprint.make({ name: 'light', params: { theme } })) + .toMatchInlineSnapshot(` { "$$type": "@backstage/ExtensionDefinition", "attachTo": { diff --git a/packages/frontend-plugin-api/src/extensions/ThemeBlueprint.ts b/packages/frontend-plugin-api/src/blueprints/ThemeBlueprint.ts similarity index 91% rename from packages/frontend-plugin-api/src/extensions/ThemeBlueprint.ts rename to packages/frontend-plugin-api/src/blueprints/ThemeBlueprint.ts index 500946713b..cd97e0437f 100644 --- a/packages/frontend-plugin-api/src/extensions/ThemeBlueprint.ts +++ b/packages/frontend-plugin-api/src/blueprints/ThemeBlueprint.ts @@ -16,12 +16,12 @@ import { AppTheme } from '@backstage/core-plugin-api'; import { createExtensionBlueprint } from '../wiring'; -import { createThemeExtension } from './createThemeExtension'; +import { createThemeExtension } from '../extensions/createThemeExtension'; +/** @public */ export const ThemeBlueprint = createExtensionBlueprint({ kind: 'theme', namespace: 'app', - name: ({ theme }) => theme.id, attachTo: { id: 'app', input: 'themes' }, output: [createThemeExtension.themeDataRef], dataRefs: { diff --git a/packages/frontend-plugin-api/src/extensions/TranslationBlueprint.test.ts b/packages/frontend-plugin-api/src/blueprints/TranslationBlueprint.test.ts similarity index 98% rename from packages/frontend-plugin-api/src/extensions/TranslationBlueprint.test.ts rename to packages/frontend-plugin-api/src/blueprints/TranslationBlueprint.test.ts index e2a979c097..dfb918053a 100644 --- a/packages/frontend-plugin-api/src/extensions/TranslationBlueprint.test.ts +++ b/packages/frontend-plugin-api/src/blueprints/TranslationBlueprint.test.ts @@ -56,7 +56,7 @@ describe('TranslationBlueprint', () => { "inputs": {}, "kind": "translation", "name": "blob", - "namespace": "translationRefId", + "namespace": undefined, "output": [ [Function], ], diff --git a/packages/frontend-plugin-api/src/extensions/TranslationBlueprint.ts b/packages/frontend-plugin-api/src/blueprints/TranslationBlueprint.ts similarity index 90% rename from packages/frontend-plugin-api/src/extensions/TranslationBlueprint.ts rename to packages/frontend-plugin-api/src/blueprints/TranslationBlueprint.ts index 581f4d176a..c70ca56f6b 100644 --- a/packages/frontend-plugin-api/src/extensions/TranslationBlueprint.ts +++ b/packages/frontend-plugin-api/src/blueprints/TranslationBlueprint.ts @@ -15,12 +15,12 @@ */ import { createExtensionBlueprint } from '../wiring'; -import { createTranslationExtension } from './createTranslationExtension'; +import { createTranslationExtension } from '../extensions/createTranslationExtension'; import { TranslationMessages, TranslationResource } from '../translation'; +/** @public */ export const TranslationBlueprint = createExtensionBlueprint({ kind: 'translation', - namespace: ({ resource }) => resource.id, attachTo: { id: 'app', input: 'translations' }, output: [createTranslationExtension.translationDataRef], dataRefs: { diff --git a/packages/frontend-plugin-api/src/blueprints/index.ts b/packages/frontend-plugin-api/src/blueprints/index.ts new file mode 100644 index 0000000000..85f7a99a2c --- /dev/null +++ b/packages/frontend-plugin-api/src/blueprints/index.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2024 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 { ApiBlueprint } from './ApiBlueprint'; +export { AppRootElementBlueprint } from './AppRootElementBlueprint'; +export { AppRootWrapperBlueprint } from './AppRootWrapperBlueprint'; +export { IconBundleBlueprint } from './IconBundleBlueprint'; +export { NavItemBlueprint } from './NavItemBlueprint'; +export { NavLogoBlueprint } from './NavLogoBlueprint'; +export { PageBlueprint } from './PageBlueprint'; +export { RouterBlueprint } from './RouterBlueprint'; +export { SignInPageBlueprint } from './SignInPageBlueprint'; +export { ThemeBlueprint } from './ThemeBlueprint'; +export { TranslationBlueprint } from './TranslationBlueprint'; diff --git a/packages/frontend-plugin-api/src/extensions/createApiExtension.ts b/packages/frontend-plugin-api/src/extensions/createApiExtension.ts index 93346f1ec9..b1db2a0106 100644 --- a/packages/frontend-plugin-api/src/extensions/createApiExtension.ts +++ b/packages/frontend-plugin-api/src/extensions/createApiExtension.ts @@ -24,7 +24,10 @@ import { import { AnyExtensionInputMap } from '../wiring/createExtension'; import { Expand } from '../types'; -/** @public */ +/** + * @public + * @deprecated Use {@link ApiBlueprint} instead. + */ export function createApiExtension< TConfig extends {}, TInputs extends AnyExtensionInputMap, diff --git a/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.ts b/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.ts index 8be82d5540..c8f7bdc366 100644 --- a/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.ts +++ b/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.ts @@ -30,6 +30,7 @@ import { * the app layout. This is useful for example for shared popups and similar. * * @public + * @deprecated Use {@link AppRootElementBlueprint} instead. */ export function createAppRootElementExtension< TConfig extends {}, diff --git a/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx index ce2eb89f25..4f70f29470 100644 --- a/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx @@ -31,6 +31,7 @@ import { Expand } from '../types'; * and similar. * * @public + * @deprecated Use {@link AppRootWrapperBlueprint} instead. */ export function createAppRootWrapperExtension< TConfig extends {}, diff --git a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx index 2a2c47835a..d694440427 100644 --- a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx @@ -21,7 +21,9 @@ import { RouteRef } from '../routing'; /** * Helper for creating extensions for a nav item. + * * @public + * @deprecated Use {@link NavItemBlueprint} instead. */ export function createNavItemExtension(options: { namespace?: string; diff --git a/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.tsx b/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.tsx index 1f2419bd02..02c32e7f34 100644 --- a/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createNavLogoExtension.tsx @@ -18,7 +18,9 @@ import { createExtension, createExtensionDataRef } from '../wiring'; /** * Helper for creating extensions for a nav logos. + * * @public + * @deprecated Use {@link NavLogoBlueprint} instead. */ export function createNavLogoExtension(options: { name?: string; diff --git a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx index cd434a3ffc..bef642e465 100644 --- a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx @@ -31,6 +31,7 @@ import { ExtensionDefinition } from '../wiring/createExtension'; * Helper for creating extensions for a routable React page component. * * @public + * @deprecated Use {@link PageBlueprint} instead. */ export function createPageExtension< TConfig extends { path: string }, diff --git a/packages/frontend-plugin-api/src/extensions/createRouterExtension.tsx b/packages/frontend-plugin-api/src/extensions/createRouterExtension.tsx index 12f946e8a7..943711f5e0 100644 --- a/packages/frontend-plugin-api/src/extensions/createRouterExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createRouterExtension.tsx @@ -31,6 +31,7 @@ import { Expand } from '../types'; * MemoryRouter in tests, or to add additional props to a BrowserRouter. * * @public + * @deprecated Use {@link RouterBlueprint} instead. */ export function createRouterExtension< TConfig extends {}, diff --git a/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx b/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx index 312d30c78c..3f41202f11 100644 --- a/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createSignInPageExtension.tsx @@ -30,6 +30,7 @@ import { SignInPageProps } from '@backstage/core-plugin-api'; /** * * @public + * @deprecated Use {@link SignInPageBlueprint} instead. */ export function createSignInPageExtension< TConfig extends {}, diff --git a/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts b/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts index 1740f05a5a..e523fd9c05 100644 --- a/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts +++ b/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts @@ -17,7 +17,10 @@ import { createExtension, createExtensionDataRef } from '../wiring'; import { AppTheme } from '@backstage/core-plugin-api'; -/** @public */ +/** + * @public + * @deprecated Use {@link ThemeBlueprint} instead. + */ export function createThemeExtension(theme: AppTheme) { return createExtension({ kind: 'theme', @@ -31,7 +34,10 @@ export function createThemeExtension(theme: AppTheme) { }); } -/** @public */ +/** + * @public + * @deprecated Use {@link ThemeBlueprint} instead. + */ export namespace createThemeExtension { export const themeDataRef = createExtensionDataRef().with({ id: 'core.theme.theme', diff --git a/packages/frontend-plugin-api/src/extensions/createTranslationExtension.ts b/packages/frontend-plugin-api/src/extensions/createTranslationExtension.ts index 9445e32e24..c4d2f6037d 100644 --- a/packages/frontend-plugin-api/src/extensions/createTranslationExtension.ts +++ b/packages/frontend-plugin-api/src/extensions/createTranslationExtension.ts @@ -17,7 +17,10 @@ import { TranslationMessages, TranslationResource } from '../translation'; import { createExtension, createExtensionDataRef } from '../wiring'; -/** @public */ +/** + * @public + * @deprecated Use {@link TranslationBlueprint} instead. + */ export function createTranslationExtension(options: { name?: string; resource: TranslationResource | TranslationMessages; @@ -34,7 +37,10 @@ export function createTranslationExtension(options: { }); } -/** @public */ +/** + * @public + * @deprecated Use {@link TranslationBlueprint} instead. + */ export namespace createTranslationExtension { export const translationDataRef = createExtensionDataRef< TranslationResource | TranslationMessages diff --git a/packages/frontend-plugin-api/src/extensions/index.ts b/packages/frontend-plugin-api/src/extensions/index.ts index 267201db81..562cb728cb 100644 --- a/packages/frontend-plugin-api/src/extensions/index.ts +++ b/packages/frontend-plugin-api/src/extensions/index.ts @@ -25,4 +25,3 @@ export { createSignInPageExtension } from './createSignInPageExtension'; export { createThemeExtension } from './createThemeExtension'; export { createComponentExtension } from './createComponentExtension'; export { createTranslationExtension } from './createTranslationExtension'; -export { IconBundleBlueprint } from './IconBundleBlueprint'; diff --git a/packages/frontend-plugin-api/src/index.ts b/packages/frontend-plugin-api/src/index.ts index 263380b1f8..957ca50bba 100644 --- a/packages/frontend-plugin-api/src/index.ts +++ b/packages/frontend-plugin-api/src/index.ts @@ -22,6 +22,7 @@ export * from './analytics'; export * from './apis'; +export * from './blueprints'; export * from './components'; export * from './extensions'; export * from './icons'; diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx index 924eba2cba..b9d1475074 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.test.tsx @@ -127,7 +127,7 @@ describe('createExtensionBlueprint', () => { }, }); - const extension = TestExtensionBlueprint.make({ + const extension = TestExtensionBlueprint.makeWithOverrides({ name: 'my-extension', factory(origFactory) { return origFactory({ @@ -185,11 +185,8 @@ describe('createExtensionBlueprint', () => { }, }); - const extension = TestExtensionBlueprint.make({ + const extension = TestExtensionBlueprint.makeWithOverrides({ name: 'my-extension', - params: { - text: 'Hello, world!', - }, config: { schema: { something: z => z.string(), @@ -236,7 +233,7 @@ describe('createExtensionBlueprint', () => { }, }); - TestExtensionBlueprint.make({ + TestExtensionBlueprint.makeWithOverrides({ name: 'my-extension', params: { text: 'Hello, world!', @@ -266,11 +263,8 @@ describe('createExtensionBlueprint', () => { }, }); - const extension = TestExtensionBlueprint.make({ + const extension = TestExtensionBlueprint.makeWithOverrides({ name: 'my-extension', - params: { - text: 'Hello, world!', - }, config: { schema: { something: z => z.string(), @@ -341,65 +335,6 @@ describe('createExtensionBlueprint', () => { expect(true).toBe(true); }); - it('should allow providing callback for properties to set with params', () => { - type TestParams = { test: string }; - - const Blueprint = createExtensionBlueprint({ - kind: 'test-extension', - attachTo: { id: 'test', input: 'default' }, - name: (params: TestParams) => `${params.test}-name`, - output: [coreExtensionData.reactElement], - namespace: (props: TestParams) => props.test, - config: { - schema: (props: TestParams) => ({ - test: z => z.string().default(props.test), - }), - }, - factory(params: TestParams) { - return [coreExtensionData.reactElement(
{params.test}
)]; - }, - }); - - expect(Blueprint.make({ params: { test: 'hello' } })) - .toMatchInlineSnapshot(` - { - "$$type": "@backstage/ExtensionDefinition", - "attachTo": { - "id": "test", - "input": "default", - }, - "configSchema": { - "parse": [Function], - "schema": { - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "test": { - "default": "hello", - "type": "string", - }, - }, - "type": "object", - }, - }, - "disabled": false, - "factory": [Function], - "inputs": {}, - "kind": "test-extension", - "name": "hello-name", - "namespace": "hello", - "output": [ - [Function], - ], - "override": [Function], - "toString": [Function], - "version": "v2", - } - `); - - expect(true).toBe(true); - }); - it('should allow merging of inputs', () => { const blueprint = createExtensionBlueprint({ kind: 'test-extension', @@ -418,7 +353,7 @@ describe('createExtensionBlueprint', () => { }, }); - blueprint.make({ + blueprint.makeWithOverrides({ inputs: { test2: createExtensionInput([coreExtensionData.reactElement], { singleton: true, @@ -453,7 +388,7 @@ describe('createExtensionBlueprint', () => { }, }); - blueprint.make({ + blueprint.makeWithOverrides({ inputs: { // @ts-expect-error test: createExtensionInput([]), // Overrides are not allowed @@ -480,7 +415,7 @@ describe('createExtensionBlueprint', () => { }); const ext = toInternalExtensionDefinition( - blueprint.make({ + blueprint.makeWithOverrides({ output: [testDataRef2], factory(origFactory) { const parent = origFactory({}); @@ -509,7 +444,7 @@ describe('createExtensionBlueprint', () => { expect( factoryOutput( - blueprint.make({ + blueprint.makeWithOverrides({ output: [testDataRef1, testDataRef2], *factory(origFactory) { yield* origFactory({}); @@ -521,7 +456,7 @@ describe('createExtensionBlueprint', () => { expect( factoryOutput( - blueprint.make({ + blueprint.makeWithOverrides({ output: [testDataRef1, testDataRef2], factory(origFactory) { return [...origFactory({}), testDataRef2('bar')]; @@ -544,9 +479,9 @@ describe('createExtensionBlueprint', () => { }, }); - // @ts-expect-error - blueprint.make({ + blueprint.makeWithOverrides({ output: [testDataRef2.optional()], + // @ts-expect-error *factory() { yield testDataRef1('foo'); yield testDataRef2('bar'); @@ -555,7 +490,7 @@ describe('createExtensionBlueprint', () => { expect( factoryOutput( - blueprint.make({ + blueprint.makeWithOverrides({ output: [testDataRef2.optional()], *factory() { yield testDataRef2('bar'); @@ -578,9 +513,9 @@ describe('createExtensionBlueprint', () => { }, }); - // @ts-expect-error - blueprint.make({ + blueprint.makeWithOverrides({ output: [testDataRef1, testDataRef2], + // @ts-expect-error *factory(origFactory) { yield* origFactory({}); }, @@ -588,7 +523,7 @@ describe('createExtensionBlueprint', () => { expect( factoryOutput( - blueprint.make({ + blueprint.makeWithOverrides({ output: [testDataRef1, testDataRef2], *factory(origFactory) { yield* origFactory({}); diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts index f749f7d412..656e681a2b 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts @@ -52,14 +52,14 @@ export type CreateExtensionBlueprintOptions< TDataRefs extends { [name in string]: AnyExtensionDataRef }, > = { kind: TKind; - namespace?: TNamespace | ((params: TParams) => TNamespace); + namespace?: TNamespace; attachTo: { id: string; input: string }; disabled?: boolean; inputs?: TInputs; output: Array; - name?: TName | ((params: TParams) => TName); + name?: TName; config?: { - schema: TConfigSchema | ((params: TParams) => TConfigSchema); + schema: TConfigSchema; }; factory( params: TParams, @@ -96,13 +96,32 @@ export interface ExtensionBlueprint< > { dataRefs: TDataRefs; + make< + TNewNamespace extends string | undefined, + TNewName extends string | undefined, + >(args: { + namespace?: TNewNamespace; + name?: TNewName; + attachTo?: { id: string; input: string }; + disabled?: boolean; + params: TParams; + }): ExtensionDefinition< + TConfig, + TConfigInput, + UOutput, + TInputs, + TKind, + string | undefined extends TNewNamespace ? TNamespace : TNewNamespace, + string | undefined extends TNewName ? TName : TNewName + >; + /** * 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< + makeWithOverrides< TNewNamespace extends string | undefined, TNewName extends string | undefined, TExtensionConfigSchema extends { @@ -116,52 +135,45 @@ export interface ExtensionBlueprint< { optional: boolean; singleton: boolean } >; }, - >( - args: { - namespace?: TNewNamespace; - name?: TNewName; - attachTo?: { id: string; input: string }; - disabled?: boolean; - inputs?: TExtraInputs & { - [KName in keyof TInputs]?: `Error: Input '${KName & - string}' is already defined in parent definition`; + >(args: { + namespace?: TNewNamespace; + name?: TNewName; + attachTo?: { id: string; input: string }; + disabled?: boolean; + inputs?: TExtraInputs & { + [KName in keyof TInputs]?: `Error: Input '${KName & + string}' is already defined in parent definition`; + }; + output?: Array; + config?: { + schema: TExtensionConfigSchema & { + [KName in keyof TConfig]?: `Error: Config key '${KName & + string}' is already defined in parent schema`; }; - output?: Array; - config?: { - schema: TExtensionConfigSchema & { - [KName in keyof TConfig]?: `Error: Config key '${KName & - string}' is already defined in parent schema`; + }; + factory( + originalFactory: ( + params: TParams, + context?: { + config?: TConfig; + inputs?: Expand>; + }, + ) => ExtensionDataContainer, + context: { + node: AppNode; + config: TConfig & { + [key in keyof TExtensionConfigSchema]: z.infer< + ReturnType + >; }; - }; - } & ( - | ({ - factory( - originalFactory: ( - params: TParams, - context?: { - config?: TConfig; - inputs?: Expand>; - }, - ) => ExtensionDataContainer, - context: { - node: AppNode; - config: TConfig & { - [key in keyof TExtensionConfigSchema]: z.infer< - ReturnType - >; - }; - inputs: Expand>; - }, - ): Iterable; - } & VerifyExtensionFactoryOutput< - AnyExtensionDataRef extends UNewOutput ? UOutput : UNewOutput, - UFactoryOutput - >) - | { - params: TParams; - } - ), - ): ExtensionDefinition< + inputs: Expand>; + }, + ): Iterable & + VerifyExtensionFactoryOutput< + AnyExtensionDataRef extends UNewOutput ? UOutput : UNewOutput, + UFactoryOutput + >; + }): ExtensionDefinition< { [key in keyof TExtensionConfigSchema]: z.infer< ReturnType @@ -243,7 +255,7 @@ class ExtensionBlueprintImpl< dataRefs: TDataRefs; - public make< + public makeWithOverrides< TExtensionConfigSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType; }, @@ -264,11 +276,10 @@ class ExtensionBlueprintImpl< disabled?: boolean; inputs?: TExtraInputs; output?: Array; - params?: TParams; config?: { schema: TExtensionConfigSchema; }; - factory?( + factory( originalFactory: ( params: TParams, context?: { @@ -312,77 +323,82 @@ class ExtensionBlueprintImpl< > > > { - const optionsSchema = // can remove this args.params check with the split apart of .make - typeof this.options.config?.schema === 'function' && args.params - ? this.options.config?.schema(args.params) - : this.options.config?.schema; - const schema = { - ...optionsSchema, + ...this.options.config?.schema, ...args.config?.schema, } as TConfigSchema & TExtensionConfigSchema; - const namespace = - typeof this.options.namespace === 'function' && args.params - ? this.options.namespace(args.params) - : this.options.namespace; - - const name = - typeof this.options.name === 'function' && args.params - ? this.options.name(args.params) - : this.options.name; - return createExtension({ kind: this.options.kind, - namespace: args.namespace ?? namespace, - name: args.name ?? name, + namespace: args.namespace ?? this.options.namespace, + name: args.name ?? this.options.name, attachTo: args.attachTo ?? this.options.attachTo, disabled: args.disabled ?? this.options.disabled, inputs: { ...args.inputs, ...this.options.inputs }, output: args.output ?? this.options.output, config: Object.keys(schema).length === 0 ? undefined : { schema }, factory: ({ node, config, inputs }) => { - if (args.factory) { - return args.factory( - ( - innerParams: TParams, - innerContext?: { - config?: { - [key in keyof TConfigSchema]: z.infer< - ReturnType - >; - }; - inputs?: Expand>; - }, - ): ExtensionDataContainer => { - return createDataContainer( - this.options.factory(innerParams, { - node, - config: innerContext?.config ?? config, - inputs: (innerContext?.inputs ?? inputs) as any, // TODO: Fix the way input values are overridden - }), - ); + return args.factory( + ( + innerParams: TParams, + innerContext?: { + config?: { + [key in keyof TConfigSchema]: z.infer< + ReturnType + >; + }; + inputs?: Expand>; }, - { - node, - config, - inputs, - }, - ); - } else if (args.params) { - return this.options.factory(args.params, { + ): ExtensionDataContainer => { + return createDataContainer( + this.options.factory(innerParams, { + node, + config: innerContext?.config ?? config, + inputs: (innerContext?.inputs ?? inputs) as any, // TODO: Fix the way input values are overridden + }), + ); + }, + { node, config, - // TODO: Figure out types once legacy data map input type is gone - inputs: inputs as unknown as Expand< - ResolvedExtensionInputs - >, - }); - } - throw new Error('Either params or factory must be provided'); + inputs, + }, + ); }, } as CreateExtensionOptions); } + + public make< + TNewNamespace extends string | undefined = undefined, + TNewName extends string | undefined = undefined, + >(args: { + namespace?: TNewNamespace; + name?: TNewName; + attachTo?: { id: string; input: string }; + disabled?: boolean; + params: TParams; + }): ExtensionDefinition< + { + [key in keyof TConfigSchema]: z.infer>; + }, + z.input< + z.ZodObject<{ + [key in keyof TConfigSchema]: ReturnType; + }> + > + > { + return createExtension({ + kind: this.options.kind, + namespace: args.namespace ?? this.options.namespace, + name: args.name ?? this.options.name, + attachTo: args.attachTo ?? this.options.attachTo, + disabled: args.disabled ?? this.options.disabled, + inputs: this.options.inputs, + output: this.options.output, + config: this.options.config, + factory: ctx => this.options.factory(args.params, ctx), + } as CreateExtensionOptions); + } } /** diff --git a/packages/frontend-test-utils/src/app/createExtensionTester.tsx b/packages/frontend-test-utils/src/app/createExtensionTester.tsx index ce7da3701d..4bfc8392cb 100644 --- a/packages/frontend-test-utils/src/app/createExtensionTester.tsx +++ b/packages/frontend-test-utils/src/app/createExtensionTester.tsx @@ -19,7 +19,6 @@ import { MemoryRouter, Link } from 'react-router-dom'; import { RenderResult, render } from '@testing-library/react'; import { createSpecializedApp } from '@backstage/frontend-app-api'; import { - ExtensionDataValue, AppNode, AppTree, Extension, @@ -169,9 +168,7 @@ export class ExtensionTester { : [...internal.output, coreExtensionData.routePath], factory: params => { const parentOutput = Array.from( - internal.factory(params as any) as Iterable< - ExtensionDataValue - >, + internal.factory(params as any), ).filter(val => val.id !== coreExtensionData.routePath.id); return [...parentOutput, coreExtensionData.routePath('/')];