diff --git a/docs/features/software-catalog/catalog-customization.md b/docs/features/software-catalog/catalog-customization.md index 07258a55cb..8f855776a0 100644 --- a/docs/features/software-catalog/catalog-customization.md +++ b/docs/features/software-catalog/catalog-customization.md @@ -34,15 +34,14 @@ export const CustomCatalogPage = ({ }: CatalogPageProps) => { return ( - - - - All your software catalog entities - - + + + }> + + All your software catalog entities + - - - + + ); }; diff --git a/packages/core-components/src/layout/ContentHeader/ContentHeader.test.tsx b/packages/core-components/src/layout/ContentHeader/ContentHeader.test.tsx index 498b859db1..37059766a8 100644 --- a/packages/core-components/src/layout/ContentHeader/ContentHeader.test.tsx +++ b/packages/core-components/src/layout/ContentHeader/ContentHeader.test.tsx @@ -32,7 +32,7 @@ describe('', () => { it('should render with titleComponent', async () => { const title = 'Custom title'; - const titleComponent = () =>

{title}

; + const titleComponent =

{title}

; const rendered = await renderInTestApp( , ); diff --git a/packages/core-components/src/layout/ContentHeader/ContentHeader.tsx b/packages/core-components/src/layout/ContentHeader/ContentHeader.tsx index 4bda2d76af..fa797212e4 100644 --- a/packages/core-components/src/layout/ContentHeader/ContentHeader.tsx +++ b/packages/core-components/src/layout/ContentHeader/ContentHeader.tsx @@ -77,7 +77,7 @@ const ContentHeaderTitle = ({ type ContentHeaderProps = { title?: ContentHeaderTitleProps['title']; - titleComponent?: ComponentType; + titleComponent?: JSX.Element; description?: string; textAlign?: 'left' | 'right' | 'center'; }; @@ -92,7 +92,7 @@ export const ContentHeader = ({ const classes = useStyles({ textAlign })(); const renderedTitle = TitleComponent ? ( - + TitleComponent ) : ( ); diff --git a/plugins/catalog-react/src/components/EntityTypePicker/EntityTypePicker.test.tsx b/plugins/catalog-react/src/components/EntityTypePicker/EntityTypePicker.test.tsx index 903a7ba4eb..a9ecf03e5c 100644 --- a/plugins/catalog-react/src/components/EntityTypePicker/EntityTypePicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityTypePicker/EntityTypePicker.test.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; -import { fireEvent, render, waitFor } from '@testing-library/react'; +import { fireEvent, waitFor } from '@testing-library/react'; import { capitalize } from 'lodash'; import { CatalogApi } from '@backstage/catalog-client'; import { Entity } from '@backstage/catalog-model'; @@ -26,6 +26,7 @@ import { EntityKindFilter, EntityTypeFilter } from '../../filters'; import { AlertApi, alertApiRef } from '@backstage/core-plugin-api'; import { ApiProvider, ApiRegistry } from '@backstage/core-app-api'; +import { renderWithEffects } from '@backstage/test-utils'; const entities: Entity[] = [ { @@ -79,7 +80,7 @@ const apis = ApiRegistry.from([ describe('', () => { it('renders available entity types', async () => { - const rendered = render( + const rendered = await renderWithEffects( ', () => { it('sets the selected type filter', async () => { const updateFilters = jest.fn(); - const rendered = render( + const rendered = await renderWithEffects( { } }, [error, alertApi]); - if (!availableTypes || error) return null; + if (availableTypes.length === 0 || error) return null; const items = [ { value: 'all', label: 'All' }, diff --git a/plugins/catalog-react/src/hooks/index.ts b/plugins/catalog-react/src/hooks/index.ts index 868e50c852..2f3ce8411d 100644 --- a/plugins/catalog-react/src/hooks/index.ts +++ b/plugins/catalog-react/src/hooks/index.ts @@ -22,6 +22,7 @@ export { } from './useEntityListProvider'; export type { DefaultEntityFilters } from './useEntityListProvider'; export { useEntityTypeFilter } from './useEntityTypeFilter'; +export { useEntityKinds } from './useEntityKinds'; export { useOwnUser } from './useOwnUser'; export { useRelatedEntities } from './useRelatedEntities'; export { useStarredEntities } from './useStarredEntities'; diff --git a/plugins/catalog-react/src/hooks/useEntityKinds.ts b/plugins/catalog-react/src/hooks/useEntityKinds.ts new file mode 100644 index 0000000000..1aaf40981a --- /dev/null +++ b/plugins/catalog-react/src/hooks/useEntityKinds.ts @@ -0,0 +1,36 @@ +/* + * Copyright 2021 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 { useEffect, useState } from 'react'; +import { useApi } from '@backstage/core-plugin-api'; +import { catalogApiRef } from '../api'; + +export function useEntityKinds() { + const [kinds, setKinds] = useState(['component']); + const catalogApi = useApi(catalogApiRef); + + useEffect(() => { + async function loadKinds() { + const entities = await catalogApi + .getEntities({ fields: ['kind'] }) + .then(response => response.items); + setKinds([...new Set(entities.map(e => e.kind))].sort()); + } + loadKinds(); + }, [catalogApi]); + + return kinds; +} diff --git a/plugins/catalog/src/components/CatalogPage/CatalogKindHeader.tsx b/plugins/catalog/src/components/CatalogPage/CatalogKindHeader.tsx new file mode 100644 index 0000000000..985f8fed6a --- /dev/null +++ b/plugins/catalog/src/components/CatalogPage/CatalogKindHeader.tsx @@ -0,0 +1,74 @@ +/* + * Copyright 2021 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, { useEffect, useState } from 'react'; +import { + capitalize, + createStyles, + InputBase, + makeStyles, + MenuItem, + Select, + Theme, +} from '@material-ui/core'; +import { + EntityKindFilter, + useEntityKinds, + useEntityListProvider, +} from '@backstage/plugin-catalog-react'; + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + root: { + ...theme.typography.h4, + }, + }), +); + +type CatalogKindHeaderProps = { + initialFilter?: string; +}; + +export const CatalogKindHeader = ({ + initialFilter = 'Component', +}: CatalogKindHeaderProps) => { + const classes = useStyles(); + const allKinds = useEntityKinds(); + const { updateFilters, queryParameters } = useEntityListProvider(); + + const [selectedKind, setSelectedKind] = useState( + [queryParameters.kind].flat()[0] ?? initialFilter, + ); + + useEffect(() => { + updateFilters({ + kind: selectedKind ? new EntityKindFilter(selectedKind) : undefined, + }); + }, [selectedKind, updateFilters]); + + return ( + + ); +}; diff --git a/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx index a4f6c01bc8..913b3dfeb6 100644 --- a/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx @@ -43,6 +43,7 @@ import { EntityListContainer, FilterContainer, } from '../FilteredEntityLayout'; +import { CatalogKindHeader } from './CatalogKindHeader'; export type CatalogPageProps = { initiallySelectedFilter?: UserListFilterKind; @@ -61,18 +62,17 @@ export const CatalogPage = ({ return ( - - - - All your software catalog entities - - + + + }> + + All your software catalog entities + - - - + + ); };