From c69e53e88fe65d3c26b1560d48902791715c5b6c Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 11 Oct 2023 13:51:30 +0200 Subject: [PATCH 1/4] frontend-app-api: add support for external route bindings Co-authored-by: Philipp Hugenroth Signed-off-by: Patrik Oldsberg --- packages/app-next/src/App.tsx | 17 +++++----- .../app-next/src/examples/pagesPlugin.tsx | 32 +++++++++++++++++-- packages/frontend-app-api/api-report.md | 2 ++ .../frontend-app-api/src/wiring/createApp.tsx | 6 +++- 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index 2ab447c68f..720075f7a7 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -16,7 +16,11 @@ import React from 'react'; import { createApp } from '@backstage/frontend-app-api'; -import { pagesPlugin } from './examples/pagesPlugin'; +import { + externalPageXRouteRef, + pageXRouteRef, + pagesPlugin, +} from './examples/pagesPlugin'; import graphiqlPlugin from '@backstage/plugin-graphiql/alpha'; import techRadarPlugin from '@backstage/plugin-tech-radar/alpha'; import userSettingsPlugin from '@backstage/plugin-user-settings/alpha'; @@ -72,14 +76,9 @@ const app = createApp({ extensions: [entityPageExtension], }), ], - // bindRoutes({ bind }) { - // bind(catalogPlugin.externalRoutes, { - // createComponent: scaffolderPlugin.routes.root, - // }); - // bind(scaffolderPlugin.externalRoutes, { - // registerComponent: catalogImportPlugin.routes.importPage, - // }); - // }, + bindRoutes({ bind }) { + bind({ x: externalPageXRouteRef }, { x: pageXRouteRef }); + }, }); // const legacyApp = createLegacyApp({ plugins: [legacyGraphiqlPlugin] }); diff --git a/packages/app-next/src/examples/pagesPlugin.tsx b/packages/app-next/src/examples/pagesPlugin.tsx index 5ae1029769..815d4926e9 100644 --- a/packages/app-next/src/examples/pagesPlugin.tsx +++ b/packages/app-next/src/examples/pagesPlugin.tsx @@ -20,11 +20,17 @@ import { createPageExtension, createPlugin, } from '@backstage/frontend-plugin-api'; -import { useRouteRef, createRouteRef } from '@backstage/core-plugin-api'; +import { + useRouteRef, + createRouteRef, + createExternalRouteRef, +} from '@backstage/core-plugin-api'; import { Route, Routes } from 'react-router-dom'; const indexRouteRef = createRouteRef({ id: 'index' }); const page1RouteRef = createRouteRef({ id: 'page1' }); +export const externalPageXRouteRef = createExternalRouteRef({ id: 'pageX' }); +export const pageXRouteRef = createRouteRef({ id: 'pageX' }); // const page2RouteRef = createSubRouteRef({ // id: 'page2', // parent: page1RouteRef, @@ -67,6 +73,7 @@ const Page1 = createPageExtension({ loader: async () => { const Component = () => { const indexLink = useRouteRef(indexRouteRef); + const xLink = useRouteRef(externalPageXRouteRef); // const page2Link = useRouteRef(page2RouteRef); return ( @@ -75,6 +82,7 @@ const Page1 = createPageExtension({ Go back Page 2 {/* Page 2 */} + Page X
Sub-page content: @@ -92,6 +100,26 @@ const Page1 = createPageExtension({ }, }); +const ExternalPage = createPageExtension({ + id: 'pageX', + defaultPath: '/pageX', + routeRef: pageXRouteRef, + loader: async () => { + const Component = () => { + const indexLink = useRouteRef(indexRouteRef); + // const pageXLink = useRouteRef(pageXRouteRef); + + return ( +
+

This is page X

+ Go back +
+ ); + }; + return ; + }, +}); + export const pagesPlugin = createPlugin({ id: 'pages', // routes: { @@ -101,5 +129,5 @@ export const pagesPlugin = createPlugin({ // // OR // // 'page1' // }, - extensions: [IndexPage, Page1], + extensions: [IndexPage, Page1, ExternalPage], }); diff --git a/packages/frontend-app-api/api-report.md b/packages/frontend-app-api/api-report.md index a576d4cfe4..74c34be5f4 100644 --- a/packages/frontend-app-api/api-report.md +++ b/packages/frontend-app-api/api-report.md @@ -3,6 +3,7 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AppRouteBinder } from '@backstage/core-app-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { Config } from '@backstage/config'; import { ConfigApi } from '@backstage/core-plugin-api'; @@ -14,6 +15,7 @@ import { JSX as JSX_2 } from 'react'; export function createApp(options: { features?: (BackstagePlugin | ExtensionOverrides)[]; configLoader?: () => Promise; + bindRoutes?(context: { bind: AppRouteBinder }): void; featureLoader?: (ctx: { config: ConfigApi; }) => Promise<(BackstagePlugin | ExtensionOverrides)[]>; diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index 044eedfefd..f262ecde72 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -57,6 +57,7 @@ import { ApiFactoryRegistry, ApiProvider, ApiResolver, + AppRouteBinder, AppThemeSelector, } from '@backstage/core-app-api'; @@ -76,6 +77,8 @@ import { overrideBaseUrlConfigs } from '../../../core-app-api/src/app/overrideBa // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { RoutingProvider } from '../../../core-app-api/src/routing/RoutingProvider'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { resolveRouteBindings } from '../../../core-app-api/src/app/resolveRouteBindings'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports import { AppLanguageSelector } from '../../../core-app-api/src/apis/implementations/AppLanguageApi/AppLanguageSelector'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { I18nextTranslationApi } from '../../../core-app-api/src/apis/implementations/TranslationApi/I18nextTranslationApi'; @@ -269,6 +272,7 @@ export function createInstances(options: { export function createApp(options: { features?: (BackstagePlugin | ExtensionOverrides)[]; configLoader?: () => Promise; + bindRoutes?(context: { bind: AppRouteBinder }): void; featureLoader?: (ctx: { config: ConfigApi; }) => Promise<(BackstagePlugin | ExtensionOverrides)[]>; @@ -309,7 +313,7 @@ export function createApp(options: { {/* TODO: set base path using the logic from AppRouter */} From f2b7cb4a567388fa772dcf64dac58db00fd3ee48 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 11 Oct 2023 14:23:19 +0200 Subject: [PATCH 2/4] frontend-plugin-api: add routes and externalRoutes to plugins Co-authored-by: Philipp Hugenroth Signed-off-by: Patrik Oldsberg --- packages/app-next/src/App.tsx | 8 ++---- .../app-next/src/examples/pagesPlugin.tsx | 7 +++++ packages/frontend-plugin-api/api-report.md | 27 ++++++++++++++++--- .../src/wiring/createPlugin.ts | 26 +++++++++++++++--- 4 files changed, 55 insertions(+), 13 deletions(-) diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index 720075f7a7..6159c044d2 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -16,11 +16,7 @@ import React from 'react'; import { createApp } from '@backstage/frontend-app-api'; -import { - externalPageXRouteRef, - pageXRouteRef, - pagesPlugin, -} from './examples/pagesPlugin'; +import { pagesPlugin } from './examples/pagesPlugin'; import graphiqlPlugin from '@backstage/plugin-graphiql/alpha'; import techRadarPlugin from '@backstage/plugin-tech-radar/alpha'; import userSettingsPlugin from '@backstage/plugin-user-settings/alpha'; @@ -77,7 +73,7 @@ const app = createApp({ }), ], bindRoutes({ bind }) { - bind({ x: externalPageXRouteRef }, { x: pageXRouteRef }); + bind(pagesPlugin.externalRoutes, { pageX: pagesPlugin.routes.pageX }); }, }); diff --git a/packages/app-next/src/examples/pagesPlugin.tsx b/packages/app-next/src/examples/pagesPlugin.tsx index 815d4926e9..ef6b55ff4c 100644 --- a/packages/app-next/src/examples/pagesPlugin.tsx +++ b/packages/app-next/src/examples/pagesPlugin.tsx @@ -129,5 +129,12 @@ export const pagesPlugin = createPlugin({ // // OR // // 'page1' // }, + routes: { + page1: page1RouteRef, + pageX: pageXRouteRef, + }, + externalRoutes: { + pageX: externalPageXRouteRef, + }, extensions: [IndexPage, Page1, ExternalPage], }); diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 36de6114e6..071b617851 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -7,6 +7,8 @@ import { AnyApiFactory } from '@backstage/core-plugin-api'; import { AnyApiRef } from '@backstage/core-plugin-api'; +import { AnyExternalRoutes } from '@backstage/core-plugin-api'; +import { AnyRoutes } from '@backstage/core-plugin-api'; import { AppTheme } from '@backstage/core-plugin-api'; import { IconComponent } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; @@ -40,13 +42,20 @@ export type AnyExtensionInputMap = { }; // @public (undocumented) -export interface BackstagePlugin { +export interface BackstagePlugin< + Routes extends AnyRoutes = AnyRoutes, + ExternalRoutes extends AnyExternalRoutes = AnyExternalRoutes, +> { // (undocumented) $$type: '@backstage/BackstagePlugin'; // (undocumented) extensions: Extension[]; // (undocumented) + externalRoutes: ExternalRoutes; + // (undocumented) id: string; + // (undocumented) + routes: Routes; } // @public (undocumented) @@ -205,7 +214,12 @@ export function createPageExtension< ): Extension; // @public (undocumented) -export function createPlugin(options: PluginOptions): BackstagePlugin; +export function createPlugin< + Routes extends AnyRoutes = AnyRoutes, + ExternalRoutes extends AnyExternalRoutes = AnyExternalRoutes, +>( + options: PluginOptions, +): BackstagePlugin; // @public (undocumented) export function createSchemaFromZod( @@ -338,11 +352,18 @@ export type NavTarget = { }; // @public (undocumented) -export interface PluginOptions { +export interface PluginOptions< + Routes extends AnyRoutes, + ExternalRoutes extends AnyExternalRoutes, +> { // (undocumented) extensions?: Extension[]; // (undocumented) + externalRoutes?: ExternalRoutes; + // (undocumented) id: string; + // (undocumented) + routes?: Routes; } // @public (undocumented) diff --git a/packages/frontend-plugin-api/src/wiring/createPlugin.ts b/packages/frontend-plugin-api/src/wiring/createPlugin.ts index bd8e9954ef..3afb5cedff 100644 --- a/packages/frontend-plugin-api/src/wiring/createPlugin.ts +++ b/packages/frontend-plugin-api/src/wiring/createPlugin.ts @@ -14,26 +14,44 @@ * limitations under the License. */ +import { AnyExternalRoutes, AnyRoutes } from '@backstage/core-plugin-api'; import { Extension } from './createExtension'; /** @public */ -export interface PluginOptions { +export interface PluginOptions< + Routes extends AnyRoutes, + ExternalRoutes extends AnyExternalRoutes, +> { id: string; + routes?: Routes; + externalRoutes?: ExternalRoutes; extensions?: Extension[]; } /** @public */ -export interface BackstagePlugin { +export interface BackstagePlugin< + Routes extends AnyRoutes = AnyRoutes, + ExternalRoutes extends AnyExternalRoutes = AnyExternalRoutes, +> { $$type: '@backstage/BackstagePlugin'; id: string; extensions: Extension[]; + routes: Routes; + externalRoutes: ExternalRoutes; } /** @public */ -export function createPlugin(options: PluginOptions): BackstagePlugin { +export function createPlugin< + Routes extends AnyRoutes = AnyRoutes, + ExternalRoutes extends AnyExternalRoutes = AnyExternalRoutes, +>( + options: PluginOptions, +): BackstagePlugin { return { ...options, - $$type: '@backstage/BackstagePlugin', + routes: options.routes ?? ({} as Routes), + externalRoutes: options.externalRoutes ?? ({} as ExternalRoutes), extensions: options.extensions ?? [], + $$type: '@backstage/BackstagePlugin', }; } From 2ecd33618a7fc1e1703f643687b50b2bbab0b98d Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 11 Oct 2023 15:08:12 +0200 Subject: [PATCH 3/4] changesets: changesets for route bindings in new system Signed-off-by: Patrik Oldsberg --- .changeset/many-impalas-wait.md | 5 +++++ .changeset/orange-cycles-wait.md | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .changeset/many-impalas-wait.md create mode 100644 .changeset/orange-cycles-wait.md diff --git a/.changeset/many-impalas-wait.md b/.changeset/many-impalas-wait.md new file mode 100644 index 0000000000..843adf66a1 --- /dev/null +++ b/.changeset/many-impalas-wait.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +Plugins can now be assigned `routes` and `externalRoutes` when created. diff --git a/.changeset/orange-cycles-wait.md b/.changeset/orange-cycles-wait.md new file mode 100644 index 0000000000..5e71b69e80 --- /dev/null +++ b/.changeset/orange-cycles-wait.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Added the `bindRoutes` option to `createApp`. From 45193226aa5c2307bcf0293a62e0c296539b0a93 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 11 Oct 2023 15:31:32 +0200 Subject: [PATCH 4/4] plugin API report updates for new frontend-plugin-api type Signed-off-by: Patrik Oldsberg --- packages/app-next-example-plugin/api-report.md | 4 +++- plugins/adr/alpha-api-report.md | 4 +++- plugins/catalog/alpha-api-report.md | 4 +++- plugins/explore/alpha-api-report.md | 4 +++- plugins/graphiql/alpha-api-report.md | 4 +++- plugins/search/alpha-api-report.md | 4 +++- plugins/tech-radar/alpha-api-report.md | 4 +++- plugins/techdocs/alpha-api-report.md | 4 +++- plugins/user-settings/alpha-api-report.md | 4 +++- 9 files changed, 27 insertions(+), 9 deletions(-) diff --git a/packages/app-next-example-plugin/api-report.md b/packages/app-next-example-plugin/api-report.md index 68a0471b6b..83449a102f 100644 --- a/packages/app-next-example-plugin/api-report.md +++ b/packages/app-next-example-plugin/api-report.md @@ -3,11 +3,13 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AnyExternalRoutes } from '@backstage/core-plugin-api'; +import { AnyRoutes } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { default as React_2 } from 'react'; // @public (undocumented) -const examplePlugin: BackstagePlugin; +const examplePlugin: BackstagePlugin; export default examplePlugin; // @public (undocumented) diff --git a/plugins/adr/alpha-api-report.md b/plugins/adr/alpha-api-report.md index 9d0bd071b1..6dd1c8043f 100644 --- a/plugins/adr/alpha-api-report.md +++ b/plugins/adr/alpha-api-report.md @@ -3,6 +3,8 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AnyExternalRoutes } from '@backstage/core-plugin-api'; +import { AnyRoutes } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { Extension } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; @@ -24,7 +26,7 @@ export const adrTranslationRef: TranslationRef< >; // @alpha (undocumented) -const _default: BackstagePlugin; +const _default: BackstagePlugin; export default _default; // (No @packageDocumentation comment for this package) diff --git a/plugins/catalog/alpha-api-report.md b/plugins/catalog/alpha-api-report.md index e89807ac34..4582a13a5d 100644 --- a/plugins/catalog/alpha-api-report.md +++ b/plugins/catalog/alpha-api-report.md @@ -3,6 +3,8 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AnyExternalRoutes } from '@backstage/core-plugin-api'; +import { AnyRoutes } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { Extension } from '@backstage/frontend-plugin-api'; @@ -15,7 +17,7 @@ export const CatalogSearchResultListItemExtension: Extension<{ }>; // @alpha (undocumented) -const _default: BackstagePlugin; +const _default: BackstagePlugin; export default _default; // @alpha (undocumented) diff --git a/plugins/explore/alpha-api-report.md b/plugins/explore/alpha-api-report.md index 3d6e527629..308cbac733 100644 --- a/plugins/explore/alpha-api-report.md +++ b/plugins/explore/alpha-api-report.md @@ -3,11 +3,13 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AnyExternalRoutes } from '@backstage/core-plugin-api'; +import { AnyRoutes } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { Extension } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) -const _default: BackstagePlugin; +const _default: BackstagePlugin; export default _default; // @alpha (undocumented) diff --git a/plugins/graphiql/alpha-api-report.md b/plugins/graphiql/alpha-api-report.md index 28537cfb15..6c0ea02988 100644 --- a/plugins/graphiql/alpha-api-report.md +++ b/plugins/graphiql/alpha-api-report.md @@ -3,6 +3,8 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AnyExternalRoutes } from '@backstage/core-plugin-api'; +import { AnyRoutes } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { Extension } from '@backstage/frontend-plugin-api'; import { GraphQLEndpoint } from '@backstage/plugin-graphiql'; @@ -19,7 +21,7 @@ export function createEndpointExtension(options: { }): Extension; // @alpha (undocumented) -const _default: BackstagePlugin; +const _default: BackstagePlugin; export default _default; // @alpha (undocumented) diff --git a/plugins/search/alpha-api-report.md b/plugins/search/alpha-api-report.md index 5799ff5cd6..58c963b1d6 100644 --- a/plugins/search/alpha-api-report.md +++ b/plugins/search/alpha-api-report.md @@ -3,11 +3,13 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AnyExternalRoutes } from '@backstage/core-plugin-api'; +import { AnyRoutes } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { Extension } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) -const _default: BackstagePlugin; +const _default: BackstagePlugin; export default _default; // @alpha (undocumented) diff --git a/plugins/tech-radar/alpha-api-report.md b/plugins/tech-radar/alpha-api-report.md index c54f692982..9245acfaf2 100644 --- a/plugins/tech-radar/alpha-api-report.md +++ b/plugins/tech-radar/alpha-api-report.md @@ -3,11 +3,13 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AnyExternalRoutes } from '@backstage/core-plugin-api'; +import { AnyRoutes } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { Extension } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) -const _default: BackstagePlugin; +const _default: BackstagePlugin; export default _default; // @alpha (undocumented) diff --git a/plugins/techdocs/alpha-api-report.md b/plugins/techdocs/alpha-api-report.md index 30d208865c..0bf8c25b33 100644 --- a/plugins/techdocs/alpha-api-report.md +++ b/plugins/techdocs/alpha-api-report.md @@ -3,11 +3,13 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AnyExternalRoutes } from '@backstage/core-plugin-api'; +import { AnyRoutes } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { Extension } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) -const _default: BackstagePlugin; +const _default: BackstagePlugin; export default _default; // @alpha (undocumented) diff --git a/plugins/user-settings/alpha-api-report.md b/plugins/user-settings/alpha-api-report.md index a4f41a729a..8a3e109e5b 100644 --- a/plugins/user-settings/alpha-api-report.md +++ b/plugins/user-settings/alpha-api-report.md @@ -3,12 +3,14 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AnyExternalRoutes } from '@backstage/core-plugin-api'; +import { AnyRoutes } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/core-plugin-api'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; // @alpha (undocumented) -const _default: BackstagePlugin; +const _default: BackstagePlugin; export default _default; // @alpha (undocumented)