Merge pull request #21592 from backstage/rugvip/compat-wrapper
core-compat-api: introduce compatWrapper
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-compat-api': patch
|
||||
---
|
||||
|
||||
Added `compatWrapper`, which can be used to wrap any React element to provide bi-directional interoperability between the `@backstage/core-*-api` and `@backstage/frontend-*-api` APIs.
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-import': patch
|
||||
'@backstage/plugin-user-settings': patch
|
||||
'@backstage/plugin-tech-radar': patch
|
||||
'@backstage/plugin-graphiql': patch
|
||||
'@backstage/plugin-techdocs': patch
|
||||
'@backstage/plugin-catalog': patch
|
||||
'@backstage/plugin-search': patch
|
||||
'@backstage/plugin-home': patch
|
||||
---
|
||||
|
||||
Wrap `/alpha` export extension elements in backwards compatibility wrapper.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-app-api': minor
|
||||
---
|
||||
|
||||
The app no longer provides the `AppContext` from `@backstage/core-plugin-api`. Components that require this context to be available should use the `compatWrapper` helper from `@backstage/core-compat-api`.
|
||||
@@ -13,6 +13,7 @@ import { ExtensionOverrides } from '@backstage/frontend-plugin-api';
|
||||
import { ExternalRouteRef } from '@backstage/core-plugin-api';
|
||||
import { ExternalRouteRef as ExternalRouteRef_2 } from '@backstage/frontend-plugin-api';
|
||||
import { default as React_2 } from 'react';
|
||||
import { ReactNode } from 'react';
|
||||
import { RouteRef } from '@backstage/core-plugin-api';
|
||||
import { RouteRef as RouteRef_2 } from '@backstage/frontend-plugin-api';
|
||||
import { SubRouteRef } from '@backstage/core-plugin-api';
|
||||
@@ -28,6 +29,9 @@ export function collectLegacyRoutes(
|
||||
flatRoutesElement: JSX.Element,
|
||||
): BackstagePlugin[];
|
||||
|
||||
// @public
|
||||
export function compatWrapper(element: ReactNode): React_2.JSX.Element;
|
||||
|
||||
// @public (undocumented)
|
||||
export function convertLegacyApp(
|
||||
rootElement: React_2.JSX.Element,
|
||||
|
||||
@@ -24,10 +24,12 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@backstage/frontend-test-utils": "workspace:^",
|
||||
"@backstage/plugin-puppetdb": "workspace:^",
|
||||
"@backstage/plugin-stackstorm": "workspace:^",
|
||||
"@oriflame/backstage-plugin-score-card": "^0.7.0",
|
||||
"@testing-library/jest-dom": "^6.0.0"
|
||||
"@testing-library/jest-dom": "^6.0.0",
|
||||
"@testing-library/react": "^14.0.0"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
@@ -40,6 +42,7 @@
|
||||
"@backstage/core-app-api": "workspace:^",
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/frontend-plugin-api": "workspace:^",
|
||||
"@backstage/version-bridge": "workspace:^",
|
||||
"@types/react": "^16.13.1 || ^17.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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 React, { useMemo } from 'react';
|
||||
import { ReactNode } from 'react';
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import { AppContextProvider } from '../../../core-app-api/src/app/AppContext';
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import {
|
||||
components as defaultComponents,
|
||||
icons as defaultIcons,
|
||||
} from '../../../app-defaults/src/defaults';
|
||||
import {
|
||||
BackstagePlugin as NewBackstagePlugin,
|
||||
appTreeApiRef,
|
||||
useApi,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import {
|
||||
AppComponents,
|
||||
IconComponent,
|
||||
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<NewBackstagePlugin, LegacyBackstagePlugin>(),
|
||||
);
|
||||
|
||||
function toLegacyPlugin(plugin: NewBackstagePlugin): 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;
|
||||
}
|
||||
|
||||
// Recreates the old AppContext APIs using the various new APIs that replaced it
|
||||
function LegacyAppContextProvider(props: { children: ReactNode }) {
|
||||
const appTreeApi = useApi(appTreeApiRef);
|
||||
|
||||
const appContext = useMemo(() => {
|
||||
const { tree } = appTreeApi.getTree();
|
||||
|
||||
let gatheredPlugins: LegacyBackstagePlugin[] | undefined = undefined;
|
||||
|
||||
return {
|
||||
getPlugins(): LegacyBackstagePlugin[] {
|
||||
if (gatheredPlugins) {
|
||||
return gatheredPlugins;
|
||||
}
|
||||
|
||||
const pluginSet = new Set<LegacyBackstagePlugin>();
|
||||
for (const node of tree.nodes.values()) {
|
||||
const plugin = node.spec.source;
|
||||
if (plugin) {
|
||||
pluginSet.add(toLegacyPlugin(plugin));
|
||||
}
|
||||
}
|
||||
gatheredPlugins = Array.from(pluginSet);
|
||||
|
||||
return gatheredPlugins;
|
||||
},
|
||||
|
||||
// TODO: Grab these from new API once it exists
|
||||
getSystemIcon(key: string): IconComponent | undefined {
|
||||
return key in defaultIcons
|
||||
? defaultIcons[key as keyof typeof defaultIcons]
|
||||
: undefined;
|
||||
},
|
||||
|
||||
// TODO: Grab these from new API once it exists
|
||||
getSystemIcons(): Record<string, IconComponent> {
|
||||
return defaultIcons;
|
||||
},
|
||||
|
||||
// TODO: Grab these from new API once it exists
|
||||
getComponents(): AppComponents {
|
||||
return defaultComponents;
|
||||
},
|
||||
};
|
||||
}, [appTreeApi]);
|
||||
|
||||
return (
|
||||
<AppContextProvider appContext={appContext}>
|
||||
{props.children}
|
||||
</AppContextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export function BackwardsCompatProvider(props: { children: ReactNode }) {
|
||||
return <LegacyAppContextProvider>{props.children}</LegacyAppContextProvider>;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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 React from 'react';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
export function ForwardsCompatProvider(props: { children: ReactNode }) {
|
||||
// TODO(Rugvip): Implement
|
||||
return <>{props.children}</>;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 React from 'react';
|
||||
import {
|
||||
coreExtensionData,
|
||||
createExtension,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import { createExtensionTester } from '@backstage/frontend-test-utils';
|
||||
import { screen } from '@testing-library/react';
|
||||
import { compatWrapper } from './compatWrapper';
|
||||
import { useApp } from '@backstage/core-plugin-api';
|
||||
|
||||
describe('BackwardsCompatProvider', () => {
|
||||
it('should convert the app context', () => {
|
||||
// TODO(Rugvip): Replace with the new renderInTestApp once it's available, and have some plugins
|
||||
createExtensionTester(
|
||||
createExtension({
|
||||
attachTo: { id: 'ignored', input: 'ignored' },
|
||||
output: {
|
||||
element: coreExtensionData.reactElement,
|
||||
},
|
||||
factory() {
|
||||
function Component() {
|
||||
const app = useApp();
|
||||
return (
|
||||
<div data-testid="ctx">
|
||||
plugins:
|
||||
{app
|
||||
.getPlugins()
|
||||
.map(p => p.getId())
|
||||
.join(', ')}
|
||||
{'\n'}
|
||||
components: {Object.keys(app.getComponents()).join(', ')}
|
||||
{'\n'}
|
||||
icons: {Object.keys(app.getSystemIcons()).join(', ')}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
element: compatWrapper(<Component />),
|
||||
};
|
||||
},
|
||||
}),
|
||||
).render();
|
||||
|
||||
expect(screen.getByTestId('ctx').textContent).toMatchInlineSnapshot(`
|
||||
"plugins:
|
||||
components: Progress, Router, NotFoundErrorPage, BootErrorPage, ErrorBoundaryFallback
|
||||
icons: brokenImage, catalog, scaffolder, techdocs, search, chat, dashboard, docs, email, github, group, help, kind:api, kind:component, kind:domain, kind:group, kind:location, kind:system, kind:user, kind:resource, kind:template, user, warning"
|
||||
`);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 React from 'react';
|
||||
import { useVersionedContext } from '@backstage/version-bridge';
|
||||
import { ReactNode } from 'react';
|
||||
import { BackwardsCompatProvider } from './BackwardsCompatProvider';
|
||||
import { ForwardsCompatProvider } from './ForwardsCompatProvider';
|
||||
|
||||
function BidirectionalCompatProvider(props: { children: ReactNode }) {
|
||||
const isInNewApp = !useVersionedContext<{ 1: unknown }>('app-context');
|
||||
|
||||
if (isInNewApp) {
|
||||
return <BackwardsCompatProvider {...props} />;
|
||||
}
|
||||
|
||||
return <ForwardsCompatProvider {...props} />;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a React element in a bidirectional compatibility provider, allow APIs
|
||||
* from `@backstage/core-plugin-api` to be used in an app from `@backstage/frontend-app-api`,
|
||||
* and APIs from `@backstage/frontend-plugin-api` to be used in an app from `@backstage/core-app-api`.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function compatWrapper(element: ReactNode) {
|
||||
return <BidirectionalCompatProvider>{element}</BidirectionalCompatProvider>;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { compatWrapper } from './compatWrapper';
|
||||
@@ -13,6 +13,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from './compatWrapper';
|
||||
|
||||
export { collectLegacyRoutes } from './collectLegacyRoutes';
|
||||
export { collectLegacyComponents } from './collectLegacyComponents';
|
||||
export { convertLegacyApp } from './convertLegacyApp';
|
||||
|
||||
@@ -35,13 +35,10 @@ import { CoreNav } from '../extensions/CoreNav';
|
||||
import {
|
||||
AnyApiFactory,
|
||||
ApiHolder,
|
||||
AppComponents,
|
||||
AppContext,
|
||||
appThemeApiRef,
|
||||
ConfigApi,
|
||||
configApiRef,
|
||||
IconComponent,
|
||||
BackstagePlugin as LegacyBackstagePlugin,
|
||||
featureFlagsApiRef,
|
||||
attachComponentData,
|
||||
identityApiRef,
|
||||
@@ -61,8 +58,6 @@ import { AppThemeProvider } from '../../../core-app-api/src/app/AppThemeProvider
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import { AppIdentityProxy } from '../../../core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy';
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import { AppContextProvider } from '../../../core-app-api/src/app/AppContext';
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import { LocalStorageFeatureFlags } from '../../../core-app-api/src/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags';
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import { defaultConfigLoaderSync } from '../../../core-app-api/src/app/defaultConfigLoader';
|
||||
@@ -75,11 +70,7 @@ import { I18nextTranslationApi } from '../../../core-app-api/src/apis/implementa
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import { resolveExtensionDefinition } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import {
|
||||
apis as defaultApis,
|
||||
components as defaultComponents,
|
||||
icons as defaultIcons,
|
||||
} from '../../../app-defaults/src/defaults';
|
||||
import { apis as defaultApis } from '../../../app-defaults/src/defaults';
|
||||
import { Route } from 'react-router-dom';
|
||||
import { SidebarItem } from '@backstage/core-components';
|
||||
import { DarkTheme, LightTheme } from '../extensions/themes';
|
||||
@@ -100,7 +91,6 @@ import {
|
||||
DefaultNotFoundErrorPageComponent,
|
||||
} from '../extensions/components';
|
||||
import { AppNode } from '@backstage/frontend-plugin-api';
|
||||
import { toLegacyPlugin } from '../routing/toLegacyPlugin';
|
||||
import { InternalAppContext } from './InternalAppContext';
|
||||
import { CoreRouter } from '../extensions/CoreRouter';
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
@@ -315,12 +305,6 @@ export function createSpecializedApp(options?: {
|
||||
config,
|
||||
});
|
||||
|
||||
const appContext = createLegacyAppContext(
|
||||
features.filter(
|
||||
(f): f is BackstagePlugin => f.$$type === '@backstage/BackstagePlugin',
|
||||
),
|
||||
);
|
||||
|
||||
const appIdentityProxy = new AppIdentityProxy();
|
||||
const apiHolder = createApiHolder(tree, config, appIdentityProxy);
|
||||
|
||||
@@ -353,17 +337,15 @@ export function createSpecializedApp(options?: {
|
||||
|
||||
const App = () => (
|
||||
<ApiProvider apis={apiHolder}>
|
||||
<AppContextProvider appContext={appContext}>
|
||||
<AppThemeProvider>
|
||||
<RoutingProvider {...routeInfo} routeBindings={routeBindings}>
|
||||
<InternalAppContext.Provider
|
||||
value={{ appIdentityProxy, routeObjects: routeInfo.routeObjects }}
|
||||
>
|
||||
{rootEl}
|
||||
</InternalAppContext.Provider>
|
||||
</RoutingProvider>
|
||||
</AppThemeProvider>
|
||||
</AppContextProvider>
|
||||
<AppThemeProvider>
|
||||
<RoutingProvider {...routeInfo} routeBindings={routeBindings}>
|
||||
<InternalAppContext.Provider
|
||||
value={{ appIdentityProxy, routeObjects: routeInfo.routeObjects }}
|
||||
>
|
||||
{rootEl}
|
||||
</InternalAppContext.Provider>
|
||||
</RoutingProvider>
|
||||
</AppThemeProvider>
|
||||
</ApiProvider>
|
||||
);
|
||||
|
||||
@@ -374,28 +356,6 @@ export function createSpecializedApp(options?: {
|
||||
};
|
||||
}
|
||||
|
||||
function createLegacyAppContext(plugins: BackstagePlugin[]): AppContext {
|
||||
return {
|
||||
getPlugins(): LegacyBackstagePlugin[] {
|
||||
return plugins.map(toLegacyPlugin);
|
||||
},
|
||||
|
||||
getSystemIcon(key: string): IconComponent | undefined {
|
||||
return key in defaultIcons
|
||||
? defaultIcons[key as keyof typeof defaultIcons]
|
||||
: undefined;
|
||||
},
|
||||
|
||||
getSystemIcons(): Record<string, IconComponent> {
|
||||
return defaultIcons;
|
||||
},
|
||||
|
||||
getComponents(): AppComponents {
|
||||
return defaultComponents;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function createApiHolder(
|
||||
tree: AppTree,
|
||||
configApi: ConfigApi,
|
||||
|
||||
@@ -20,7 +20,10 @@ import {
|
||||
discoveryApiRef,
|
||||
identityApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { convertLegacyRouteRef } from '@backstage/core-compat-api';
|
||||
import {
|
||||
compatWrapper,
|
||||
convertLegacyRouteRef,
|
||||
} from '@backstage/core-compat-api';
|
||||
import {
|
||||
createApiExtension,
|
||||
createPageExtension,
|
||||
@@ -40,7 +43,10 @@ import { catalogApiRef } from '@backstage/plugin-catalog-react';
|
||||
const CatalogImportPageExtension = createPageExtension({
|
||||
defaultPath: '/catalog-import',
|
||||
routeRef: convertLegacyRouteRef(rootRouteRef),
|
||||
loader: () => import('./components/ImportPage').then(m => <m.ImportPage />),
|
||||
loader: () =>
|
||||
import('./components/ImportPage').then(m =>
|
||||
compatWrapper(<m.ImportPage />),
|
||||
),
|
||||
});
|
||||
|
||||
const CatalogImportService = createApiExtension({
|
||||
|
||||
@@ -16,79 +16,80 @@
|
||||
|
||||
import React from 'react';
|
||||
import { createEntityCardExtension } from '@backstage/plugin-catalog-react/alpha';
|
||||
import { compatWrapper } from '@backstage/core-compat-api';
|
||||
|
||||
export const EntityAboutCard = createEntityCardExtension({
|
||||
name: 'about',
|
||||
loader: async () =>
|
||||
import('../components/AboutCard').then(m => (
|
||||
<m.AboutCard variant="gridItem" />
|
||||
)),
|
||||
import('../components/AboutCard').then(m =>
|
||||
compatWrapper(<m.AboutCard variant="gridItem" />),
|
||||
),
|
||||
});
|
||||
|
||||
export const EntityLinksCard = createEntityCardExtension({
|
||||
name: 'links',
|
||||
filter: 'has:links',
|
||||
loader: async () =>
|
||||
import('../components/EntityLinksCard').then(m => {
|
||||
return <m.EntityLinksCard variant="gridItem" />;
|
||||
}),
|
||||
import('../components/EntityLinksCard').then(m =>
|
||||
compatWrapper(<m.EntityLinksCard variant="gridItem" />),
|
||||
),
|
||||
});
|
||||
|
||||
export const EntityLabelsCard = createEntityCardExtension({
|
||||
name: 'labels',
|
||||
filter: 'has:labels',
|
||||
loader: async () =>
|
||||
import('../components/EntityLabelsCard').then(m => (
|
||||
<m.EntityLabelsCard variant="gridItem" />
|
||||
)),
|
||||
import('../components/EntityLabelsCard').then(m =>
|
||||
compatWrapper(<m.EntityLabelsCard variant="gridItem" />),
|
||||
),
|
||||
});
|
||||
|
||||
export const EntityDependsOnComponentsCard = createEntityCardExtension({
|
||||
name: 'depends-on-components',
|
||||
loader: async () =>
|
||||
import('../components/DependsOnComponentsCard').then(m => (
|
||||
<m.DependsOnComponentsCard variant="gridItem" />
|
||||
)),
|
||||
import('../components/DependsOnComponentsCard').then(m =>
|
||||
compatWrapper(<m.DependsOnComponentsCard variant="gridItem" />),
|
||||
),
|
||||
});
|
||||
|
||||
export const EntityDependsOnResourcesCard = createEntityCardExtension({
|
||||
name: 'depends-on-resources',
|
||||
loader: async () =>
|
||||
import('../components/DependsOnResourcesCard').then(m => (
|
||||
<m.DependsOnResourcesCard variant="gridItem" />
|
||||
)),
|
||||
import('../components/DependsOnResourcesCard').then(m =>
|
||||
compatWrapper(<m.DependsOnResourcesCard variant="gridItem" />),
|
||||
),
|
||||
});
|
||||
|
||||
export const EntityHasComponentsCard = createEntityCardExtension({
|
||||
name: 'has-components',
|
||||
loader: async () =>
|
||||
import('../components/HasComponentsCard').then(m => (
|
||||
<m.HasComponentsCard variant="gridItem" />
|
||||
)),
|
||||
import('../components/HasComponentsCard').then(m =>
|
||||
compatWrapper(<m.HasComponentsCard variant="gridItem" />),
|
||||
),
|
||||
});
|
||||
|
||||
export const EntityHasResourcesCard = createEntityCardExtension({
|
||||
name: 'has-resources',
|
||||
loader: async () =>
|
||||
import('../components/HasResourcesCard').then(m => (
|
||||
<m.HasResourcesCard variant="gridItem" />
|
||||
)),
|
||||
import('../components/HasResourcesCard').then(m =>
|
||||
compatWrapper(<m.HasResourcesCard variant="gridItem" />),
|
||||
),
|
||||
});
|
||||
|
||||
export const EntityHasSubcomponentsCard = createEntityCardExtension({
|
||||
name: 'has-subcomponents',
|
||||
loader: async () =>
|
||||
import('../components/HasSubcomponentsCard').then(m => (
|
||||
<m.HasSubcomponentsCard variant="gridItem" />
|
||||
)),
|
||||
import('../components/HasSubcomponentsCard').then(m =>
|
||||
compatWrapper(<m.HasSubcomponentsCard variant="gridItem" />),
|
||||
),
|
||||
});
|
||||
|
||||
export const EntityHasSystemsCard = createEntityCardExtension({
|
||||
name: 'has-systems',
|
||||
loader: async () =>
|
||||
import('../components/HasSystemsCard').then(m => (
|
||||
<m.HasSystemsCard variant="gridItem" />
|
||||
)),
|
||||
import('../components/HasSystemsCard').then(m =>
|
||||
compatWrapper(<m.HasSystemsCard variant="gridItem" />),
|
||||
),
|
||||
});
|
||||
|
||||
export default [
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { convertLegacyRouteRef } from '@backstage/core-compat-api';
|
||||
import {
|
||||
compatWrapper,
|
||||
convertLegacyRouteRef,
|
||||
} from '@backstage/core-compat-api';
|
||||
import {
|
||||
createPageExtension,
|
||||
coreExtensionData,
|
||||
@@ -40,7 +43,7 @@ export const CatalogIndexPage = createPageExtension({
|
||||
loader: async ({ inputs }) => {
|
||||
const { BaseCatalogPage } = await import('../components/CatalogPage');
|
||||
const filters = inputs.filters.map(filter => filter.output.element);
|
||||
return <BaseCatalogPage filters={<>{filters}</>} />;
|
||||
return compatWrapper(<BaseCatalogPage filters={<>{filters}</>} />);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -75,7 +78,7 @@ export const CatalogEntityPage = createPageExtension({
|
||||
</AsyncEntityProvider>
|
||||
);
|
||||
};
|
||||
return <Component />;
|
||||
return compatWrapper(<Component />);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -34,13 +34,17 @@ import {
|
||||
} from '@backstage/plugin-graphiql';
|
||||
import { createApiFactory, IconComponent } from '@backstage/core-plugin-api';
|
||||
import { graphiQLRouteRef } from './route-refs';
|
||||
import { convertLegacyRouteRef } from '@backstage/core-compat-api';
|
||||
import {
|
||||
compatWrapper,
|
||||
convertLegacyRouteRef,
|
||||
} from '@backstage/core-compat-api';
|
||||
|
||||
/** @alpha */
|
||||
export const GraphiqlPage = createPageExtension({
|
||||
defaultPath: '/graphiql',
|
||||
routeRef: convertLegacyRouteRef(graphiQLRouteRef),
|
||||
loader: () => import('./components').then(m => <m.GraphiQLPage />),
|
||||
loader: () =>
|
||||
import('./components').then(m => compatWrapper(<m.GraphiQLPage />)),
|
||||
});
|
||||
|
||||
/** @alpha */
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
"@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:^",
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
createPlugin,
|
||||
createRouteRef,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import { compatWrapper } from '@backstage/core-compat-api';
|
||||
|
||||
const rootRouteRef = createRouteRef();
|
||||
|
||||
@@ -49,12 +50,14 @@ const HomepageCompositionRootExtension = createPageExtension({
|
||||
),
|
||||
},
|
||||
loader: ({ inputs }) =>
|
||||
import('./components/').then(m => (
|
||||
<m.HomepageCompositionRoot
|
||||
children={inputs.props?.output.children}
|
||||
title={inputs.props?.output.title}
|
||||
/>
|
||||
)),
|
||||
import('./components/').then(m =>
|
||||
compatWrapper(
|
||||
<m.HomepageCompositionRoot
|
||||
children={inputs.props?.output.children}
|
||||
title={inputs.props?.output.title}
|
||||
/>,
|
||||
),
|
||||
),
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -67,7 +67,10 @@ import { rootRouteRef } from './plugin';
|
||||
import { SearchClient } from './apis';
|
||||
import { SearchType } from './components/SearchType';
|
||||
import { UrlUpdater } from './components/SearchPage/SearchPage';
|
||||
import { convertLegacyRouteRef } from '@backstage/core-compat-api';
|
||||
import {
|
||||
compatWrapper,
|
||||
convertLegacyRouteRef,
|
||||
} from '@backstage/core-compat-api';
|
||||
|
||||
/** @alpha */
|
||||
export const SearchApi = createApiExtension({
|
||||
@@ -225,11 +228,11 @@ export const SearchPage = createPageExtension({
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
return compatWrapper(
|
||||
<SearchContextProvider>
|
||||
<UrlUpdater />
|
||||
<Component />
|
||||
</SearchContextProvider>
|
||||
</SearchContextProvider>,
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -24,7 +24,10 @@ import {
|
||||
import React from 'react';
|
||||
import { techRadarApiRef } from './api';
|
||||
import { SampleTechRadarApi } from './sample';
|
||||
import { convertLegacyRouteRef } from '@backstage/core-compat-api';
|
||||
import {
|
||||
compatWrapper,
|
||||
convertLegacyRouteRef,
|
||||
} from '@backstage/core-compat-api';
|
||||
import { rootRouteRef } from './plugin';
|
||||
|
||||
/** @alpha */
|
||||
@@ -44,7 +47,9 @@ export const TechRadarPage = createPageExtension({
|
||||
}),
|
||||
),
|
||||
loader: ({ config }) =>
|
||||
import('./components').then(m => <m.RadarPage {...config} />),
|
||||
import('./components').then(m =>
|
||||
compatWrapper(<m.RadarPage {...config} />),
|
||||
),
|
||||
});
|
||||
|
||||
/** @alpha */
|
||||
|
||||
@@ -31,7 +31,10 @@ import {
|
||||
fetchApiRef,
|
||||
identityApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { convertLegacyRouteRef } from '@backstage/core-compat-api';
|
||||
import {
|
||||
compatWrapper,
|
||||
convertLegacyRouteRef,
|
||||
} from '@backstage/core-compat-api';
|
||||
import {
|
||||
techdocsApiRef,
|
||||
techdocsStorageApiRef,
|
||||
@@ -100,7 +103,8 @@ export const TechDocsSearchResultListItemExtension =
|
||||
const { TechDocsSearchResultListItem } = await import(
|
||||
'./search/components/TechDocsSearchResultListItem'
|
||||
);
|
||||
return props => <TechDocsSearchResultListItem {...props} {...config} />;
|
||||
return props =>
|
||||
compatWrapper(<TechDocsSearchResultListItem {...props} {...config} />);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -113,9 +117,9 @@ const TechDocsIndexPage = createPageExtension({
|
||||
defaultPath: '/docs',
|
||||
routeRef: convertLegacyRouteRef(rootRouteRef),
|
||||
loader: () =>
|
||||
import('./home/components/TechDocsIndexPage').then(m => (
|
||||
<m.TechDocsIndexPage />
|
||||
)),
|
||||
import('./home/components/TechDocsIndexPage').then(m =>
|
||||
compatWrapper(<m.TechDocsIndexPage />),
|
||||
),
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -128,9 +132,9 @@ const TechDocsReaderPage = createPageExtension({
|
||||
defaultPath: '/docs/:namespace/:kind/:name',
|
||||
routeRef: convertLegacyRouteRef(rootDocsRouteRef),
|
||||
loader: () =>
|
||||
import('./reader/components/TechDocsReaderPage').then(m => (
|
||||
<m.TechDocsReaderPage />
|
||||
)),
|
||||
import('./reader/components/TechDocsReaderPage').then(m =>
|
||||
compatWrapper(<m.TechDocsReaderPage />),
|
||||
),
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -141,7 +145,8 @@ const TechDocsReaderPage = createPageExtension({
|
||||
const TechDocsEntityContent = createEntityContentExtension({
|
||||
defaultPath: 'docs',
|
||||
defaultTitle: 'TechDocs',
|
||||
loader: () => import('./Router').then(m => <m.EmbeddedDocsRouter />),
|
||||
loader: () =>
|
||||
import('./Router').then(m => compatWrapper(<m.EmbeddedDocsRouter />)),
|
||||
});
|
||||
|
||||
/** @alpha */
|
||||
|
||||
@@ -19,7 +19,10 @@ import {
|
||||
createPageExtension,
|
||||
createPlugin,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import { convertLegacyRouteRef } from '@backstage/core-compat-api';
|
||||
import {
|
||||
convertLegacyRouteRef,
|
||||
compatWrapper,
|
||||
} from '@backstage/core-compat-api';
|
||||
import { settingsRouteRef } from './plugin';
|
||||
|
||||
import React from 'react';
|
||||
@@ -38,11 +41,13 @@ const UserSettingsPage = createPageExtension({
|
||||
),
|
||||
},
|
||||
loader: ({ inputs }) =>
|
||||
import('./components/SettingsPage').then(m => (
|
||||
<m.SettingsPage
|
||||
providerSettings={inputs.providerSettings?.output.element}
|
||||
/>
|
||||
)),
|
||||
import('./components/SettingsPage').then(m =>
|
||||
compatWrapper(
|
||||
<m.SettingsPage
|
||||
providerSettings={inputs.providerSettings?.output.element}
|
||||
/>,
|
||||
),
|
||||
),
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -3855,10 +3855,13 @@ __metadata:
|
||||
"@backstage/core-app-api": "workspace:^"
|
||||
"@backstage/core-plugin-api": "workspace:^"
|
||||
"@backstage/frontend-plugin-api": "workspace:^"
|
||||
"@backstage/frontend-test-utils": "workspace:^"
|
||||
"@backstage/plugin-puppetdb": "workspace:^"
|
||||
"@backstage/plugin-stackstorm": "workspace:^"
|
||||
"@backstage/version-bridge": "workspace:^"
|
||||
"@oriflame/backstage-plugin-score-card": ^0.7.0
|
||||
"@testing-library/jest-dom": ^6.0.0
|
||||
"@testing-library/react": ^14.0.0
|
||||
"@types/react": ^16.13.1 || ^17.0.0
|
||||
peerDependencies:
|
||||
react: ^16.13.1 || ^17.0.0 || ^18.0.0
|
||||
@@ -7380,6 +7383,7 @@ __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:^"
|
||||
|
||||
Reference in New Issue
Block a user