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:
Patrik Oldsberg
2023-09-08 11:17:42 +02:00
parent 8d5e6825f1
commit e0088d9d1a
4 changed files with 89 additions and 13 deletions
+1
View File
@@ -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:^",
+53 -13
View File
@@ -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() {},
});
+1
View File
@@ -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:^"