From 358c6f70218ccc03643868d119a89f25c59f447e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 23 Nov 2025 00:44:12 +0100 Subject: [PATCH 1/8] core-plugin-api: add forwards compatibility for useApp and useRouteRef Signed-off-by: Patrik Oldsberg --- .changeset/metal-boxes-laugh.md | 5 + .../core-plugin-api/src/app/useApp.test.tsx | 125 ++++++++- packages/core-plugin-api/src/app/useApp.tsx | 132 +++++++++ .../src/routing/useRouteRef.test.tsx | 263 +++++++++++------- .../src/routing/useRouteRef.tsx | 45 ++- 5 files changed, 453 insertions(+), 117 deletions(-) create mode 100644 .changeset/metal-boxes-laugh.md diff --git a/.changeset/metal-boxes-laugh.md b/.changeset/metal-boxes-laugh.md new file mode 100644 index 0000000000..9a5ab24e0e --- /dev/null +++ b/.changeset/metal-boxes-laugh.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-plugin-api': patch +--- + +The `useApp` and `useRouteRef` functions are now forwards compatible with the new frontend system. Along with the previous route reference changes this means that there is no longer a need to use `compatWrapper` from `@backstage/core-compat-api` to make code based on `@backstage/core-plugin-api` compatible with `@backstage/frontend-plugin-api` APIs. diff --git a/packages/core-plugin-api/src/app/useApp.test.tsx b/packages/core-plugin-api/src/app/useApp.test.tsx index 34c956138e..2cee7f6f3c 100644 --- a/packages/core-plugin-api/src/app/useApp.test.tsx +++ b/packages/core-plugin-api/src/app/useApp.test.tsx @@ -15,20 +15,129 @@ */ import { renderHook } from '@testing-library/react'; +import { PropsWithChildren } from 'react'; import { createVersionedContextForTesting } from '@backstage/version-bridge'; +import { + appTreeApiRef, + iconsApiRef, + AppTreeApi, + IconsApi, + AppTree, + AppNode, +} from '@backstage/frontend-plugin-api'; import { useApp } from './useApp'; +import { TestApiProvider, withLogCollector } from '@backstage/test-utils'; -describe('v1 consumer', () => { - const context = createVersionedContextForTesting('app-context'); +describe('useApp', () => { + describe('old system', () => { + const context = createVersionedContextForTesting('app-context'); - afterEach(() => { - context.reset(); + afterEach(() => { + context.reset(); + }); + + it('should provide an app context', () => { + const wrapper = ({ children }: PropsWithChildren<{}>) => ( + {children} + ); + context.set({ 1: 'context-value' }); + + const renderedHook = renderHook(() => useApp(), { wrapper }); + expect(renderedHook.result.current).toBe('context-value'); + }); }); - it('should provide an app context', () => { - context.set({ 1: 'context-value' }); + describe('new system', () => { + const mockIcon = () => null; + const mockIconsApi: IconsApi = { + getIcon: jest.fn((key: string) => + key === 'test-icon' ? mockIcon : undefined, + ), + listIconKeys: jest.fn(() => ['test-icon']), + }; - const renderedHook = renderHook(() => useApp()); - expect(renderedHook.result.current).toBe('context-value'); + const mockPlugin = { + id: 'test-plugin', + }; + + const mockAppNode: AppNode = { + spec: { + id: 'test-node', + attachTo: { id: 'root', input: 'children' }, + extension: {} as any, + disabled: false, + plugin: mockPlugin as any, + }, + edges: { + attachments: new Map(), + }, + }; + + const mockAppTree: AppTree = { + root: mockAppNode, + nodes: new Map([['test-node', mockAppNode]]), + orphans: [], + }; + + const mockAppTreeApi: AppTreeApi = { + getTree: jest.fn(() => ({ tree: mockAppTree })), + getNodesByRoutePath: jest.fn(() => ({ nodes: [] })), + }; + + it('should provide an app context from new app system', () => { + const wrapper = ({ children }: PropsWithChildren<{}>) => ( + + {children} + + ); + + const renderedHook = renderHook(() => useApp(), { wrapper }); + + const appContext = renderedHook.result.current; + expect(appContext).toBeDefined(); + expect(appContext.getPlugins()).toHaveLength(1); + expect(appContext.getPlugins()[0].getId()).toBe('test-plugin'); + expect(appContext.getSystemIcon('test-icon')).toBe(mockIcon); + expect(appContext.getSystemIcons()).toEqual({ 'test-icon': mockIcon }); + expect(appContext.getComponents().Progress).toBeDefined(); + expect(appContext.getComponents().NotFoundErrorPage).toBeDefined(); + }); + + it('should error on missing appTreeApi or iconsApi', () => { + withLogCollector(['error'], () => { + expect(() => + renderHook(() => useApp(), { + wrapper: ({ children }: PropsWithChildren<{}>) => ( + {children} + ), + }), + ).toThrow('App context is not available'); + + expect(() => + renderHook(() => useApp(), { + wrapper: ({ children }: PropsWithChildren<{}>) => ( + + {children} + + ), + }), + ).toThrow('App context is not available'); + + expect(() => + renderHook(() => useApp(), { + wrapper: ({ children }: PropsWithChildren<{}>) => ( + + {children} + + ), + }), + ).toThrow('App context is not available'); + }); + }); }); }); diff --git a/packages/core-plugin-api/src/app/useApp.tsx b/packages/core-plugin-api/src/app/useApp.tsx index 05723ee387..8368ed955f 100644 --- a/packages/core-plugin-api/src/app/useApp.tsx +++ b/packages/core-plugin-api/src/app/useApp.tsx @@ -14,18 +14,150 @@ * limitations under the License. */ +import { useMemo } from 'react'; import { useVersionedContext } from '@backstage/version-bridge'; +import { + appTreeApiRef, + iconsApiRef, + useApiHolder, + ErrorDisplay, + NotFoundErrorPage, + Progress, + createFrontendPlugin, + FrontendPlugin, +} from '@backstage/frontend-plugin-api'; +import { + AppComponents, + IconComponent, + BackstagePlugin, +} from '@backstage/core-plugin-api'; +import { getOrCreateGlobalSingleton } from '@backstage/version-bridge'; import { AppContext as AppContextV1 } from './types'; +const legacyPluginStore = getOrCreateGlobalSingleton( + 'legacy-plugin-compatibility-store', + () => new WeakMap(), +); + +function toLegacyPlugin(plugin: FrontendPlugin): BackstagePlugin { + let legacy = legacyPluginStore.get(plugin); + if (legacy) { + return legacy; + } + + const errorMsg = 'Not implemented in legacy plugin compatibility layer'; + const notImplemented = () => { + throw new Error(errorMsg); + }; + + legacy = { + getId(): string { + return plugin.id; + }, + get routes() { + return {}; + }, + get externalRoutes() { + return {}; + }, + getApis: notImplemented, + getFeatureFlags: notImplemented, + provide: notImplemented, + }; + + legacyPluginStore.set(plugin, legacy); + return legacy; +} + +function toNewPlugin(plugin: BackstagePlugin): FrontendPlugin { + return createFrontendPlugin({ + pluginId: plugin.getId(), + }); +} + /** * React hook providing {@link AppContext}. * * @public */ export const useApp = (): AppContextV1 => { + const apiHolder = useApiHolder(); + const appTreeApi = apiHolder.get(appTreeApiRef); const versionedContext = useVersionedContext<{ 1: AppContextV1 }>( 'app-context', ); + + const newAppContext = useMemo(() => { + if (!appTreeApi) { + return null; + } + + const iconsApi = apiHolder.get(iconsApiRef); + if (!iconsApi) { + return null; + } + + const { tree } = appTreeApi.getTree(); + + let gatheredPlugins: BackstagePlugin[] | undefined = undefined; + + const ErrorBoundaryFallbackWrapper: AppComponents['ErrorBoundaryFallback'] = + ({ plugin, ...rest }) => ( + + ); + + return { + getPlugins(): BackstagePlugin[] { + if (gatheredPlugins) { + return gatheredPlugins; + } + + const pluginSet = new Set(); + for (const node of tree.nodes.values()) { + const plugin = node.spec.plugin; + if (plugin) { + pluginSet.add(toLegacyPlugin(plugin)); + } + } + gatheredPlugins = Array.from(pluginSet); + + return gatheredPlugins; + }, + + getSystemIcon(key: string): IconComponent | undefined { + return iconsApi.getIcon(key); + }, + + getSystemIcons(): Record { + return Object.fromEntries( + iconsApi.listIconKeys().map(key => [key, iconsApi.getIcon(key)!]), + ); + }, + + getComponents(): AppComponents { + return { + NotFoundErrorPage: NotFoundErrorPage, + BootErrorPage() { + throw new Error( + 'The BootErrorPage app component should not be accessed by plugins', + ); + }, + Progress: Progress, + Router() { + throw new Error( + 'The Router app component should not be accessed by plugins', + ); + }, + ErrorBoundaryFallback: ErrorBoundaryFallbackWrapper, + }; + }, + }; + }, [appTreeApi, apiHolder]); + + if (newAppContext) { + return newAppContext; + } + if (!versionedContext) { throw new Error('App context is not available'); } diff --git a/packages/core-plugin-api/src/routing/useRouteRef.test.tsx b/packages/core-plugin-api/src/routing/useRouteRef.test.tsx index b96fc5fc23..325690b6eb 100644 --- a/packages/core-plugin-api/src/routing/useRouteRef.test.tsx +++ b/packages/core-plugin-api/src/routing/useRouteRef.test.tsx @@ -18,140 +18,203 @@ import { renderHook } from '@testing-library/react'; import { PropsWithChildren } from 'react'; import { MemoryRouter, Router } from 'react-router-dom'; import { createVersionedContextForTesting } from '@backstage/version-bridge'; +import { + routeResolutionApiRef, + RouteResolutionApi, + RouteFunc, +} from '@backstage/frontend-plugin-api'; import { useRouteRef } from './useRouteRef'; import { createRouteRef } from './RouteRef'; +import { createExternalRouteRef } from './ExternalRouteRef'; import { createBrowserHistory } from 'history'; +import { TestApiProvider } from '@backstage/test-utils'; -describe('v1 consumer', () => { - const context = createVersionedContextForTesting('routing-context'); +describe('useRouteRef', () => { + describe('old app system', () => { + const context = createVersionedContextForTesting('routing-context'); - afterEach(() => { - context.reset(); - }); - - it('should resolve routes', () => { - const resolve = jest.fn(() => () => '/hello'); - context.set({ 1: { resolve } }); - - const routeRef = createRouteRef({ id: 'ref1' }); - - const renderedHook = renderHook(() => useRouteRef(routeRef), { - wrapper: ({ children }: PropsWithChildren<{}>) => ( - - ), + afterEach(() => { + context.reset(); }); - const routeFunc = renderedHook.result.current; - expect(routeFunc()).toBe('/hello'); - expect(resolve).toHaveBeenCalledWith( - routeRef, - expect.objectContaining({ - pathname: '/my-page', - }), - ); - }); + it('should resolve routes', () => { + const resolve = jest.fn(() => () => '/hello'); + context.set({ 1: { resolve } }); - it('re-resolves the routeFunc when the search parameters change', () => { - const resolve = jest.fn(() => () => '/hello'); - context.set({ 1: { resolve } }); + const routeRef = createRouteRef({ id: 'ref1' }); - const routeRef = createRouteRef({ id: 'ref1' }); - const history = createBrowserHistory(); - history.push('/my-page'); + const renderedHook = renderHook(() => useRouteRef(routeRef), { + wrapper: ({ children }: PropsWithChildren<{}>) => ( + + ), + }); - const { rerender } = renderHook(() => useRouteRef(routeRef), { - wrapper: ({ children }: PropsWithChildren<{}>) => ( - - ), + const routeFunc = renderedHook.result.current; + expect(routeFunc()).toBe('/hello'); + expect(resolve).toHaveBeenCalledWith( + routeRef, + expect.objectContaining({ + pathname: '/my-page', + }), + ); }); - expect(resolve).toHaveBeenCalledTimes(1); + it('re-resolves the routeFunc when the search parameters change', () => { + const resolve = jest.fn(() => () => '/hello'); + context.set({ 1: { resolve } }); - history.push('/my-new-page'); - rerender(); + const routeRef = createRouteRef({ id: 'ref1' }); + const history = createBrowserHistory(); + history.push('/my-page'); - expect(resolve).toHaveBeenCalledTimes(2); - }); + const { rerender } = renderHook(() => useRouteRef(routeRef), { + wrapper: ({ children }: PropsWithChildren<{}>) => ( + + ), + }); - it('does not re-resolve the routeFunc the location pathname does not change', () => { - const resolve = jest.fn(() => () => '/hello'); - context.set({ 1: { resolve } }); + expect(resolve).toHaveBeenCalledTimes(1); - const routeRef = createRouteRef({ id: 'ref1' }); - const history = createBrowserHistory(); - history.push('/my-page'); + history.push('/my-new-page'); + rerender(); - const { rerender } = renderHook(() => useRouteRef(routeRef), { - wrapper: ({ children }: PropsWithChildren<{}>) => ( - - ), + expect(resolve).toHaveBeenCalledTimes(2); }); - expect(resolve).toHaveBeenCalledTimes(1); + it('does not re-resolve the routeFunc the location pathname does not change', () => { + const resolve = jest.fn(() => () => '/hello'); + context.set({ 1: { resolve } }); - history.push('/my-page'); - rerender(); + const routeRef = createRouteRef({ id: 'ref1' }); + const history = createBrowserHistory(); + history.push('/my-page'); - expect(resolve).toHaveBeenCalledTimes(1); - }); + const { rerender } = renderHook(() => useRouteRef(routeRef), { + wrapper: ({ children }: PropsWithChildren<{}>) => ( + + ), + }); - it('does not re-resolve the routeFunc when the search parameter changes', () => { - const resolve = jest.fn(() => () => '/hello'); - context.set({ 1: { resolve } }); + expect(resolve).toHaveBeenCalledTimes(1); - const routeRef = createRouteRef({ id: 'ref1' }); - const history = createBrowserHistory(); - history.push('/my-page'); + history.push('/my-page'); + rerender(); - const { rerender } = renderHook(() => useRouteRef(routeRef), { - wrapper: ({ children }: PropsWithChildren<{}>) => ( - - ), + expect(resolve).toHaveBeenCalledTimes(1); }); - expect(resolve).toHaveBeenCalledTimes(1); + it('does not re-resolve the routeFunc when the search parameter changes', () => { + const resolve = jest.fn(() => () => '/hello'); + context.set({ 1: { resolve } }); - history.push('/my-page?foo=bar'); - rerender(); + const routeRef = createRouteRef({ id: 'ref1' }); + const history = createBrowserHistory(); + history.push('/my-page'); - expect(resolve).toHaveBeenCalledTimes(1); - }); + const { rerender } = renderHook(() => useRouteRef(routeRef), { + wrapper: ({ children }: PropsWithChildren<{}>) => ( + + ), + }); - it('does not re-resolve the routeFunc when the hash parameter changes', () => { - const resolve = jest.fn(() => () => '/hello'); - context.set({ 1: { resolve } }); + expect(resolve).toHaveBeenCalledTimes(1); - const routeRef = createRouteRef({ id: 'ref1' }); - const history = createBrowserHistory(); - history.push('/my-page'); + history.push('/my-page?foo=bar'); + rerender(); - const { rerender } = renderHook(() => useRouteRef(routeRef), { - wrapper: ({ children }: PropsWithChildren<{}>) => ( - - ), + expect(resolve).toHaveBeenCalledTimes(1); }); - expect(resolve).toHaveBeenCalledTimes(1); + it('does not re-resolve the routeFunc when the hash parameter changes', () => { + const resolve = jest.fn(() => () => '/hello'); + context.set({ 1: { resolve } }); - history.push('/my-page#foo'); - rerender(); + const routeRef = createRouteRef({ id: 'ref1' }); + const history = createBrowserHistory(); + history.push('/my-page'); - expect(resolve).toHaveBeenCalledTimes(1); + const { rerender } = renderHook(() => useRouteRef(routeRef), { + wrapper: ({ children }: PropsWithChildren<{}>) => ( + + ), + }); + + expect(resolve).toHaveBeenCalledTimes(1); + + history.push('/my-page#foo'); + rerender(); + + expect(resolve).toHaveBeenCalledTimes(1); + }); + }); + + describe('new app system', () => { + it('should resolve routes using routeResolutionApi', () => { + const routeRef = createRouteRef({ id: 'ref1' }); + const mockRouteFunc: RouteFunc = jest.fn(() => '/new-route'); + + const mockRouteResolutionApi: RouteResolutionApi = { + resolve: jest.fn(() => mockRouteFunc), + }; + + const wrapper = ({ children }: PropsWithChildren<{}>) => ( + + {children} + + ); + + const renderedHook = renderHook(() => useRouteRef(routeRef), { wrapper }); + + const routeFunc = renderedHook.result.current; + expect(routeFunc).toBe(mockRouteFunc); + expect(mockRouteResolutionApi.resolve).toHaveBeenCalledWith( + expect.anything(), + { sourcePath: '/my-page' }, + ); + expect(routeFunc()).toBe('/new-route'); + }); + + it('should handle optional external route refs', () => { + const externalRouteRef = createExternalRouteRef({ + id: 'external-ref', + optional: true, + }); + + const mockRouteResolutionApi: RouteResolutionApi = { + resolve: jest.fn(() => undefined), + }; + + const wrapper = ({ children }: PropsWithChildren<{}>) => ( + + {children} + + ); + + const renderedHook = renderHook(() => useRouteRef(externalRouteRef), { + wrapper, + }); + + expect(renderedHook.result.current).toBeUndefined(); + }); }); }); diff --git a/packages/core-plugin-api/src/routing/useRouteRef.tsx b/packages/core-plugin-api/src/routing/useRouteRef.tsx index cf292b110f..a46e96ba9e 100644 --- a/packages/core-plugin-api/src/routing/useRouteRef.tsx +++ b/packages/core-plugin-api/src/routing/useRouteRef.tsx @@ -17,6 +17,10 @@ import { useMemo } from 'react'; import { matchRoutes, useLocation } from 'react-router-dom'; import { useVersionedContext } from '@backstage/version-bridge'; +import { + routeResolutionApiRef, + useApiHolder, +} from '@backstage/frontend-plugin-api'; import { AnyParams, ExternalRouteRef, @@ -86,30 +90,53 @@ export function useRouteRef( | ExternalRouteRef, ): RouteFunc | undefined { const { pathname } = useLocation(); + const apiHolder = useApiHolder(); + const routeResolutionApi = apiHolder.get(routeResolutionApiRef); const versionedContext = useVersionedContext<{ 1: RouteResolver }>( 'routing-context', ); - if (!versionedContext) { - throw new Error('Routing context is not available'); - } - const resolver = versionedContext.atVersion(1); - const routeFunc = useMemo( + const resolver = versionedContext?.atVersion(1); + + const newRouteFunc = useMemo(() => { + if (!routeResolutionApi) { + return null; + } + + try { + return routeResolutionApi.resolve(routeRef, { + sourcePath: pathname, + }); + } catch { + return null; + } + }, [routeResolutionApi, routeRef, pathname]); + + const legacyRouteFunc = useMemo( () => resolver && resolver.resolve(routeRef, { pathname }), [resolver, routeRef, pathname], ); - if (!versionedContext) { - throw new Error('useRouteRef used outside of routing context'); + if (newRouteFunc !== null) { + const isOptional = 'optional' in routeRef && routeRef.optional; + if (!newRouteFunc && !isOptional) { + throw new Error(`No path for ${routeRef}`); + } + return newRouteFunc; } + + if (!versionedContext) { + throw new Error('Routing context is not available'); + } + if (!resolver) { throw new Error('RoutingContext v1 not available'); } const isOptional = 'optional' in routeRef && routeRef.optional; - if (!routeFunc && !isOptional) { + if (!legacyRouteFunc && !isOptional) { throw new Error(`No path for ${routeRef}`); } - return routeFunc; + return legacyRouteFunc; } From d02db50b426e5a3d3e4c9ca13d5bd03eaa6e9664 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 23 Nov 2025 00:51:55 +0100 Subject: [PATCH 2/8] plugins: cleanup unnecessary use of compatWrapper Signed-off-by: Patrik Oldsberg --- .changeset/metal-humans-lose.md | 21 +++++ plugins/api-docs/src/alpha.tsx | 88 ++++++++----------- plugins/catalog-graph/src/alpha.tsx | 17 ++-- plugins/catalog-import/src/alpha.tsx | 17 ++-- .../src/alpha/plugin.tsx | 11 +-- .../catalog/src/alpha/contextMenuItems.tsx | 33 ++++--- plugins/catalog/src/alpha/entityCards.tsx | 59 ++++++------- plugins/catalog/src/alpha/pages.tsx | 11 +-- plugins/devtools/src/alpha/plugin.tsx | 9 +- plugins/home/package.json | 1 - plugins/home/src/alpha.tsx | 15 ++-- .../kubernetes/src/alpha/entityContents.tsx | 5 +- plugins/kubernetes/src/alpha/pages.tsx | 9 +- plugins/notifications/src/alpha.tsx | 7 +- plugins/org/src/alpha.tsx | 51 +++++------ plugins/scaffolder/src/alpha/extensions.tsx | 13 +-- plugins/search/src/alpha.tsx | 5 +- plugins/techdocs/src/alpha/index.tsx | 32 +++---- plugins/user-settings/src/alpha.tsx | 17 ++-- 19 files changed, 186 insertions(+), 235 deletions(-) create mode 100644 .changeset/metal-humans-lose.md diff --git a/.changeset/metal-humans-lose.md b/.changeset/metal-humans-lose.md new file mode 100644 index 0000000000..490ae28ab2 --- /dev/null +++ b/.changeset/metal-humans-lose.md @@ -0,0 +1,21 @@ +--- +'@backstage/plugin-catalog-unprocessed-entities': patch +'@backstage/plugin-app-visualizer': patch +'@backstage/plugin-catalog-import': patch +'@backstage/plugin-catalog-graph': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-notifications': patch +'@backstage/plugin-user-settings': patch +'@backstage/plugin-kubernetes': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-api-docs': patch +'@backstage/plugin-devtools': patch +'@backstage/plugin-techdocs': patch +'@backstage/plugin-catalog': patch +'@backstage/plugin-search': patch +'@backstage/plugin-home': patch +'@backstage/plugin-app': patch +'@backstage/plugin-org': patch +--- + +Remove unnecessary use of `compatWrapper` for the new frontend system. diff --git a/plugins/api-docs/src/alpha.tsx b/plugins/api-docs/src/alpha.tsx index 7693b97259..87dccdf713 100644 --- a/plugins/api-docs/src/alpha.tsx +++ b/plugins/api-docs/src/alpha.tsx @@ -23,10 +23,7 @@ import { createFrontendPlugin, } from '@backstage/frontend-plugin-api'; -import { - compatWrapper, - convertLegacyRouteRef, -} from '@backstage/core-compat-api'; +import { convertLegacyRouteRef } from '@backstage/core-compat-api'; import { ApiEntity, @@ -48,7 +45,7 @@ const apiDocsNavItem = NavItemBlueprint.make({ params: { title: 'APIs', routeRef: convertLegacyRouteRef(rootRoute), - icon: () => compatWrapper(), + icon: () => , }, }); @@ -82,13 +79,11 @@ const apiDocsExplorerPage = PageBlueprint.makeWithOverrides({ path: '/api-docs', routeRef: convertLegacyRouteRef(rootRoute), loader: () => - import('./components/ApiExplorerPage').then(m => - compatWrapper( - , - ), - ), + import('./components/ApiExplorerPage').then(m => ( + + )), }); }, }); @@ -109,10 +104,7 @@ const apiDocsHasApisEntityCard = EntityCardBlueprint.make({ )!! ); }, - loader: () => - import('./components/ApisCards').then(m => - compatWrapper(), - ), + loader: () => import('./components/ApisCards').then(m => ), }, }); @@ -121,9 +113,9 @@ const apiDocsDefinitionEntityCard = EntityCardBlueprint.make({ params: { filter: 'kind:api', loader: () => - import('./components/ApiDefinitionCard').then(m => - compatWrapper(), - ), + import('./components/ApiDefinitionCard').then(m => ( + + )), }, }); @@ -135,9 +127,7 @@ const apiDocsConsumedApisEntityCard = EntityCardBlueprint.make({ // See: https://github.com/backstage/backstage/pull/22619#discussion_r1477333252 filter: 'kind:component', loader: () => - import('./components/ApisCards').then(m => - compatWrapper(), - ), + import('./components/ApisCards').then(m => ), }, }); @@ -149,9 +139,7 @@ const apiDocsProvidedApisEntityCard = EntityCardBlueprint.make({ // See: https://github.com/backstage/backstage/pull/22619#discussion_r1477333252 filter: 'kind:component', loader: () => - import('./components/ApisCards').then(m => - compatWrapper(), - ), + import('./components/ApisCards').then(m => ), }, }); @@ -163,9 +151,9 @@ const apiDocsConsumingComponentsEntityCard = EntityCardBlueprint.make({ // See: https://github.com/backstage/backstage/pull/22619#discussion_r1477333252 filter: 'kind:api', loader: () => - import('./components/ComponentsCards').then(m => - compatWrapper(), - ), + import('./components/ComponentsCards').then(m => ( + + )), }, }); @@ -177,9 +165,9 @@ const apiDocsProvidingComponentsEntityCard = EntityCardBlueprint.make({ // See: https://github.com/backstage/backstage/pull/22619#discussion_r1477333252 filter: 'kind:api', loader: () => - import('./components/ComponentsCards').then(m => - compatWrapper(), - ), + import('./components/ComponentsCards').then(m => ( + + )), }, }); @@ -190,15 +178,13 @@ const apiDocsDefinitionEntityContent = EntityContentBlueprint.make({ title: 'Definition', filter: 'kind:api', loader: async () => - import('./components/ApiDefinitionCard').then(m => - compatWrapper( - - - - - , - ), - ), + import('./components/ApiDefinitionCard').then(m => ( + + + + + + )), }, }); @@ -209,18 +195,16 @@ const apiDocsApisEntityContent = EntityContentBlueprint.make({ title: 'APIs', filter: 'kind:component', loader: async () => - import('./components/ApisCards').then(m => - compatWrapper( - - - - - - - - , - ), - ), + import('./components/ApisCards').then(m => ( + + + + + + + + + )), }, }); diff --git a/plugins/catalog-graph/src/alpha.tsx b/plugins/catalog-graph/src/alpha.tsx index 9a7f15e553..bd9726513b 100644 --- a/plugins/catalog-graph/src/alpha.tsx +++ b/plugins/catalog-graph/src/alpha.tsx @@ -19,10 +19,7 @@ import { createFrontendPlugin, PageBlueprint, } from '@backstage/frontend-plugin-api'; -import { - compatWrapper, - convertLegacyRouteRef, -} from '@backstage/core-compat-api'; +import { convertLegacyRouteRef } from '@backstage/core-compat-api'; import { EntityCardBlueprint } from '@backstage/plugin-catalog-react/alpha'; import { catalogGraphRouteRef, catalogEntityRouteRef } from './routes'; import { @@ -53,9 +50,9 @@ const CatalogGraphEntityCard = EntityCardBlueprint.makeWithOverrides({ factory(originalFactory, { config }) { return originalFactory({ loader: async () => - import('./components/CatalogGraphCard').then(m => - compatWrapper(), - ), + import('./components/CatalogGraphCard').then(m => ( + + )), }); }, }); @@ -83,9 +80,9 @@ const CatalogGraphPage = PageBlueprint.makeWithOverrides({ path: '/catalog-graph', routeRef: convertLegacyRouteRef(catalogGraphRouteRef), loader: () => - import('./components/CatalogGraphPage').then(m => - compatWrapper(), - ), + import('./components/CatalogGraphPage').then(m => ( + + )), }); }, }); diff --git a/plugins/catalog-import/src/alpha.tsx b/plugins/catalog-import/src/alpha.tsx index 2d9e5deaba..42caa06f42 100644 --- a/plugins/catalog-import/src/alpha.tsx +++ b/plugins/catalog-import/src/alpha.tsx @@ -19,10 +19,7 @@ import { discoveryApiRef, fetchApiRef, } from '@backstage/core-plugin-api'; -import { - compatWrapper, - convertLegacyRouteRef, -} from '@backstage/core-compat-api'; +import { convertLegacyRouteRef } from '@backstage/core-compat-api'; import { createFrontendPlugin, PageBlueprint, @@ -47,13 +44,11 @@ const catalogImportPage = PageBlueprint.make({ path: '/catalog-import', routeRef: convertLegacyRouteRef(rootRouteRef), loader: () => - import('./components/ImportPage').then(m => - compatWrapper( - - - , - ), - ), + import('./components/ImportPage').then(m => ( + + + + )), }, }); diff --git a/plugins/catalog-unprocessed-entities/src/alpha/plugin.tsx b/plugins/catalog-unprocessed-entities/src/alpha/plugin.tsx index 39a51184d3..2b39f941fa 100644 --- a/plugins/catalog-unprocessed-entities/src/alpha/plugin.tsx +++ b/plugins/catalog-unprocessed-entities/src/alpha/plugin.tsx @@ -27,10 +27,7 @@ import { catalogUnprocessedEntitiesApiRef, CatalogUnprocessedEntitiesClient, } from '../api'; -import { - compatWrapper, - convertLegacyRouteRef, -} from '@backstage/core-compat-api'; +import { convertLegacyRouteRef } from '@backstage/core-compat-api'; import QueueIcon from '@material-ui/icons/Queue'; import { rootRouteRef } from '../routes'; @@ -54,9 +51,9 @@ export const catalogUnprocessedEntitiesPage = PageBlueprint.make({ path: '/catalog-unprocessed-entities', routeRef: convertLegacyRouteRef(rootRouteRef), loader: () => - import('../components/UnprocessedEntities').then(m => - compatWrapper(), - ), + import('../components/UnprocessedEntities').then(m => ( + + )), }, }); diff --git a/plugins/catalog/src/alpha/contextMenuItems.tsx b/plugins/catalog/src/alpha/contextMenuItems.tsx index 4173a4d074..4b37321c6f 100644 --- a/plugins/catalog/src/alpha/contextMenuItems.tsx +++ b/plugins/catalog/src/alpha/contextMenuItems.tsx @@ -37,7 +37,6 @@ import { import { rootRouteRef, unregisterRedirectRouteRef } from '../routes'; import { catalogEntityDeletePermission } from '@backstage/plugin-catalog-common/alpha'; import { useEffect } from 'react'; -import { compatWrapper } from '@backstage/core-compat-api'; export const copyEntityUrlContextMenuItem = EntityContextMenuItemBlueprint.make( { @@ -111,23 +110,21 @@ export const unregisterEntityContextMenuItem = title: t('entityContextMenu.unregisterMenuTitle'), disabled: !unregisterPermission.allowed, onClick: async () => { - dialogApi.showModal(({ dialog }: { dialog: DialogApiDialog }) => - compatWrapper( - dialog.close()} - onConfirm={() => { - dialog.close(); - navigate( - unregisterRedirectRoute - ? unregisterRedirectRoute() - : catalogRoute(), - ); - }} - />, - ), - ); + dialogApi.showModal(({ dialog }: { dialog: DialogApiDialog }) => ( + dialog.close()} + onConfirm={() => { + dialog.close(); + navigate( + unregisterRedirectRoute + ? unregisterRedirectRoute() + : catalogRoute(), + ); + }} + /> + )); }, }; }, diff --git a/plugins/catalog/src/alpha/entityCards.tsx b/plugins/catalog/src/alpha/entityCards.tsx index f99c5961a1..6df50a5123 100644 --- a/plugins/catalog/src/alpha/entityCards.tsx +++ b/plugins/catalog/src/alpha/entityCards.tsx @@ -18,7 +18,6 @@ import { EntityIconLinkBlueprint, EntityCardBlueprint, } from '@backstage/plugin-catalog-react/alpha'; -import { compatWrapper } from '@backstage/core-compat-api'; import { createExtensionInput } from '@backstage/frontend-plugin-api'; import { HeaderIconLinkRow, @@ -65,8 +64,8 @@ export const catalogAboutEntityCard = EntityCardBlueprint.makeWithOverrides({ const { InternalAboutCard } = await import( '../components/AboutCard/AboutCard' ); - return compatWrapper( - } />, + return ( + } /> ); }, }); @@ -79,9 +78,9 @@ export const catalogLinksEntityCard = EntityCardBlueprint.make({ type: 'info', filter: { 'metadata.links': { $exists: true } }, loader: async () => - import('../components/EntityLinksCard').then(m => - compatWrapper(), - ), + import('../components/EntityLinksCard').then(m => ( + + )), }, }); @@ -91,9 +90,9 @@ export const catalogLabelsEntityCard = EntityCardBlueprint.make({ type: 'info', filter: { 'metadata.labels': { $exists: true } }, loader: async () => - import('../components/EntityLabelsCard').then(m => - compatWrapper(), - ), + import('../components/EntityLabelsCard').then(m => ( + + )), }, }); @@ -102,9 +101,9 @@ export const catalogDependsOnComponentsEntityCard = EntityCardBlueprint.make({ params: { filter: { kind: 'component' }, loader: async () => - import('../components/DependsOnComponentsCard').then(m => - compatWrapper(), - ), + import('../components/DependsOnComponentsCard').then(m => ( + + )), }, }); @@ -113,9 +112,9 @@ export const catalogDependsOnResourcesEntityCard = EntityCardBlueprint.make({ params: { filter: { kind: 'component' }, loader: async () => - import('../components/DependsOnResourcesCard').then(m => - compatWrapper(), - ), + import('../components/DependsOnResourcesCard').then(m => ( + + )), }, }); @@ -124,9 +123,9 @@ export const catalogHasComponentsEntityCard = EntityCardBlueprint.make({ params: { filter: { kind: 'system' }, loader: async () => - import('../components/HasComponentsCard').then(m => - compatWrapper(), - ), + import('../components/HasComponentsCard').then(m => ( + + )), }, }); @@ -135,9 +134,9 @@ export const catalogHasResourcesEntityCard = EntityCardBlueprint.make({ params: { filter: { kind: 'system' }, loader: async () => - import('../components/HasResourcesCard').then(m => - compatWrapper(), - ), + import('../components/HasResourcesCard').then(m => ( + + )), }, }); @@ -146,9 +145,9 @@ export const catalogHasSubcomponentsEntityCard = EntityCardBlueprint.make({ params: { filter: { kind: 'component' }, loader: async () => - import('../components/HasSubcomponentsCard').then(m => - compatWrapper(), - ), + import('../components/HasSubcomponentsCard').then(m => ( + + )), }, }); @@ -157,9 +156,9 @@ export const catalogHasSubdomainsEntityCard = EntityCardBlueprint.make({ params: { filter: { kind: 'domain' }, loader: async () => - import('../components/HasSubdomainsCard').then(m => - compatWrapper(), - ), + import('../components/HasSubdomainsCard').then(m => ( + + )), }, }); @@ -168,9 +167,9 @@ export const catalogHasSystemsEntityCard = EntityCardBlueprint.make({ params: { filter: { kind: 'domain' }, loader: async () => - import('../components/HasSystemsCard').then(m => - compatWrapper(), - ), + import('../components/HasSystemsCard').then(m => ( + + )), }, }); diff --git a/plugins/catalog/src/alpha/pages.tsx b/plugins/catalog/src/alpha/pages.tsx index 9d4e3b4bac..616e6f3a29 100644 --- a/plugins/catalog/src/alpha/pages.tsx +++ b/plugins/catalog/src/alpha/pages.tsx @@ -14,10 +14,7 @@ * limitations under the License. */ -import { - compatWrapper, - convertLegacyRouteRef, -} from '@backstage/core-compat-api'; +import { convertLegacyRouteRef } from '@backstage/core-compat-api'; import { coreExtensionData, createExtensionInput, @@ -65,11 +62,11 @@ export const catalogPage = PageBlueprint.makeWithOverrides({ const filters = inputs.filters.map(filter => filter.get(coreExtensionData.reactElement), ); - return compatWrapper( + return ( {filters}} pagination={config.pagination} - />, + /> ); }, }); @@ -220,7 +217,7 @@ export const catalogEntityPage = PageBlueprint.makeWithOverrides({ ); }; - return compatWrapper(); + return ; }, }); }, diff --git a/plugins/devtools/src/alpha/plugin.tsx b/plugins/devtools/src/alpha/plugin.tsx index 0f6d9ec4a1..a331a53243 100644 --- a/plugins/devtools/src/alpha/plugin.tsx +++ b/plugins/devtools/src/alpha/plugin.tsx @@ -24,10 +24,7 @@ import { } from '@backstage/frontend-plugin-api'; import { devToolsApiRef, DevToolsClient } from '../api'; -import { - compatWrapper, - convertLegacyRouteRef, -} from '@backstage/core-compat-api'; +import { convertLegacyRouteRef } from '@backstage/core-compat-api'; import BuildIcon from '@material-ui/icons/Build'; import { rootRouteRef } from '../routes'; @@ -51,9 +48,7 @@ export const devToolsPage = PageBlueprint.make({ path: '/devtools', routeRef: convertLegacyRouteRef(rootRouteRef), loader: () => - import('../components/DevToolsPage').then(m => - compatWrapper(), - ), + import('../components/DevToolsPage').then(m => ), }, }); diff --git a/plugins/home/package.json b/plugins/home/package.json index 4bc9361884..e15b2f5866 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -60,7 +60,6 @@ "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", "@backstage/core-app-api": "workspace:^", - "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/frontend-plugin-api": "workspace:^", diff --git a/plugins/home/src/alpha.tsx b/plugins/home/src/alpha.tsx index a92316c7f0..6cad71d643 100644 --- a/plugins/home/src/alpha.tsx +++ b/plugins/home/src/alpha.tsx @@ -26,7 +26,6 @@ import { storageApiRef, ApiBlueprint, } from '@backstage/frontend-plugin-api'; -import { compatWrapper } from '@backstage/core-compat-api'; import { VisitListener } from './components/'; import { visitsApiRef, VisitsStorageApi } from './api'; @@ -57,14 +56,12 @@ const homePage = PageBlueprint.makeWithOverrides({ path: '/home', routeRef: rootRouteRef, loader: () => - import('./components/').then(m => - compatWrapper( - , - ), - ), + import('./components/').then(m => ( + + )), }); }, }); diff --git a/plugins/kubernetes/src/alpha/entityContents.tsx b/plugins/kubernetes/src/alpha/entityContents.tsx index d75893c6e4..0a85cadaed 100644 --- a/plugins/kubernetes/src/alpha/entityContents.tsx +++ b/plugins/kubernetes/src/alpha/entityContents.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { compatWrapper } from '@backstage/core-compat-api'; import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha'; import { isKubernetesAvailable } from '../Router'; @@ -26,8 +25,6 @@ export const entityKubernetesContent = EntityContentBlueprint.make({ group: 'deployment', filter: isKubernetesAvailable, loader: () => - import('./KubernetesContentPage').then(m => - compatWrapper(), - ), + import('./KubernetesContentPage').then(m => ), }, }); diff --git a/plugins/kubernetes/src/alpha/pages.tsx b/plugins/kubernetes/src/alpha/pages.tsx index 6a2d98ddcc..23e78f9264 100644 --- a/plugins/kubernetes/src/alpha/pages.tsx +++ b/plugins/kubernetes/src/alpha/pages.tsx @@ -14,11 +14,8 @@ * limitations under the License. */ -import { PageBlueprint } from '@backstage/frontend-plugin-api'; // Add this line to import React -import { - compatWrapper, - convertLegacyRouteRef, -} from '@backstage/core-compat-api'; +import { PageBlueprint } from '@backstage/frontend-plugin-api'; +import { convertLegacyRouteRef } from '@backstage/core-compat-api'; import { rootCatalogKubernetesRouteRef } from '../plugin'; export const kubernetesPage = PageBlueprint.make({ @@ -28,6 +25,6 @@ export const kubernetesPage = PageBlueprint.make({ // by wrapping into the convertLegacyRouteRef. routeRef: convertLegacyRouteRef(rootCatalogKubernetesRouteRef), // these inputs usually match the props required by the component. - loader: () => import('../Router').then(m => compatWrapper()), + loader: () => import('../Router').then(m => ), }, }); diff --git a/plugins/notifications/src/alpha.tsx b/plugins/notifications/src/alpha.tsx index ca4be58209..6d32150c35 100644 --- a/plugins/notifications/src/alpha.tsx +++ b/plugins/notifications/src/alpha.tsx @@ -23,7 +23,6 @@ import { } from '@backstage/frontend-plugin-api'; import { rootRouteRef } from './routes'; import { - compatWrapper, convertLegacyRouteRef, convertLegacyRouteRefs, } from '@backstage/core-compat-api'; @@ -34,9 +33,9 @@ const page = PageBlueprint.make({ path: '/notifications', routeRef: convertLegacyRouteRef(rootRouteRef), loader: () => - import('./components/NotificationsPage').then(m => - compatWrapper(), - ), + import('./components/NotificationsPage').then(m => ( + + )), }, }); diff --git a/plugins/org/src/alpha.tsx b/plugins/org/src/alpha.tsx index ddb8094688..6e158436c3 100644 --- a/plugins/org/src/alpha.tsx +++ b/plugins/org/src/alpha.tsx @@ -14,10 +14,7 @@ * limitations under the License. */ -import { - compatWrapper, - convertLegacyRouteRefs, -} from '@backstage/core-compat-api'; +import { convertLegacyRouteRefs } from '@backstage/core-compat-api'; import { createFrontendPlugin } from '@backstage/frontend-plugin-api'; import { catalogIndexRouteRef } from './routes'; import { EntityCardBlueprint } from '@backstage/plugin-catalog-react/alpha'; @@ -29,8 +26,8 @@ const EntityGroupProfileCard = EntityCardBlueprint.make({ type: 'info', filter: { kind: 'group' }, loader: async () => - import('./components/Cards/Group/GroupProfile/GroupProfileCard').then(m => - compatWrapper(), + import('./components/Cards/Group/GroupProfile/GroupProfileCard').then( + m => , ), }, }); @@ -49,12 +46,12 @@ const EntityMembersListCard = EntityCardBlueprint.makeWithOverrides({ return originalFactory({ filter: { kind: 'group' }, loader: async () => - import('./components/Cards/Group/MembersList/MembersListCard').then(m => - compatWrapper( + import('./components/Cards/Group/MembersList/MembersListCard').then( + m => ( , + /> ), ), }); @@ -75,19 +72,16 @@ const EntityOwnershipCard = EntityCardBlueprint.makeWithOverrides({ return originalFactory({ filter: { kind: { $in: ['group', 'user'] } }, loader: async () => - import('./components/Cards/OwnershipCard/OwnershipCard').then(m => - compatWrapper( - , - ), - ), + import('./components/Cards/OwnershipCard/OwnershipCard').then(m => ( + + )), }); }, }); @@ -107,13 +101,12 @@ const EntityUserProfileCard = EntityCardBlueprint.makeWithOverrides({ filter: { kind: 'user' }, loader: async () => import('./components/Cards/User/UserProfileCard/UserProfileCard').then( - m => - compatWrapper( - , - ), + m => ( + + ), ), }); }, diff --git a/plugins/scaffolder/src/alpha/extensions.tsx b/plugins/scaffolder/src/alpha/extensions.tsx index cb69e691b8..30054ece6e 100644 --- a/plugins/scaffolder/src/alpha/extensions.tsx +++ b/plugins/scaffolder/src/alpha/extensions.tsx @@ -14,10 +14,7 @@ * limitations under the License. */ -import { - compatWrapper, - convertLegacyRouteRef, -} from '@backstage/core-compat-api'; +import { convertLegacyRouteRef } from '@backstage/core-compat-api'; import { ApiBlueprint, createExtensionInput, @@ -48,11 +45,9 @@ export const scaffolderPage = PageBlueprint.makeWithOverrides({ routeRef: convertLegacyRouteRef(rootRouteRef), path: '/create', loader: () => - import('../components/Router/Router').then(m => - compatWrapper( - , - ), - ), + import('../components/Router/Router').then(m => ( + + )), }); }, }); diff --git a/plugins/search/src/alpha.tsx b/plugins/search/src/alpha.tsx index 97bd7dfe87..eb98f70ee0 100644 --- a/plugins/search/src/alpha.tsx +++ b/plugins/search/src/alpha.tsx @@ -69,7 +69,6 @@ import { SearchClient } from './apis'; import { SearchType } from './components/SearchType'; import { UrlUpdater } from './components/SearchPage/SearchPage'; import { - compatWrapper, convertLegacyRouteRef, convertLegacyRouteRefs, } from '@backstage/core-compat-api'; @@ -254,11 +253,11 @@ export const searchPage = PageBlueprint.makeWithOverrides({ ); }; - return compatWrapper( + return ( - , + ); }, }); diff --git a/plugins/techdocs/src/alpha/index.tsx b/plugins/techdocs/src/alpha/index.tsx index 96454600d9..ebc84a1837 100644 --- a/plugins/techdocs/src/alpha/index.tsx +++ b/plugins/techdocs/src/alpha/index.tsx @@ -30,7 +30,6 @@ import { fetchApiRef, } from '@backstage/core-plugin-api'; import { - compatWrapper, convertLegacyRouteRef, convertLegacyRouteRefs, } from '@backstage/core-compat-api'; @@ -123,10 +122,9 @@ export const techDocsSearchResultListItemExtension = const { TechDocsSearchResultListItem } = await import( '../search/components/TechDocsSearchResultListItem' ); - return props => - compatWrapper( - , - ); + return props => ( + + ); }, }); }, @@ -142,9 +140,9 @@ const techDocsPage = PageBlueprint.make({ path: '/docs', routeRef: convertLegacyRouteRef(rootRouteRef), loader: () => - import('../home/components/TechDocsIndexPage').then(m => - compatWrapper(), - ), + import('../home/components/TechDocsIndexPage').then(m => ( + + )), }, }); @@ -170,14 +168,12 @@ const techDocsReaderPage = PageBlueprint.makeWithOverrides({ path: '/docs/:namespace/:kind/:name', routeRef: convertLegacyRouteRef(rootDocsRouteRef), loader: async () => - await import('../Router').then(({ TechDocsReaderRouter }) => { - return compatWrapper( - - - {addons} - , - ); - }), + await import('../Router').then(({ TechDocsReaderRouter }) => ( + + + {addons} + + )), }); }, }); @@ -212,14 +208,14 @@ const techDocsEntityContent = EntityContentBlueprint.makeWithOverrides({ attachTechDocsAddonComponentData(Addon, options); return ; }); - return compatWrapper( + return ( {addons} - , + ); }), }, diff --git a/plugins/user-settings/src/alpha.tsx b/plugins/user-settings/src/alpha.tsx index e71c61febc..bd0d9a1a82 100644 --- a/plugins/user-settings/src/alpha.tsx +++ b/plugins/user-settings/src/alpha.tsx @@ -23,7 +23,6 @@ import { import { convertLegacyRouteRef, convertLegacyRouteRefs, - compatWrapper, } from '@backstage/core-compat-api'; import SettingsIcon from '@material-ui/icons/Settings'; import { settingsRouteRef } from './plugin'; @@ -42,15 +41,13 @@ const userSettingsPage = PageBlueprint.makeWithOverrides({ path: '/settings', routeRef: convertLegacyRouteRef(settingsRouteRef), loader: () => - import('./components/SettingsPage').then(m => - compatWrapper( - , - ), - ), + import('./components/SettingsPage').then(m => ( + + )), }); }, }); From e5a1b33b0bdbac6f17bd5d59840827d93a53f49a Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 23 Nov 2025 13:04:53 +0100 Subject: [PATCH 3/8] docs/frontend-system: remove use of compatWrapper Signed-off-by: Patrik Oldsberg --- .../building-apps/08-migrating.md | 52 ++++++++----------- .../building-plugins/05-migrating.md | 8 +-- 2 files changed, 24 insertions(+), 36 deletions(-) diff --git a/docs/frontend-system/building-apps/08-migrating.md b/docs/frontend-system/building-apps/08-migrating.md index 2b248b12a7..1fd74becfc 100644 --- a/docs/frontend-system/building-apps/08-migrating.md +++ b/docs/frontend-system/building-apps/08-migrating.md @@ -676,8 +676,6 @@ createApp({ AppRootWrapperBlueprint.make({ name: 'custom-app-barrier', params: { - // Whenever your component uses legacy core packages, wrap it with "compatWrapper" - // e.g. props => compatWrapper() Component: CustomAppBarrier, }, }), @@ -700,41 +698,37 @@ import { SidebarContent } from './Sidebar'; export const navModule = createFrontendModule({ pluginId: 'app', - extensions: [SidebarContent], + extensions: [sidebarContent], }); ``` -Then in the actual implementation for the `SidebarContent` extension, you can provide something like the following, where the component that is passed to the `compatWrapper` is the entire `Sidebar` component from your `Root` component. - -The `compatWrapper` is there to ensure that any legacy plugins using things like `useRouteRef` work well in the new system, so if you run into some errors which look like compatibility issues, make sure that this wrapper is used in the relevant places. +Then in the actual implementation for the `sidebarContent` extension, you can provide something like the following, where you implement the entire `Sidebar` component. ```tsx title="in packages/app/src/modules/nav/Sidebar.tsx" -import { compatWrapper } from '@backstage/core-compat-api'; import { NavContentBlueprint } from '@backstage/frontend-plugin-api'; -export const SidebarContent = NavContentBlueprint.make({ +export const sidebarContent = NavContentBlueprint.make({ params: { - component: ({ items }) => - compatWrapper( - - - } to="/search"> - - - - }> - ... - - - - {/* Items in this group will be scrollable if they run out of space */} - {items.map((item, index) => ( - - ))} - - - , - ), + component: ({ items }) => ( + + + } to="/search"> + + + + }> + ... + + + + {/* Items in this group will be scrollable if they run out of space */} + {items.map((item, index) => ( + + ))} + + + + ), }, }); ``` diff --git a/docs/frontend-system/building-plugins/05-migrating.md b/docs/frontend-system/building-plugins/05-migrating.md index 4940e0526b..b0e9816a17 100644 --- a/docs/frontend-system/building-plugins/05-migrating.md +++ b/docs/frontend-system/building-plugins/05-migrating.md @@ -106,7 +106,6 @@ it can be migrated as the following, keeping in mind that you may need to switch ```tsx import { PageBlueprint } from '@backstage/frontend-plugin-api'; -import { compatWrapper } from '@backstage/core-compat-api'; const fooPage = PageBlueprint.make({ params: { @@ -116,12 +115,7 @@ const fooPage = PageBlueprint.make({ // You can reuse the existing routeRef. routeRef: rootRouteRef, // these inputs usually match the props required by the component. - loader: () => - import('./components/').then(m => - // The compatWrapper utility allows you to keep using @backstage/core-plugin-api in the - // implementation of the component and switch to @backstage/frontend-plugin-api later. - compatWrapper(), - ), + loader: () => import('./components/').then(m => ), }, }); ``` From f28c68a13d6de3146c055c121236bd752450923f Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 23 Nov 2025 13:06:13 +0100 Subject: [PATCH 4/8] app-next: remove compatWrapper Signed-off-by: Patrik Oldsberg --- .../app-next/src/modules/appModuleNav.tsx | 59 +++++++++---------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/packages/app-next/src/modules/appModuleNav.tsx b/packages/app-next/src/modules/appModuleNav.tsx index aa7d92bd1b..ff89b2d1de 100644 --- a/packages/app-next/src/modules/appModuleNav.tsx +++ b/packages/app-next/src/modules/appModuleNav.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { compatWrapper } from '@backstage/core-compat-api'; import { Link, Sidebar, @@ -106,36 +105,34 @@ export const appModuleNav = createFrontendModule({ extensions: [ NavContentBlueprint.make({ params: { - component: ({ items }) => { - return compatWrapper( - - - } to="/search"> - - - - }> - - {items.map((item, index) => ( - - ))} - - - - - - } - to="/settings" - > - - - - - , - ); - }, + component: ({ items }) => ( + + + } to="/search"> + + + + }> + + {items.map((item, index) => ( + + ))} + + + + + + } + to="/settings" + > + + + + + + ), }, }), ], From c8fc1429b47b945ec691454cb1d0d37ca349afaf Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 23 Nov 2025 13:24:42 +0100 Subject: [PATCH 5/8] yarn.lock: sync Signed-off-by: Patrik Oldsberg --- yarn.lock | 1 - 1 file changed, 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index b9106a487d..c218f0d58b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5742,7 +5742,6 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/core-app-api": "workspace:^" - "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" From 1c7ea4a3e800eb9608f77a4f8d67aa4eada8518a Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 23 Nov 2025 14:17:58 +0100 Subject: [PATCH 6/8] plugins: remove unnecessary use of convertLegacyRouteRef(s) Signed-off-by: Patrik Oldsberg --- .changeset/metal-humans-lose.md | 2 +- plugins/api-docs/report-alpha.api.md | 23 +++++---- plugins/api-docs/src/alpha.tsx | 10 ++-- plugins/catalog-graph/report-alpha.api.md | 22 ++++---- plugins/catalog-graph/src/alpha.tsx | 7 ++- plugins/catalog-import/report-alpha.api.md | 7 +-- plugins/catalog-import/src/alpha.tsx | 5 +- .../report-alpha.api.md | 11 ++-- .../src/alpha/plugin.tsx | 7 ++- plugins/catalog/report-alpha.api.md | 51 +++++++++++-------- plugins/catalog/src/alpha/navItems.tsx | 3 +- plugins/catalog/src/alpha/pages.tsx | 2 +- plugins/catalog/src/alpha/plugin.tsx | 9 ++-- plugins/devtools/report-alpha.api.md | 11 ++-- plugins/devtools/src/alpha/plugin.tsx | 7 ++- plugins/kubernetes/report-alpha.api.md | 11 ++-- plugins/kubernetes/src/alpha/pages.tsx | 6 +-- plugins/kubernetes/src/alpha/plugin.tsx | 3 +- plugins/mui-to-bui/report.api.md | 10 ++-- plugins/mui-to-bui/src/plugin.tsx | 10 ++-- plugins/notifications/report-alpha.api.md | 7 +-- plugins/notifications/src/alpha.tsx | 10 ++-- plugins/org/report-alpha.api.md | 4 +- plugins/org/src/alpha.tsx | 5 +- plugins/scaffolder/report-alpha.api.md | 30 ++++++----- plugins/scaffolder/src/alpha/extensions.tsx | 5 +- plugins/scaffolder/src/alpha/plugin.tsx | 9 ++-- plugins/search/report-alpha.api.md | 3 +- plugins/search/src/alpha.tsx | 12 ++--- plugins/techdocs/report-alpha.api.md | 19 +++---- plugins/techdocs/src/alpha/index.tsx | 16 +++--- plugins/user-settings/report-alpha.api.md | 3 +- plugins/user-settings/src/alpha.tsx | 12 ++--- 33 files changed, 170 insertions(+), 182 deletions(-) diff --git a/.changeset/metal-humans-lose.md b/.changeset/metal-humans-lose.md index 490ae28ab2..f96d33a779 100644 --- a/.changeset/metal-humans-lose.md +++ b/.changeset/metal-humans-lose.md @@ -18,4 +18,4 @@ '@backstage/plugin-org': patch --- -Remove unnecessary use of `compatWrapper` for the new frontend system. +Remove unnecessary use of `compatWrapper` and `convertLegacyRouteRef`(s) for the new frontend system. diff --git a/plugins/api-docs/report-alpha.api.md b/plugins/api-docs/report-alpha.api.md index e969afd777..3e8b0153d8 100644 --- a/plugins/api-docs/report-alpha.api.md +++ b/plugins/api-docs/report-alpha.api.md @@ -13,12 +13,13 @@ import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha'; import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDataRef } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; -import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; +import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { IconComponent } from '@backstage/frontend-plugin-api'; import { JSX as JSX_2 } from 'react'; import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api'; import { OverridableFrontendPlugin } from '@backstage/frontend-plugin-api'; -import { RouteRef } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/core-plugin-api'; +import { RouteRef as RouteRef_2 } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) @@ -63,7 +64,7 @@ const _default: OverridableFrontendPlugin< root: RouteRef; }, { - registerApi: ExternalRouteRef; + registerApi: ExternalRouteRef; }, { 'api:api-docs/config': OverridableExtensionDefinition<{ @@ -346,7 +347,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -383,7 +384,7 @@ const _default: OverridableFrontendPlugin< defaultGroup?: [Error: `Use the 'group' param instead`]; group?: keyof defaultEntityContentGroups | (string & {}); loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; filter?: string | EntityPredicate | ((entity: Entity) => boolean); }; }>; @@ -406,7 +407,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -443,7 +444,7 @@ const _default: OverridableFrontendPlugin< defaultGroup?: [Error: `Use the 'group' param instead`]; group?: keyof defaultEntityContentGroups | (string & {}); loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; filter?: string | EntityPredicate | ((entity: Entity) => boolean); }; }>; @@ -456,7 +457,7 @@ const _default: OverridableFrontendPlugin< { title: string; icon: IconComponent; - routeRef: RouteRef; + routeRef: RouteRef_2; }, 'core.nav-item.target', {} @@ -465,7 +466,7 @@ const _default: OverridableFrontendPlugin< params: { title: string; icon: IconComponent; - routeRef: RouteRef; + routeRef: RouteRef_2; }; }>; 'page:api-docs': OverridableExtensionDefinition<{ @@ -483,7 +484,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -504,7 +505,7 @@ const _default: OverridableFrontendPlugin< defaultPath?: [Error: `Use the 'path' param instead`]; path: string; loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; }; }>; } diff --git a/plugins/api-docs/src/alpha.tsx b/plugins/api-docs/src/alpha.tsx index 87dccdf713..73b1c008ab 100644 --- a/plugins/api-docs/src/alpha.tsx +++ b/plugins/api-docs/src/alpha.tsx @@ -23,8 +23,6 @@ import { createFrontendPlugin, } from '@backstage/frontend-plugin-api'; -import { convertLegacyRouteRef } from '@backstage/core-compat-api'; - import { ApiEntity, parseEntityRef, @@ -44,7 +42,7 @@ import { const apiDocsNavItem = NavItemBlueprint.make({ params: { title: 'APIs', - routeRef: convertLegacyRouteRef(rootRoute), + routeRef: rootRoute, icon: () => , }, }); @@ -77,7 +75,7 @@ const apiDocsExplorerPage = PageBlueprint.makeWithOverrides({ factory(originalFactory, { config }) { return originalFactory({ path: '/api-docs', - routeRef: convertLegacyRouteRef(rootRoute), + routeRef: rootRoute, loader: () => import('./components/ApiExplorerPage').then(m => ( import('../package.json') }, routes: { - root: convertLegacyRouteRef(rootRoute), + root: rootRoute, }, externalRoutes: { - registerApi: convertLegacyRouteRef(registerComponentRouteRef), + registerApi: registerComponentRouteRef, }, extensions: [ apiDocsNavItem, diff --git a/plugins/catalog-graph/report-alpha.api.md b/plugins/catalog-graph/report-alpha.api.md index 285b8b3119..2f5c713ee8 100644 --- a/plugins/catalog-graph/report-alpha.api.md +++ b/plugins/catalog-graph/report-alpha.api.md @@ -12,11 +12,12 @@ import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha'; import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDataRef } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; -import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; +import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { JSX as JSX_2 } from 'react'; import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api'; import { OverridableFrontendPlugin } from '@backstage/frontend-plugin-api'; -import { RouteRef } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/core-plugin-api'; +import { RouteRef as RouteRef_2 } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) @@ -53,11 +54,14 @@ const _default: OverridableFrontendPlugin< catalogGraph: RouteRef; }, { - catalogEntity: ExternalRouteRef<{ - name: string; - kind: string; - namespace: string; - }>; + catalogEntity: ExternalRouteRef< + { + name: string; + kind: string; + namespace: string; + }, + true + >; }, { 'api:catalog-graph': OverridableExtensionDefinition<{ @@ -187,7 +191,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -208,7 +212,7 @@ const _default: OverridableFrontendPlugin< defaultPath?: [Error: `Use the 'path' param instead`]; path: string; loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; }; }>; } diff --git a/plugins/catalog-graph/src/alpha.tsx b/plugins/catalog-graph/src/alpha.tsx index bd9726513b..a2a8c7eb5e 100644 --- a/plugins/catalog-graph/src/alpha.tsx +++ b/plugins/catalog-graph/src/alpha.tsx @@ -19,7 +19,6 @@ import { createFrontendPlugin, PageBlueprint, } from '@backstage/frontend-plugin-api'; -import { convertLegacyRouteRef } from '@backstage/core-compat-api'; import { EntityCardBlueprint } from '@backstage/plugin-catalog-react/alpha'; import { catalogGraphRouteRef, catalogEntityRouteRef } from './routes'; import { @@ -78,7 +77,7 @@ const CatalogGraphPage = PageBlueprint.makeWithOverrides({ factory(originalFactory, { config }) { return originalFactory({ path: '/catalog-graph', - routeRef: convertLegacyRouteRef(catalogGraphRouteRef), + routeRef: catalogGraphRouteRef, loader: () => import('./components/CatalogGraphPage').then(m => ( @@ -100,10 +99,10 @@ export default createFrontendPlugin({ pluginId: 'catalog-graph', info: { packageJson: () => import('../package.json') }, routes: { - catalogGraph: convertLegacyRouteRef(catalogGraphRouteRef), + catalogGraph: catalogGraphRouteRef, }, externalRoutes: { - catalogEntity: convertLegacyRouteRef(catalogEntityRouteRef), + catalogEntity: catalogEntityRouteRef, }, extensions: [CatalogGraphPage, CatalogGraphEntityCard, CatalogGraphApi], }); diff --git a/plugins/catalog-import/report-alpha.api.md b/plugins/catalog-import/report-alpha.api.md index 5dfa90388a..a718145b24 100644 --- a/plugins/catalog-import/report-alpha.api.md +++ b/plugins/catalog-import/report-alpha.api.md @@ -11,7 +11,8 @@ import { ExtensionDataRef } from '@backstage/frontend-plugin-api'; import { JSX as JSX_2 } from 'react'; import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api'; import { OverridableFrontendPlugin } from '@backstage/frontend-plugin-api'; -import { RouteRef } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/core-plugin-api'; +import { RouteRef as RouteRef_2 } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; // @alpha (undocumented) @@ -122,7 +123,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -133,7 +134,7 @@ const _default: OverridableFrontendPlugin< defaultPath?: [Error: `Use the 'path' param instead`]; path: string; loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; }; }>; } diff --git a/plugins/catalog-import/src/alpha.tsx b/plugins/catalog-import/src/alpha.tsx index 42caa06f42..a00eb39988 100644 --- a/plugins/catalog-import/src/alpha.tsx +++ b/plugins/catalog-import/src/alpha.tsx @@ -19,7 +19,6 @@ import { discoveryApiRef, fetchApiRef, } from '@backstage/core-plugin-api'; -import { convertLegacyRouteRef } from '@backstage/core-compat-api'; import { createFrontendPlugin, PageBlueprint, @@ -42,7 +41,7 @@ export * from './translation'; const catalogImportPage = PageBlueprint.make({ params: { path: '/catalog-import', - routeRef: convertLegacyRouteRef(rootRouteRef), + routeRef: rootRouteRef, loader: () => import('./components/ImportPage').then(m => ( @@ -89,7 +88,7 @@ export default createFrontendPlugin({ info: { packageJson: () => import('../package.json') }, extensions: [catalogImportApi, catalogImportPage], routes: { - importPage: convertLegacyRouteRef(rootRouteRef), + importPage: rootRouteRef, }, }); diff --git a/plugins/catalog-unprocessed-entities/report-alpha.api.md b/plugins/catalog-unprocessed-entities/report-alpha.api.md index 96827c78f6..50bc0c22fa 100644 --- a/plugins/catalog-unprocessed-entities/report-alpha.api.md +++ b/plugins/catalog-unprocessed-entities/report-alpha.api.md @@ -12,7 +12,8 @@ import { IconComponent } from '@backstage/frontend-plugin-api'; import { JSX as JSX_2 } from 'react'; import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api'; import { OverridableFrontendPlugin } from '@backstage/frontend-plugin-api'; -import { RouteRef } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/core-plugin-api'; +import { RouteRef as RouteRef_2 } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) const _default: OverridableFrontendPlugin< @@ -45,7 +46,7 @@ const _default: OverridableFrontendPlugin< { title: string; icon: IconComponent; - routeRef: RouteRef; + routeRef: RouteRef_2; }, 'core.nav-item.target', {} @@ -54,7 +55,7 @@ const _default: OverridableFrontendPlugin< params: { title: string; icon: IconComponent; - routeRef: RouteRef; + routeRef: RouteRef_2; }; }>; 'page:catalog-unprocessed-entities': OverridableExtensionDefinition<{ @@ -70,7 +71,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -81,7 +82,7 @@ const _default: OverridableFrontendPlugin< defaultPath?: [Error: `Use the 'path' param instead`]; path: string; loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; }; }>; } diff --git a/plugins/catalog-unprocessed-entities/src/alpha/plugin.tsx b/plugins/catalog-unprocessed-entities/src/alpha/plugin.tsx index 2b39f941fa..5ccae907aa 100644 --- a/plugins/catalog-unprocessed-entities/src/alpha/plugin.tsx +++ b/plugins/catalog-unprocessed-entities/src/alpha/plugin.tsx @@ -27,7 +27,6 @@ import { catalogUnprocessedEntitiesApiRef, CatalogUnprocessedEntitiesClient, } from '../api'; -import { convertLegacyRouteRef } from '@backstage/core-compat-api'; import QueueIcon from '@material-ui/icons/Queue'; import { rootRouteRef } from '../routes'; @@ -49,7 +48,7 @@ export const catalogUnprocessedEntitiesApi = ApiBlueprint.make({ export const catalogUnprocessedEntitiesPage = PageBlueprint.make({ params: { path: '/catalog-unprocessed-entities', - routeRef: convertLegacyRouteRef(rootRouteRef), + routeRef: rootRouteRef, loader: () => import('../components/UnprocessedEntities').then(m => ( @@ -61,7 +60,7 @@ export const catalogUnprocessedEntitiesPage = PageBlueprint.make({ export const catalogUnprocessedEntitiesNavItem = NavItemBlueprint.make({ params: { title: 'Unprocessed Entities', - routeRef: convertLegacyRouteRef(rootRouteRef), + routeRef: rootRouteRef, icon: QueueIcon, }, }); @@ -71,7 +70,7 @@ export default createFrontendPlugin({ pluginId: 'catalog-unprocessed-entities', info: { packageJson: () => import('../../package.json') }, routes: { - root: convertLegacyRouteRef(rootRouteRef), + root: rootRouteRef, }, extensions: [ catalogUnprocessedEntitiesApi, diff --git a/plugins/catalog/report-alpha.api.md b/plugins/catalog/report-alpha.api.md index abf66113c7..e40444bd07 100644 --- a/plugins/catalog/report-alpha.api.md +++ b/plugins/catalog/report-alpha.api.md @@ -16,13 +16,14 @@ import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha'; import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDataRef } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; -import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; +import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { IconComponent } from '@backstage/frontend-plugin-api'; import { IconLinkVerticalProps } from '@backstage/core-components'; import { JSX as JSX_2 } from 'react'; import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api'; import { OverridableFrontendPlugin } from '@backstage/frontend-plugin-api'; -import { RouteRef } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/core-plugin-api'; +import { RouteRef as RouteRef_2 } from '@backstage/frontend-plugin-api'; import { SearchResultItemExtensionComponent } from '@backstage/plugin-search-react/alpha'; import { SearchResultItemExtensionPredicate } from '@backstage/plugin-search-react/alpha'; import { SearchResultListItemBlueprintParams } from '@backstage/plugin-search-react/alpha'; @@ -124,17 +125,23 @@ const _default: OverridableFrontendPlugin< }>; }, { - viewTechDoc: ExternalRouteRef<{ - name: string; - kind: string; - namespace: string; - }>; - createComponent: ExternalRouteRef; - createFromTemplate: ExternalRouteRef<{ - namespace: string; - templateName: string; - }>; - unregisterRedirect: ExternalRouteRef; + viewTechDoc: ExternalRouteRef< + { + name: string; + kind: string; + namespace: string; + }, + true + >; + createComponent: ExternalRouteRef; + createFromTemplate: ExternalRouteRef< + { + namespace: string; + templateName: string; + }, + true + >; + unregisterRedirect: ExternalRouteRef; }, { 'api:catalog': OverridableExtensionDefinition<{ @@ -759,7 +766,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -852,7 +859,7 @@ const _default: OverridableFrontendPlugin< defaultGroup?: [Error: `Use the 'group' param instead`]; group?: keyof defaultEntityContentGroups | (string & {}); loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; filter?: string | EntityPredicate | ((entity: Entity) => boolean); }; }>; @@ -967,7 +974,7 @@ const _default: OverridableFrontendPlugin< { title: string; icon: IconComponent; - routeRef: RouteRef; + routeRef: RouteRef_2; }, 'core.nav-item.target', {} @@ -976,7 +983,7 @@ const _default: OverridableFrontendPlugin< params: { title: string; icon: IconComponent; - routeRef: RouteRef; + routeRef: RouteRef_2; }; }>; 'page:catalog': OverridableExtensionDefinition<{ @@ -1007,7 +1014,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -1028,7 +1035,7 @@ const _default: OverridableFrontendPlugin< defaultPath?: [Error: `Use the 'path' param instead`]; path: string; loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; }; }>; 'page:catalog/entity': OverridableExtensionDefinition<{ @@ -1060,7 +1067,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -1091,7 +1098,7 @@ const _default: OverridableFrontendPlugin< | ConfigurableExtensionDataRef | ConfigurableExtensionDataRef | ConfigurableExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -1149,7 +1156,7 @@ const _default: OverridableFrontendPlugin< defaultPath?: [Error: `Use the 'path' param instead`]; path: string; loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; }; }>; 'search-result-list-item:catalog': OverridableExtensionDefinition<{ diff --git a/plugins/catalog/src/alpha/navItems.tsx b/plugins/catalog/src/alpha/navItems.tsx index 0eb4e6827e..e72c20ebf4 100644 --- a/plugins/catalog/src/alpha/navItems.tsx +++ b/plugins/catalog/src/alpha/navItems.tsx @@ -15,13 +15,12 @@ */ import HomeIcon from '@material-ui/icons/Home'; -import { convertLegacyRouteRef } from '@backstage/core-compat-api'; import { NavItemBlueprint } from '@backstage/frontend-plugin-api'; import { rootRouteRef } from '../routes'; export const catalogNavItem = NavItemBlueprint.make({ params: { - routeRef: convertLegacyRouteRef(rootRouteRef), + routeRef: rootRouteRef, title: 'Catalog', icon: HomeIcon, }, diff --git a/plugins/catalog/src/alpha/pages.tsx b/plugins/catalog/src/alpha/pages.tsx index 616e6f3a29..b9b8f9ba1f 100644 --- a/plugins/catalog/src/alpha/pages.tsx +++ b/plugins/catalog/src/alpha/pages.tsx @@ -56,7 +56,7 @@ export const catalogPage = PageBlueprint.makeWithOverrides({ factory(originalFactory, { inputs, config }) { return originalFactory({ path: '/catalog', - routeRef: convertLegacyRouteRef(rootRouteRef), + routeRef: rootRouteRef, loader: async () => { const { BaseCatalogPage } = await import('../components/CatalogPage'); const filters = inputs.filters.map(filter => diff --git a/plugins/catalog/src/alpha/plugin.tsx b/plugins/catalog/src/alpha/plugin.tsx index ff26d20003..44cf2101b6 100644 --- a/plugins/catalog/src/alpha/plugin.tsx +++ b/plugins/catalog/src/alpha/plugin.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { convertLegacyRouteRefs } from '@backstage/core-compat-api'; import { createFrontendPlugin } from '@backstage/frontend-plugin-api'; import { entityRouteRef } from '@backstage/plugin-catalog-react'; @@ -41,16 +40,16 @@ import contextMenuItems from './contextMenuItems'; export default createFrontendPlugin({ pluginId: 'catalog', info: { packageJson: () => import('../../package.json') }, - routes: convertLegacyRouteRefs({ + routes: { catalogIndex: rootRouteRef, catalogEntity: entityRouteRef, - }), - externalRoutes: convertLegacyRouteRefs({ + }, + externalRoutes: { viewTechDoc: viewTechDocRouteRef, createComponent: createComponentRouteRef, createFromTemplate: createFromTemplateRouteRef, unregisterRedirect: unregisterRedirectRouteRef, - }), + }, extensions: [ ...apis, ...pages, diff --git a/plugins/devtools/report-alpha.api.md b/plugins/devtools/report-alpha.api.md index c9a538be0b..9640158e53 100644 --- a/plugins/devtools/report-alpha.api.md +++ b/plugins/devtools/report-alpha.api.md @@ -12,7 +12,8 @@ import { IconComponent } from '@backstage/frontend-plugin-api'; import { JSX as JSX_2 } from 'react'; import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api'; import { OverridableFrontendPlugin } from '@backstage/frontend-plugin-api'; -import { RouteRef } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/core-plugin-api'; +import { RouteRef as RouteRef_2 } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) const _default: OverridableFrontendPlugin< @@ -45,7 +46,7 @@ const _default: OverridableFrontendPlugin< { title: string; icon: IconComponent; - routeRef: RouteRef; + routeRef: RouteRef_2; }, 'core.nav-item.target', {} @@ -54,7 +55,7 @@ const _default: OverridableFrontendPlugin< params: { title: string; icon: IconComponent; - routeRef: RouteRef; + routeRef: RouteRef_2; }; }>; 'page:devtools': OverridableExtensionDefinition<{ @@ -70,7 +71,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -81,7 +82,7 @@ const _default: OverridableFrontendPlugin< defaultPath?: [Error: `Use the 'path' param instead`]; path: string; loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; }; }>; } diff --git a/plugins/devtools/src/alpha/plugin.tsx b/plugins/devtools/src/alpha/plugin.tsx index a331a53243..85021e9857 100644 --- a/plugins/devtools/src/alpha/plugin.tsx +++ b/plugins/devtools/src/alpha/plugin.tsx @@ -24,7 +24,6 @@ import { } from '@backstage/frontend-plugin-api'; import { devToolsApiRef, DevToolsClient } from '../api'; -import { convertLegacyRouteRef } from '@backstage/core-compat-api'; import BuildIcon from '@material-ui/icons/Build'; import { rootRouteRef } from '../routes'; @@ -46,7 +45,7 @@ export const devToolsApi = ApiBlueprint.make({ export const devToolsPage = PageBlueprint.make({ params: { path: '/devtools', - routeRef: convertLegacyRouteRef(rootRouteRef), + routeRef: rootRouteRef, loader: () => import('../components/DevToolsPage').then(m => ), }, @@ -56,7 +55,7 @@ export const devToolsPage = PageBlueprint.make({ export const devToolsNavItem = NavItemBlueprint.make({ params: { title: 'DevTools', - routeRef: convertLegacyRouteRef(rootRouteRef), + routeRef: rootRouteRef, icon: BuildIcon, }, }); @@ -66,7 +65,7 @@ export default createFrontendPlugin({ pluginId: 'devtools', info: { packageJson: () => import('../../package.json') }, routes: { - root: convertLegacyRouteRef(rootRouteRef), + root: rootRouteRef, }, extensions: [devToolsApi, devToolsPage, devToolsNavItem], }); diff --git a/plugins/kubernetes/report-alpha.api.md b/plugins/kubernetes/report-alpha.api.md index 571e09d546..2872ab89e4 100644 --- a/plugins/kubernetes/report-alpha.api.md +++ b/plugins/kubernetes/report-alpha.api.md @@ -14,7 +14,8 @@ import { ExtensionDataRef } from '@backstage/frontend-plugin-api'; import { JSX as JSX_2 } from 'react'; import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api'; import { OverridableFrontendPlugin } from '@backstage/frontend-plugin-api'; -import { RouteRef } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/core-plugin-api'; +import { RouteRef as RouteRef_2 } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; // @public (undocumented) @@ -103,7 +104,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -140,7 +141,7 @@ const _default: OverridableFrontendPlugin< defaultGroup?: [Error: `Use the 'group' param instead`]; group?: keyof defaultEntityContentGroups | (string & {}); loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; filter?: string | EntityPredicate | ((entity: Entity) => boolean); }; }>; @@ -157,7 +158,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -168,7 +169,7 @@ const _default: OverridableFrontendPlugin< defaultPath?: [Error: `Use the 'path' param instead`]; path: string; loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; }; }>; } diff --git a/plugins/kubernetes/src/alpha/pages.tsx b/plugins/kubernetes/src/alpha/pages.tsx index 23e78f9264..3069d25cd6 100644 --- a/plugins/kubernetes/src/alpha/pages.tsx +++ b/plugins/kubernetes/src/alpha/pages.tsx @@ -15,16 +15,12 @@ */ import { PageBlueprint } from '@backstage/frontend-plugin-api'; -import { convertLegacyRouteRef } from '@backstage/core-compat-api'; import { rootCatalogKubernetesRouteRef } from '../plugin'; export const kubernetesPage = PageBlueprint.make({ params: { path: '/kubernetes', - // you can reuse the existing routeRef - // by wrapping into the convertLegacyRouteRef. - routeRef: convertLegacyRouteRef(rootCatalogKubernetesRouteRef), - // these inputs usually match the props required by the component. + routeRef: rootCatalogKubernetesRouteRef, loader: () => import('../Router').then(m => ), }, }); diff --git a/plugins/kubernetes/src/alpha/plugin.tsx b/plugins/kubernetes/src/alpha/plugin.tsx index db7b2439bf..fdca467886 100644 --- a/plugins/kubernetes/src/alpha/plugin.tsx +++ b/plugins/kubernetes/src/alpha/plugin.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { convertLegacyRouteRefs } from '@backstage/core-compat-api'; import { createFrontendPlugin } from '@backstage/frontend-plugin-api'; import { kubernetesPage } from './pages'; import { entityKubernetesContent } from './entityContents'; @@ -37,5 +36,5 @@ export default createFrontendPlugin({ kubernetesAuthProvidersApi, kubernetesClusterLinkFormatterApi, ], - routes: convertLegacyRouteRefs({ kubernetes: rootCatalogKubernetesRouteRef }), + routes: { kubernetes: rootCatalogKubernetesRouteRef }, }); diff --git a/plugins/mui-to-bui/report.api.md b/plugins/mui-to-bui/report.api.md index 519f0c1bc7..db1d49f828 100644 --- a/plugins/mui-to-bui/report.api.md +++ b/plugins/mui-to-bui/report.api.md @@ -10,8 +10,8 @@ import { JSX as JSX_2 } from 'react'; import { JSX as JSX_3 } from 'react/jsx-runtime'; import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api'; import { OverridableFrontendPlugin } from '@backstage/frontend-plugin-api'; -import { RouteRef } from '@backstage/frontend-plugin-api'; -import { RouteRef as RouteRef_2 } from '@backstage/core-plugin-api'; +import { RouteRef } from '@backstage/core-plugin-api'; +import { RouteRef as RouteRef_2 } from '@backstage/frontend-plugin-api'; // @public (undocumented) export const BuiThemerPage: () => JSX_3.Element; @@ -19,7 +19,7 @@ export const BuiThemerPage: () => JSX_3.Element; // @public (undocumented) export const buiThemerPlugin: BackstagePlugin< { - root: RouteRef_2; + root: RouteRef; }, {} >; @@ -44,7 +44,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -55,7 +55,7 @@ const _default: OverridableFrontendPlugin< defaultPath?: [Error: `Use the 'path' param instead`]; path: string; loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; }; }>; } diff --git a/plugins/mui-to-bui/src/plugin.tsx b/plugins/mui-to-bui/src/plugin.tsx index aca19c9978..ccebe6e379 100644 --- a/plugins/mui-to-bui/src/plugin.tsx +++ b/plugins/mui-to-bui/src/plugin.tsx @@ -14,10 +14,6 @@ * limitations under the License. */ -import { - convertLegacyRouteRef, - convertLegacyRouteRefs, -} from '@backstage/core-compat-api'; import { createPlugin, createRoutableExtension, @@ -57,11 +53,11 @@ export default createFrontendPlugin({ path: '/mui-to-bui', loader: () => import('./components/BuiThemerPage').then(m => ), - routeRef: convertLegacyRouteRef(rootRouteRef), + routeRef: rootRouteRef, }, }), ], - routes: convertLegacyRouteRefs({ + routes: { root: rootRouteRef, - }), + }, }); diff --git a/plugins/notifications/report-alpha.api.md b/plugins/notifications/report-alpha.api.md index 713d4c3998..98d036365e 100644 --- a/plugins/notifications/report-alpha.api.md +++ b/plugins/notifications/report-alpha.api.md @@ -11,7 +11,8 @@ import { ExtensionDataRef } from '@backstage/frontend-plugin-api'; import { JSX as JSX_2 } from 'react'; import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api'; import { OverridableFrontendPlugin } from '@backstage/frontend-plugin-api'; -import { RouteRef } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/core-plugin-api'; +import { RouteRef as RouteRef_2 } from '@backstage/frontend-plugin-api'; // @alpha (undocumented) const _default: OverridableFrontendPlugin< @@ -48,7 +49,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -59,7 +60,7 @@ const _default: OverridableFrontendPlugin< defaultPath?: [Error: `Use the 'path' param instead`]; path: string; loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; }; }>; } diff --git a/plugins/notifications/src/alpha.tsx b/plugins/notifications/src/alpha.tsx index 6d32150c35..32b9ae429a 100644 --- a/plugins/notifications/src/alpha.tsx +++ b/plugins/notifications/src/alpha.tsx @@ -22,16 +22,12 @@ import { fetchApiRef, } from '@backstage/frontend-plugin-api'; import { rootRouteRef } from './routes'; -import { - convertLegacyRouteRef, - convertLegacyRouteRefs, -} from '@backstage/core-compat-api'; import { NotificationsClient, notificationsApiRef } from './api'; const page = PageBlueprint.make({ params: { path: '/notifications', - routeRef: convertLegacyRouteRef(rootRouteRef), + routeRef: rootRouteRef, loader: () => import('./components/NotificationsPage').then(m => ( @@ -53,9 +49,9 @@ const api = ApiBlueprint.make({ export default createFrontendPlugin({ pluginId: 'notifications', info: { packageJson: () => import('../package.json') }, - routes: convertLegacyRouteRefs({ + routes: { root: rootRouteRef, - }), + }, // TODO(Rugvip): Nav item (i.e. NotificationsSidebarItem) currently needs to be installed manually extensions: [page, api], }); diff --git a/plugins/org/report-alpha.api.md b/plugins/org/report-alpha.api.md index 3e113868a6..05f1169dfb 100644 --- a/plugins/org/report-alpha.api.md +++ b/plugins/org/report-alpha.api.md @@ -8,7 +8,7 @@ import { EntityCardType } from '@backstage/plugin-catalog-react/alpha'; import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha'; import { ExtensionDataRef } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; -import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; +import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { JSX as JSX_2 } from 'react'; import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api'; import { OverridableFrontendPlugin } from '@backstage/frontend-plugin-api'; @@ -18,7 +18,7 @@ import { TranslationRef } from '@backstage/frontend-plugin-api'; const _default: OverridableFrontendPlugin< {}, { - catalogIndex: ExternalRouteRef; + catalogIndex: ExternalRouteRef; }, { 'entity-card:org/group-profile': OverridableExtensionDefinition<{ diff --git a/plugins/org/src/alpha.tsx b/plugins/org/src/alpha.tsx index 6e158436c3..57924a0269 100644 --- a/plugins/org/src/alpha.tsx +++ b/plugins/org/src/alpha.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { convertLegacyRouteRefs } from '@backstage/core-compat-api'; import { createFrontendPlugin } from '@backstage/frontend-plugin-api'; import { catalogIndexRouteRef } from './routes'; import { EntityCardBlueprint } from '@backstage/plugin-catalog-react/alpha'; @@ -122,9 +121,9 @@ export default createFrontendPlugin({ EntityOwnershipCard, EntityUserProfileCard, ], - externalRoutes: convertLegacyRouteRefs({ + externalRoutes: { catalogIndex: catalogIndexRouteRef, - }), + }, }); export { orgTranslationRef } from './translation'; diff --git a/plugins/scaffolder/report-alpha.api.md b/plugins/scaffolder/report-alpha.api.md index 80c0054882..df46f9feb6 100644 --- a/plugins/scaffolder/report-alpha.api.md +++ b/plugins/scaffolder/report-alpha.api.md @@ -14,7 +14,7 @@ import { EntityPredicate } from '@backstage/plugin-catalog-react/alpha'; import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api'; import { ExtensionDataRef } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; -import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; +import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; import { FormField } from '@backstage/plugin-scaffolder-react/alpha'; import { formFieldsApiRef } from '@backstage/plugin-scaffolder-react/alpha'; @@ -28,10 +28,11 @@ import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api'; import { OverridableFrontendPlugin } from '@backstage/frontend-plugin-api'; import { PathParams } from '@backstage/core-plugin-api'; import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; -import { RouteRef } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/core-plugin-api'; +import { RouteRef as RouteRef_2 } from '@backstage/frontend-plugin-api'; import { ScaffolderFormDecorator } from '@backstage/plugin-scaffolder-react/alpha'; import { ScaffolderFormFieldsApi } from '@backstage/plugin-scaffolder-react/alpha'; -import { SubRouteRef } from '@backstage/frontend-plugin-api'; +import { SubRouteRef } from '@backstage/core-plugin-api'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; @@ -50,12 +51,15 @@ const _default: OverridableFrontendPlugin< templatingExtensions: SubRouteRef; }, { - registerComponent: ExternalRouteRef; - viewTechDoc: ExternalRouteRef<{ - name: string; - kind: string; - namespace: string; - }>; + registerComponent: ExternalRouteRef; + viewTechDoc: ExternalRouteRef< + { + name: string; + kind: string; + namespace: string; + }, + true + >; }, { 'api:scaffolder': OverridableExtensionDefinition<{ @@ -175,7 +179,7 @@ const _default: OverridableFrontendPlugin< { title: string; icon: IconComponent; - routeRef: RouteRef; + routeRef: RouteRef_2; }, 'core.nav-item.target', {} @@ -184,7 +188,7 @@ const _default: OverridableFrontendPlugin< params: { title: string; icon: IconComponent; - routeRef: RouteRef; + routeRef: RouteRef_2; }; }>; 'page:scaffolder': OverridableExtensionDefinition<{ @@ -198,7 +202,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -223,7 +227,7 @@ const _default: OverridableFrontendPlugin< defaultPath?: [Error: `Use the 'path' param instead`]; path: string; loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; }; }>; 'scaffolder-form-field:scaffolder/entity-name-picker': OverridableExtensionDefinition<{ diff --git a/plugins/scaffolder/src/alpha/extensions.tsx b/plugins/scaffolder/src/alpha/extensions.tsx index 30054ece6e..429e6d493a 100644 --- a/plugins/scaffolder/src/alpha/extensions.tsx +++ b/plugins/scaffolder/src/alpha/extensions.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { convertLegacyRouteRef } from '@backstage/core-compat-api'; import { ApiBlueprint, createExtensionInput, @@ -42,7 +41,7 @@ export const scaffolderPage = PageBlueprint.makeWithOverrides({ i.get(FormFieldBlueprint.dataRefs.formFieldLoader), ); return originalFactory({ - routeRef: convertLegacyRouteRef(rootRouteRef), + routeRef: rootRouteRef, path: '/create', loader: () => import('../components/Router/Router').then(m => ( @@ -54,7 +53,7 @@ export const scaffolderPage = PageBlueprint.makeWithOverrides({ export const scaffolderNavItem = NavItemBlueprint.make({ params: { - routeRef: convertLegacyRouteRef(rootRouteRef), + routeRef: rootRouteRef, title: 'Create...', icon: CreateComponentIcon, }, diff --git a/plugins/scaffolder/src/alpha/plugin.tsx b/plugins/scaffolder/src/alpha/plugin.tsx index 3b41aa3893..5bb744e2ea 100644 --- a/plugins/scaffolder/src/alpha/plugin.tsx +++ b/plugins/scaffolder/src/alpha/plugin.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { convertLegacyRouteRefs } from '@backstage/core-compat-api'; import { createFrontendPlugin } from '@backstage/frontend-plugin-api'; import { actionsRouteRef, @@ -60,7 +59,7 @@ const scaffolderEntityIconLink = EntityIconLinkBlueprint.make({ export default createFrontendPlugin({ pluginId: 'scaffolder', info: { packageJson: () => import('../../package.json') }, - routes: convertLegacyRouteRefs({ + routes: { root: rootRouteRef, selectedTemplate: selectedTemplateRouteRef, ongoingTask: scaffolderTaskRouteRef, @@ -68,11 +67,11 @@ export default createFrontendPlugin({ listTasks: scaffolderListTaskRouteRef, edit: editRouteRef, templatingExtensions: templatingExtensionsRouteRef, - }), - externalRoutes: convertLegacyRouteRefs({ + }, + externalRoutes: { registerComponent: registerComponentRouteRef, viewTechDoc: viewTechDocRouteRef, - }), + }, extensions: [ scaffolderApi, scaffolderPage, diff --git a/plugins/search/report-alpha.api.md b/plugins/search/report-alpha.api.md index 5ac036ca68..742bf1bf3b 100644 --- a/plugins/search/report-alpha.api.md +++ b/plugins/search/report-alpha.api.md @@ -15,6 +15,7 @@ import { JSX as JSX_2 } from 'react'; import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api'; import { OverridableFrontendPlugin } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; +import { RouteRef as RouteRef_2 } from '@backstage/core-plugin-api'; import { SearchFilterExtensionComponent } from '@backstage/plugin-search-react/alpha'; import { SearchResultItemExtensionComponent } from '@backstage/plugin-search-react/alpha'; import { SearchResultItemExtensionPredicate } from '@backstage/plugin-search-react/alpha'; @@ -23,7 +24,7 @@ import { TranslationRef } from '@backstage/core-plugin-api/alpha'; // @alpha (undocumented) const _default: OverridableFrontendPlugin< { - root: RouteRef; + root: RouteRef_2; }, {}, { diff --git a/plugins/search/src/alpha.tsx b/plugins/search/src/alpha.tsx index eb98f70ee0..2efe9978e0 100644 --- a/plugins/search/src/alpha.tsx +++ b/plugins/search/src/alpha.tsx @@ -68,10 +68,6 @@ import { rootRouteRef } from './plugin'; import { SearchClient } from './apis'; import { SearchType } from './components/SearchType'; import { UrlUpdater } from './components/SearchPage/SearchPage'; -import { - convertLegacyRouteRef, - convertLegacyRouteRefs, -} from '@backstage/core-compat-api'; /** @alpha */ export const searchApi = ApiBlueprint.make({ @@ -115,7 +111,7 @@ export const searchPage = PageBlueprint.makeWithOverrides({ factory(originalFactory, { config, inputs }) { return originalFactory({ path: '/search', - routeRef: convertLegacyRouteRef(rootRouteRef), + routeRef: rootRouteRef, loader: async () => { const getResultItemComponent = (result: SearchResult) => { const value = inputs.items.find(item => @@ -267,7 +263,7 @@ export const searchPage = PageBlueprint.makeWithOverrides({ /** @alpha */ export const searchNavItem = NavItemBlueprint.make({ params: { - routeRef: convertLegacyRouteRef(rootRouteRef), + routeRef: rootRouteRef, title: 'Search', icon: SearchIcon, }, @@ -278,9 +274,9 @@ export default createFrontendPlugin({ pluginId: 'search', info: { packageJson: () => import('../package.json') }, extensions: [searchApi, searchPage, searchNavItem], - routes: convertLegacyRouteRefs({ + routes: { root: rootRouteRef, - }), + }, }); /** @alpha */ diff --git a/plugins/techdocs/report-alpha.api.md b/plugins/techdocs/report-alpha.api.md index f950670f22..bc3a5d6c34 100644 --- a/plugins/techdocs/report-alpha.api.md +++ b/plugins/techdocs/report-alpha.api.md @@ -18,7 +18,8 @@ import { IconLinkVerticalProps } from '@backstage/core-components'; import { JSX as JSX_2 } from 'react'; import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api'; import { OverridableFrontendPlugin } from '@backstage/frontend-plugin-api'; -import { RouteRef } from '@backstage/frontend-plugin-api'; +import { RouteRef } from '@backstage/core-plugin-api'; +import { RouteRef as RouteRef_2 } from '@backstage/frontend-plugin-api'; import { SearchResultItemExtensionComponent } from '@backstage/plugin-search-react/alpha'; import { SearchResultItemExtensionPredicate } from '@backstage/plugin-search-react/alpha'; import { SearchResultListItemBlueprintParams } from '@backstage/plugin-search-react/alpha'; @@ -107,7 +108,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -171,7 +172,7 @@ const _default: OverridableFrontendPlugin< defaultGroup?: [Error: `Use the 'group' param instead`]; group?: keyof defaultEntityContentGroups | (string & {}); loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; filter?: string | EntityPredicate | ((entity: Entity) => boolean); }; }>; @@ -223,7 +224,7 @@ const _default: OverridableFrontendPlugin< { title: string; icon: IconComponent; - routeRef: RouteRef; + routeRef: RouteRef_2; }, 'core.nav-item.target', {} @@ -232,7 +233,7 @@ const _default: OverridableFrontendPlugin< params: { title: string; icon: IconComponent; - routeRef: RouteRef; + routeRef: RouteRef_2; }; }>; 'page:techdocs': OverridableExtensionDefinition<{ @@ -248,7 +249,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -259,7 +260,7 @@ const _default: OverridableFrontendPlugin< defaultPath?: [Error: `Use the 'path' param instead`]; path: string; loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; }; }>; 'page:techdocs/reader': OverridableExtensionDefinition<{ @@ -273,7 +274,7 @@ const _default: OverridableFrontendPlugin< | ExtensionDataRef | ExtensionDataRef | ExtensionDataRef< - RouteRef, + RouteRef_2, 'core.routing.ref', { optional: true; @@ -298,7 +299,7 @@ const _default: OverridableFrontendPlugin< defaultPath?: [Error: `Use the 'path' param instead`]; path: string; loader: () => Promise; - routeRef?: RouteRef; + routeRef?: RouteRef_2; }; }>; 'search-result-list-item:techdocs': OverridableExtensionDefinition<{ diff --git a/plugins/techdocs/src/alpha/index.tsx b/plugins/techdocs/src/alpha/index.tsx index ebc84a1837..d3fc94c7a8 100644 --- a/plugins/techdocs/src/alpha/index.tsx +++ b/plugins/techdocs/src/alpha/index.tsx @@ -29,10 +29,6 @@ import { discoveryApiRef, fetchApiRef, } from '@backstage/core-plugin-api'; -import { - convertLegacyRouteRef, - convertLegacyRouteRefs, -} from '@backstage/core-compat-api'; import { EntityContentBlueprint, EntityIconLinkBlueprint, @@ -138,7 +134,7 @@ export const techDocsSearchResultListItemExtension = const techDocsPage = PageBlueprint.make({ params: { path: '/docs', - routeRef: convertLegacyRouteRef(rootRouteRef), + routeRef: rootRouteRef, loader: () => import('../home/components/TechDocsIndexPage').then(m => ( @@ -166,7 +162,7 @@ const techDocsReaderPage = PageBlueprint.makeWithOverrides({ return originalFactory({ path: '/docs/:namespace/:kind/:name', - routeRef: convertLegacyRouteRef(rootDocsRouteRef), + routeRef: rootDocsRouteRef, loader: async () => await import('../Router').then(({ TechDocsReaderRouter }) => ( @@ -199,7 +195,7 @@ const techDocsEntityContent = EntityContentBlueprint.makeWithOverrides({ { path: 'docs', title: 'TechDocs', - routeRef: convertLegacyRouteRef(rootCatalogDocsRouteRef), + routeRef: rootCatalogDocsRouteRef, loader: () => import('../Router').then(({ EmbeddedDocsRouter }) => { const addons = context.inputs.addons.map(output => { @@ -237,7 +233,7 @@ const techDocsNavItem = NavItemBlueprint.make({ params: { icon: LibraryBooks, title: 'Docs', - routeRef: convertLegacyRouteRef(rootRouteRef), + routeRef: rootRouteRef, }, }); @@ -256,9 +252,9 @@ export default createFrontendPlugin({ techDocsEntityContentEmptyState, techDocsSearchResultListItemExtension, ], - routes: convertLegacyRouteRefs({ + routes: { root: rootRouteRef, docRoot: rootDocsRouteRef, entityContent: rootCatalogDocsRouteRef, - }), + }, }); diff --git a/plugins/user-settings/report-alpha.api.md b/plugins/user-settings/report-alpha.api.md index e9f05fe3f9..5d28bb85aa 100644 --- a/plugins/user-settings/report-alpha.api.md +++ b/plugins/user-settings/report-alpha.api.md @@ -12,12 +12,13 @@ import { JSX as JSX_2 } from 'react'; import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api'; import { OverridableFrontendPlugin } from '@backstage/frontend-plugin-api'; import { RouteRef } from '@backstage/frontend-plugin-api'; +import { RouteRef as RouteRef_2 } from '@backstage/core-plugin-api'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; // @alpha (undocumented) const _default: OverridableFrontendPlugin< { - root: RouteRef; + root: RouteRef_2; }, {}, { diff --git a/plugins/user-settings/src/alpha.tsx b/plugins/user-settings/src/alpha.tsx index bd0d9a1a82..bea75bbdd8 100644 --- a/plugins/user-settings/src/alpha.tsx +++ b/plugins/user-settings/src/alpha.tsx @@ -20,10 +20,6 @@ import { PageBlueprint, NavItemBlueprint, } from '@backstage/frontend-plugin-api'; -import { - convertLegacyRouteRef, - convertLegacyRouteRefs, -} from '@backstage/core-compat-api'; import SettingsIcon from '@material-ui/icons/Settings'; import { settingsRouteRef } from './plugin'; @@ -39,7 +35,7 @@ const userSettingsPage = PageBlueprint.makeWithOverrides({ factory(originalFactory, { inputs }) { return originalFactory({ path: '/settings', - routeRef: convertLegacyRouteRef(settingsRouteRef), + routeRef: settingsRouteRef, loader: () => import('./components/SettingsPage').then(m => ( import('../package.json') }, extensions: [userSettingsPage, settingsNavItem], - routes: convertLegacyRouteRefs({ + routes: { root: settingsRouteRef, - }), + }, }); From 395ff1c43b39a257f547ca97d80142f807e7e493 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 23 Nov 2025 14:18:57 +0100 Subject: [PATCH 7/8] plugins: remove unused dependencies on core-compat-api Signed-off-by: Patrik Oldsberg --- plugins/api-docs/package.json | 1 - plugins/catalog-graph/package.json | 1 - plugins/catalog-import/package.json | 1 - plugins/catalog-unprocessed-entities/package.json | 1 - plugins/devtools/package.json | 1 - plugins/kubernetes/package.json | 1 - plugins/mui-to-bui/package.json | 1 - plugins/notifications/package.json | 1 - plugins/org/package.json | 1 - plugins/scaffolder/package.json | 1 - plugins/search/package.json | 1 - plugins/signals/package.json | 1 - plugins/techdocs/package.json | 1 - plugins/user-settings/package.json | 1 - yarn.lock | 14 -------------- 15 files changed, 28 deletions(-) diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index f89c75b8f7..e8e1dae16b 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -55,7 +55,6 @@ "dependencies": { "@asyncapi/react-component": "^2.3.3", "@backstage/catalog-model": "workspace:^", - "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/frontend-plugin-api": "workspace:^", diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 49f4a9836b..d42a7aabf0 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -51,7 +51,6 @@ "dependencies": { "@backstage/catalog-client": "workspace:^", "@backstage/catalog-model": "workspace:^", - "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/frontend-plugin-api": "workspace:^", diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 6d9b3dd66d..ffb0034296 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -57,7 +57,6 @@ "@backstage/catalog-client": "workspace:^", "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", - "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", diff --git a/plugins/catalog-unprocessed-entities/package.json b/plugins/catalog-unprocessed-entities/package.json index 5610db4c50..a6e960367e 100644 --- a/plugins/catalog-unprocessed-entities/package.json +++ b/plugins/catalog-unprocessed-entities/package.json @@ -51,7 +51,6 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", - "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", diff --git a/plugins/devtools/package.json b/plugins/devtools/package.json index 6ba69e0b56..7eebbf675e 100644 --- a/plugins/devtools/package.json +++ b/plugins/devtools/package.json @@ -51,7 +51,6 @@ "test": "backstage-cli package test" }, "dependencies": { - "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index a003601bbe..f703304ab3 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -59,7 +59,6 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", - "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/frontend-plugin-api": "workspace:^", diff --git a/plugins/mui-to-bui/package.json b/plugins/mui-to-bui/package.json index ca66765d79..6cf3cf4fbb 100644 --- a/plugins/mui-to-bui/package.json +++ b/plugins/mui-to-bui/package.json @@ -35,7 +35,6 @@ "test": "backstage-cli package test" }, "dependencies": { - "@backstage/core-compat-api": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/frontend-plugin-api": "workspace:^", "@backstage/theme": "workspace:^", diff --git a/plugins/notifications/package.json b/plugins/notifications/package.json index dbafa426f6..5ceb333ca0 100644 --- a/plugins/notifications/package.json +++ b/plugins/notifications/package.json @@ -51,7 +51,6 @@ "test": "backstage-cli package test" }, "dependencies": { - "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", diff --git a/plugins/org/package.json b/plugins/org/package.json index d2f44a3c5c..3ace5508ed 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -52,7 +52,6 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", - "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/frontend-plugin-api": "workspace:^", diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index d85495c9e4..5c07960027 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -60,7 +60,6 @@ "dependencies": { "@backstage/catalog-client": "workspace:^", "@backstage/catalog-model": "workspace:^", - "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", diff --git a/plugins/search/package.json b/plugins/search/package.json index 48bc3abfb9..9ab3b6810f 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -58,7 +58,6 @@ "test": "backstage-cli package test" }, "dependencies": { - "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", diff --git a/plugins/signals/package.json b/plugins/signals/package.json index 4ee2efbe22..b443a08b1b 100644 --- a/plugins/signals/package.json +++ b/plugins/signals/package.json @@ -51,7 +51,6 @@ "test": "backstage-cli package test" }, "dependencies": { - "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/frontend-plugin-api": "workspace:^", diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 18ac26eafe..ae680061df 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -62,7 +62,6 @@ "@backstage/catalog-client": "workspace:^", "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", - "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 508ca6000d..3491d7eabc 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -57,7 +57,6 @@ "dependencies": { "@backstage/catalog-model": "workspace:^", "@backstage/core-app-api": "workspace:^", - "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", diff --git a/yarn.lock b/yarn.lock index c218f0d58b..ffebdf9687 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3954,7 +3954,6 @@ __metadata: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/core-app-api": "workspace:^" - "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" @@ -5122,7 +5121,6 @@ __metadata: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/core-app-api": "workspace:^" - "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" @@ -5167,7 +5165,6 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/core-app-api": "workspace:^" - "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" @@ -5300,7 +5297,6 @@ __metadata: dependencies: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" - "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" @@ -5472,7 +5468,6 @@ __metadata: resolution: "@backstage/plugin-devtools@workspace:plugins/devtools" dependencies: "@backstage/cli": "workspace:^" - "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" @@ -5952,7 +5947,6 @@ __metadata: dependencies: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" - "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" @@ -6006,7 +6000,6 @@ __metadata: resolution: "@backstage/plugin-mui-to-bui@workspace:plugins/mui-to-bui" dependencies: "@backstage/cli": "workspace:^" - "@backstage/core-compat-api": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" "@backstage/frontend-plugin-api": "workspace:^" @@ -6148,7 +6141,6 @@ __metadata: resolution: "@backstage/plugin-notifications@workspace:plugins/notifications" dependencies: "@backstage/cli": "workspace:^" - "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" @@ -6227,7 +6219,6 @@ __metadata: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/core-app-api": "workspace:^" - "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" @@ -6918,7 +6909,6 @@ __metadata: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/core-app-api": "workspace:^" - "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" @@ -7209,7 +7199,6 @@ __metadata: dependencies: "@backstage/cli": "workspace:^" "@backstage/core-app-api": "workspace:^" - "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" @@ -7319,7 +7308,6 @@ __metadata: resolution: "@backstage/plugin-signals@workspace:plugins/signals" dependencies: "@backstage/cli": "workspace:^" - "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" @@ -7546,7 +7534,6 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/core-app-api": "workspace:^" - "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" @@ -7631,7 +7618,6 @@ __metadata: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/core-app-api": "workspace:^" - "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" From 338c89936c7da4cd933a0ea13b89d136bd499c02 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 23 Nov 2025 17:43:19 +0100 Subject: [PATCH 8/8] core-plugin-api: avoid adding api context requirement for useApp and useRouteRef Signed-off-by: Patrik Oldsberg --- packages/core-plugin-api/src/app/useApp.tsx | 23 +++++++++++++------ .../src/routing/useRouteRef.tsx | 16 +++++++++---- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/packages/core-plugin-api/src/app/useApp.tsx b/packages/core-plugin-api/src/app/useApp.tsx index 8368ed955f..fde807c317 100644 --- a/packages/core-plugin-api/src/app/useApp.tsx +++ b/packages/core-plugin-api/src/app/useApp.tsx @@ -25,6 +25,7 @@ import { Progress, createFrontendPlugin, FrontendPlugin, + ApiHolder, } from '@backstage/frontend-plugin-api'; import { AppComponents, @@ -75,26 +76,34 @@ function toNewPlugin(plugin: BackstagePlugin): FrontendPlugin { }); } +function useOptionalApiHolder(): ApiHolder | undefined { + try { + return useApiHolder(); + } catch { + return undefined; + } +} + /** * React hook providing {@link AppContext}. * * @public */ export const useApp = (): AppContextV1 => { - const apiHolder = useApiHolder(); - const appTreeApi = apiHolder.get(appTreeApiRef); + const apiHolder = useOptionalApiHolder(); + const appTreeApi = apiHolder?.get(appTreeApiRef); + const iconsApi = apiHolder?.get(iconsApiRef); const versionedContext = useVersionedContext<{ 1: AppContextV1 }>( 'app-context', ); - const newAppContext = useMemo(() => { + const newAppContext = useMemo(() => { if (!appTreeApi) { - return null; + return undefined; } - const iconsApi = apiHolder.get(iconsApiRef); if (!iconsApi) { - return null; + return undefined; } const { tree } = appTreeApi.getTree(); @@ -152,7 +161,7 @@ export const useApp = (): AppContextV1 => { }; }, }; - }, [appTreeApi, apiHolder]); + }, [appTreeApi, iconsApi]); if (newAppContext) { return newAppContext; diff --git a/packages/core-plugin-api/src/routing/useRouteRef.tsx b/packages/core-plugin-api/src/routing/useRouteRef.tsx index a46e96ba9e..48908ada5d 100644 --- a/packages/core-plugin-api/src/routing/useRouteRef.tsx +++ b/packages/core-plugin-api/src/routing/useRouteRef.tsx @@ -18,8 +18,9 @@ import { useMemo } from 'react'; import { matchRoutes, useLocation } from 'react-router-dom'; import { useVersionedContext } from '@backstage/version-bridge'; import { + RouteResolutionApi, routeResolutionApiRef, - useApiHolder, + useApi, } from '@backstage/frontend-plugin-api'; import { AnyParams, @@ -42,6 +43,14 @@ export interface RouteResolver { ): RouteFunc | undefined; } +function useRouteResolutionApi(): RouteResolutionApi | undefined { + try { + return useApi(routeResolutionApiRef); + } catch { + return undefined; + } +} + /** * React hook for constructing URLs to routes. * @@ -90,8 +99,7 @@ export function useRouteRef( | ExternalRouteRef, ): RouteFunc | undefined { const { pathname } = useLocation(); - const apiHolder = useApiHolder(); - const routeResolutionApi = apiHolder.get(routeResolutionApiRef); + const routeResolutionApi = useRouteResolutionApi(); const versionedContext = useVersionedContext<{ 1: RouteResolver }>( 'routing-context', ); @@ -104,7 +112,7 @@ export function useRouteRef( } try { - return routeResolutionApi.resolve(routeRef, { + return routeResolutionApi?.resolve(routeRef, { sourcePath: pathname, }); } catch {