From 50a9e40122c76bd9c5deb8bfcfcc9daf029eba48 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Mon, 13 Nov 2023 14:20:45 +0100 Subject: [PATCH] frontend-app-api: fix circular dependency Signed-off-by: Vincenzo Scamporlino --- packages/frontend-app-api/api-report.md | 2 +- .../routing/extractRouteInfoFromAppNode.ts | 3 +- .../src/routing/toLegacyPlugin.ts | 55 +++++++++++++++++++ .../frontend-app-api/src/wiring/createApp.tsx | 38 +------------ 4 files changed, 58 insertions(+), 40 deletions(-) create mode 100644 packages/frontend-app-api/src/routing/toLegacyPlugin.ts diff --git a/packages/frontend-app-api/api-report.md b/packages/frontend-app-api/api-report.md index 3ca51f6331..f87eaf6684 100644 --- a/packages/frontend-app-api/api-report.md +++ b/packages/frontend-app-api/api-report.md @@ -27,7 +27,7 @@ export type AppRouteBinder = < ) => void; // @public (undocumented) -export function createApp(options?: { +export function createApp(options: { features?: (BackstagePlugin | ExtensionOverrides)[]; configLoader?: () => Promise; bindRoutes?(context: { bind: AppRouteBinder }): void; diff --git a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.ts b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.ts index 43955328a8..2bfd09a3e8 100644 --- a/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.ts +++ b/packages/frontend-app-api/src/routing/extractRouteInfoFromAppNode.ts @@ -15,10 +15,9 @@ */ import { RouteRef, coreExtensionData } from '@backstage/frontend-plugin-api'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { toLegacyPlugin } from '../wiring/createApp'; import { BackstageRouteObject } from './types'; import { AppNode } from '@backstage/frontend-plugin-api'; +import { toLegacyPlugin } from './toLegacyPlugin'; // We always add a child that matches all subroutes but without any route refs. This makes // sure that we're always able to match each route no matter how deep the navigation goes. diff --git a/packages/frontend-app-api/src/routing/toLegacyPlugin.ts b/packages/frontend-app-api/src/routing/toLegacyPlugin.ts new file mode 100644 index 0000000000..2d04d04dda --- /dev/null +++ b/packages/frontend-app-api/src/routing/toLegacyPlugin.ts @@ -0,0 +1,55 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { BackstagePlugin as LegacyBackstagePlugin } from '@backstage/core-plugin-api'; +import { getOrCreateGlobalSingleton } from '@backstage/version-bridge'; + +// Make sure that we only convert each new plugin instance to its legacy equivalent once +const legacyPluginStore = getOrCreateGlobalSingleton( + 'legacy-plugin-compatibility-store', + () => new WeakMap(), +); + +export function toLegacyPlugin(plugin: BackstagePlugin): LegacyBackstagePlugin { + 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; +} diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index 8495f961db..d39111eb99 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -80,7 +80,6 @@ import { BrowserRouter, Route } from 'react-router-dom'; import { SidebarItem } from '@backstage/core-components'; import { DarkTheme, LightTheme } from '../extensions/themes'; import { extractRouteInfoFromAppNode } from '../routing/extractRouteInfoFromAppNode'; -import { getOrCreateGlobalSingleton } from '@backstage/version-bridge'; import { appLanguageApiRef, translationApiRef, @@ -91,6 +90,7 @@ import { resolveRouteBindings } from '../routing/resolveRouteBindings'; import { collectRouteIds } from '../routing/collectRouteIds'; import { createAppTree } from '../tree'; import { AppNode } from '@backstage/frontend-plugin-api'; +import { toLegacyPlugin } from '../routing/toLegacyPlugin'; const builtinExtensions = [ Core, @@ -328,42 +328,6 @@ export function createSpecializedApp(options?: { }; } -// Make sure that we only convert each new plugin instance to its legacy equivalent once -const legacyPluginStore = getOrCreateGlobalSingleton( - 'legacy-plugin-compatibility-store', - () => new WeakMap(), -); - -export function toLegacyPlugin(plugin: BackstagePlugin): LegacyBackstagePlugin { - 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 createLegacyAppContext(plugins: BackstagePlugin[]): AppContext { return { getPlugins(): LegacyBackstagePlugin[] {