From f8e2383016dc5d42719d4d8d67f573b604897388 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 4 Aug 2024 11:40:32 +0200 Subject: [PATCH] core-compat-api: add forwards compat for routing context Signed-off-by: Patrik Oldsberg --- .../compatWrapper/ForwardsCompatProvider.tsx | 55 ++++++++++++++++++- .../src/compatWrapper/compatWrapper.test.tsx | 16 ++++++ 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/packages/core-compat-api/src/compatWrapper/ForwardsCompatProvider.tsx b/packages/core-compat-api/src/compatWrapper/ForwardsCompatProvider.tsx index 182b774cca..b2200387cc 100644 --- a/packages/core-compat-api/src/compatWrapper/ForwardsCompatProvider.tsx +++ b/packages/core-compat-api/src/compatWrapper/ForwardsCompatProvider.tsx @@ -21,22 +21,34 @@ import { useApp, } from '@backstage/core-plugin-api'; import { + AnyRouteRefParams, ComponentRef, ComponentsApi, CoreErrorBoundaryFallbackProps, CoreNotFoundErrorPageProps, CoreProgressProps, + ExternalRouteRef, IconComponent, IconsApi, + RouteFunc, + RouteRef, + RouteResolutionApi, + RouteResolutionApiResolveOptions, + SubRouteRef, componentsApiRef, coreComponentRefs, iconsApiRef, + routeResolutionApiRef, } from '@backstage/frontend-plugin-api'; import React, { ComponentType, useMemo } from 'react'; import { ReactNode } from 'react'; import { toLegacyPlugin } from './BackwardsCompatProvider'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { ApiProvider } from '../../../core-app-api/src/apis/system/ApiProvider'; +import { useVersionedContext } from '@backstage/version-bridge'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { type RouteResolver } from '../../../core-plugin-api/src/routing/useRouteRef'; +import { convertLegacyRouteRef } from '../convertLegacyRouteRef'; class CompatComponentsApi implements ComponentsApi { readonly #Progress: ComponentType; @@ -88,13 +100,34 @@ class CompatIconsApi implements IconsApi { } } -class AppFallbackApis implements ApiHolder { +class CompatRouteResolutionApi implements RouteResolutionApi { + readonly #routeResolver: RouteResolver; + + constructor(routeResolver: RouteResolver) { + this.#routeResolver = routeResolver; + } + + resolve( + anyRouteRef: + | RouteRef + | SubRouteRef + | ExternalRouteRef, + options?: RouteResolutionApiResolveOptions | undefined, + ): RouteFunc | undefined { + const legacyRef = convertLegacyRouteRef(anyRouteRef as RouteRef); + return this.#routeResolver.resolve(legacyRef, options?.sourcePath ?? '/'); + } +} + +class ForwardsCompatApis implements ApiHolder { readonly #componentsApi: ComponentsApi; readonly #iconsApi: IconsApi; + readonly #routeResolutionApi: RouteResolutionApi; - constructor(app: AppContext) { + constructor(app: AppContext, routeResolver: RouteResolver) { this.#componentsApi = new CompatComponentsApi(app); this.#iconsApi = new CompatIconsApi(app); + this.#routeResolutionApi = new CompatRouteResolutionApi(routeResolver); } get(ref: ApiRef): T | undefined { @@ -102,6 +135,8 @@ class AppFallbackApis implements ApiHolder { return this.#componentsApi as T; } else if (ref.id === iconsApiRef.id) { return this.#iconsApi as T; + } else if (ref.id === routeResolutionApiRef.id) { + return this.#routeResolutionApi as T; } return undefined; } @@ -109,7 +144,21 @@ class AppFallbackApis implements ApiHolder { function NewAppApisProvider(props: { children: ReactNode }) { const app = useApp(); - const appFallbackApis = useMemo(() => new AppFallbackApis(app), [app]); + const versionedRouteResolverContext = useVersionedContext<{ + 1: RouteResolver; + }>('routing-context'); + if (!versionedRouteResolverContext) { + throw new Error('Routing context is not available'); + } + const routeResolver = versionedRouteResolverContext.atVersion(1); + if (!routeResolver) { + throw new Error('RoutingContext v1 not available'); + } + + const appFallbackApis = useMemo( + () => new ForwardsCompatApis(app, routeResolver), + [app, routeResolver], + ); return {props.children}; } diff --git a/packages/core-compat-api/src/compatWrapper/compatWrapper.test.tsx b/packages/core-compat-api/src/compatWrapper/compatWrapper.test.tsx index b17ca2d508..6a27bf19e8 100644 --- a/packages/core-compat-api/src/compatWrapper/compatWrapper.test.tsx +++ b/packages/core-compat-api/src/compatWrapper/compatWrapper.test.tsx @@ -22,6 +22,7 @@ import { createExtension, iconsApiRef, useRouteRef as useNewRouteRef, + createRouteRef as createNewRouteRef, useApi, } from '@backstage/frontend-plugin-api'; import { @@ -122,4 +123,19 @@ describe('ForwardsCompatProvider', () => { icons: kind:api, kind:component, kind:domain, kind:group, kind:location, kind:system, kind:user, kind:resource, kind:template, brokenImage, catalog, scaffolder, techdocs, search, chat, dashboard, docs, email, github, group, help, user, warning" `); }); + + it('should convert the routing context', async () => { + const routeRef = createNewRouteRef(); + + function Component() { + const link = useNewRouteRef(routeRef); + return
link: {link()}
; + } + + await renderInOldTestApp(compatWrapper(), { + mountedRoutes: { '/test': convertLegacyRouteRef(routeRef) }, + }); + + expect(screen.getByText('link: /test')).toBeInTheDocument(); + }); });