feat(devtools): add extension to allow providing tabs
Signed-off-by: secustor <sebastian@poxhofer.at>
This commit is contained in:
@@ -185,5 +185,8 @@
|
||||
}
|
||||
},
|
||||
"tsConfig": "./tsconfig.json"
|
||||
},
|
||||
"volta": {
|
||||
"node": "22.19.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
"@backstage/plugin-catalog-import": "workspace:^",
|
||||
"@backstage/plugin-catalog-react": "workspace:^",
|
||||
"@backstage/plugin-catalog-unprocessed-entities": "workspace:^",
|
||||
"@backstage/plugin-devtools": "workspace:^",
|
||||
"@backstage/plugin-home": "workspace:^",
|
||||
"@backstage/plugin-kubernetes": "workspace:^",
|
||||
"@backstage/plugin-kubernetes-cluster": "workspace:^",
|
||||
|
||||
@@ -45,6 +45,8 @@ import { convertLegacyPageExtension } from '@backstage/core-compat-api';
|
||||
import { convertLegacyEntityContentExtension } from '@backstage/plugin-catalog-react/alpha';
|
||||
import { pluginInfoResolver } from './pluginInfoResolver';
|
||||
import { appModuleNav } from './modules/appModuleNav';
|
||||
import devtoolsPlugin from '@backstage/plugin-devtools/alpha';
|
||||
import { unprocessedEntitiesDevToolsRoute } from '@backstage/plugin-catalog-unprocessed-entities/alpha';
|
||||
|
||||
/*
|
||||
|
||||
@@ -113,7 +115,7 @@ const customHomePageModule = createFrontendModule({
|
||||
|
||||
const notFoundErrorPageModule = createFrontendModule({
|
||||
pluginId: 'app',
|
||||
extensions: [notFoundErrorPage],
|
||||
extensions: [notFoundErrorPage, unprocessedEntitiesDevToolsRoute],
|
||||
});
|
||||
|
||||
const collectedLegacyPlugins = convertLegacyAppRoot(
|
||||
@@ -133,6 +135,7 @@ const app = createApp({
|
||||
notFoundErrorPageModule,
|
||||
appModuleNav,
|
||||
customHomePageModule,
|
||||
devtoolsPlugin,
|
||||
...collectedLegacyPlugins,
|
||||
],
|
||||
advanced: {
|
||||
|
||||
@@ -71,5 +71,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^"
|
||||
},
|
||||
"volta": {
|
||||
"node": "22.19.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@backstage/frontend-plugin-api": "workspace:^",
|
||||
"@backstage/plugin-devtools": "workspace:^",
|
||||
"@material-ui/core": "^4.9.13",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "^4.0.0-alpha.60",
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2024 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 { DevToolsRouteBlueprint } from '@backstage/plugin-devtools/alpha';
|
||||
|
||||
/**
|
||||
* DevTools route extension for catalog unprocessed entities
|
||||
* This demonstrates how to create extensions at the app level using the new DevTools extension system
|
||||
*/
|
||||
export const unprocessedEntitiesDevToolsRoute = DevToolsRouteBlueprint.make({
|
||||
params: {
|
||||
path: 'unprocessed-entities',
|
||||
title: 'Unprocessed Entities',
|
||||
loader: () =>
|
||||
import('../components/UnprocessedEntities').then(m => ({
|
||||
default: m.UnprocessedEntitiesContent,
|
||||
})),
|
||||
},
|
||||
});
|
||||
@@ -15,3 +15,4 @@
|
||||
*/
|
||||
|
||||
export { default } from './plugin';
|
||||
export { unprocessedEntitiesDevToolsRoute } from './devToolsRoute';
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2024 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 { createExtensionBlueprint } from '@backstage/frontend-plugin-api';
|
||||
import { devToolsRouteDataRef } from './devToolsRouteDataRef';
|
||||
import { lazy, Suspense, JSX } from 'react';
|
||||
|
||||
/**
|
||||
* Parameters for creating a DevTools route extension
|
||||
* @alpha
|
||||
*/
|
||||
export interface DevToolsRouteBlueprintParams {
|
||||
path: string;
|
||||
title: string;
|
||||
loader: () => Promise<{ default: () => JSX.Element }> | (() => JSX.Element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension blueprint for creating DevTools routes
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* const myDevToolsRoute = DevToolsRouteBlueprint.make({
|
||||
* params: {
|
||||
* path: 'my-feature',
|
||||
* title: 'My Feature',
|
||||
* loader: () => import('./MyContent').then(m => ({ default: m.MyContent }))
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
export const DevToolsRouteBlueprint = createExtensionBlueprint({
|
||||
kind: 'devtools-route',
|
||||
attachTo: { id: 'page:devtools', input: 'routes' },
|
||||
output: [devToolsRouteDataRef],
|
||||
factory(params: DevToolsRouteBlueprintParams) {
|
||||
// Handle both sync and async component loading
|
||||
const Component = typeof params.loader === 'function'
|
||||
? (() => {
|
||||
const result = params.loader();
|
||||
if (result instanceof Promise) {
|
||||
// Create a lazy component for async loading
|
||||
return lazy(() => result);
|
||||
}
|
||||
// Direct component function
|
||||
return result;
|
||||
|
||||
})()
|
||||
: params.loader;
|
||||
|
||||
const children = typeof Component === 'function'
|
||||
? <Suspense fallback={<div>Loading...</div>}><Component /></Suspense>
|
||||
: Component;
|
||||
|
||||
return [
|
||||
devToolsRouteDataRef({
|
||||
path: params.path,
|
||||
title: params.title,
|
||||
children,
|
||||
}),
|
||||
];
|
||||
},
|
||||
dataRefs: {
|
||||
route: devToolsRouteDataRef,
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2024 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 { createExtensionDataRef } from '@backstage/frontend-plugin-api';
|
||||
import { JSX } from 'react';
|
||||
|
||||
/**
|
||||
* Represents a DevTools route that can be contributed by extensions
|
||||
* @alpha
|
||||
*/
|
||||
export interface DevToolsRouteData {
|
||||
path: string;
|
||||
title: string;
|
||||
children: JSX.Element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension data reference for DevTools routes
|
||||
* @alpha
|
||||
*/
|
||||
export const devToolsRouteDataRef = createExtensionDataRef<DevToolsRouteData>()
|
||||
.with({
|
||||
id: 'devtools.route',
|
||||
});
|
||||
@@ -15,3 +15,7 @@
|
||||
*/
|
||||
|
||||
export { default } from './plugin';
|
||||
export { DevToolsRouteBlueprint } from './devToolsRouteBlueprint';
|
||||
export { devToolsRouteDataRef } from './devToolsRouteDataRef';
|
||||
export type { DevToolsRouteData } from './devToolsRouteDataRef';
|
||||
export type { DevToolsRouteBlueprintParams } from './devToolsRouteBlueprint';
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
ApiBlueprint,
|
||||
PageBlueprint,
|
||||
NavItemBlueprint,
|
||||
createExtensionInput,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
|
||||
import { devToolsApiRef, DevToolsClient } from '../api';
|
||||
@@ -30,6 +31,7 @@ import {
|
||||
} from '@backstage/core-compat-api';
|
||||
import BuildIcon from '@material-ui/icons/Build';
|
||||
import { rootRouteRef } from '../routes';
|
||||
import { devToolsRouteDataRef } from './devToolsRouteDataRef';
|
||||
|
||||
/** @alpha */
|
||||
export const devToolsApi = ApiBlueprint.make({
|
||||
@@ -46,14 +48,21 @@ export const devToolsApi = ApiBlueprint.make({
|
||||
});
|
||||
|
||||
/** @alpha */
|
||||
export const devToolsPage = PageBlueprint.make({
|
||||
params: {
|
||||
path: '/devtools',
|
||||
routeRef: convertLegacyRouteRef(rootRouteRef),
|
||||
loader: () =>
|
||||
import('../components/DevToolsPage').then(m =>
|
||||
compatWrapper(<m.DevToolsPage />),
|
||||
),
|
||||
export const devToolsPage = PageBlueprint.makeWithOverrides({
|
||||
inputs: {
|
||||
routes: createExtensionInput([devToolsRouteDataRef], {
|
||||
optional: true,
|
||||
}),
|
||||
},
|
||||
factory(originalFactory, { inputs }) {
|
||||
return originalFactory({
|
||||
path: '/devtools',
|
||||
routeRef: convertLegacyRouteRef(rootRouteRef),
|
||||
loader: () =>
|
||||
import('../components/DevToolsPage').then(m =>
|
||||
compatWrapper(<m.DevToolsPage extensionRoutes={inputs.routes?.map(route => route.get(devToolsRouteDataRef))} />),
|
||||
),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -23,9 +23,14 @@ import { ConfigContent } from '../Content/ConfigContent';
|
||||
import { DevToolsLayout } from '../DevToolsLayout';
|
||||
import { InfoContent } from '../Content/InfoContent';
|
||||
import { RequirePermission } from '@backstage/plugin-permission-react';
|
||||
import { DevToolsRouteData } from '../../alpha/devToolsRouteDataRef';
|
||||
|
||||
export interface DefaultDevToolsPageProps {
|
||||
extensionRoutes?: DevToolsRouteData[];
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export const DefaultDevToolsPage = () => (
|
||||
export const DefaultDevToolsPage = ({ extensionRoutes }: DefaultDevToolsPageProps) => (
|
||||
<DevToolsLayout>
|
||||
<DevToolsLayout.Route path="info" title="Info">
|
||||
<RequirePermission permission={devToolsInfoReadPermission}>
|
||||
@@ -37,5 +42,14 @@ export const DefaultDevToolsPage = () => (
|
||||
<ConfigContent />
|
||||
</RequirePermission>
|
||||
</DevToolsLayout.Route>
|
||||
{extensionRoutes?.map((route, index) => (
|
||||
<DevToolsLayout.Route
|
||||
key={`extension-${route.path}-${index}`}
|
||||
path={route.path}
|
||||
title={route.title}
|
||||
>
|
||||
{route.children}
|
||||
</DevToolsLayout.Route>
|
||||
))}
|
||||
</DevToolsLayout>
|
||||
);
|
||||
|
||||
@@ -16,9 +16,14 @@
|
||||
|
||||
import { useOutlet } from 'react-router-dom';
|
||||
import { DefaultDevToolsPage } from '../DefaultDevToolsPage';
|
||||
import { DevToolsRouteData } from '../../alpha/devToolsRouteDataRef';
|
||||
|
||||
export const DevToolsPage = () => {
|
||||
export interface DevToolsPageProps {
|
||||
extensionRoutes?: DevToolsRouteData[];
|
||||
}
|
||||
|
||||
export const DevToolsPage = ({ extensionRoutes }: DevToolsPageProps) => {
|
||||
const outlet = useOutlet();
|
||||
|
||||
return <>{outlet || <DefaultDevToolsPage />}</>;
|
||||
return <>{outlet || <DefaultDevToolsPage extensionRoutes={extensionRoutes} />}</>;
|
||||
};
|
||||
|
||||
@@ -4938,6 +4938,7 @@ __metadata:
|
||||
"@backstage/dev-utils": "workspace:^"
|
||||
"@backstage/errors": "workspace:^"
|
||||
"@backstage/frontend-plugin-api": "workspace:^"
|
||||
"@backstage/plugin-devtools": "workspace:^"
|
||||
"@material-ui/core": "npm:^4.9.13"
|
||||
"@material-ui/icons": "npm:^4.9.1"
|
||||
"@material-ui/lab": "npm:^4.0.0-alpha.60"
|
||||
@@ -29922,6 +29923,7 @@ __metadata:
|
||||
"@backstage/plugin-catalog-import": "workspace:^"
|
||||
"@backstage/plugin-catalog-react": "workspace:^"
|
||||
"@backstage/plugin-catalog-unprocessed-entities": "workspace:^"
|
||||
"@backstage/plugin-devtools": "workspace:^"
|
||||
"@backstage/plugin-home": "workspace:^"
|
||||
"@backstage/plugin-kubernetes": "workspace:^"
|
||||
"@backstage/plugin-kubernetes-cluster": "workspace:^"
|
||||
|
||||
Reference in New Issue
Block a user