frontend-app-api: implement api factory discovery
Co-authored-by: Camila Belo <camilaibs@gmail.com> Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"@backstage/config": "workspace:^",
|
||||
"@backstage/core-app-api": "workspace:^",
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/frontend-plugin-api": "workspace:^",
|
||||
"@backstage/plugin-graphiql": "workspace:^",
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
coreExtensionData,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import { CoreRouter } from './extensions/CoreRouter';
|
||||
import { Core } from './extensions/Core';
|
||||
import {
|
||||
createExtensionInstance,
|
||||
ExtensionInstance,
|
||||
@@ -31,8 +32,13 @@ import {
|
||||
readAppExtensionParameters,
|
||||
} from './wiring/parameters';
|
||||
import { RoutingProvider } from './routing/RoutingContext';
|
||||
import { RouteRef } from '@backstage/core-plugin-api';
|
||||
import { ApiHolder, RouteRef } from '@backstage/core-plugin-api';
|
||||
import { getAvailablePlugins } from './wiring/discovery';
|
||||
import {
|
||||
ApiFactoryRegistry,
|
||||
ApiProvider,
|
||||
ApiResolver,
|
||||
} from '@backstage/core-app-api';
|
||||
|
||||
/** @public */
|
||||
export function createApp(options: { plugins: BackstagePlugin[] }): {
|
||||
@@ -40,7 +46,7 @@ export function createApp(options: { plugins: BackstagePlugin[] }): {
|
||||
} {
|
||||
const appConfig = ConfigReader.fromConfigs(process.env.APP_CONFIG as any);
|
||||
|
||||
const builtinExtensions = [CoreRouter];
|
||||
const builtinExtensions = [CoreRouter, Core];
|
||||
const discoveredPlugins = getAvailablePlugins();
|
||||
|
||||
// pull in default extension instance from discovered packages
|
||||
@@ -115,25 +121,59 @@ export function createApp(options: { plugins: BackstagePlugin[] }): {
|
||||
|
||||
const routePaths = extractRouteInfoFromInstanceTree(rootInstances);
|
||||
|
||||
const coreInstance = rootInstances.find(({ id }) => id === 'core');
|
||||
if (!coreInstance) {
|
||||
throw Error('Unable to find core extension instance');
|
||||
}
|
||||
|
||||
const apiHolder = createApiHolder(coreInstance);
|
||||
|
||||
return {
|
||||
createRoot() {
|
||||
const rootComponents = rootInstances.map(
|
||||
e =>
|
||||
e.data.get(
|
||||
coreExtensionData.reactComponent.id,
|
||||
) as typeof coreExtensionData.reactComponent.T,
|
||||
);
|
||||
const rootComponents = rootInstances
|
||||
.map(
|
||||
e =>
|
||||
e.data.get(
|
||||
coreExtensionData.reactComponent.id,
|
||||
) as typeof coreExtensionData.reactComponent.T,
|
||||
)
|
||||
.filter(Boolean);
|
||||
return (
|
||||
<RoutingProvider routePaths={routePaths}>
|
||||
{rootComponents.map((Component, i) => (
|
||||
<Component key={i} />
|
||||
))}
|
||||
</RoutingProvider>
|
||||
<ApiProvider apis={apiHolder}>
|
||||
<RoutingProvider routePaths={routePaths}>
|
||||
{rootComponents.map((Component, i) => (
|
||||
<Component key={i} />
|
||||
))}
|
||||
</RoutingProvider>
|
||||
</ApiProvider>
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function createApiHolder(coreExtension: ExtensionInstance): ApiHolder {
|
||||
const factoryRegistry = new ApiFactoryRegistry();
|
||||
|
||||
const apiFactories =
|
||||
coreExtension.attachments
|
||||
.get('apis')
|
||||
?.map(
|
||||
e =>
|
||||
e.data.get(
|
||||
coreExtensionData.apiFactory.id,
|
||||
) as typeof coreExtensionData.apiFactory.T,
|
||||
)
|
||||
.filter(Boolean) ?? [];
|
||||
|
||||
for (const factory of apiFactories) {
|
||||
factoryRegistry.register('default', factory);
|
||||
}
|
||||
|
||||
ApiResolver.validateFactories(factoryRegistry, factoryRegistry.getAllApis());
|
||||
|
||||
return new ApiResolver(factoryRegistry);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function extractRouteInfoFromInstanceTree(
|
||||
roots: ExtensionInstance[],
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 {
|
||||
coreExtensionData,
|
||||
createExtension,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
|
||||
export const Core = createExtension({
|
||||
id: 'core',
|
||||
at: 'root',
|
||||
inputs: {
|
||||
apis: {
|
||||
extensionData: {
|
||||
api: coreExtensionData.apiFactory,
|
||||
},
|
||||
},
|
||||
},
|
||||
output: {},
|
||||
factory() {},
|
||||
});
|
||||
@@ -4317,6 +4317,7 @@ __metadata:
|
||||
dependencies:
|
||||
"@backstage/cli": "workspace:^"
|
||||
"@backstage/config": "workspace:^"
|
||||
"@backstage/core-app-api": "workspace:^"
|
||||
"@backstage/core-plugin-api": "workspace:^"
|
||||
"@backstage/frontend-plugin-api": "workspace:^"
|
||||
"@backstage/plugin-graphiql": "workspace:^"
|
||||
|
||||
Reference in New Issue
Block a user