From 2d88a424054fd83455d2c4d090ce4d691ed7f89e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 15 Aug 2024 17:28:24 +0200 Subject: [PATCH 01/11] docs/frontend-system: update app migration docs to 1.30 Signed-off-by: Patrik Oldsberg --- .../building-apps/08-migrating.md | 113 ++++++++++-------- 1 file changed, 63 insertions(+), 50 deletions(-) diff --git a/docs/frontend-system/building-apps/08-migrating.md b/docs/frontend-system/building-apps/08-migrating.md index b8fd49c269..ceb3f34c35 100644 --- a/docs/frontend-system/building-apps/08-migrating.md +++ b/docs/frontend-system/building-apps/08-migrating.md @@ -95,7 +95,7 @@ At this point the contents of your app should be past the initial migration stag ## Migrating `createApp` Options -Many of the `createApp` options have been migrated to use extensions instead. Each will have their own [extension creator](../architecture/20-extensions.md#extension-creators) that you use to create a custom extension. To add these standalone extensions to the app they need to be passed to `createExtensionOverrides`, which bundles them into a _feature_ that you can install in the app. See the [standalone extensions](../architecture/25-extension-overrides.md#create-standalone-extensions) section for more information. +Many of the `createApp` options have been migrated to use extensions instead. Each will have their own [extension blueprint](../architecture/23-extension-blueprints.md) that you use to create a custom extension. To add these standalone extensions to the app they need to be passed to `createExtensionOverrides`, which bundles them into a _feature_ that you can install in the app. See the [standalone extensions](../architecture/25-extension-overrides.md#creating-a-standalone-extension-bundle) section for more information. For example, assuming you have a `lightTheme` extension that you want to add to your app, you can use the following: @@ -115,7 +115,7 @@ You can then also add any additional extensions that you may need to create as p ### `apis` -[Utility API](../utility-apis/01-index.md) factories are now installed as extensions instead. Pass the existing factory to `createApiExtension` and install it in the app. For more information, see the section on [configuring Utility APIs](../utility-apis/04-configuring.md). +[Utility API](../utility-apis/01-index.md) factories are now installed as extensions instead. Pass the existing factory to `ApiBlueprint` and install it in the app. For more information, see the section on [configuring Utility APIs](../utility-apis/04-configuring.md). For example, the following `apis` configuration: @@ -134,12 +134,15 @@ const app = createApp({ Can be converted to the following extension: ```ts -const scmIntegrationsApi = createApiExtension({ - factory: createApiFactory({ - api: scmIntegrationsApiRef, - deps: { configApi: configApiRef }, - factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi), - }), +const scmIntegrationsApi = ApiBlueprint.make({ + name: 'scm-integrations', + params: { + factory: createApiFactory({ + api: scmIntegrationsApiRef, + deps: { configApi: configApiRef }, + factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi), + }), + }, }); ``` @@ -221,7 +224,7 @@ Many app components are now installed as extensions instead using `createCompone The `Router` component is now a built-in extension that you can [override](../architecture/25-extension-overrides.md) using `createRouterExtension`. -The Sign-in page is now installed as an extension using the `createSignInPageExtension` instead. +The Sign-in page is now installed as an extension, created using the `SignInPageBlueprint` instead. For example, the following sign-in page configuration: @@ -246,25 +249,27 @@ const app = createApp({ Can be converted to the following extension: ```tsx -const signInPage = createSignInPageExtension({ - loader: async () => props => - ( - - ), +const signInPage = SignInPageBlueprint.make({ + params: { + loader: async () => props => + ( + + ), + }, }); ``` ### `themes` -Themes are now installed as extensions, using `createThemeExtension`. +Themes are now installed as extensions, created using `ThemeBlueprint`. For example, the following theme configuration: @@ -287,14 +292,19 @@ const app = createApp({ Can be converted to the following extension: ```tsx -const lightTheme = createThemeExtension({ - id: 'light', - title: 'Light Theme', - variant: 'light', - icon: , - Provider: ({ children }) => ( - - ), +const lightTheme = ThemeBlueprint.make({ + name: 'light', + params: { + theme: { + id: 'light', + title: 'Light Theme', + variant: 'light', + icon: , + Provider: ({ children }) => ( + + ), + }, + }, }); ``` @@ -360,7 +370,7 @@ const app = createApp({ ### `__experimentalTranslations` -Translations are now installed as extensions, using `createTranslationExtension`. +Translations are now installed as extensions, created using `TranslationBlueprint`. For example, the following translations configuration: @@ -383,11 +393,14 @@ createApp({ Can be converted to the following extension: ```tsx -createTranslationExtension({ - resource: createTranslationMessages({ - ref: catalogTranslationRef, - catalog_page_create_button_title: 'Create Software', - }), +TranslationBlueprint.make({ + name: 'catalog-overrides', + params: { + resource: createTranslationMessages({ + ref: catalogTranslationRef, + catalog_page_create_button_title: 'Create Software', + }), + }, }); ``` @@ -489,17 +502,15 @@ const nav = createExtension({ namespace: 'app', name: 'nav', attachTo: { id: 'app/layout', input: 'nav' }, - output: { - element: coreExtensionData.reactElement, - }, + output: [coreExtensionData.reactElement], factory({ inputs }) { - return { - element: ( + return [ + coreExtensionData.reactElement( {/* Sidebar contents from packages/app/src/components/Root.tsx go here */} - + , ), - }; + ]; }, }); ``` @@ -548,7 +559,7 @@ export default app.createRoot( ); ``` -Any app root wrapper needs to be migrated to be an extension, using `createAppRootWrapperExtension`. Note that if you have multiple wrappers they must be completely independent of each other, i.e. the order in which they the appear in the React tree should not matter. If that is not the case then you should group them into a single wrapper. +Any app root wrapper needs to be migrated to be an extension, created using `AppRootWrapperBlueprint`. Note that if you have multiple wrappers they must be completely independent of each other, i.e. the order in which they the appear in the React tree should not matter. If that is not the case then you should group them into a single wrapper. Here is an example converting the `CustomAppBarrier` into extension: @@ -558,11 +569,13 @@ createApp({ features: [ createExtensionOverrides({ extensions: [ - createAppRootWrapperExtension({ - name: 'CustomAppBarrier', - // Whenever your component uses legacy core packages, wrap it with "compatWrapper" - // e.g. props => compatWrapper() - Component: CustomAppBarrier, + AppRootWrapperBlueprint.make({ + name: 'custom-app-barrier', + params: { + // Whenever your component uses legacy core packages, wrap it with "compatWrapper" + // e.g. props => compatWrapper() + Component: CustomAppBarrier, + }, }), ], }), From 75bf997914d3c97c9651e1af731a5ac004141fa5 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 15 Aug 2024 17:32:23 +0200 Subject: [PATCH 02/11] docs/frontend-system: update plugin index docs to 1.30 Signed-off-by: Patrik Oldsberg --- .../building-plugins/01-index.md | 68 +++++++++++-------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/docs/frontend-system/building-plugins/01-index.md b/docs/frontend-system/building-plugins/01-index.md index 355de26616..06f1dbc517 100644 --- a/docs/frontend-system/building-plugins/01-index.md +++ b/docs/frontend-system/building-plugins/01-index.md @@ -49,7 +49,7 @@ The plugin ID should be a lowercase dash-separated string, while the plugin inst The plugin that we created above is empty, and doesn't provide any actual functionality. To add functionality to a plugin you need to create and provide it with one or more [extensions](../architecture/20-extensions.md). Let's continue by adding a standalone page to our plugin, as well as a navigation item that allows users to navigate to the page. -To create a new extension you typically use pre-defined [extension creators](../architecture/20-extensions.md#extension-creators), provided either by the framework itself or by other plugins. In this case we'll need to use `createPageExtension` and `createNavItemExtension`, both from `@backstage/frontend-plugin-api`. We will also need to [create a route reference](../architecture/36-routes.md#creating-a-route-reference) to use as a reference for out page, allowing us to dynamically create URLs that link to our page. +To create a new extension you typically use pre-defined [extension blueprints](../architecture/23-extension-blueprints.md), provided either by the framework itself or by other plugins. In this case we'll use `PageBlueprint` and `NavItemBlueprint`, both from `@backstage/frontend-plugin-api`. We will also need to [create a route reference](../architecture/36-routes.md#creating-a-route-reference) to use as a reference for out page, allowing us to dynamically create URLs that link to our page. ```tsx title="in src/routes.ts" import { createRouteRef } from '@backstage/frontend-plugin-api'; @@ -71,24 +71,29 @@ import { rootRouteRef } from './routes'; // Note that these extensions aren't exported, only the plugin itself is. // You can export it locally for testing purposes, but don't export it from the plugin package. -const examplePage = createPageExtension({ - routeRef: rootRouteRef, +const examplePage = PageBlueprint.make({ + params: { + routeRef: rootRouteRef, - // This is the default path of this page, but integrators are free to override it - defaultPath: '/example', + // This is the default path of this page, but integrators are free to override it + defaultPath: '/example', - // Page extensions are always dynamically loaded using React.lazy(). - // All of the functionality of this page is implemented in the - // ExamplePage component, which is a regular React component. - // highlight-next-line - loader: () => import('./components/ExamplePage').then(m => ), + // Page extensions are always dynamically loaded using React.lazy(). + // All of the functionality of this page is implemented in the + // ExamplePage component, which is a regular React component. + // highlight-next-line + loader: () => + import('./components/ExamplePage').then(m => ), + }, }); // This nav item is provided to the app.nav extension, and will by default be rendered as a sidebar item -const exampleNavItem = createNavItemExtension({ - routeRef: rootRouteRef, - title: 'Example', - icon: ExampleIcon, // Custom SvgIcon, or one from the Material UI icon library +const exampleNavItem = NavItemBlueprint.make({ + params: { + routeRef: rootRouteRef, + title: 'Example', + icon: ExampleIcon, // Custom SvgIcon, or one from the Material UI icon library + }, }); // The same plugin as above, now with the extensions added @@ -157,12 +162,15 @@ import { import { exampleApiRef, DefaultExampleApi } from './api'; // highlight-add-start -const exampleApi = createApiExtension({ - factory: createApiFactory({ - api: exampleApiRef, - deps: {}, - factory: () => new DefaultExampleApi(), - }), +const exampleApi = ApiBlueprint.make({ + name: 'example', + params: { + factory: createApiFactory({ + api: exampleApiRef, + deps: {}, + factory: () => new DefaultExampleApi(), + }), + }, }); // highlight-add-end @@ -187,26 +195,28 @@ export const examplePlugin = createFrontendPlugin({ There are many different plugins that you can extend with additional functionality through extensions. One such plugin is [the catalog plugin](../../features/software-catalog/), one of the core features of Backstage. It lets you catalog the software in your organization, where each item in the catalog has its own page that can be populated with tools and information relating to that catalog entity. In this example we will explore how our plugin can provide such a tool to display on an entity page. ```tsx title="in src/plugin.ts - An example entity content extension" -import { createEntityContentExtension } from '@backstage/plugin-catalog-react'; +import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha'; // Entity content extensions are similar to page extensions in that they are rendered at a route, // although they also have a title to support in-line navigation between the different content. // Just like a page extension the content is lazy loaded, and you can also provide a // route reference if you want to be able to generate a URL that links to the content. -const exampleEntityContent = createEntityContentExtension({ - defaultPath: 'example', - defaultTitle: 'Example', - loader: () => - import('./components/ExampleEntityContent').then(m => ( - - )), +const exampleEntityContent = EntityContentBlueprint.make({ + params: { + defaultPath: 'example', + defaultTitle: 'Example', + loader: () => + import('./components/ExampleEntityContent').then(m => ( + + )), + }, }); export const examplePlugin = createFrontendPlugin({ id: 'example', extensions: [ // highlight-add-next-line - exampleEntityContent + exampleEntityContent, exampleApi, examplePage, exampleNavItem, From c6072b1083b7b68c81ef9ae69f9695b2eecde329 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 15 Aug 2024 21:33:48 +0200 Subject: [PATCH 03/11] docs/frontend-system: update plugin testing docs for 1.30 Signed-off-by: Patrik Oldsberg --- .../building-plugins/02-testing.md | 135 ++++++------------ 1 file changed, 43 insertions(+), 92 deletions(-) diff --git a/docs/frontend-system/building-plugins/02-testing.md b/docs/frontend-system/building-plugins/02-testing.md index f665ed0f0c..956fdb8394 100644 --- a/docs/frontend-system/building-plugins/02-testing.md +++ b/docs/frontend-system/building-plugins/02-testing.md @@ -85,6 +85,8 @@ describe('Entity details component', () => { }); ``` +This pattern also works for many other context providers. An important example is the `EntityProvider` from the `@backstage/plugin-catalog-react` package, which you can use to provide a mocked entity context to the component. + ## Testing extensions To facilitate testing of frontend extensions, the `@backstage/frontend-test-utils` package provides a tester class which starts up an entire frontend harness, complete with a number of default features. You can then provide overrides for extensions whose behavior you need to adjust for the test run. @@ -93,7 +95,7 @@ A number of features (frontend extensions and overrides) are also accepted by th ### Single extension -In order to test an extension in isolation, you simply need to pass it into the tester factory, then call the render method on the returned instance: +In order to test an extension in isolation, you can use `createExtensionTester` to create a tester instance and access the element that the extension outputs. This element can then be rendered as usual with `renderInTestApp`: ```tsx import { screen } from '@testing-library/react'; @@ -101,90 +103,49 @@ import { createExtensionTester } from '@backstage/frontend-test-utils'; import { indexPageExtension } from './plugin'; describe('Index page', () => { - it('should render a the index page', () => { - createExtensionTester(indexPageExtension).render(); + it('should render a the index page', async () => { + await renderInTestApp( + createExtensionTester(indexPageExtension).reactElement(), + ); expect(screen.getByText('Index Page')).toBeInTheDocument(); }); }); ``` -### Extension preset +This pattern also allows you to wrap the extension with context providers, such as the `TestApiProvider` that was introduced [above](#testing-react-components). -There are some extensions that rely on other extensions existence, such as a page that links to another page. In that case, you can add more than one extension to the preset of features you want to render in the test, as shown below: +Note that the `.reactElement()` method will look for the `coreExtensionData.reactElement` data in the extension outputs. If that doesn't exist and the extension outputs something else that you want to test, you can access the output data using the `.get(dataRef)` method instead. + +### Multiple extensions + +In some cases you might need to test multiple extensions together, in particular when testing inputs. In this case, you can add more extensions to the tester instance using the `.add(...)` method. It also accepts an optional options object as the second argument, which you can use to provide configuration for the extension instance. ```tsx import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { createExtensionTester } from '@backstage/frontend-test-utils'; -import { indexPageExtension, detailsPageExtension } from './plugin'; +import { indexPageExtension, indexPageHeader } from './plugin'; describe('Index page', async () => { - it('should link to the details page', () => { - createExtensionTester(indexPageExtension) - // Adding more extensions to the preset being tested - .add(detailsPageExtension) - .render(); + it('should link to the index page with header', async () => { + const tester = createExtensionTester(indexPageExtension) + // Adding the header to be rendered on the index page + .add(indexPageHeader); - await expect(screen.findByText('Index Page')).toBeInTheDocument(); + await renderInTestApp(tester.reactElement()); - await userEvent.click(screen.getByRole('link', { name: 'See details' })); + await expect(screen.findByText('Index page')).toBeInTheDocument(); + await expect(screen.findByText('Index page header')).toBeInTheDocument(); - await expect( - screen.findByText('Details Page'), - ).resolves.toBeInTheDocument(); + expect( + tester.query(indexPageHeader).get(headerDataRef), + ).toMatchObject(/* ... */); }); }); ``` -### Mocking apis - -If your extensions requires implementation of APIs that aren't wired up by default, you'll have to add overrides to the preset of features being tested: - -```tsx -import { screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import { createApiFactory } from '@backestage/core-plugin-api'; -import { - createExtensionOverrides, - configApiRef, - analyticsApiRef, -} from '@backstage/frontend-plugin-api'; -import { - createExtensionTester, - MockConfigApi, - MockAnalyticsApi, -} from '@backstage/frontend-test-utils'; -import { indexPageExtension } from './plugin'; - -describe('Index page', () => { - it('should capture click events in analytics', async () => { - // Mocking the analytics api implementation - const analyticsApiMock = new MockAnalyticsApi(); - - const analyticsApiOverride = createApiExtension({ - factory: createApiFactory({ - api: analyticsApiRef, - factory: () => analyticsApiMock, - }), - }); - - createExtensionTester(indexPageExtension) - // Overriding the analytics api extension - .add(analyticsApiOverride) - .render(); - - await userEvent.click( - await screen.findByRole('link', { name: 'See details' }), - ); - - expect(analyticsApiMock.getEvents()[0]).toMatchObject({ - action: 'click', - subject: 'See details', - }); - }); -}); -``` +When testing multiple extensions you may sometimes want to access the output of other extensions than the main test subject. You can use the `.query(ext)` method to query a different extension that has been added to the tester, either via its ID or passing the extension directly. ### Setting configuration @@ -198,36 +159,26 @@ import { indexPageExtension, detailsPageExtension } from './plugin'; describe('Index page', () => { it('should accepts a custom title via config', async () => { - createExtensionTester(indexPageExtension, { - // Configuration specific of index page - config: { title: 'Custom index' }, - }) - .add(detailsExtensionPage, { - // Configuration specific of details page - config: { title: 'Custom details' }, - }) - .render({ - // Configuration specific of the instance - config: { - app: { - title: 'Custom app', - }, + const tester = createExtensionTester(indexPageExtension, { + // Extension configuration for the index page + config: { title: 'Custom page' }, + }).add(indexPageHeader, { + // Extension configuration for the index page header + config: { title: 'Custom page header' }, + }); + + await renderInTestApp(tester.reactElement(), { + // Global configuration for the app + config: { + app: { + title: 'Custom app', }, - }); + }, + }); - await expect( - screen.findByRole('heading', { name: 'Custom app' }), - ).resolves.toBeInTheDocument(); - - await expect( - screen.findByRole('heading', { name: 'Custom index' }), - ).resolves.toBeInTheDocument(); - - await userEvent.click(screen.getByRole('link', { name: 'See details' })); - - await expect( - screen.findByText('Custom details'), - ).resolves.toBeInTheDocument(); + await expect(screen.findByText('Custom app')).toBeInTheDocument(); + await expect(screen.findByText('Custom page')).toBeInTheDocument(); + await expect(screen.findByText('Custom page header')).toBeInTheDocument(); }); }); ``` From 6d1d1779b158581281956e8f15388f0be0c940cb Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 15 Aug 2024 21:43:44 +0200 Subject: [PATCH 04/11] docs/frontend-system: migrate plugin extension types docs to blueprints Signed-off-by: Patrik Oldsberg --- .../frontend-system/building-apps/01-index.md | 2 +- .../building-plugins/01-index.md | 2 +- ...on-types.md => 03-extension-blueprints.md} | 40 +++++++++---------- microsite/sidebars.json | 2 +- plugins/catalog-graph/README-alpha.md | 2 +- 5 files changed, 24 insertions(+), 24 deletions(-) rename docs/frontend-system/building-plugins/{03-extension-types.md => 03-extension-blueprints.md} (62%) diff --git a/docs/frontend-system/building-apps/01-index.md b/docs/frontend-system/building-apps/01-index.md index bb09fb6907..c6a83bb0b7 100644 --- a/docs/frontend-system/building-apps/01-index.md +++ b/docs/frontend-system/building-apps/01-index.md @@ -78,7 +78,7 @@ It is possible to enable, disable and configure extensions individually in the ` ### Customize or override built-in extensions -Previously you would customize the application route, components, apis, sidebar, etc. through the code in `App.tsx`. Now we want you to write less code and install more extensions to customize your Backstage instance. See [here](../building-plugins/03-extension-types.md) which types of extensions are available for you to customize your application. +Previously you would customize the application route, components, apis, sidebar, etc. through the code in `App.tsx`. Now we want you to write less code and install more extensions to customize your Backstage instance. See the [extension blueprints](../building-plugins/03-extension-blueprints.md) section for a list of common extension kinds that are available for you to customize and extend your application. ## Use code to customize the app at a more granular level diff --git a/docs/frontend-system/building-plugins/01-index.md b/docs/frontend-system/building-plugins/01-index.md index 06f1dbc517..1925083ce3 100644 --- a/docs/frontend-system/building-plugins/01-index.md +++ b/docs/frontend-system/building-plugins/01-index.md @@ -229,4 +229,4 @@ export const examplePlugin = createFrontendPlugin({ The `ExampleEntityContent` itself is again a regular React component where you can implement any functionality you want. To access the entity that the content is being rendered for, you can use the `useEntity` hook from `@backstage/plugin-catalog-react`. You can see a full list of APIs provided by the catalog React library in [the API reference](../../reference/plugin-catalog-react.md). -For a more complete list of the different types of extensions that you can create for your plugin, see the [extension types](./03-extension-types.md) section. +For a more complete list of the different kinds of extensions that you can create for your plugin, see the [extension blueprints](./03-extension-blueprints.md) section. diff --git a/docs/frontend-system/building-plugins/03-extension-types.md b/docs/frontend-system/building-plugins/03-extension-blueprints.md similarity index 62% rename from docs/frontend-system/building-plugins/03-extension-types.md rename to docs/frontend-system/building-plugins/03-extension-blueprints.md index c7c2e2ab1f..1607050fa6 100644 --- a/docs/frontend-system/building-plugins/03-extension-types.md +++ b/docs/frontend-system/building-plugins/03-extension-blueprints.md @@ -1,63 +1,63 @@ --- -id: extension-types -title: Frontend System Extension Types -sidebar_label: Extension Types +id: extension-blueprints +title: Frontend System Extension Blueprints +sidebar_label: Extension Blueprints # prettier-ignore -description: Extension types provided by the frontend system and core features +description: Extension blueprints provided by the frontend system and core features --- > **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** -This section covers many of the [extension types](../architecture/20-extensions.md#extension-creators) available at your disposal when building Backstage frontend plugins. +This section covers many of the [extension blueprints](../architecture/23-extension-blueprints.md) available at your disposal when building Backstage frontend plugins. -## Built-in extension types +## Built-in extension blueprints -These are the extension types provided by the Backstage frontend framework itself. +These are the [extension blueprints](../architecture/23-extension-blueprints.md) provided by the Backstage frontend framework itself. -### Api - [Reference](../../reference/frontend-plugin-api.createapiextension.md) +### Api - [Reference](../../reference/frontend-plugin-api.apiblueprint.md) An API extension is used to add or override [Utility API factories](../utility-apis/01-index.md) in the app. They are commonly used by plugins for both internal and shared APIs. There are also many built-in Api extensions provided by the framework that you are able to override. ### Component - [Reference](../../reference/frontend-plugin-api.createcomponentextension.md) -Components extensions are used to override the component associated with a component reference throughout the app. +Components extensions are used to override the component associated with a component reference throughout the app. This uses an extension creator function rather than a blueprint, but will likely be migrated to a blueprint in the future. -### NavItem - [Reference](../../reference/frontend-plugin-api.createnavitemextension.md) +### NavItem - [Reference](../../reference/frontend-plugin-api.navitemblueprint) Navigation item extensions are used to provide menu items that link to different parts of the app. By default nav items are attached to the app nav extension, which by default is rendered as the left sidebar in the app. -### Page - [Reference](../../reference/frontend-plugin-api.createpageextension.md) +### Page - [Reference](../../reference/frontend-plugin-api.pageblueprint.md) Page extensions provide content for a particular route in the app. By default pages are attached to the app routes extensions, which renders the root routes. -### SignInPage - [Reference](../../reference/frontend-plugin-api.createsigninpageextension.md) +### SignInPage - [Reference](../../reference/frontend-plugin-api.signinpageblueprint.md) Sign-in page extension have a single purpose - to implement a custom sign-in page. They are always attached to the app root extension and are rendered before the rest of the app until the user is signed in. -### Theme - [Reference](../../reference/frontend-plugin-api.createthemeextension.md) +### Theme - [Reference](../../reference/frontend-plugin-api.themeblueprint.md) Theme extensions provide custom themes for the app. They are always attached to the app extension and you can have any number of themes extensions installed in an app at once, letting the user choose which theme to use. -### Icons - [Reference](../../reference/frontend-plugin-api.iconbundleblueprint.md) +### Icons - [Reference](../../reference/frontend-plugin-api.ndleblueprint.md) Icon bundle extensions provide the ability to replace or provide new icons to the app. You can use the above blueprint to make new extension instances which can be installed into the app. -### Translation - [Reference](../../reference/frontend-plugin-api.createtranslationextension.md) +### Translation - [Reference](../../reference/frontend-plugin-api.translationblueprint.md) Translation extension provide custom translation messages for the app. They can be used both to override the default english messages to custom ones, as well as provide translations for additional languages. -## Core feature extension types +## Core feature extension blueprints -These are the extension types provided by the Backstage core feature plugins. +These are the [extension blueprints](../architecture/23-extension-blueprints.md) provided by the Backstage core feature plugins. ### EntityCard - [Reference](https://github.com/backstage/backstage/blob/master/plugins/catalog-react/api-report-alpha.md) -Creates entity cards to be displayed on the entity pages of the catalog plugin. +Creates entity cards to be displayed on the entity pages of the catalog plugin. Exported as `EntityCardBlueprint`. ### EntityContent - [Reference](https://github.com/backstage/backstage/blob/master/plugins/catalog-react/api-report-alpha.md) -Creates entity content to be displayed on the entity pages of the catalog plugin. +Creates entity content to be displayed on the entity pages of the catalog plugin. Exported as `EntityContentBlueprint`. ### SearchResultListItem - [Reference](https://github.com/backstage/backstage/blob/master/plugins/search-react/api-report-alpha.md) -Creates search result list items for different types of search results, to be displayed in search result lists. +Creates search result list items for different types of search results, to be displayed in search result lists. Exported as `SearchResultListItemBlueprint`. diff --git a/microsite/sidebars.json b/microsite/sidebars.json index 8874ede56e..2accf2847b 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -469,7 +469,7 @@ "items": [ "frontend-system/building-plugins/index", "frontend-system/building-plugins/testing", - "frontend-system/building-plugins/extension-types", + "frontend-system/building-plugins/extension-blueprints", "frontend-system/building-plugins/built-in-data-refs", "frontend-system/building-plugins/migrating" ] diff --git a/plugins/catalog-graph/README-alpha.md b/plugins/catalog-graph/README-alpha.md index 52c09c4b50..784066c44f 100644 --- a/plugins/catalog-graph/README-alpha.md +++ b/plugins/catalog-graph/README-alpha.md @@ -126,7 +126,7 @@ The Catalog graphics plugin provides extensions for each of its features, see be #### Catalog Entity Relations Graph Card -An [entity card](https://backstage.io/docs/frontend-system/building-plugins/extension-types#entitycard---reference) extension that renders the relation graph for an entity on the Catalog entity page and has an action that redirects users to the more advanced [relations graph page](#catalog-entity-relations-graph-page). +An [entity card](https://backstage.io/docs/frontend-system/building-plugins/extension-blueprints#entitycard---reference) extension that renders the relation graph for an entity on the Catalog entity page and has an action that redirects users to the more advanced [relations graph page](#catalog-entity-relations-graph-page). | kind | namespace | name | id | Default enabled | | ----------- | ------------- | ---------------- | ------------------------------------- | --------------- | From aefe2bd316cd49926d54104deef401a62f289fe1 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 15 Aug 2024 21:46:16 +0200 Subject: [PATCH 05/11] docs/frontend-system: update built-in dataref docs for 1.30 Signed-off-by: Patrik Oldsberg --- .../building-plugins/04-built-in-data-refs.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/docs/frontend-system/building-plugins/04-built-in-data-refs.md b/docs/frontend-system/building-plugins/04-built-in-data-refs.md index d13e734279..a26f6549b7 100644 --- a/docs/frontend-system/building-plugins/04-built-in-data-refs.md +++ b/docs/frontend-system/building-plugins/04-built-in-data-refs.md @@ -24,18 +24,15 @@ The `reactElement` data reference can be used for defining the extension input/o ```tsx import { + createExtension, coreExtensionData, - createExtensionInput, - createPageExtension, } from '@backstage/frontend-plugin-api'; -const homePage = createPageExtension({ - defaultPath: '/home', - routeRef: rootRouteRef, - inputs: { - props: createExtensionInput({ - children: coreExtensionData.reactElement.optional(), - }), +const examplePage = createExtension({ + name: 'example', + output: [coreExtensionData.reactElement], + factor() { + return [coreExtensionData.reactElement(

Example

)]; }, }); ``` From 2ffb8a616b2cb34f543444696da4d4c4a4955af1 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 15 Aug 2024 21:52:27 +0200 Subject: [PATCH 06/11] docs/frontend-system: migrate plugin migration docs to 1.30 Signed-off-by: Patrik Oldsberg --- .../building-plugins/05-migrating.md | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/docs/frontend-system/building-plugins/05-migrating.md b/docs/frontend-system/building-plugins/05-migrating.md index 79b259a2e5..9d978869e5 100644 --- a/docs/frontend-system/building-plugins/05-migrating.md +++ b/docs/frontend-system/building-plugins/05-migrating.md @@ -8,7 +8,7 @@ description: How to migrate an existing frontend plugin to the new frontend syst This guide allows you to migrate a frontend plugin and its own components, routes, apis to the new frontend system. -The main concept is that routes, components, apis are now extensions. You can use the appropriate extension creators to migrate all of them to extensions. +The main concept is that routes, components, apis are now extensions. You can use the appropriate [extension blueprints](../architecture/23-extension-blueprints.md) to migrate all of them to extensions. ## Migrating the plugin @@ -77,7 +77,7 @@ The code above binds all the extensions to the plugin. _Important_: Make sure to ## Migrating Pages -Pages that were previously created using the `createRoutableExtension` extension function can be migrated to the new Frontend System using the `createPageExtension` extension creator, exported by `@backstage/frontend-plugin-api`. +Pages that were previously created using the `createRoutableExtension` extension function can be migrated to the new Frontend System using the `PageBlueprint` [extension blueprint](../architecture/23-extension-blueprints.md), exported by `@backstage/frontend-plugin-api`. For example, given the following page: @@ -94,28 +94,30 @@ export const FooPage = fooPlugin.provide( it can be migrated as the following: ```tsx -import { createPageExtension } from '@backstage/frontend-plugin-api'; +import { PageBlueprint } from '@backstage/frontend-plugin-api'; import { compatWrapper, convertLegacyRouteRef, } from '@backstage/core-compat-api'; -const fooPage = createPageExtension({ - defaultPath: '/foo', - // you can reuse the existing routeRef - // by wrapping into the convertLegacyRouteRef. - routeRef: convertLegacyRouteRef(rootRouteRef), - // these inputs usually match the props required by the component. - loader: ({ inputs }) => - import('./components/').then(m => - // The compatWrapper utility allows you to use the existing - // legacy frontend utilities used internally by the components. - compatWrapper(), - ), +const fooPage = PageBlueprint.make({ + params: { + defaultPath: '/foo', + // you can reuse the existing routeRef + // by wrapping into the convertLegacyRouteRef. + routeRef: convertLegacyRouteRef(rootRouteRef), + // these inputs usually match the props required by the component. + loader: ({ inputs }) => + import('./components/').then(m => + // The compatWrapper utility allows you to use the existing + // legacy frontend utilities used internally by the components. + compatWrapper(), + ), + }, }); ``` -then add the `fooPage` extension to the plugin: +Then add the `fooPage` extension to the plugin: ```ts title="my-plugin/src/alpha.ts" import { createFrontendPlugin } from '@backstage/frontend-plugin-api'; @@ -133,7 +135,7 @@ then add the `fooPage` extension to the plugin: ## Migrating Components -The equivalent utility to replace components created with `createComponentExtension` is `createExtension` from `@backstage/frontend-plugin-api`. However, we recommend searching for a more appropriate extension creator first. +The equivalent utility to replace components created with `createComponentExtension` depends on the context within which the component is used, typically indicated by the naming pattern of the export. Many of these can be migrated to one of the [existing blueprints](03-extension-blueprints.md), but in rare cases it may be necessary to use [`createExtension`](../architecture/20-extensions.md#creating-an-extension) directly. ## Migrating APIs @@ -182,7 +184,7 @@ const exampleWorkApi = createApiFactory({ The major changes we'll make are - Change the old `@backstage/core-plugin-api` imports to the new `@backstage/frontend-plugin-api` package as per the top section of this guide -- Wrap the existing API factory in a `createApiExtension` +- Wrap the existing API factory in a `ApiBlueprint` The end result, after simplifying imports and cleaning up a bit, might look like this: @@ -190,17 +192,19 @@ The end result, after simplifying imports and cleaning up a bit, might look like import { storageApiRef, createApiFactory, - createApiExtension, + ApiBlueprint, } from '@backstage/frontend-plugin-api'; import { workApiRef } from '@internal/plugin-example-react'; import { WorkImpl } from './WorkImpl'; -const exampleWorkApi = createApiExtension({ - factory: createApiFactory({ - api: workApiRef, - deps: { storageApi: storageApiRef }, - factory: ({ storageApi }) => new WorkImpl({ storageApi }), - }), +const exampleWorkApi = ApiBlueprint.make({ + params: { + factory: createApiFactory({ + api: workApiRef, + deps: { storageApi: storageApiRef }, + factory: ({ storageApi }) => new WorkImpl({ storageApi }), + }), + }, }); ``` From 9058fd4e165d086dcf2fc9fb48240b6430653219 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 15 Aug 2024 22:08:19 +0200 Subject: [PATCH 07/11] docs/frontend-system: update API creation docs for 1.30 Signed-off-by: Patrik Oldsberg --- .../utility-apis/02-creating.md | 79 +++++++++---------- 1 file changed, 38 insertions(+), 41 deletions(-) diff --git a/docs/frontend-system/utility-apis/02-creating.md b/docs/frontend-system/utility-apis/02-creating.md index bd0b71120d..01c21fe656 100644 --- a/docs/frontend-system/utility-apis/02-creating.md +++ b/docs/frontend-system/utility-apis/02-creating.md @@ -45,7 +45,7 @@ The plugin itself now wants to provide this API and its default implementation, ```tsx title="in @internal/plugin-example" import { - createApiExtension, + ApiBlueprint, createApiFactory, createFrontendPlugin, storageApiRef, @@ -62,14 +62,17 @@ class WorkImpl implements WorkApi { } } -const exampleWorkApi = createApiExtension({ - factory: createApiFactory({ - api: workApiRef, - deps: { storageApi: storageApiRef }, - factory: ({ storageApi }) => { - return new WorkImpl({ storageApi }); - }, - }), +const workApi = ApiBlueprint.make({ + name: 'work', + params: { + factory: createApiFactory({ + api: workApiRef, + deps: { storageApi: storageApiRef }, + factory: ({ storageApi }) => { + return new WorkImpl({ storageApi }); + }, + }), + }, }); /** @@ -86,43 +89,37 @@ For illustration we make a skeleton implementation class and the API extension a The code also illustrates how the API factory declares a dependency on another utility API - the core storage API in this case. An instance of that utility API is then provided to the factory function. -The resulting extension ID of the work API will be the kind `api:` followed by the plugin ID as the namespace, in this case ending up as `api:plugin.example.work`. Check out [the naming patterns doc](../architecture/50-naming-patterns.md) for more information on how this works. You can now use this ID to refer to the API in app-config and elsewhere. +The extension ID of the work API will be the kind `api:` followed by the plugin ID as the namespace, a `/` separator, and lastly the name we used of the extension. In this case we end up with `api:example/work`. Check out [the naming patterns doc](../architecture/50-naming-patterns.md) for more information on how this works. You can now use this ID to refer to the API in app-config and elsewhere. In case there is a single API that is a central to the functionality of the plugin, most typically an API client, you can choose to omit the name of the extension so that you end up with just `api:`. ## Adding configurability -Here we will describe how to amend a utility API with the capability of having extension config, which is driven by [your app-config](../../conf/writing.md). You do this by giving an extension config schema to your API extension factory function. Let's make the required additions to our original work example API. +Here we will describe how to amend a utility API with the capability of having extension config, which is driven by [your app-config](../../conf/writing.md). You do this by giving an extension config schema to your API extension factory function. Let's refactory the example above to also accept configuration, which will require us to use the [override method of the blueprint](../architecture/23-extension-blueprints.md#creating-an-extension-from-a-blueprint-with-overrides). ```tsx title="in @internal/plugin-example" -/* highlight-add-next-line */ -import { createSchemaFromZod } from '@backstage/frontend-plugin-api'; - -const exampleWorkApi = createApiExtension({ - /* highlight-add-start */ - api: workApiRef, - configSchema: createSchemaFromZod(z => - z.object({ - goSlow: z.boolean().default(false), - }), - ), - /* highlight-add-end */ - /* highlight-remove-next-line */ - factory: createApiFactory({ - /* highlight-add-next-line */ - factory: ({ config }) => createApiFactory({ - api: workApiRef, - deps: { storageApi: storageApiRef }, - factory: ({ storageApi }) => { - /* highlight-add-start */ - if (config.goSlow) { - /* ... */ - } - /* highlight-add-end */ +const exampleWorkApi = ApiBlueprint.makeWithOverrides({ + config: { + schema: { + goSlow: z => z.boolean().default(false), }, - }), + }, + factory(originalFactory, { config }) { + return originalFactory({ + factory: createApiFactory({ + api: workApiRef, + deps: { storageApi: storageApiRef }, + factory: ({ storageApi }) => { + return new WorkImpl({ + storageApi, + goSlow: config.goSlow, + }); + }, + }), + }); + }, }); ``` -We wanted users to be able to set a `goSlow` extension config parameter for our API instances. So we passed in a `configSchema` to `createApiExtension` which matches that interface. This example builds it using [the zod library](https://zod.dev/). The actual extension config values will then be passed in a type safe manner in to the `factory` which is now a callback, wherein we can do what we wish with them. When changing to the callback form, we also had to add a top level `api: workApiRef` under `createApiExtension`. +We wanted users to be able to set a `goSlow` extension config parameter for our API instances, which we declared in our new configuration schema. The actual extension config values will then be passed in a type safe manner in to the blueprint `factory`, wherein we can use them to create our API factory and pass as our blueprint parameters. Note that the expression "extension config" as used here, is _not_ the same thing as the `configApi` which gives you access to the full app-config. The extension config discussed here is instead the particular configuration settings given to your utility API instance. This is discussed more [in the Configuring section](./04-configuring.md). @@ -130,11 +127,11 @@ Note also that the extension config schema contained a default value fo the `goS ## Adding inputs -Inputs are added to Utility APIs in the same way as other extension types: +Inputs are added to Utility APIs in the same way as other extension blueprints: -- Declaring a set of `inputs` on your extension -- If needed, create custom extension data types to be used in those inputs -- If needed, export an extension creator function for creating that particular attachment type +- Use `.makeWithOverrides` and declare a set of `inputs` for your extension. +- If needed, create custom extension data types to be used in those inputs. +- If needed, create and export an [extension blueprint](../architecture/23-extension-blueprints.md#creating-an-extension-blueprint) for creating that particular attachment type. This is a power use case and not very commonly used. From 1fde8285ecbc29c9930e33438c88fc4471d98d34 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 15 Aug 2024 22:11:30 +0200 Subject: [PATCH 08/11] docs/frontend-system: update the rest of the API docs for 1.30 Signed-off-by: Patrik Oldsberg --- .../utility-apis/03-consuming.md | 26 ++++++++++--------- .../utility-apis/04-configuring.md | 8 +++--- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/docs/frontend-system/utility-apis/03-consuming.md b/docs/frontend-system/utility-apis/03-consuming.md index 5c53c8617e..bdf3b8dcdb 100644 --- a/docs/frontend-system/utility-apis/03-consuming.md +++ b/docs/frontend-system/utility-apis/03-consuming.md @@ -46,23 +46,25 @@ Your utility APIs can depend on other utility APIs in their factories. You do th ```tsx import { configApiRef, - createApiExtension, + ApiBlueprint, createApiFactory, discoveryApiRef, } from '@backstage/frontend-plugin-api'; import { MyApiImpl } from './MyApiImpl'; -const myApi = createApiExtension({ - factory: createApiFactory({ - api: myApiRef, - deps: { - configApi: configApiRef, - discoveryApi: discoveryApiRef, - }, - factory: ({ configApi, discoveryApi }) => { - return new MyApiImpl({ configApi, discoveryApi }); - }, - }), +const myApi = ApiBlueprint.make({ + params: { + factory: createApiFactory({ + api: myApiRef, + deps: { + configApi: configApiRef, + discoveryApi: discoveryApiRef, + }, + factory: ({ configApi, discoveryApi }) => { + return new MyApiImpl({ configApi, discoveryApi }); + }, + }), + }, }); ``` diff --git a/docs/frontend-system/utility-apis/04-configuring.md b/docs/frontend-system/utility-apis/04-configuring.md index d22e10011b..e403104506 100644 --- a/docs/frontend-system/utility-apis/04-configuring.md +++ b/docs/frontend-system/utility-apis/04-configuring.md @@ -49,13 +49,13 @@ class CustomWorkImpl implements WorkApi { const myOverrides = createExtensionOverrides({ extensions: [ - createApiExtension({ - api: workApiRef, - factory: () => - createApiFactory({ + ApiBlueprint.make({ + params: { + factory: createApiFactory({ api: workApiRef, factory: () => new CustomWorkImpl(), }), + }, }), ], }); From a0315a8a65753bee63cf086aef18b747f83adfaf Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 16 Aug 2024 09:47:57 +0200 Subject: [PATCH 09/11] docs/frontend-system: rename plugin extension blueprints to common extension blueprints + fix links Signed-off-by: Patrik Oldsberg --- docs/frontend-system/building-apps/01-index.md | 2 +- docs/frontend-system/building-plugins/01-index.md | 2 +- ...blueprints.md => 03-common-extension-blueprints.md} | 10 +++++----- docs/frontend-system/building-plugins/05-migrating.md | 2 +- microsite/sidebars.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) rename docs/frontend-system/building-plugins/{03-extension-blueprints.md => 03-common-extension-blueprints.md} (94%) diff --git a/docs/frontend-system/building-apps/01-index.md b/docs/frontend-system/building-apps/01-index.md index c6a83bb0b7..0654a9dd23 100644 --- a/docs/frontend-system/building-apps/01-index.md +++ b/docs/frontend-system/building-apps/01-index.md @@ -78,7 +78,7 @@ It is possible to enable, disable and configure extensions individually in the ` ### Customize or override built-in extensions -Previously you would customize the application route, components, apis, sidebar, etc. through the code in `App.tsx`. Now we want you to write less code and install more extensions to customize your Backstage instance. See the [extension blueprints](../building-plugins/03-extension-blueprints.md) section for a list of common extension kinds that are available for you to customize and extend your application. +Previously you would customize the application route, components, apis, sidebar, etc. through the code in `App.tsx`. Now we want you to write less code and install more extensions to customize your Backstage instance. See the [extension blueprints](../building-plugins/03-common-extension-blueprints.md) section for a list of common extension kinds that are available for you to customize and extend your application. ## Use code to customize the app at a more granular level diff --git a/docs/frontend-system/building-plugins/01-index.md b/docs/frontend-system/building-plugins/01-index.md index 1925083ce3..c2a5de7280 100644 --- a/docs/frontend-system/building-plugins/01-index.md +++ b/docs/frontend-system/building-plugins/01-index.md @@ -229,4 +229,4 @@ export const examplePlugin = createFrontendPlugin({ The `ExampleEntityContent` itself is again a regular React component where you can implement any functionality you want. To access the entity that the content is being rendered for, you can use the `useEntity` hook from `@backstage/plugin-catalog-react`. You can see a full list of APIs provided by the catalog React library in [the API reference](../../reference/plugin-catalog-react.md). -For a more complete list of the different kinds of extensions that you can create for your plugin, see the [extension blueprints](./03-extension-blueprints.md) section. +For a more complete list of the different kinds of extensions that you can create for your plugin, see the [extension blueprints](./03-common-extension-blueprints.md) section. diff --git a/docs/frontend-system/building-plugins/03-extension-blueprints.md b/docs/frontend-system/building-plugins/03-common-extension-blueprints.md similarity index 94% rename from docs/frontend-system/building-plugins/03-extension-blueprints.md rename to docs/frontend-system/building-plugins/03-common-extension-blueprints.md index 1607050fa6..5193fd85b1 100644 --- a/docs/frontend-system/building-plugins/03-extension-blueprints.md +++ b/docs/frontend-system/building-plugins/03-common-extension-blueprints.md @@ -1,7 +1,7 @@ --- -id: extension-blueprints -title: Frontend System Extension Blueprints -sidebar_label: Extension Blueprints +id: common-extension-blueprints +title: Common Extension Blueprints +sidebar_label: Common Extension Blueprints # prettier-ignore description: Extension blueprints provided by the frontend system and core features --- @@ -22,7 +22,7 @@ An API extension is used to add or override [Utility API factories](../utility-a Components extensions are used to override the component associated with a component reference throughout the app. This uses an extension creator function rather than a blueprint, but will likely be migrated to a blueprint in the future. -### NavItem - [Reference](../../reference/frontend-plugin-api.navitemblueprint) +### NavItem - [Reference](../../reference/frontend-plugin-api.navitemblueprint.md) Navigation item extensions are used to provide menu items that link to different parts of the app. By default nav items are attached to the app nav extension, which by default is rendered as the left sidebar in the app. @@ -38,7 +38,7 @@ Sign-in page extension have a single purpose - to implement a custom sign-in pag Theme extensions provide custom themes for the app. They are always attached to the app extension and you can have any number of themes extensions installed in an app at once, letting the user choose which theme to use. -### Icons - [Reference](../../reference/frontend-plugin-api.ndleblueprint.md) +### Icons - [Reference](../../reference/frontend-plugin-api.iconbundleblueprint.md) Icon bundle extensions provide the ability to replace or provide new icons to the app. You can use the above blueprint to make new extension instances which can be installed into the app. diff --git a/docs/frontend-system/building-plugins/05-migrating.md b/docs/frontend-system/building-plugins/05-migrating.md index 9d978869e5..f0abc97c81 100644 --- a/docs/frontend-system/building-plugins/05-migrating.md +++ b/docs/frontend-system/building-plugins/05-migrating.md @@ -135,7 +135,7 @@ Then add the `fooPage` extension to the plugin: ## Migrating Components -The equivalent utility to replace components created with `createComponentExtension` depends on the context within which the component is used, typically indicated by the naming pattern of the export. Many of these can be migrated to one of the [existing blueprints](03-extension-blueprints.md), but in rare cases it may be necessary to use [`createExtension`](../architecture/20-extensions.md#creating-an-extension) directly. +The equivalent utility to replace components created with `createComponentExtension` depends on the context within which the component is used, typically indicated by the naming pattern of the export. Many of these can be migrated to one of the [existing blueprints](03-common-extension-blueprints.md), but in rare cases it may be necessary to use [`createExtension`](../architecture/20-extensions.md#creating-an-extension) directly. ## Migrating APIs diff --git a/microsite/sidebars.json b/microsite/sidebars.json index 2accf2847b..1a95b5a492 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -469,7 +469,7 @@ "items": [ "frontend-system/building-plugins/index", "frontend-system/building-plugins/testing", - "frontend-system/building-plugins/extension-blueprints", + "frontend-system/building-plugins/common-extension-blueprints", "frontend-system/building-plugins/built-in-data-refs", "frontend-system/building-plugins/migrating" ] From 1cdc1172503a7332fad7e152961dcfdd9b94c4b5 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 16 Aug 2024 10:01:37 +0200 Subject: [PATCH 10/11] Update docs/frontend-system/building-plugins/02-testing.md Co-authored-by: Ben Lambert Signed-off-by: Patrik Oldsberg --- docs/frontend-system/building-plugins/02-testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/building-plugins/02-testing.md b/docs/frontend-system/building-plugins/02-testing.md index 956fdb8394..225c570fbd 100644 --- a/docs/frontend-system/building-plugins/02-testing.md +++ b/docs/frontend-system/building-plugins/02-testing.md @@ -145,7 +145,7 @@ describe('Index page', async () => { }); ``` -When testing multiple extensions you may sometimes want to access the output of other extensions than the main test subject. You can use the `.query(ext)` method to query a different extension that has been added to the tester, either via its ID or passing the extension directly. +When testing multiple extensions you may sometimes want to access the output of other extensions than the main test subject. You can use the `.query(ext)` method to query a different extension that has been added to the tester, by passing the extension used with the `createExtensionTester(...).add(ext)` ### Setting configuration From 56be6445736df0629c856ab01e5c1c79d86ca959 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 16 Aug 2024 11:46:53 +0200 Subject: [PATCH 11/11] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Patrik Oldsberg --- docs/frontend-system/building-apps/01-index.md | 2 +- docs/frontend-system/building-plugins/01-index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/frontend-system/building-apps/01-index.md b/docs/frontend-system/building-apps/01-index.md index 0654a9dd23..16aacc1185 100644 --- a/docs/frontend-system/building-apps/01-index.md +++ b/docs/frontend-system/building-apps/01-index.md @@ -78,7 +78,7 @@ It is possible to enable, disable and configure extensions individually in the ` ### Customize or override built-in extensions -Previously you would customize the application route, components, apis, sidebar, etc. through the code in `App.tsx`. Now we want you to write less code and install more extensions to customize your Backstage instance. See the [extension blueprints](../building-plugins/03-common-extension-blueprints.md) section for a list of common extension kinds that are available for you to customize and extend your application. +Previously you would customize the application routes, components, apis, sidebar, etc. through the code in `App.tsx`. Now we want to allow the same thing to be achieved while writing less code and instead installing more extensions to customize your Backstage instance. See the [extension blueprints](../building-plugins/03-common-extension-blueprints.md) section for a list of common extension kinds that are available for you to customize and extend your application. ## Use code to customize the app at a more granular level diff --git a/docs/frontend-system/building-plugins/01-index.md b/docs/frontend-system/building-plugins/01-index.md index c2a5de7280..57a783d406 100644 --- a/docs/frontend-system/building-plugins/01-index.md +++ b/docs/frontend-system/building-plugins/01-index.md @@ -49,7 +49,7 @@ The plugin ID should be a lowercase dash-separated string, while the plugin inst The plugin that we created above is empty, and doesn't provide any actual functionality. To add functionality to a plugin you need to create and provide it with one or more [extensions](../architecture/20-extensions.md). Let's continue by adding a standalone page to our plugin, as well as a navigation item that allows users to navigate to the page. -To create a new extension you typically use pre-defined [extension blueprints](../architecture/23-extension-blueprints.md), provided either by the framework itself or by other plugins. In this case we'll use `PageBlueprint` and `NavItemBlueprint`, both from `@backstage/frontend-plugin-api`. We will also need to [create a route reference](../architecture/36-routes.md#creating-a-route-reference) to use as a reference for out page, allowing us to dynamically create URLs that link to our page. +To create a new extension you typically use pre-defined [extension blueprints](../architecture/23-extension-blueprints.md), provided either by the framework itself or by other plugins. In this case we'll use `PageBlueprint` and `NavItemBlueprint`, both from `@backstage/frontend-plugin-api`. We will also need to [create a route reference](../architecture/36-routes.md#creating-a-route-reference) to use as a reference for our page, allowing us to dynamically create URLs that link to our page. ```tsx title="in src/routes.ts" import { createRouteRef } from '@backstage/frontend-plugin-api';