chore: migrate some of the catalog plugin to blueprints

Co-authored-by: Fredrik Adelöw <freben@users.noreply.github.com>
Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
blam
2024-08-14 13:06:32 +02:00
parent cb7bc2bd04
commit 1129e946b8
36 changed files with 295 additions and 115 deletions
+1
View File
@@ -90,6 +90,7 @@
"@backstage/cli": "workspace:^",
"@backstage/core-app-api": "workspace:^",
"@backstage/dev-utils": "workspace:^",
"@backstage/frontend-test-utils": "workspace:^",
"@backstage/plugin-permission-common": "workspace:^",
"@backstage/test-utils": "workspace:^",
"@testing-library/dom": "^10.0.0",
@@ -0,0 +1,102 @@
/*
* 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 React from 'react';
import { CatalogFilterBlueprint } from './CatalogFilterBlueprint';
import {
coreExtensionData,
createExtension,
createExtensionInput,
} from '@backstage/frontend-plugin-api';
import { createExtensionTester } from '@backstage/frontend-test-utils';
import { waitFor, screen } from '@testing-library/react';
describe('CatalogFilterBlueprint', () => {
it('should create an extension with sane defaults', () => {
const extension = CatalogFilterBlueprint.make({
params: {
loader: async () => <div />,
},
});
expect(extension).toMatchInlineSnapshot(`
{
"$$type": "@backstage/ExtensionDefinition",
"attachTo": {
"id": "page:catalog",
"input": "filters",
},
"configSchema": undefined,
"disabled": false,
"factory": [Function],
"inputs": {},
"kind": "catalog-filter",
"name": undefined,
"namespace": undefined,
"output": [
[Function],
],
"override": [Function],
"toString": [Function],
"version": "v2",
}
`);
});
it('should allow overrding of inputs and config', async () => {
const extension = CatalogFilterBlueprint.makeWithOverrides({
name: 'test-name',
inputs: {
mock: createExtensionInput([coreExtensionData.reactElement]),
},
config: {
schema: {
test: z => z.string(),
},
},
factory(originalFactory, { config, inputs }) {
return originalFactory({
loader: async () => (
<div data-testid="test">
config: {config.test}
<div data-testid="contents">
{inputs.mock.map(i => i.get(coreExtensionData.reactElement))}
</div>
</div>
),
});
},
});
const mockExtension = createExtension({
attachTo: { id: 'catalog-filter:test-name', input: 'mock' },
output: [coreExtensionData.reactElement],
factory() {
return [coreExtensionData.reactElement(<div>im a mock</div>)];
},
});
createExtensionTester(extension, { config: { test: 'mock test config' } })
.add(mockExtension)
.render();
await waitFor(() => {
expect(screen.getByTestId('test')).toBeInTheDocument();
expect(screen.getByTestId('test')).toHaveTextContent(
'config: mock test config',
);
expect(screen.getByTestId('contents')).toHaveTextContent('im a mock');
});
});
});
@@ -0,0 +1,44 @@
/*
* 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 React, { lazy } from 'react';
import {
ExtensionBoundary,
coreExtensionData,
createExtensionBlueprint,
} from '@backstage/frontend-plugin-api';
/**
* Creates Catalog Filter Extensions
* @alpha
*/
export const CatalogFilterBlueprint = createExtensionBlueprint({
kind: 'catalog-filter',
attachTo: { id: 'page:catalog', input: 'filters' },
output: [coreExtensionData.reactElement],
factory(params: { loader: () => Promise<JSX.Element> }, { node }) {
const ExtensionComponent = lazy(() =>
params.loader().then(element => ({ default: () => element })),
);
return [
coreExtensionData.reactElement(
<ExtensionBoundary node={node}>
<ExtensionComponent />
</ExtensionBoundary>,
),
];
},
});
@@ -1,5 +1,5 @@
/*
* Copyright 2023 The Backstage Authors
* 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.
@@ -13,8 +13,4 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './alpha/index';
export { default } from './alpha/index';
export { catalogTranslationRef } from './translation';
export * from './translation';
export { CatalogFilterBlueprint } from './CatalogFilterBlueprint';
@@ -23,7 +23,10 @@ import {
createExtension,
} from '@backstage/frontend-plugin-api';
/** @alpha */
/**
* @alpha
* @deprecated Use {@link CatalogFilterExtensionBlueprint} instead
*/
export function createCatalogFilterExtension<
TInputs extends AnyExtensionInputMap,
TConfig,
+80 -60
View File
@@ -15,96 +15,116 @@
*/
import React from 'react';
import { createEntityCardExtension } from '@backstage/plugin-catalog-react/alpha';
import { EntityCardBlueprint } from '@backstage/plugin-catalog-react/alpha';
import { compatWrapper } from '@backstage/core-compat-api';
export const catalogAboutEntityCard = createEntityCardExtension({
export const catalogAboutEntityCard = EntityCardBlueprint.make({
name: 'about',
loader: async () =>
import('../components/AboutCard').then(m =>
compatWrapper(<m.AboutCard variant="gridItem" />),
),
params: {
loader: async () =>
import('../components/AboutCard').then(m =>
compatWrapper(<m.AboutCard variant="gridItem" />),
),
},
});
export const catalogLinksEntityCard = createEntityCardExtension({
export const catalogLinksEntityCard = EntityCardBlueprint.make({
name: 'links',
filter: 'has:links',
loader: async () =>
import('../components/EntityLinksCard').then(m =>
compatWrapper(<m.EntityLinksCard variant="gridItem" />),
),
params: {
filter: 'has:links',
loader: async () =>
import('../components/EntityLinksCard').then(m =>
compatWrapper(<m.EntityLinksCard variant="gridItem" />),
),
},
});
export const catalogLabelsEntityCard = createEntityCardExtension({
export const catalogLabelsEntityCard = EntityCardBlueprint.make({
name: 'labels',
filter: 'has:labels',
loader: async () =>
import('../components/EntityLabelsCard').then(m =>
compatWrapper(<m.EntityLabelsCard variant="gridItem" />),
),
params: {
filter: 'has:labels',
loader: async () =>
import('../components/EntityLabelsCard').then(m =>
compatWrapper(<m.EntityLabelsCard variant="gridItem" />),
),
},
});
export const catalogDependsOnComponentsEntityCard = createEntityCardExtension({
export const catalogDependsOnComponentsEntityCard = EntityCardBlueprint.make({
name: 'depends-on-components',
filter: 'kind:component',
loader: async () =>
import('../components/DependsOnComponentsCard').then(m =>
compatWrapper(<m.DependsOnComponentsCard variant="gridItem" />),
),
params: {
filter: 'kind:component',
loader: async () =>
import('../components/DependsOnComponentsCard').then(m =>
compatWrapper(<m.DependsOnComponentsCard variant="gridItem" />),
),
},
});
export const catalogDependsOnResourcesEntityCard = createEntityCardExtension({
export const catalogDependsOnResourcesEntityCard = EntityCardBlueprint.make({
name: 'depends-on-resources',
filter: 'kind:component',
loader: async () =>
import('../components/DependsOnResourcesCard').then(m =>
compatWrapper(<m.DependsOnResourcesCard variant="gridItem" />),
),
params: {
filter: 'kind:component',
loader: async () =>
import('../components/DependsOnResourcesCard').then(m =>
compatWrapper(<m.DependsOnResourcesCard variant="gridItem" />),
),
},
});
export const catalogHasComponentsEntityCard = createEntityCardExtension({
export const catalogHasComponentsEntityCard = EntityCardBlueprint.make({
name: 'has-components',
filter: 'kind:system',
loader: async () =>
import('../components/HasComponentsCard').then(m =>
compatWrapper(<m.HasComponentsCard variant="gridItem" />),
),
params: {
filter: 'kind:system',
loader: async () =>
import('../components/HasComponentsCard').then(m =>
compatWrapper(<m.HasComponentsCard variant="gridItem" />),
),
},
});
export const catalogHasResourcesEntityCard = createEntityCardExtension({
export const catalogHasResourcesEntityCard = EntityCardBlueprint.make({
name: 'has-resources',
filter: 'kind:system',
loader: async () =>
import('../components/HasResourcesCard').then(m =>
compatWrapper(<m.HasResourcesCard variant="gridItem" />),
),
params: {
filter: 'kind:system',
loader: async () =>
import('../components/HasResourcesCard').then(m =>
compatWrapper(<m.HasResourcesCard variant="gridItem" />),
),
},
});
export const catalogHasSubcomponentsEntityCard = createEntityCardExtension({
export const catalogHasSubcomponentsEntityCard = EntityCardBlueprint.make({
name: 'has-subcomponents',
filter: 'kind:component',
loader: async () =>
import('../components/HasSubcomponentsCard').then(m =>
compatWrapper(<m.HasSubcomponentsCard variant="gridItem" />),
),
params: {
filter: 'kind:component',
loader: async () =>
import('../components/HasSubcomponentsCard').then(m =>
compatWrapper(<m.HasSubcomponentsCard variant="gridItem" />),
),
},
});
export const catalogHasSubdomainsEntityCard = createEntityCardExtension({
export const catalogHasSubdomainsEntityCard = EntityCardBlueprint.make({
name: 'has-subdomains',
filter: 'kind:domain',
loader: async () =>
import('../components/HasSubdomainsCard').then(m =>
compatWrapper(<m.HasSubdomainsCard variant="gridItem" />),
),
params: {
filter: 'kind:domain',
loader: async () =>
import('../components/HasSubdomainsCard').then(m =>
compatWrapper(<m.HasSubdomainsCard variant="gridItem" />),
),
},
});
export const catalogHasSystemsEntityCard = createEntityCardExtension({
export const catalogHasSystemsEntityCard = EntityCardBlueprint.make({
name: 'has-systems',
filter: 'kind:domain',
loader: async () =>
import('../components/HasSystemsCard').then(m =>
compatWrapper(<m.HasSystemsCard variant="gridItem" />),
),
params: {
filter: 'kind:domain',
loader: async () =>
import('../components/HasSystemsCard').then(m =>
compatWrapper(<m.HasSystemsCard variant="gridItem" />),
),
},
});
export default [
+32 -21
View File
@@ -19,27 +19,38 @@ import {
coreExtensionData,
createExtensionInput,
} from '@backstage/frontend-plugin-api';
import {
createEntityContentExtension,
catalogExtensionData,
} from '@backstage/plugin-catalog-react/alpha';
import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';
export const catalogOverviewEntityContent = createEntityContentExtension({
name: 'overview',
defaultPath: '/',
defaultTitle: 'Overview',
disabled: false,
inputs: {
cards: createExtensionInput({
element: coreExtensionData.reactElement,
filterFunction: catalogExtensionData.entityFilterFunction.optional(),
filterExpression: catalogExtensionData.entityFilterExpression.optional(),
}),
},
loader: async ({ inputs }) =>
import('./EntityOverviewPage').then(m => (
<m.EntityOverviewPage cards={inputs.cards.map(c => c.output)} />
)),
});
export const catalogOverviewEntityContent =
EntityContentBlueprint.makeWithOverrides({
name: 'overview',
inputs: {
cards: createExtensionInput([
coreExtensionData.reactElement,
EntityContentBlueprint.dataRefs.filterFunction.optional(),
EntityContentBlueprint.dataRefs.filterExpression.optional(),
]),
},
factory: (originalFactory, { inputs }) => {
return originalFactory({
defaultPath: '/',
defaultTitle: 'Overview',
loader: async () =>
import('./EntityOverviewPage').then(m => (
<m.EntityOverviewPage
cards={inputs.cards.map(c => ({
element: c.get(coreExtensionData.reactElement),
filterFunction: c.get(
EntityContentBlueprint.dataRefs.filterFunction,
),
filterExpression: c.get(
EntityContentBlueprint.dataRefs.filterExpression,
),
}))}
/>
)),
});
},
});
export default [catalogOverviewEntityContent];
+3
View File
@@ -16,3 +16,6 @@
export { default } from './plugin';
export { createCatalogFilterExtension } from './createCatalogFilterExtension';
export * from './blueprints';
export * from './translation';
@@ -64,7 +64,7 @@ import { catalogEntityRefreshPermission } from '@backstage/plugin-catalog-common
import { useSourceTemplateCompoundEntityRef } from './hooks';
import { taskCreatePermission } from '@backstage/plugin-scaffolder-common/alpha';
import { usePermission } from '@backstage/plugin-permission-react';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
const TECHDOCS_ANNOTATION = 'backstage.io/techdocs-ref';
@@ -33,7 +33,7 @@ import React from 'react';
import { AboutField } from './AboutField';
import { LinksGridList } from '../EntityLinksCard/LinksGridList';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
const useStyles = makeStyles({
description: {
@@ -33,7 +33,7 @@ import {
import React, { ReactNode } from 'react';
import { createComponentRouteRef } from '../../routes';
import { CatalogTable, CatalogTableRow } from '../CatalogTable';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
import { CatalogTableColumnsFunc } from '../CatalogTable/types';
@@ -27,7 +27,7 @@ import {
ResultHighlight,
} from '@backstage/plugin-search-common';
import { HighlightedSearchResultText } from '@backstage/plugin-search-react';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/frontend-plugin-api';
const useStyles = makeStyles(
@@ -49,7 +49,7 @@ import { CatalogTableColumnsFunc, CatalogTableRow } from './types';
import { PaginatedCatalogTable } from './PaginatedCatalogTable';
import { defaultCatalogTableColumnsFunc } from './defaultCatalogTableColumnsFunc';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
/**
* Props for {@link CatalogTable}.
@@ -30,7 +30,7 @@ import {
componentEntityHelpLink,
RelatedEntitiesCard,
} from '../RelatedEntitiesCard';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
/** @public */
@@ -27,7 +27,7 @@ import {
componentEntityHelpLink,
RelatedEntitiesCard,
} from '../RelatedEntitiesCard';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
/** @public */
@@ -27,7 +27,7 @@ import {
RelatedEntitiesCard,
resourceEntityColumns,
} from '../RelatedEntitiesCard';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
/** @public */
@@ -33,7 +33,7 @@ import { catalogEntityDeletePermission } from '@backstage/plugin-catalog-common/
import { UnregisterEntity, UnregisterEntityOptions } from './UnregisterEntity';
import { useApi, alertApiRef } from '@backstage/core-plugin-api';
import useCopyToClipboard from 'react-use/esm/useCopyToClipboard';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
/** @public */
@@ -19,7 +19,7 @@ import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import MenuItem from '@material-ui/core/MenuItem';
import CancelIcon from '@material-ui/icons/Cancel';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
type VisibleType = 'visible' | 'hidden' | 'disable';
@@ -25,7 +25,7 @@ import {
import { EntityLabelsEmptyState } from './EntityLabelsEmptyState';
import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
/** @public */
@@ -19,7 +19,7 @@ import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
import React from 'react';
import { CodeSnippet } from '@backstage/core-components';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
const ENTITY_YAML = `metadata:
@@ -53,7 +53,7 @@ import React, { useEffect, useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { EntityContextMenu } from '../EntityContextMenu/EntityContextMenu';
import { rootRouteRef, unregisterRedirectRouteRef } from '../../routes';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
/** @public */
@@ -23,7 +23,7 @@ import { ColumnBreakpoints } from './types';
import { IconComponent, useApp } from '@backstage/core-plugin-api';
import { InfoCard, InfoCardVariants } from '@backstage/core-components';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
/** @public */
export interface EntityLinksCardProps {
@@ -20,7 +20,7 @@ import { makeStyles } from '@material-ui/core/styles';
import React from 'react';
import { CodeSnippet } from '@backstage/core-components';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
const ENTITY_YAML = `metadata:
name: example
@@ -20,7 +20,7 @@ import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
import { Illo } from './Illo';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
const useStyles = makeStyles(theme => ({
@@ -23,7 +23,7 @@ import DialogTitle from '@material-ui/core/DialogTitle';
import React, { useState } from 'react';
import { alertApiRef, useApi } from '@backstage/core-plugin-api';
import { assertError } from '@backstage/errors';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
interface DeleteEntityDialogProps {
@@ -22,7 +22,7 @@ import { useNavigate } from 'react-router-dom';
import { DeleteEntityDialog } from './DeleteEntityDialog';
import { useRouteRef } from '@backstage/core-plugin-api';
import { rootRouteRef } from '../../routes';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
/**
@@ -31,7 +31,7 @@ import {
import { useApi, ApiHolder } from '@backstage/core-plugin-api';
import useAsync from 'react-use/esm/useAsync';
import { SerializedError } from '@backstage/errors';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
const errorFilter = (i: EntityStatusItem) =>
@@ -26,7 +26,7 @@ import useAsync from 'react-use/esm/useAsync';
import Box from '@material-ui/core/Box';
import { ResponseErrorPanel } from '@backstage/core-components';
import { useApi, ApiHolder } from '@backstage/core-plugin-api';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
async function getRelationWarnings(entity: Entity, catalogApi: CatalogApi) {
@@ -27,7 +27,7 @@ import {
componentEntityHelpLink,
RelatedEntitiesCard,
} from '../RelatedEntitiesCard';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
/** @public */
@@ -27,7 +27,7 @@ import {
resourceEntityColumns,
resourceEntityHelpLink,
} from '../RelatedEntitiesCard';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
/** @public */
@@ -26,7 +26,7 @@ import {
componentEntityColumns,
RelatedEntitiesCard,
} from '../RelatedEntitiesCard';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
/** @public */
@@ -22,7 +22,7 @@ import {
componentEntityColumns,
RelatedEntitiesCard,
} from '../RelatedEntitiesCard';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
/** @public */
@@ -27,7 +27,7 @@ import {
systemEntityColumns,
systemEntityHelpLink,
} from '../RelatedEntitiesCard';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
/** @public */
@@ -42,7 +42,7 @@ import {
systemEntityColumns,
systemEntityHelpLink,
} from './presets';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
/** @public */
@@ -46,7 +46,7 @@ import {
} from '@backstage/core-components';
import { useApi, useRouteRef } from '@backstage/core-plugin-api';
import { catalogTranslationRef } from '../../translation';
import { catalogTranslationRef } from '../../alpha/translation';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
/** @public */