app-next: add custom plugin info example

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2025-05-15 11:56:20 +02:00
parent fa5650cc80
commit 32a64e999e
4 changed files with 92 additions and 0 deletions
+14
View File
@@ -8,6 +8,20 @@ app:
catalog.createComponent: catalog-import.importPage
org.catalogIndex: catalog.catalogIndex
pluginOverrides:
- match:
pluginId: pages
info:
description: 'This description was overridden in packages/app-next/app-config.yaml'
- match:
pluginId: /^catalog(-.*)?$/
info:
ownerEntityRefs: [cubic-belugas]
- match:
packageName: '@backstage/plugin-scaffolder'
info:
ownerEntityRefs: [cubic-belugas]
extensions:
# - apis.plugin.graphiql.browse.gitlab: true
# - graphiql-endpoint:graphiql/gitlab: true
+2
View File
@@ -43,6 +43,7 @@ import kubernetesPlugin from '@backstage/plugin-kubernetes/alpha';
import { convertLegacyPlugin } from '@backstage/core-compat-api';
import { convertLegacyPageExtension } from '@backstage/core-compat-api';
import { convertLegacyEntityContentExtension } from '@backstage/plugin-catalog-react/alpha';
import { pluginInfoResolver } from './pluginInfoResolver';
/*
@@ -132,6 +133,7 @@ const app = createApp({
customHomePageModule,
...collectedLegacyPlugins,
],
pluginInfoResolver,
/* Handled through config instead */
// bindRoutes({ bind }) {
// bind(pagesPlugin.externalRoutes, { pageX: pagesPlugin.routes.pageX });
@@ -21,7 +21,10 @@ import {
createExternalRouteRef,
useRouteRef,
PageBlueprint,
FrontendPluginInfo,
useAppNode,
} from '@backstage/frontend-plugin-api';
import { useEffect, useState } from 'react';
import { Route, Routes } from 'react-router-dom';
const indexRouteRef = createRouteRef();
@@ -36,6 +39,22 @@ export const pageXRouteRef = createRouteRef();
// path: '/page2',
// });
function PluginInfo() {
const node = useAppNode();
const [info, setInfo] = useState<FrontendPluginInfo | undefined>(undefined);
useEffect(() => {
node?.spec.source?.info().then(setInfo);
}, [node]);
return (
<div>
<h3>Plugin Info</h3>
<pre>{JSON.stringify(info, null, 2)}</pre>
</div>
);
}
const IndexPage = PageBlueprint.make({
name: 'index',
params: {
@@ -64,6 +83,7 @@ const IndexPage = PageBlueprint.make({
<div>
<Link to="/settings">Settings</Link>
</div>
<PluginInfo />
</div>
);
};
@@ -139,6 +159,10 @@ export const pagesPlugin = createFrontendPlugin({
// // OR
// // 'page1'
// },
info: {
packageJson: () => import('../../package.json'),
manifest: () => import('../../catalog-info.yaml'),
},
routes: {
page1: page1RouteRef,
pageX: pageXRouteRef,
@@ -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 { Entity } from '@backstage/catalog-model';
import { FrontendPluginInfoResolver } from '@backstage/frontend-app-api';
// This file shows an example of what it looks like to extend the plugin info
// resolution with custom logic and fields. In this case we're reading the
// `spec.type` field from the plugin manifest (catalog-info.yaml).
//
// Using module augmentation we extend the `FrontendPluginInfo` interface to
// include our custom fields. This makes these fields available throughout our project.
declare module '@backstage/frontend-plugin-api' {
export interface FrontendPluginInfo {
/**
* **DO NOT USE**
*
* This field is added in the example app to showcase module augmentation
* for extending the plugin info in internal apps. It only exists as an
* example in this project.
*/
exampleFieldDoNotUse?: string;
}
}
export const pluginInfoResolver: FrontendPluginInfoResolver = async ctx => {
const manifest = (await ctx.manifest?.()) as Entity | undefined;
const { info: defaultInfo } = await ctx.defaultResolver({
packageJson: await ctx.packageJson(),
manifest: manifest,
});
return {
info: {
...defaultInfo,
exampleFieldDoNotUse: manifest?.spec?.type?.toString(),
},
};
};