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`. 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/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index 2ab447c68f..6159c044d2 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -72,14 +72,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(pagesPlugin.externalRoutes, { pageX: pagesPlugin.routes.pageX }); + }, }); // 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..ef6b55ff4c 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,12 @@ export const pagesPlugin = createPlugin({ // // OR // // 'page1' // }, - extensions: [IndexPage, Page1], + routes: { + page1: page1RouteRef, + pageX: pageXRouteRef, + }, + externalRoutes: { + pageX: externalPageXRouteRef, + }, + 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 */} 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', }; } 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)