frontend-plugin-api,catalog-react: remove default* prefix from blueprint params

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2025-08-01 14:41:21 +02:00
parent 9ad8a1d30e
commit e4ddf22854
68 changed files with 275 additions and 176 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/frontend-plugin-api': minor
---
**BREAKING**: The `defaultPath` param of `PageBlueprint` has been renamed to `path`. This change does not affect the compatibility of extensions created with older versions of this blueprint.
+21
View File
@@ -0,0 +1,21 @@
---
'@backstage/plugin-catalog-unprocessed-entities': patch
'@backstage/frontend-defaults': patch
'@backstage/core-compat-api': patch
'@backstage/plugin-app-visualizer': patch
'@backstage/plugin-catalog-import': patch
'@backstage/plugin-catalog-graph': patch
'@backstage/plugin-notifications': patch
'@backstage/plugin-user-settings': patch
'@backstage/plugin-search-react': patch
'@backstage/plugin-kubernetes': patch
'@backstage/plugin-scaffolder': patch
'@backstage/plugin-api-docs': patch
'@backstage/plugin-devtools': patch
'@backstage/plugin-techdocs': patch
'@backstage/plugin-catalog': patch
'@backstage/plugin-search': patch
'@backstage/plugin-home': patch
---
Internal update to align with new blueprint parameter naming in the new frontend system.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-compat-api': minor
---
**BREAKING**: The `defaultPath` override of `convertLegacyPageExtension` has been renamed to `path`, in order to align with the same update that was made to the `PageBlueprint`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-react': minor
---
**BREAKING ALPHA**: The `defaultPath`, `defaultTitle`, and `defaultGroup` params of `PageBlueprint` has been renamed to `path`, `title`, and `group`. The `convertLegacyEntityContentExtension` utility has also received the same change. This change does not affect the compatibility of extensions created with older versions of this blueprint.
@@ -21,7 +21,7 @@ Frontend plugin instances are created with the `createFrontendPlugin` function,
// This creates a new extension, see "Extension Blueprints" documentation for more details
const myPage = PageBlueprint.make({
params: {
defaultPath: '/my-page',
path: '/my-page',
loader: () => import('./MyPage').then(m => <m.MyPage />),
},
});
@@ -107,7 +107,7 @@ export default plugin.withOverrides({
// Override the catalog index page with a completely custom implementation
PageBlueprint.make({
params: {
defaultPath: '/catalog',
path: '/catalog',
routeRef: plugin.routes.catalogIndex,
loader: () => import('./CustomCatalogIndexPage').then(m => <m.Page />),
},
@@ -18,7 +18,7 @@ The following is a simple example of how one might use the blueprint `make` meth
```tsx
const myPageExtension = PageBlueprint.make({
params: {
defaultPath: '/my-page',
path: '/my-page',
loader: () => import('./components/MyPage').then(m => <m.MyPage />),
},
});
@@ -44,7 +44,7 @@ const myPageExtension = PageBlueprint.makeWithOverrides({
// Call and forward the result from the original factory, providing
// the blueprint parameters as the first argument.
return originalFactory({
defaultPath: '/my-page',
path: '/my-page',
loader: () =>
import('./components/MyPage').then(m => (
// We can now access values from the factory context when providing
@@ -101,7 +101,7 @@ The following is an example of how one might create a new extension blueprint:
```tsx
export interface MyWidgetBlueprintParams {
defaultTitle: string;
title: string;
element: JSX.Element;
}
@@ -119,7 +119,7 @@ export const MyWidgetBlueprint = createExtensionBlueprint({
// Note that while this is a valid pattern, you might often want to
// return separate pieces of data instead, more on that below.
coreExtensionData.reactElement(
<MyWidgetContainer title={config.title ?? params.defaultTitle}>
<MyWidgetContainer title={config.title ?? params.title}>
{params.element}
</MyWidgetContainer>,
),
@@ -175,7 +175,7 @@ To do that, we create a new extension data reference for our widget title. This
```tsx
export interface MyWidgetBlueprintParams {
defaultTitle: string;
title: string;
element: JSX.Element;
}
@@ -194,7 +194,7 @@ export const MyWidgetBlueprint = createExtensionBlueprint({
output: [widgetTitleRef, coreExtensionData.reactElement],
factory(params: MyWidgetBlueprintParams, { config }) {
return [
widgetTitleRef(config.title ?? params.defaultTitle),
widgetTitleRef(config.title ?? params.title),
coreExtensionData.reactElement(params.element),
];
},
@@ -89,7 +89,7 @@ const exampleExtension = PageBlueprint.make({
params: {
loader: () =>
import('./components/ExamplePage').then(m => <m.ExamplePage />),
defaultPath: '/example',
path: '/example',
},
});
```
@@ -318,7 +318,7 @@ import {
const customSearchPage = PageBlueprint.make({
params: {
defaultPath: '/search',
path: '/search',
loader: () =>
import('./CustomSearchPage').then(m => <m.CustomSearchPage />),
},
@@ -47,7 +47,7 @@ import { indexRouteRef } from './routes';
const catalogIndexPage = createPageExtension({
// The `name` option is omitted because this is an index page
defaultPath: '/entities',
path: '/entities',
// highlight-next-line
routeRef: indexRouteRef,
loader: () => import('./components').then(m => <m.IndexPage />),
@@ -197,7 +197,7 @@ import {
import { indexRouteRef, createComponentExternalRouteRef } from './routes';
const catalogIndexPage = createPageExtension({
defaultPath: '/entities',
path: '/entities',
routeRef: indexRouteRef,
loader: () => import('./components').then(m => <m.IndexPage />),
});
@@ -404,7 +404,7 @@ import {
import { indexRouteRef, detailsSubRouteRef } from './routes';
const catalogIndexPage = createPageExtension({
defaultPath: '/entities',
path: '/entities',
routeRef: indexRouteRef,
loader: () => import('./components').then(m => <m.IndexPage />),
});
@@ -42,7 +42,7 @@ The conversion functions such as `convertLegacyPageExtension` will attempt to in
```ts
const convertedIndexPage = convertLegacyPageExtension(TechDocsIndexPage, {
name: 'index',
defaultPath: '/docs',
path: '/docs',
});
```
@@ -72,10 +72,10 @@ const convertedTechdocsPlugin = convertLegacyPlugin(techdocsPlugin, {
extensions: [
convertLegacyPageExtension(TechDocsIndexPage, {
name: 'index',
defaultPath: '/docs',
path: '/docs',
}),
convertLegacyPageExtension(TechDocsReaderPage, {
defaultPath: '/docs/:namespace/:kind/:name/*',
path: '/docs/:namespace/:kind/:name/*',
}),
convertLegacyEntityContentExtension(EntityTechdocsContent),
],
@@ -75,7 +75,7 @@ const examplePage = PageBlueprint.make({
routeRef: rootRouteRef,
// This is the default path of this page, but integrators are free to override it
defaultPath: '/example',
path: '/example',
// Page extensions are always dynamically loaded using React.lazy().
// All of the functionality of this page is implemented in the
@@ -198,8 +198,8 @@ import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';
// route reference if you want to be able to generate a URL that links to the content.
const exampleEntityContent = EntityContentBlueprint.make({
params: {
defaultPath: 'example',
defaultTitle: 'Example',
path: 'example',
title: 'Example',
loader: () =>
import('./components/ExampleEntityContent').then(m => (
<m.ExampleEntityContent />
@@ -119,7 +119,7 @@ const fooPage = PageBlueprint.make({
params: {
// This is the path that was previously defined in the app code.
// It's labelled as the default one because it can be changed via configuration.
defaultPath: '/foo',
path: '/foo',
// You can reuse the existing routeRef by wrapping it with convertLegacyRouteRef.
routeRef: convertLegacyRouteRef(rootRouteRef),
// these inputs usually match the props required by the component.
@@ -37,7 +37,8 @@ const examplePlugin: FrontendPlugin<
>;
inputs: {};
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
@@ -21,7 +21,7 @@ import {
export const ExamplePage = PageBlueprint.make({
params: {
defaultPath: '/example',
path: '/example',
loader: () => import('./Component').then(m => <m.Component />),
},
});
+2 -2
View File
@@ -85,10 +85,10 @@ const convertedTechdocsPlugin = convertLegacyPlugin(techdocsPlugin, {
// TODO: We likely also need a way to convert an entire <Route> tree similar to collectLegacyRoutes
convertLegacyPageExtension(TechDocsIndexPage, {
name: 'index',
defaultPath: '/docs',
path: '/docs',
}),
convertLegacyPageExtension(TechDocsReaderPage, {
defaultPath: '/docs/:namespace/:kind/:name/*',
path: '/docs/:namespace/:kind/:name/*',
}),
convertLegacyEntityContentExtension(EntityTechdocsContent),
],
@@ -58,7 +58,7 @@ function PluginInfo() {
const IndexPage = PageBlueprint.make({
name: 'index',
params: {
defaultPath: '/',
path: '/',
routeRef: indexRouteRef,
loader: async () => {
const Component = () => {
@@ -95,7 +95,7 @@ const IndexPage = PageBlueprint.make({
const Page1 = PageBlueprint.make({
name: 'page1',
params: {
defaultPath: '/page1',
path: '/page1',
routeRef: page1RouteRef,
loader: async () => {
const Component = () => {
@@ -131,7 +131,7 @@ const Page1 = PageBlueprint.make({
const ExternalPage = PageBlueprint.make({
name: 'pageX',
params: {
defaultPath: '/pageX',
path: '/pageX',
routeRef: pageXRouteRef,
loader: async () => {
const Component = () => {
+2 -1
View File
@@ -59,7 +59,8 @@ export function convertLegacyPageExtension(
LegacyExtension: ComponentType<{}>,
overrides?: {
name?: string;
defaultPath?: string;
path?: string;
defaultPath?: [Error: `Use the 'path' override instead`];
},
): ExtensionDefinition;
@@ -115,8 +115,8 @@ export function collectEntityPageContents(
name,
factory(originalFactory, { apis }) {
return originalFactory({
defaultPath: normalizeRoutePath(pageNode.path),
defaultTitle: pageNode.title,
path: normalizeRoutePath(pageNode.path),
title: pageNode.title,
filter: mergedIf && (entity => mergedIf(entity, { apis })),
loader: () => Promise.resolve(pageNode.children),
});
@@ -235,7 +235,7 @@ export function collectLegacyRoutes(
factory(originalFactory, { inputs: _inputs }) {
// todo(blam): why do we not use the inputs here?
return originalFactory({
defaultPath: normalizeRoutePath(path),
path: normalizeRoutePath(path),
routeRef: routeRef ? convertLegacyRouteRef(routeRef) : undefined,
loader: async () =>
compatWrapper(
@@ -75,7 +75,7 @@ describe('convertLegacyPageExtension', () => {
const converted = convertLegacyPageExtension(LegacyExtension, {
name: 'other',
defaultPath: '/other',
path: '/other',
});
const tester = createExtensionTester(converted);
@@ -32,7 +32,11 @@ export function convertLegacyPageExtension(
LegacyExtension: ComponentType<{}>,
overrides?: {
name?: string;
defaultPath?: string;
path?: string;
/**
* @deprecated Use the `path` param instead.
*/
defaultPath?: [Error: `Use the 'path' override instead`];
},
): ExtensionDefinition {
const element = <LegacyExtension />;
@@ -55,7 +59,7 @@ export function convertLegacyPageExtension(
return PageBlueprint.make({
name: overrides?.name ?? kebabName,
params: {
defaultPath: overrides?.defaultPath ?? `/${kebabName}`,
path: overrides?.path ?? `/${kebabName}`,
routeRef: mountPoint && convertLegacyRouteRef(mountPoint),
loader: async () => compatWrapper(element),
},
@@ -70,7 +70,7 @@ describe('convertLegacyPlugin', () => {
{
extensions: [
PageBlueprint.make({
params: { defaultPath: '/test', loader: async () => ({} as any) },
params: { path: '/test', loader: async () => ({} as any) },
}),
],
},
@@ -92,7 +92,7 @@ describe('createApp', () => {
extensions: [
PageBlueprint.make({
params: {
defaultPath: '/',
path: '/',
loader: async () => <div>First Page</div>,
},
}),
@@ -103,7 +103,7 @@ describe('createApp', () => {
extensions: [
PageBlueprint.make({
params: {
defaultPath: '/',
path: '/',
loader: async () => <div>Last Page</div>,
},
}),
@@ -146,7 +146,7 @@ describe('createApp', () => {
extensions: [
PageBlueprint.make({
params: {
defaultPath: '/',
path: '/',
loader: async () => <TestComponent />,
},
}),
@@ -177,7 +177,7 @@ describe('createApp', () => {
extensions: [
PageBlueprint.make({
params: {
defaultPath: '/',
path: '/',
loader: async () => <div>{config.getString('key')}</div>,
},
}),
@@ -289,7 +289,7 @@ describe('createApp', () => {
extensions: [
PageBlueprint.make({
params: {
defaultPath: '/',
path: '/',
loader: async () => <div>Derp</div>,
},
}),
@@ -315,7 +315,7 @@ describe('createApp', () => {
extensions: [
PageBlueprint.make({
params: {
defaultPath: '/',
path: '/',
loader: async () => {
const Component = () => {
appTreeApi = useApi(appTreeApiRef);
@@ -477,7 +477,7 @@ describe('createApp', () => {
PageBlueprint.make({
name: 'test-page',
params: {
defaultPath: '/',
path: '/',
loader: async () => <>Test Page</>,
},
}),
@@ -41,7 +41,7 @@ describe('resolveAsyncFeatures', () => {
extensions: [
PageBlueprint.make({
params: {
defaultPath: '/',
path: '/',
loader: () => new Promise(() => {}),
},
}),
@@ -79,7 +79,7 @@ describe('resolveAsyncFeatures', () => {
extensions: [
PageBlueprint.make({
params: {
defaultPath: '/',
path: '/',
loader: () => new Promise(() => {}),
},
}),
+4 -3
View File
@@ -922,7 +922,7 @@ export interface ExtensionBlueprint<
? TParamsInput
: T['params'] extends ExtensionBlueprintParamsDefiner
? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `<blueprint>.make({ params: define => define(<params>) })`'
: TParamsInput;
: T['params'];
}): ExtensionDefinition<{
kind: T['kind'];
name: string | undefined extends TName ? undefined : TName;
@@ -971,7 +971,7 @@ export interface ExtensionBlueprint<
? TParamsInput
: T['params'] extends ExtensionBlueprintParamsDefiner
? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define(<params>))`'
: TParamsInput,
: T['params'],
context?: {
config?: T['config'];
inputs?: ResolveInputValueOverrides<NonNullable<T['inputs']>>;
@@ -1546,7 +1546,8 @@ export { OpenIdConnectApi };
export const PageBlueprint: ExtensionBlueprint<{
kind: 'page';
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
@@ -34,7 +34,7 @@ describe('PageBlueprint', () => {
name: 'test-page',
params: {
loader: () => Promise.resolve(<div>Test</div>),
defaultPath: '/test',
path: '/test',
routeRef: mockRouteRef,
},
});
@@ -90,7 +90,7 @@ describe('PageBlueprint', () => {
name: 'test-page',
params: {
loader: () => Promise.resolve(<div data-testid="test">Test</div>),
defaultPath: '/test',
path: '/test',
routeRef: mockRouteRef,
},
});
@@ -123,7 +123,7 @@ describe('PageBlueprint', () => {
{inputs.cards.map(c => c.get(coreExtensionData.reactElement))}
</div>
),
defaultPath: '/test',
path: '/test',
routeRef: mockRouteRef,
});
},
@@ -37,21 +37,23 @@ export const PageBlueprint = createExtensionBlueprint({
},
},
*factory(
{
defaultPath,
loader,
routeRef,
}: {
defaultPath: string;
params: {
/**
* @deprecated Use the `path` param instead.
*/
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
},
{ config, node },
) {
yield coreExtensionData.routePath(config.path ?? defaultPath);
yield coreExtensionData.reactElement(ExtensionBoundary.lazy(node, loader));
if (routeRef) {
yield coreExtensionData.routeRef(routeRef);
yield coreExtensionData.routePath(config.path ?? params.path);
yield coreExtensionData.reactElement(
ExtensionBoundary.lazy(node, params.loader),
);
if (params.routeRef) {
yield coreExtensionData.routeRef(params.routeRef);
}
},
});
@@ -235,7 +235,7 @@ export interface ExtensionBlueprint<
? TParamsInput
: T['params'] extends ExtensionBlueprintParamsDefiner
? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `<blueprint>.make({ params: define => define(<params>) })`'
: TParamsInput;
: T['params'];
}): ExtensionDefinition<{
kind: T['kind'];
name: string | undefined extends TName ? undefined : TName;
@@ -288,7 +288,7 @@ export interface ExtensionBlueprint<
? TParamsInput
: T['params'] extends ExtensionBlueprintParamsDefiner
? 'Error: This blueprint uses advanced parameter types and requires you to pass parameters as using the following callback syntax: `originalFactory(define => define(<params>))`'
: TParamsInput,
: T['params'],
context?: {
config?: T['config'];
inputs?: ResolveInputValueOverrides<NonNullable<T['inputs']>>;
+1 -1
View File
@@ -287,7 +287,7 @@ export default createFrontendModule({
createPageExtension({
// Omitting name since we are overriding a plugin index page
// It's up to you whether to use the original default path or not, but links that are hardcoded to the default path won't work if you change it
defaultPath: '/api-docs',
path: '/api-docs',
// Associating the page with a different route ref may result in the sidebar item or external plugin route pointing to an unreachable page
routeRef: convertLegacyRouteRef(rootRoute),
// Custom page components are loaded here
+14 -7
View File
@@ -382,10 +382,13 @@ const _default: FrontendPlugin<
>;
inputs: {};
params: {
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
defaultTitle?: [Error: `Use the 'title' param instead`];
title: string;
defaultGroup?: [Error: `Use the 'group' param instead`];
group?: keyof defaultEntityContentGroups | (string & {});
loader: () => Promise<JSX.Element>;
defaultPath: string;
defaultTitle: string;
defaultGroup?: keyof defaultEntityContentGroups | (string & {});
routeRef?: RouteRef;
filter?: string | EntityPredicate | ((entity: Entity) => boolean);
};
@@ -443,10 +446,13 @@ const _default: FrontendPlugin<
>;
inputs: {};
params: {
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
defaultTitle?: [Error: `Use the 'title' param instead`];
title: string;
defaultGroup?: [Error: `Use the 'group' param instead`];
group?: keyof defaultEntityContentGroups | (string & {});
loader: () => Promise<JSX.Element>;
defaultPath: string;
defaultTitle: string;
defaultGroup?: keyof defaultEntityContentGroups | (string & {});
routeRef?: RouteRef;
filter?: string | EntityPredicate | ((entity: Entity) => boolean);
};
@@ -505,7 +511,8 @@ const _default: FrontendPlugin<
kind: 'page';
name: undefined;
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
+5 -5
View File
@@ -79,7 +79,7 @@ const apiDocsExplorerPage = PageBlueprint.makeWithOverrides({
},
factory(originalFactory, { config }) {
return originalFactory({
defaultPath: '/api-docs',
path: '/api-docs',
routeRef: convertLegacyRouteRef(rootRoute),
loader: () =>
import('./components/ApiExplorerPage').then(m =>
@@ -186,8 +186,8 @@ const apiDocsProvidingComponentsEntityCard = EntityCardBlueprint.make({
const apiDocsDefinitionEntityContent = EntityContentBlueprint.make({
name: 'definition',
params: {
defaultPath: '/definition',
defaultTitle: 'Definition',
path: '/definition',
title: 'Definition',
filter: 'kind:api',
loader: async () =>
import('./components/ApiDefinitionCard').then(m =>
@@ -205,8 +205,8 @@ const apiDocsDefinitionEntityContent = EntityContentBlueprint.make({
const apiDocsApisEntityContent = EntityContentBlueprint.make({
name: 'apis',
params: {
defaultPath: '/apis',
defaultTitle: 'APIs',
path: '/apis',
title: 'APIs',
filter: 'kind:component',
loader: async () =>
import('./components/ApisCards').then(m =>
+2 -1
View File
@@ -58,7 +58,8 @@ const visualizerPlugin: FrontendPlugin<
>;
inputs: {};
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
+1 -1
View File
@@ -26,7 +26,7 @@ const rootRouteRef = createRouteRef();
const appVisualizerPage = PageBlueprint.make({
params: {
defaultPath: '/visualizer',
path: '/visualizer',
routeRef: rootRouteRef,
loader: () =>
import('./components/AppVisualizerPage').then(m => (
+1 -1
View File
@@ -306,7 +306,7 @@ export default createFrontendModule({
extensions: [
createPageExtension({
// Omitting name since it is an index page
defaultPath: '/catalog-graph',
path: '/catalog-graph',
routeRef: convertLegacyRouteRef(catalogGraphRouteRef),
createSchemaFromZod(z => z.object({
path: z.string().default('/catalog-graph')
+2 -1
View File
@@ -189,7 +189,8 @@ const _default: FrontendPlugin<
kind: 'page';
name: undefined;
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
+1 -1
View File
@@ -75,7 +75,7 @@ const CatalogGraphPage = PageBlueprint.makeWithOverrides({
},
factory(originalFactory, { config }) {
return originalFactory({
defaultPath: '/catalog-graph',
path: '/catalog-graph',
routeRef: convertLegacyRouteRef(catalogGraphRouteRef),
loader: () =>
import('./components/CatalogGraphPage').then(m =>
+2 -1
View File
@@ -134,7 +134,8 @@ const _default: FrontendPlugin<
>;
inputs: {};
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
+1 -1
View File
@@ -42,7 +42,7 @@ export * from './translation';
// whether this type of override is typically done with an input or by overriding the entire extension.
const catalogImportPage = PageBlueprint.make({
params: {
defaultPath: '/catalog-import',
path: '/catalog-import',
routeRef: convertLegacyRouteRef(rootRouteRef),
loader: () =>
import('./components/ImportPage').then(m =>
+10 -5
View File
@@ -104,8 +104,10 @@ export function convertLegacyEntityContentExtension(
overrides?: {
name?: string;
filter?: string | EntityPredicate | ((entity: Entity) => boolean);
defaultPath?: string;
defaultTitle?: string;
path?: string;
title?: string;
defaultPath?: [Error: `Use the 'path' override instead`];
defaultTitle?: [Error: `Use the 'title' override instead`];
},
): ExtensionDefinition;
@@ -185,10 +187,13 @@ export type EntityCardType = 'summary' | 'info' | 'content';
export const EntityContentBlueprint: ExtensionBlueprint<{
kind: 'entity-content';
params: {
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
defaultTitle?: [Error: `Use the 'title' param instead`];
title: string;
defaultGroup?: [Error: `Use the 'group' param instead`];
group?: keyof typeof defaultEntityContentGroups | (string & {});
loader: () => Promise<JSX.Element>;
defaultPath: string;
defaultTitle: string;
defaultGroup?: keyof typeof defaultEntityContentGroups | (string & {});
routeRef?: RouteRef;
filter?: string | EntityPredicate | ((entity: Entity) => boolean);
};
@@ -32,8 +32,8 @@ describe('EntityContentBlueprint', () => {
const extension = EntityContentBlueprint.make({
name: 'test',
params: {
defaultPath: '/test',
defaultTitle: 'Test',
path: '/test',
title: 'Test',
loader: async () => <div>Test!</div>,
},
});
@@ -253,8 +253,8 @@ describe('EntityContentBlueprint', () => {
const extension = EntityContentBlueprint.make({
name: 'test',
params: {
defaultPath: '/test',
defaultTitle: 'Test',
path: '/test',
title: 'Test',
routeRef: mockRouteRef,
loader: async () => <div>Test!</div>,
},
@@ -277,8 +277,8 @@ describe('EntityContentBlueprint', () => {
EntityContentBlueprint.make({
name: 'test',
params: {
defaultPath: '/test',
defaultTitle: 'Test',
path: '/test',
title: 'Test',
loader: async () => <div>Test!</div>,
filter: 'test',
},
@@ -291,8 +291,8 @@ describe('EntityContentBlueprint', () => {
EntityContentBlueprint.make({
name: 'test',
params: {
defaultPath: '/test',
defaultTitle: 'Test',
path: '/test',
title: 'Test',
loader: async () => <div>Test!</div>,
},
}),
@@ -305,8 +305,8 @@ describe('EntityContentBlueprint', () => {
EntityContentBlueprint.make({
name: 'test',
params: {
defaultPath: '/test',
defaultTitle: 'Test',
path: '/test',
title: 'Test',
filter: mockFilter,
loader: async () => <div>Test!</div>,
},
@@ -328,8 +328,8 @@ describe('EntityContentBlueprint', () => {
},
factory(originalFactory, { inputs, config }) {
return originalFactory({
defaultPath: '/test',
defaultTitle: 'Test',
path: '/test',
title: 'Test',
loader: async () => (
<div data-testid="test">
config: {config.mock}
@@ -64,38 +64,45 @@ export const EntityContentBlueprint = createExtensionBlueprint({
},
},
*factory(
{
loader,
defaultPath,
defaultTitle,
defaultGroup,
filter,
routeRef,
}: {
params: {
/**
* @deprecated Use the `path` param instead.
*/
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
/**
* @deprecated Use the `path` param instead.
*/
defaultTitle?: [Error: `Use the 'title' param instead`];
title: string;
/**
* @deprecated Use the `path` param instead.
*/
defaultGroup?: [Error: `Use the 'group' param instead`];
group?: keyof typeof defaultEntityContentGroups | (string & {});
loader: () => Promise<JSX.Element>;
defaultPath: string;
defaultTitle: string;
defaultGroup?: keyof typeof defaultEntityContentGroups | (string & {});
routeRef?: RouteRef;
filter?: string | EntityPredicate | ((entity: Entity) => boolean);
},
{ node, config },
) {
const path = config.path ?? defaultPath;
const title = config.title ?? defaultTitle;
const group = config.group ?? defaultGroup;
const path = config.path ?? params.path;
const title = config.title ?? params.title;
const group = config.group ?? params.group;
yield coreExtensionData.reactElement(ExtensionBoundary.lazy(node, loader));
yield coreExtensionData.reactElement(
ExtensionBoundary.lazy(node, params.loader),
);
yield coreExtensionData.routePath(path);
yield entityContentTitleDataRef(title);
if (routeRef) {
yield coreExtensionData.routeRef(routeRef);
if (params.routeRef) {
yield coreExtensionData.routeRef(params.routeRef);
}
yield* resolveEntityFilterData(filter, config, node);
yield* resolveEntityFilterData(params.filter, config, node);
if (group) {
yield entityContentGroupDataRef(group);
@@ -82,8 +82,8 @@ describe('convertLegacyEntityContentExtension', () => {
const converted = convertLegacyEntityContentExtension(LegacyExtension, {
name: 'other',
defaultPath: '/other',
defaultTitle: 'Other',
path: '/other',
title: 'Other',
filter: 'my-filter',
});
@@ -37,8 +37,18 @@ export function convertLegacyEntityContentExtension(
overrides?: {
name?: string;
filter?: string | EntityPredicate | ((entity: Entity) => boolean);
defaultPath?: string;
defaultTitle?: string;
path?: string;
title?: string;
/**
* @deprecated Use the `path` param instead.
*/
defaultPath?: [Error: `Use the 'path' override instead`];
/**
* @deprecated Use the `path` param instead.
*/
defaultTitle?: [Error: `Use the 'title' override instead`];
},
): ExtensionDefinition {
const element = <LegacyExtension />;
@@ -77,8 +87,8 @@ export function convertLegacyEntityContentExtension(
name: overrides?.name ?? name,
params: {
filter: overrides?.filter,
defaultPath: overrides?.defaultPath ?? `/${kebabCase(infix)}`,
defaultTitle: overrides?.defaultTitle ?? startCase(infix),
path: overrides?.path ?? `/${kebabCase(infix)}`,
title: overrides?.title ?? startCase(infix),
routeRef: mountPoint && convertLegacyRouteRef(mountPoint),
loader: async () => compatWrapper(element),
},
@@ -82,7 +82,8 @@ const _default: FrontendPlugin<
>;
inputs: {};
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
@@ -51,7 +51,7 @@ export const catalogUnprocessedEntitiesApi = ApiBlueprint.make({
/** @alpha */
export const catalogUnprocessedEntitiesPage = PageBlueprint.make({
params: {
defaultPath: '/catalog-unprocessed-entities',
path: '/catalog-unprocessed-entities',
routeRef: convertLegacyRouteRef(rootRouteRef),
loader: () =>
import('../components/UnprocessedEntities').then(m =>
+10 -5
View File
@@ -893,10 +893,13 @@ const _default: FrontendPlugin<
kind: 'entity-content';
name: 'overview';
params: {
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
defaultTitle?: [Error: `Use the 'title' param instead`];
title: string;
defaultGroup?: [Error: `Use the 'group' param instead`];
group?: keyof defaultEntityContentGroups | (string & {});
loader: () => Promise<JSX.Element>;
defaultPath: string;
defaultTitle: string;
defaultGroup?: keyof defaultEntityContentGroups | (string & {});
routeRef?: RouteRef;
filter?: string | EntityPredicate | ((entity: Entity) => boolean);
};
@@ -1070,7 +1073,8 @@ const _default: FrontendPlugin<
kind: 'page';
name: undefined;
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
@@ -1190,7 +1194,8 @@ const _default: FrontendPlugin<
kind: 'page';
name: 'entity';
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
+3 -3
View File
@@ -47,9 +47,9 @@ export const catalogOverviewEntityContent =
},
factory: (originalFactory, { node, inputs }) => {
return originalFactory({
defaultPath: '/',
defaultTitle: 'Overview',
defaultGroup: 'overview',
path: '/',
title: 'Overview',
group: 'overview',
loader: async () => {
const LazyDefaultLayoutComponent = reactLazy(() =>
import('./DefaultEntityContentLayout').then(m => ({
+8 -8
View File
@@ -116,8 +116,8 @@ describe('Entity page', () => {
const overviewEntityContent = EntityContentBlueprint.make({
name: 'overview',
params: {
defaultPath: '/overview',
defaultTitle: 'Overview',
path: '/overview',
title: 'Overview',
loader: async () => <div>Mock Overview content</div>,
},
});
@@ -125,9 +125,9 @@ describe('Entity page', () => {
const techdocsEntityContent = EntityContentBlueprint.make({
name: 'techdocs',
params: {
defaultPath: '/techdocs',
defaultTitle: 'TechDocs',
defaultGroup: 'documentation',
path: '/techdocs',
title: 'TechDocs',
group: 'documentation',
loader: async () => <div>Mock TechDocs content</div>,
},
});
@@ -135,9 +135,9 @@ describe('Entity page', () => {
const apidocsEntityContent = EntityContentBlueprint.make({
name: 'apidocs',
params: {
defaultPath: '/apidocs',
defaultTitle: 'ApiDocs',
defaultGroup: 'documentation',
path: '/apidocs',
title: 'ApiDocs',
group: 'documentation',
loader: async () => <div>Mock ApiDocs content</div>,
},
});
+2 -2
View File
@@ -58,7 +58,7 @@ export const catalogPage = PageBlueprint.makeWithOverrides({
},
factory(originalFactory, { inputs, config }) {
return originalFactory({
defaultPath: '/catalog',
path: '/catalog',
routeRef: convertLegacyRouteRef(rootRouteRef),
loader: async () => {
const { BaseCatalogPage } = await import('../components/CatalogPage');
@@ -107,7 +107,7 @@ export const catalogEntityPage = PageBlueprint.makeWithOverrides({
},
factory(originalFactory, { config, inputs }) {
return originalFactory({
defaultPath: '/catalog/:namespace/:kind/:name',
path: '/catalog/:namespace/:kind/:name',
routeRef: convertLegacyRouteRef(entityRouteRef),
loader: async () => {
const { EntityLayout } = await import('./components/EntityLayout');
+2 -1
View File
@@ -82,7 +82,8 @@ const _default: FrontendPlugin<
>;
inputs: {};
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
+1 -1
View File
@@ -48,7 +48,7 @@ export const devToolsApi = ApiBlueprint.make({
/** @alpha */
export const devToolsPage = PageBlueprint.make({
params: {
defaultPath: '/devtools',
path: '/devtools',
routeRef: convertLegacyRouteRef(rootRouteRef),
loader: () =>
import('../components/DevToolsPage').then(m =>
+2 -1
View File
@@ -98,7 +98,8 @@ const _default: FrontendPlugin<
kind: 'page';
name: undefined;
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
+1 -1
View File
@@ -54,7 +54,7 @@ const homePage = PageBlueprint.makeWithOverrides({
},
factory: (originalFactory, { inputs }) => {
return originalFactory({
defaultPath: '/home',
path: '/home',
routeRef: rootRouteRef,
loader: () =>
import('./components/').then(m =>
+8 -4
View File
@@ -153,10 +153,13 @@ const _default: FrontendPlugin<
>;
inputs: {};
params: {
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
defaultTitle?: [Error: `Use the 'title' param instead`];
title: string;
defaultGroup?: [Error: `Use the 'group' param instead`];
group?: keyof defaultEntityContentGroups | (string & {});
loader: () => Promise<JSX.Element>;
defaultPath: string;
defaultTitle: string;
defaultGroup?: keyof defaultEntityContentGroups | (string & {});
routeRef?: RouteRef;
filter?: string | EntityPredicate | ((entity: Entity) => boolean);
};
@@ -182,7 +185,8 @@ const _default: FrontendPlugin<
>;
inputs: {};
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
@@ -21,9 +21,9 @@ import { isKubernetesAvailable } from '../Router';
export const entityKubernetesContent = EntityContentBlueprint.make({
name: 'kubernetes',
params: {
defaultPath: '/kubernetes',
defaultTitle: 'Kubernetes',
defaultGroup: 'deployment',
path: '/kubernetes',
title: 'Kubernetes',
group: 'deployment',
filter: isKubernetesAvailable,
loader: () =>
import('./KubernetesContentPage').then(m =>
+1 -1
View File
@@ -23,7 +23,7 @@ import { rootCatalogKubernetesRouteRef } from '../plugin';
export const kubernetesPage = PageBlueprint.make({
params: {
defaultPath: '/kubernetes',
path: '/kubernetes',
// you can reuse the existing routeRef
// by wrapping into the convertLegacyRouteRef.
routeRef: convertLegacyRouteRef(rootCatalogKubernetesRouteRef),
+2 -1
View File
@@ -60,7 +60,8 @@ const _default: FrontendPlugin<
>;
inputs: {};
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
+1 -1
View File
@@ -30,7 +30,7 @@ import { NotificationsClient, notificationsApiRef } from './api';
const page = PageBlueprint.make({
params: {
defaultPath: '/notifications',
path: '/notifications',
routeRef: convertLegacyRouteRef(rootRouteRef),
loader: () =>
import('./components/NotificationsPage').then(m => (
+2 -1
View File
@@ -231,7 +231,8 @@ const _default: FrontendPlugin<
kind: 'page';
name: undefined;
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
+1 -1
View File
@@ -46,7 +46,7 @@ export const scaffolderPage = PageBlueprint.makeWithOverrides({
);
return originalFactory({
routeRef: convertLegacyRouteRef(rootRouteRef),
defaultPath: '/create',
path: '/create',
loader: () =>
import('../components/Router/Router').then(m =>
compatWrapper(
@@ -73,7 +73,7 @@ describe('SearchFilterBlueprint', () => {
},
factory(originalFactory, { inputs }) {
return originalFactory({
defaultPath: '/',
path: '/',
loader: async () => {
const searchFilters = inputs.searchFilters.map(
t => t.get(searchFilterDataRef).component,
@@ -77,7 +77,7 @@ describe('SearchFilterResultTypeBlueprint', () => {
},
factory(originalFactory, { inputs }) {
return originalFactory({
defaultPath: '/',
path: '/',
loader: async () => {
const resultTypes = inputs.resultTypes.map(t =>
t.get(searchResultTypeDataRef),
@@ -91,7 +91,7 @@ describe('SearchResultListItemBlueprint', () => {
},
factory(originalFactory, { inputs }) {
return originalFactory({
defaultPath: '/',
path: '/',
loader: async () => {
const items = inputs.items.map(i =>
i.get(searchResultListItemDataRef),
+4 -2
View File
@@ -134,7 +134,8 @@ const _default: FrontendPlugin<
kind: 'page';
name: undefined;
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
@@ -252,7 +253,8 @@ export const searchPage: ExtensionDefinition<{
kind: 'page';
name: undefined;
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
+1 -1
View File
@@ -115,7 +115,7 @@ export const searchPage = PageBlueprint.makeWithOverrides({
},
factory(originalFactory, { config, inputs }) {
return originalFactory({
defaultPath: '/search',
path: '/search',
routeRef: convertLegacyRouteRef(rootRouteRef),
loader: async () => {
const getResultItemComponent = (result: SearchResult) => {
+10 -5
View File
@@ -176,10 +176,13 @@ const _default: FrontendPlugin<
kind: 'entity-content';
name: undefined;
params: {
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
defaultTitle?: [Error: `Use the 'title' param instead`];
title: string;
defaultGroup?: [Error: `Use the 'group' param instead`];
group?: keyof defaultEntityContentGroups | (string & {});
loader: () => Promise<JSX.Element>;
defaultPath: string;
defaultTitle: string;
defaultGroup?: keyof defaultEntityContentGroups | (string & {});
routeRef?: RouteRef;
filter?: string | EntityPredicate | ((entity: Entity) => boolean);
};
@@ -265,7 +268,8 @@ const _default: FrontendPlugin<
>;
inputs: {};
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
@@ -303,7 +307,8 @@ const _default: FrontendPlugin<
kind: 'page';
name: 'reader';
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
+4 -4
View File
@@ -137,7 +137,7 @@ export const techDocsSearchResultListItemExtension =
*/
const techDocsPage = PageBlueprint.make({
params: {
defaultPath: '/docs',
path: '/docs',
routeRef: convertLegacyRouteRef(rootRouteRef),
loader: () =>
import('../home/components/TechDocsIndexPage').then(m =>
@@ -165,7 +165,7 @@ const techDocsReaderPage = PageBlueprint.makeWithOverrides({
});
return originalFactory({
defaultPath: '/docs/:namespace/:kind/:name',
path: '/docs/:namespace/:kind/:name',
routeRef: convertLegacyRouteRef(rootDocsRouteRef),
loader: async () =>
await import('../Router').then(({ TechDocsReaderRouter }) => {
@@ -199,8 +199,8 @@ const techDocsEntityContent = EntityContentBlueprint.makeWithOverrides({
factory(originalFactory, context) {
return originalFactory(
{
defaultPath: 'docs',
defaultTitle: 'TechDocs',
path: 'docs',
title: 'TechDocs',
routeRef: convertLegacyRouteRef(rootCatalogDocsRouteRef),
loader: () =>
import('../Router').then(({ EmbeddedDocsRouter }) => {
+2 -1
View File
@@ -70,7 +70,8 @@ const _default: FrontendPlugin<
kind: 'page';
name: undefined;
params: {
defaultPath: string;
defaultPath?: [Error: `Use the 'path' param instead`];
path: string;
loader: () => Promise<JSX.Element>;
routeRef?: RouteRef;
};
+1 -1
View File
@@ -39,7 +39,7 @@ const userSettingsPage = PageBlueprint.makeWithOverrides({
},
factory(originalFactory, { inputs }) {
return originalFactory({
defaultPath: '/settings',
path: '/settings',
routeRef: convertLegacyRouteRef(settingsRouteRef),
loader: () =>
import('./components/SettingsPage').then(m =>