diff --git a/.changeset/fast-bears-lick.md b/.changeset/fast-bears-lick.md new file mode 100644 index 0000000000..8e0dc8e60b --- /dev/null +++ b/.changeset/fast-bears-lick.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Migrate catalog entity cards to new frontend system extension format. diff --git a/plugins/catalog/src/alpha/apis.tsx b/plugins/catalog/src/alpha/apis.tsx new file mode 100644 index 0000000000..a887a33a04 --- /dev/null +++ b/plugins/catalog/src/alpha/apis.tsx @@ -0,0 +1,51 @@ +/* + * Copyright 2023 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 { + createApiFactory, + discoveryApiRef, + fetchApiRef, + storageApiRef, +} from '@backstage/core-plugin-api'; +import { CatalogClient } from '@backstage/catalog-client'; +import { createApiExtension } from '@backstage/frontend-plugin-api'; +import { + catalogApiRef, + starredEntitiesApiRef, +} from '@backstage/plugin-catalog-react'; +import { DefaultStarredEntitiesApi } from '../apis'; + +export const CatalogApi = createApiExtension({ + factory: createApiFactory({ + api: catalogApiRef, + deps: { + discoveryApi: discoveryApiRef, + fetchApi: fetchApiRef, + }, + factory: ({ discoveryApi, fetchApi }) => + new CatalogClient({ discoveryApi, fetchApi }), + }), +}); + +export const StarredEntitiesApi = createApiExtension({ + factory: createApiFactory({ + api: starredEntitiesApiRef, + deps: { storageApi: storageApiRef }, + factory: ({ storageApi }) => new DefaultStarredEntitiesApi({ storageApi }), + }), +}); + +export default [CatalogApi, StarredEntitiesApi]; diff --git a/plugins/catalog/src/alpha/entityCards.tsx b/plugins/catalog/src/alpha/entityCards.tsx new file mode 100644 index 0000000000..cc30928fcf --- /dev/null +++ b/plugins/catalog/src/alpha/entityCards.tsx @@ -0,0 +1,102 @@ +/* + * Copyright 2023 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 { createEntityCardExtension } from '@backstage/plugin-catalog-react/alpha'; + +export const EntityAboutCard = createEntityCardExtension({ + id: 'about', + loader: async () => + import('../components/AboutCard').then(m => ( + + )), +}); + +export const EntityLinksCard = createEntityCardExtension({ + id: 'links', + loader: async () => + import('../components/EntityLinksCard').then(m => { + return ; + }), +}); + +export const EntityLabelsCard = createEntityCardExtension({ + id: 'labels', + loader: async () => + import('../components/EntityLabelsCard').then(m => ( + + )), +}); + +export const EntityDependsOnComponentsCard = createEntityCardExtension({ + id: 'dependsOn.components', + loader: async () => + import('../components/DependsOnComponentsCard').then(m => ( + + )), +}); + +export const EntityDependsOnResourcesCard = createEntityCardExtension({ + id: 'dependsOn.resources', + loader: async () => + import('../components/DependsOnResourcesCard').then(m => ( + + )), +}); + +export const EntityHasComponentsCard = createEntityCardExtension({ + id: 'has.components', + loader: async () => + import('../components/HasComponentsCard').then(m => ( + + )), +}); + +export const EntityHasResourcesCard = createEntityCardExtension({ + id: 'has.resources', + loader: async () => + import('../components/HasResourcesCard').then(m => ( + + )), +}); + +export const EntityHasSubcomponentsCard = createEntityCardExtension({ + id: 'has.subcomponents', + loader: async () => + import('../components/HasSubcomponentsCard').then(m => ( + + )), +}); + +export const EntityHasSystemsCard = createEntityCardExtension({ + id: 'has.systems', + loader: async () => + import('../components/HasSystemsCard').then(m => ( + + )), +}); + +export default [ + EntityAboutCard, + EntityLinksCard, + EntityLabelsCard, + EntityDependsOnComponentsCard, + EntityDependsOnResourcesCard, + EntityHasComponentsCard, + EntityHasResourcesCard, + EntityHasSubcomponentsCard, + EntityHasSystemsCard, +]; diff --git a/plugins/catalog/src/alpha/entityContents.tsx b/plugins/catalog/src/alpha/entityContents.tsx new file mode 100644 index 0000000000..0e26373b5e --- /dev/null +++ b/plugins/catalog/src/alpha/entityContents.tsx @@ -0,0 +1,46 @@ +/* + * Copyright 2023 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 { Grid } from '@material-ui/core'; +import { + coreExtensionData, + createExtensionInput, +} from '@backstage/frontend-plugin-api'; +import { createEntityContentExtension } from '@backstage/plugin-catalog-react/alpha'; + +export const OverviewEntityContent = createEntityContentExtension({ + id: 'overview', + defaultPath: '/', + defaultTitle: 'Overview', + disabled: false, + inputs: { + cards: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + loader: async ({ inputs }) => ( + + {inputs.cards.map(card => ( + + {card.element} + + ))} + + ), +}); + +export default [OverviewEntityContent]; diff --git a/plugins/catalog/src/alpha/builtInFilterExtensions.tsx b/plugins/catalog/src/alpha/filters.tsx similarity index 98% rename from plugins/catalog/src/alpha/builtInFilterExtensions.tsx rename to plugins/catalog/src/alpha/filters.tsx index 5a7575c4f5..7b73c2d14b 100644 --- a/plugins/catalog/src/alpha/builtInFilterExtensions.tsx +++ b/plugins/catalog/src/alpha/filters.tsx @@ -109,7 +109,7 @@ const CatalogUserListFilter = createCatalogFilterExtension({ }, }); -export const builtInFilterExtensions = [ +export default [ CatalogEntityTagFilter, CatalogEntityKindFilter, CatalogEntityTypeFilter, diff --git a/plugins/catalog/src/alpha/navItems.tsx b/plugins/catalog/src/alpha/navItems.tsx new file mode 100644 index 0000000000..b6481fd764 --- /dev/null +++ b/plugins/catalog/src/alpha/navItems.tsx @@ -0,0 +1,29 @@ +/* + * Copyright 2023 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 HomeIcon from '@material-ui/icons/Home'; +import { convertLegacyRouteRef } from '@backstage/core-plugin-api/alpha'; +import { createNavItemExtension } from '@backstage/frontend-plugin-api'; +import { rootRouteRef } from '../routes'; + +export const CatalogIndexNavItem = createNavItemExtension({ + id: 'catalog.nav.index', + routeRef: convertLegacyRouteRef(rootRouteRef), + title: 'Catalog', + icon: HomeIcon, +}); + +export default [CatalogIndexNavItem]; diff --git a/plugins/catalog/src/alpha/pages.tsx b/plugins/catalog/src/alpha/pages.tsx new file mode 100644 index 0000000000..6270ae777d --- /dev/null +++ b/plugins/catalog/src/alpha/pages.tsx @@ -0,0 +1,83 @@ +/* + * Copyright 2023 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 { convertLegacyRouteRef } from '@backstage/core-plugin-api/alpha'; +import { + createPageExtension, + coreExtensionData, + createExtensionInput, +} from '@backstage/frontend-plugin-api'; +import { + AsyncEntityProvider, + entityRouteRef, +} from '@backstage/plugin-catalog-react'; +import { entityContentTitleExtensionDataRef } from '@backstage/plugin-catalog-react/alpha'; +import { rootRouteRef } from '../routes'; +import { useEntityFromUrl } from '../components/CatalogEntityPage/useEntityFromUrl'; + +export const CatalogIndexPage = createPageExtension({ + id: 'plugin.catalog.page.index', + defaultPath: '/catalog', + routeRef: convertLegacyRouteRef(rootRouteRef), + inputs: { + filters: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + loader: async ({ inputs }) => { + const { BaseCatalogPage } = await import('../components/CatalogPage'); + const filters = inputs.filters.map(filter => filter.element); + return {filters}} />; + }, +}); + +export const CatalogEntityPage = createPageExtension({ + id: 'plugin.catalog.page.entity', + defaultPath: '/catalog/:namespace/:kind/:name', + routeRef: convertLegacyRouteRef(entityRouteRef), + inputs: { + contents: createExtensionInput({ + element: coreExtensionData.reactElement, + path: coreExtensionData.routePath, + routeRef: coreExtensionData.routeRef.optional(), + title: entityContentTitleExtensionDataRef, + }), + }, + loader: async ({ inputs }) => { + const { EntityLayout } = await import('../components/EntityLayout'); + const Component = () => { + return ( + + + {inputs.contents.map(content => ( + + {content.element} + + ))} + + + ); + }; + return ; + }, +}); + +export default [CatalogIndexPage, CatalogEntityPage]; diff --git a/plugins/catalog/src/alpha/plugin.tsx b/plugins/catalog/src/alpha/plugin.tsx index d9d2878213..2f019ca33e 100644 --- a/plugins/catalog/src/alpha/plugin.tsx +++ b/plugins/catalog/src/alpha/plugin.tsx @@ -14,166 +14,25 @@ * limitations under the License. */ -import React from 'react'; -import HomeIcon from '@material-ui/icons/Home'; -import { - createApiFactory, - discoveryApiRef, - fetchApiRef, - storageApiRef, -} from '@backstage/core-plugin-api'; import { convertLegacyRouteRef } from '@backstage/core-plugin-api/alpha'; -import { CatalogClient } from '@backstage/catalog-client'; -import { - createApiExtension, - createPageExtension, - createPlugin, - createNavItemExtension, - coreExtensionData, - createExtensionInput, -} from '@backstage/frontend-plugin-api'; -import { - AsyncEntityProvider, - catalogApiRef, - entityRouteRef, - starredEntitiesApiRef, -} from '@backstage/plugin-catalog-react'; -import { - createEntityContentExtension, - createEntityCardExtension, - entityContentTitleExtensionDataRef, -} from '@backstage/plugin-catalog-react/alpha'; -import { createSearchResultListItemExtension } from '@backstage/plugin-search-react/alpha'; -import { DefaultStarredEntitiesApi } from '../apis'; +import { createPlugin } from '@backstage/frontend-plugin-api'; + +import { entityRouteRef } from '@backstage/plugin-catalog-react'; + import { createComponentRouteRef, createFromTemplateRouteRef, rootRouteRef, viewTechDocRouteRef, } from '../routes'; -import { builtInFilterExtensions } from './builtInFilterExtensions'; -import { useEntityFromUrl } from '../components/CatalogEntityPage/useEntityFromUrl'; -import Grid from '@material-ui/core/Grid'; -/** @alpha */ -export const CatalogApi = createApiExtension({ - factory: createApiFactory({ - api: catalogApiRef, - deps: { - discoveryApi: discoveryApiRef, - fetchApi: fetchApiRef, - }, - factory: ({ discoveryApi, fetchApi }) => - new CatalogClient({ discoveryApi, fetchApi }), - }), -}); - -/** @alpha */ -export const StarredEntitiesApi = createApiExtension({ - factory: createApiFactory({ - api: starredEntitiesApiRef, - deps: { storageApi: storageApiRef }, - factory: ({ storageApi }) => new DefaultStarredEntitiesApi({ storageApi }), - }), -}); - -/** @alpha */ -export const CatalogSearchResultListItemExtension = - createSearchResultListItemExtension({ - id: 'catalog', - predicate: result => result.type === 'software-catalog', - component: () => - import('../components/CatalogSearchResultListItem').then( - m => m.CatalogSearchResultListItem, - ), - }); - -const CatalogIndexPage = createPageExtension({ - id: 'plugin.catalog.page.index', - defaultPath: '/catalog', - routeRef: convertLegacyRouteRef(rootRouteRef), - inputs: { - filters: createExtensionInput({ - element: coreExtensionData.reactElement, - }), - }, - loader: async ({ inputs }) => { - const { BaseCatalogPage } = await import('../components/CatalogPage'); - const filters = inputs.filters.map(filter => filter.element); - return {filters}} />; - }, -}); - -const CatalogEntityPage = createPageExtension({ - id: 'plugin.catalog.page.entity', - defaultPath: '/catalog/:namespace/:kind/:name', - routeRef: convertLegacyRouteRef(entityRouteRef), - inputs: { - contents: createExtensionInput({ - element: coreExtensionData.reactElement, - path: coreExtensionData.routePath, - routeRef: coreExtensionData.routeRef.optional(), - title: entityContentTitleExtensionDataRef, - }), - }, - loader: async ({ inputs }) => { - const { EntityLayout } = await import('../components/EntityLayout'); - const Component = () => { - return ( - - - {inputs.contents.map(content => ( - - {content.element} - - ))} - - - ); - }; - return ; - }, -}); - -const EntityAboutCard = createEntityCardExtension({ - id: 'about', - loader: async () => - import('../components/AboutCard').then(m => ( - - )), -}); - -const OverviewEntityContent = createEntityContentExtension({ - id: 'overview', - defaultPath: '/', - defaultTitle: 'Overview', - disabled: false, - inputs: { - cards: createExtensionInput({ - element: coreExtensionData.reactElement, - }), - }, - loader: async ({ inputs }) => ( - - {inputs.cards.map(card => ( - - {card.element} - - ))} - - ), -}); - -const CatalogNavItem = createNavItemExtension({ - id: 'catalog.nav.index', - routeRef: convertLegacyRouteRef(rootRouteRef), - title: 'Catalog', - icon: HomeIcon, -}); +import apis from './apis'; +import pages from './pages'; +import filters from './filters'; +import navItems from './navItems'; +import entityCards from './entityCards'; +import entityContents from './entityContents'; +import searchResultItems from './searchResultItems'; /** @alpha */ export default createPlugin({ @@ -188,14 +47,12 @@ export default createPlugin({ createFromTemplate: convertLegacyRouteRef(createFromTemplateRouteRef), }, extensions: [ - CatalogApi, - StarredEntitiesApi, - CatalogSearchResultListItemExtension, - CatalogIndexPage, - CatalogEntityPage, - CatalogNavItem, - OverviewEntityContent, - EntityAboutCard, - ...builtInFilterExtensions, + ...apis, + ...pages, + ...filters, + ...navItems, + ...entityCards, + ...entityContents, + ...searchResultItems, ], }); diff --git a/plugins/catalog/src/alpha/searchResultItems.tsx b/plugins/catalog/src/alpha/searchResultItems.tsx new file mode 100644 index 0000000000..f677869136 --- /dev/null +++ b/plugins/catalog/src/alpha/searchResultItems.tsx @@ -0,0 +1,29 @@ +/* + * Copyright 2023 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 { createSearchResultListItemExtension } from '@backstage/plugin-search-react/alpha'; + +export const CatalogSearchResultListItemExtension = + createSearchResultListItemExtension({ + id: 'catalog', + predicate: result => result.type === 'software-catalog', + component: () => + import('../components/CatalogSearchResultListItem').then( + m => m.CatalogSearchResultListItem, + ), + }); + +export default [CatalogSearchResultListItemExtension];