plugin icons and titles

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2026-02-09 23:02:34 +01:00
parent 4b996d05d3
commit e1f22f2d15
31 changed files with 1362 additions and 89 deletions
+205 -2
View File
@@ -4,7 +4,9 @@
```ts
import { AnyRouteRefParams } from '@backstage/frontend-plugin-api';
import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
import { ExtensionDataRef } from '@backstage/frontend-plugin-api';
import { ExtensionInput } from '@backstage/frontend-plugin-api';
import { IconComponent } from '@backstage/frontend-plugin-api';
import { JSX as JSX_2 } from 'react';
import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api';
@@ -42,24 +44,225 @@ const visualizerPlugin: OverridableFrontendPlugin<
name: undefined;
config: {
path: string | undefined;
title: string | undefined;
};
configInput: {
title?: string | undefined;
path?: string | undefined;
};
output:
| ExtensionDataRef<string, 'core.routing.path', {}>
| ExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>
| ExtensionDataRef<
RouteRef<AnyRouteRefParams>,
'core.routing.ref',
{
optional: true;
}
>
| ExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>
| ExtensionDataRef<
string,
'core.title',
{
optional: true;
}
>
| ExtensionDataRef<
IconComponent,
'core.icon',
{
optional: true;
}
>;
inputs: {};
inputs: {
pages: ExtensionInput<
| ConfigurableExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>
| ConfigurableExtensionDataRef<string, 'core.routing.path', {}>
| ConfigurableExtensionDataRef<
RouteRef<AnyRouteRefParams>,
'core.routing.ref',
{
optional: true;
}
>
| ConfigurableExtensionDataRef<
string,
'core.title',
{
optional: true;
}
>,
{
singleton: false;
optional: false;
internal: false;
}
>;
};
params: {
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
title?: string;
icon?: IconComponent;
loader?: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
}>;
'page:app-visualizer/2': OverridableExtensionDefinition<{
kind: 'page';
name: '2';
config: {
path: string | undefined;
title: string | undefined;
};
configInput: {
title?: string | undefined;
path?: string | undefined;
};
output:
| ExtensionDataRef<string, 'core.routing.path', {}>
| ExtensionDataRef<
RouteRef<AnyRouteRefParams>,
'core.routing.ref',
{
optional: true;
}
>
| ExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>
| ExtensionDataRef<
string,
'core.title',
{
optional: true;
}
>
| ExtensionDataRef<
IconComponent,
'core.icon',
{
optional: true;
}
>;
inputs: {
pages: ExtensionInput<
| ConfigurableExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>
| ConfigurableExtensionDataRef<string, 'core.routing.path', {}>
| ConfigurableExtensionDataRef<
RouteRef<AnyRouteRefParams>,
'core.routing.ref',
{
optional: true;
}
>
| ConfigurableExtensionDataRef<
string,
'core.title',
{
optional: true;
}
>,
{
singleton: false;
optional: false;
internal: false;
}
>;
};
params: {
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
title?: string;
icon?: IconComponent;
loader?: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
}>;
'sub-page:app-visualizer/details': OverridableExtensionDefinition<{
kind: 'sub-page';
name: 'details';
config: {
path: string | undefined;
title: string | undefined;
};
configInput: {
title?: string | undefined;
path?: string | undefined;
};
output:
| ExtensionDataRef<string, 'core.routing.path', {}>
| ExtensionDataRef<
RouteRef<AnyRouteRefParams>,
'core.routing.ref',
{
optional: true;
}
>
| ExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>
| ExtensionDataRef<string, 'core.title', {}>;
inputs: {};
params: {
path: string;
title: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
}>;
'sub-page:app-visualizer/text': OverridableExtensionDefinition<{
kind: 'sub-page';
name: 'text';
config: {
path: string | undefined;
title: string | undefined;
};
configInput: {
title?: string | undefined;
path?: string | undefined;
};
output:
| ExtensionDataRef<string, 'core.routing.path', {}>
| ExtensionDataRef<
RouteRef<AnyRouteRefParams>,
'core.routing.ref',
{
optional: true;
}
>
| ExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>
| ExtensionDataRef<string, 'core.title', {}>;
inputs: {};
params: {
path: string;
title: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
}>;
'sub-page:app-visualizer/tree': OverridableExtensionDefinition<{
kind: 'sub-page';
name: 'tree';
config: {
path: string | undefined;
title: string | undefined;
};
configInput: {
title?: string | undefined;
path?: string | undefined;
};
output:
| ExtensionDataRef<string, 'core.routing.path', {}>
| ExtensionDataRef<
RouteRef<AnyRouteRefParams>,
'core.routing.ref',
{
optional: true;
}
>
| ExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>
| ExtensionDataRef<string, 'core.title', {}>;
inputs: {};
params: {
path: string;
title: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
+13 -11
View File
@@ -21,7 +21,7 @@ import {
PageBlueprint,
SubPageBlueprint,
} from '@backstage/frontend-plugin-api';
import { RiEyeLine as VisualizerIcon } from '@remixicon/react';
import { RiEyeLine } from '@remixicon/react';
const rootRouteRef = createRouteRef();
@@ -81,9 +81,9 @@ const appVisualizerTreePage = SubPageBlueprint.make({
routeRef: treeRouteRef,
title: 'Tree',
loader: () =>
import('./components/AppVisualizerPage/TreeVisualizer').then(
m => <m.TreeVisualizer />,
),
import('./components/AppVisualizerPage/TreeVisualizer').then(m => (
<m.TreeVisualizer />
)),
},
});
const appVisualizerDetailedPage = SubPageBlueprint.make({
@@ -94,9 +94,9 @@ const appVisualizerDetailedPage = SubPageBlueprint.make({
routeRef: detailedRouteRef,
title: 'Detailed',
loader: () =>
import('./components/AppVisualizerPage/DetailedVisualizer').then(
m => <m.DetailedVisualizer />,
),
import('./components/AppVisualizerPage/DetailedVisualizer').then(m => (
<m.DetailedVisualizer />
)),
},
});
const appVisualizerTextPage = SubPageBlueprint.make({
@@ -107,16 +107,16 @@ const appVisualizerTextPage = SubPageBlueprint.make({
routeRef: textRouteRef,
title: 'Text',
loader: () =>
import('./components/AppVisualizerPage/TextVisualizer').then(
m => <m.TextVisualizer />,
),
import('./components/AppVisualizerPage/TextVisualizer').then(m => (
<m.TextVisualizer />
)),
},
});
export const appVisualizerNavItem = NavItemBlueprint.make({
params: {
title: 'Visualizer',
icon: () => <VisualizerIcon />,
icon: () => <RiEyeLine />,
routeRef: rootRouteRef,
},
});
@@ -124,6 +124,8 @@ export const appVisualizerNavItem = NavItemBlueprint.make({
/** @public */
export const visualizerPlugin = createFrontendPlugin({
pluginId: 'app-visualizer',
title: 'App Visualizer',
icon: () => <RiEyeLine />,
info: { packageJson: () => import('../package.json') },
extensions: [
appVisualizerPage,