techdocs: migrate nfs addons to utility API
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs-react': patch
|
||||
---
|
||||
|
||||
TechDocs addons in the new frontend system now use a Utility API pattern instead of multiple attachment points. The `AddonBlueprint` now uses this new approach, and while addons created with older versions still work, they will produce a deprecation warning and will stop working in a future release.
|
||||
|
||||
As part of this change, the `techDocsAddonDataRef` alpha export was removed.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs': patch
|
||||
---
|
||||
|
||||
TechDocs addons in the new frontend system now use a Utility API pattern instead of multiple attachment points. The `AddonBlueprint` now uses this new approach, and while addons created with older versions still work, they will produce a deprecation warning and will stop working in a future release.
|
||||
@@ -31,13 +31,6 @@ export const attachTechDocsAddonComponentData: <P>(
|
||||
data: TechDocsAddonOptions,
|
||||
) => void;
|
||||
|
||||
// @alpha (undocumented)
|
||||
export const techDocsAddonDataRef: ConfigurableExtensionDataRef<
|
||||
TechDocsAddonOptions,
|
||||
'techdocs.addon',
|
||||
{}
|
||||
>;
|
||||
|
||||
// @public
|
||||
export const TechDocsAddonLocations: Readonly<{
|
||||
readonly Header: 'Header';
|
||||
|
||||
@@ -29,8 +29,7 @@ import {
|
||||
/** @alpha */
|
||||
export type { TechDocsAddonOptions, TechDocsAddonLocations } from './types';
|
||||
|
||||
/** @alpha */
|
||||
export const techDocsAddonDataRef =
|
||||
const techDocsAddonDataRef =
|
||||
createExtensionDataRef<TechDocsAddonOptions>().with({
|
||||
id: 'techdocs.addon',
|
||||
});
|
||||
@@ -41,10 +40,7 @@ export const techDocsAddonDataRef =
|
||||
*/
|
||||
export const AddonBlueprint = createExtensionBlueprint({
|
||||
kind: 'addon',
|
||||
attachTo: [
|
||||
{ id: 'page:techdocs/reader', input: 'addons' },
|
||||
{ id: 'entity-content:techdocs', input: 'addons' },
|
||||
],
|
||||
attachTo: { id: 'api:techdocs/addons', input: 'addons' },
|
||||
output: [techDocsAddonDataRef],
|
||||
factory: (params: TechDocsAddonOptions) => [techDocsAddonDataRef(params)],
|
||||
dataRefs: {
|
||||
|
||||
@@ -53,6 +53,34 @@ const _default: OverridableFrontendPlugin<
|
||||
params: ApiFactory<TApi, TImpl, TDeps>,
|
||||
) => ExtensionBlueprintParams<AnyApiFactory>;
|
||||
}>;
|
||||
'api:techdocs/addons': OverridableExtensionDefinition<{
|
||||
config: {};
|
||||
configInput: {};
|
||||
output: ExtensionDataRef<AnyApiFactory, 'core.api.factory', {}>;
|
||||
inputs: {
|
||||
addons: ExtensionInput<
|
||||
ConfigurableExtensionDataRef<
|
||||
TechDocsAddonOptions,
|
||||
'techdocs.addon',
|
||||
{}
|
||||
>,
|
||||
{
|
||||
singleton: false;
|
||||
optional: false;
|
||||
internal: false;
|
||||
}
|
||||
>;
|
||||
};
|
||||
kind: 'api';
|
||||
name: 'addons';
|
||||
params: <
|
||||
TApi,
|
||||
TImpl extends TApi,
|
||||
TDeps extends { [name in string]: unknown },
|
||||
>(
|
||||
params: ApiFactory<TApi, TImpl, TDeps>,
|
||||
) => ExtensionBlueprintParams<AnyApiFactory>;
|
||||
}>;
|
||||
'api:techdocs/storage': OverridableExtensionDefinition<{
|
||||
kind: 'api';
|
||||
name: 'storage';
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2025 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 {
|
||||
ApiBlueprint,
|
||||
createApiRef,
|
||||
createExtensionInput,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import { AddonBlueprint } from '@backstage/plugin-techdocs-react/alpha';
|
||||
import { TechDocsAddonOptions } from '@backstage/plugin-techdocs-react';
|
||||
|
||||
interface TechDocsAddonsApi {
|
||||
getAddons(): TechDocsAddonOptions[];
|
||||
}
|
||||
|
||||
export const techdocsAddonsApiRef = createApiRef<TechDocsAddonsApi>({
|
||||
id: 'plugin.techdocs.addons',
|
||||
});
|
||||
|
||||
export const TechDocsAddonsApiExtension = ApiBlueprint.makeWithOverrides({
|
||||
name: 'addons',
|
||||
inputs: {
|
||||
addons: createExtensionInput([AddonBlueprint.dataRefs.addon]),
|
||||
},
|
||||
factory(originalFactory, { inputs }) {
|
||||
const addons = inputs.addons.map(output =>
|
||||
output.get(AddonBlueprint.dataRefs.addon),
|
||||
);
|
||||
return originalFactory(defineParams =>
|
||||
defineParams({
|
||||
api: techdocsAddonsApiRef,
|
||||
deps: {},
|
||||
factory: () => ({
|
||||
getAddons: () => addons,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Suspense } from 'react';
|
||||
import LibraryBooks from '@material-ui/icons/LibraryBooks';
|
||||
import {
|
||||
createFrontendPlugin,
|
||||
@@ -34,7 +35,11 @@ import {
|
||||
EntityIconLinkBlueprint,
|
||||
} from '@backstage/plugin-catalog-react/alpha';
|
||||
import { SearchResultListItemBlueprint } from '@backstage/plugin-search-react/alpha';
|
||||
import { AddonBlueprint } from '@backstage/plugin-techdocs-react/alpha';
|
||||
import {
|
||||
AddonBlueprint,
|
||||
attachTechDocsAddonComponentData,
|
||||
} from '@backstage/plugin-techdocs-react/alpha';
|
||||
import { TechDocsAddonsApiExtension, techdocsAddonsApiRef } from './addonsApi';
|
||||
import { TechDocsClient, TechDocsStorageClient } from '../client';
|
||||
import {
|
||||
rootCatalogDocsRouteRef,
|
||||
@@ -42,7 +47,6 @@ import {
|
||||
rootRouteRef,
|
||||
} from '../routes';
|
||||
import { TechDocsReaderLayout } from '../reader';
|
||||
import { attachTechDocsAddonComponentData } from '@backstage/plugin-techdocs-react/alpha';
|
||||
import {
|
||||
TechDocsAddons,
|
||||
techdocsApiRef,
|
||||
@@ -152,24 +156,37 @@ const techDocsReaderPage = PageBlueprint.makeWithOverrides({
|
||||
inputs: {
|
||||
addons: createExtensionInput([AddonBlueprint.dataRefs.addon]),
|
||||
},
|
||||
factory(originalFactory, { inputs }) {
|
||||
const addons = inputs.addons.map(output => {
|
||||
const options = output.get(AddonBlueprint.dataRefs.addon);
|
||||
const Addon = options.component;
|
||||
attachTechDocsAddonComponentData(Addon, options);
|
||||
return <Addon key={options.name} />;
|
||||
});
|
||||
factory(originalFactory, { apis, inputs }) {
|
||||
const addonsApi = apis.get(techdocsAddonsApiRef);
|
||||
|
||||
return originalFactory({
|
||||
path: '/docs/:namespace/:kind/:name',
|
||||
routeRef: rootDocsRouteRef,
|
||||
loader: async () =>
|
||||
await import('../Router').then(({ TechDocsReaderRouter }) => (
|
||||
loader: async () => {
|
||||
// Merge addons from the API with old-style direct attachments
|
||||
const apiAddons = addonsApi?.getAddons() ?? [];
|
||||
const directAddons = inputs.addons.map(output =>
|
||||
output.get(AddonBlueprint.dataRefs.addon),
|
||||
);
|
||||
const addonOptions = [...apiAddons, ...directAddons];
|
||||
|
||||
const addons = addonOptions.map(options => {
|
||||
const Addon = options.component;
|
||||
attachTechDocsAddonComponentData(Addon, options);
|
||||
return (
|
||||
<Suspense key={options.name} fallback={null}>
|
||||
<Addon />
|
||||
</Suspense>
|
||||
);
|
||||
});
|
||||
|
||||
return import('../Router').then(({ TechDocsReaderRouter }) => (
|
||||
<TechDocsReaderRouter>
|
||||
<TechDocsReaderLayout />
|
||||
<TechDocsAddons>{addons}</TechDocsAddons>
|
||||
</TechDocsReaderRouter>
|
||||
)),
|
||||
));
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -191,29 +208,41 @@ const techDocsEntityContent = EntityContentBlueprint.makeWithOverrides({
|
||||
),
|
||||
},
|
||||
factory(originalFactory, context) {
|
||||
const addonsApi = context.apis.get(techdocsAddonsApiRef);
|
||||
|
||||
return originalFactory(
|
||||
{
|
||||
path: 'docs',
|
||||
title: 'TechDocs',
|
||||
routeRef: rootCatalogDocsRouteRef,
|
||||
loader: () =>
|
||||
import('../Router').then(({ EmbeddedDocsRouter }) => {
|
||||
const addons = context.inputs.addons.map(output => {
|
||||
const options = output.get(AddonBlueprint.dataRefs.addon);
|
||||
const Addon = options.component;
|
||||
attachTechDocsAddonComponentData(Addon, options);
|
||||
return <Addon key={options.name} />;
|
||||
});
|
||||
loader: () => {
|
||||
// Merge addons from the API with old-style direct attachments
|
||||
const apiAddons = addonsApi?.getAddons() ?? [];
|
||||
const directAddons = context.inputs.addons.map(output =>
|
||||
output.get(AddonBlueprint.dataRefs.addon),
|
||||
);
|
||||
const addonOptions = [...apiAddons, ...directAddons];
|
||||
|
||||
const addons = addonOptions.map(options => {
|
||||
const Addon = options.component;
|
||||
attachTechDocsAddonComponentData(Addon, options);
|
||||
return (
|
||||
<EmbeddedDocsRouter
|
||||
emptyState={context.inputs.emptyState?.get(
|
||||
coreExtensionData.reactElement,
|
||||
)}
|
||||
>
|
||||
<TechDocsAddons>{addons}</TechDocsAddons>
|
||||
</EmbeddedDocsRouter>
|
||||
<Suspense key={options.name} fallback={null}>
|
||||
<Addon />
|
||||
</Suspense>
|
||||
);
|
||||
}),
|
||||
});
|
||||
|
||||
return import('../Router').then(({ EmbeddedDocsRouter }) => (
|
||||
<EmbeddedDocsRouter
|
||||
emptyState={context.inputs.emptyState?.get(
|
||||
coreExtensionData.reactElement,
|
||||
)}
|
||||
>
|
||||
<TechDocsAddons>{addons}</TechDocsAddons>
|
||||
</EmbeddedDocsRouter>
|
||||
));
|
||||
},
|
||||
},
|
||||
context,
|
||||
);
|
||||
@@ -244,6 +273,7 @@ export default createFrontendPlugin({
|
||||
extensions: [
|
||||
techDocsClientApi,
|
||||
techDocsStorageApi,
|
||||
TechDocsAddonsApiExtension,
|
||||
techDocsNavItem,
|
||||
techDocsPage,
|
||||
techDocsReaderPage,
|
||||
|
||||
Reference in New Issue
Block a user