diff --git a/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.tsx b/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.tsx index e0564d170e..65ec949b4a 100644 --- a/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.tsx +++ b/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.tsx @@ -20,7 +20,7 @@ import { Box } from '@material-ui/core'; import React, { useEffect, useMemo, useState } from 'react'; import { EntityKindFilter } from '../../filters'; import { useEntityList } from '../../hooks'; -import { filterKinds, useAllKinds } from '../../utils/kindFilterUtils'; +import { filterKinds, useAllKinds } from './kindFilterUtils'; function useEntityKindFilter(opts: { initialFilter: string }): { loading: boolean; diff --git a/plugins/catalog-react/src/utils/kindFilterUtils.ts b/plugins/catalog-react/src/components/EntityKindPicker/kindFilterUtils.ts similarity index 98% rename from plugins/catalog-react/src/utils/kindFilterUtils.ts rename to plugins/catalog-react/src/components/EntityKindPicker/kindFilterUtils.ts index 851dcfb702..aed4c41295 100644 --- a/plugins/catalog-react/src/utils/kindFilterUtils.ts +++ b/plugins/catalog-react/src/components/EntityKindPicker/kindFilterUtils.ts @@ -16,7 +16,7 @@ import { useApi } from '@backstage/core-plugin-api'; import useAsync from 'react-use/lib/useAsync'; -import { catalogApiRef } from '../api'; +import { catalogApiRef } from '../../api'; /** * Fetch and return all availible kinds. diff --git a/plugins/catalog-react/src/utils/index.ts b/plugins/catalog-react/src/utils/index.ts index 8262d1cc81..5afc32af63 100644 --- a/plugins/catalog-react/src/utils/index.ts +++ b/plugins/catalog-react/src/utils/index.ts @@ -18,4 +18,3 @@ export { getEntityRelations } from './getEntityRelations'; export { getEntitySourceLocation } from './getEntitySourceLocation'; export type { EntitySourceLocation } from './getEntitySourceLocation'; export { isOwnerOf } from './isOwnerOf'; -export { useAllKinds, filterKinds } from './kindFilterUtils'; diff --git a/plugins/catalog/src/components/CatalogKindHeader/CatalogKindHeader.tsx b/plugins/catalog/src/components/CatalogKindHeader/CatalogKindHeader.tsx index 0b27cf9ccb..8247116e4a 100644 --- a/plugins/catalog/src/components/CatalogKindHeader/CatalogKindHeader.tsx +++ b/plugins/catalog/src/components/CatalogKindHeader/CatalogKindHeader.tsx @@ -27,11 +27,8 @@ import { EntityKindFilter, useEntityList, } from '@backstage/plugin-catalog-react'; -import { - filterKinds, - useAllKinds, -} from '@backstage/plugin-catalog-react/src/utils'; import pluralize from 'pluralize'; +import { filterKinds, useAllKinds } from './kindFilterUtils'; const useStyles = makeStyles((theme: Theme) => createStyles({ diff --git a/plugins/catalog/src/components/CatalogKindHeader/kindFilterUtils.ts b/plugins/catalog/src/components/CatalogKindHeader/kindFilterUtils.ts new file mode 100644 index 0000000000..4f74d10a6c --- /dev/null +++ b/plugins/catalog/src/components/CatalogKindHeader/kindFilterUtils.ts @@ -0,0 +1,82 @@ +/* + * Copyright 2022 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 { useApi } from '@backstage/core-plugin-api'; +import { catalogApiRef } from '@backstage/plugin-catalog-react'; +import useAsync from 'react-use/lib/useAsync'; + +/** + * Fetch and return all availible kinds. + */ +export function useAllKinds(): { + loading: boolean; + error?: Error; + allKinds: string[]; +} { + const catalogApi = useApi(catalogApiRef); + + const { + error, + loading, + value: allKinds, + } = useAsync(async () => { + const items = await catalogApi + .getEntityFacets({ facets: ['kind'] }) + .then(response => response.facets.kind?.map(f => f.value).sort() || []); + return items; + }, [catalogApi]); + + return { loading, error, allKinds: allKinds ?? [] }; +} + +/** + * Filter and capitalize accessible kinds. + */ +export function filterKinds( + allKinds: string[], + allowedKinds?: string[], + forcedKinds?: string, +): Record { + // Before allKinds is loaded, or when a kind is entered manually in the URL, selectedKind may not + // be present in allKinds. It should still be shown in the dropdown, but may not have the nice + // enforced casing from the catalog-backend. This makes a key/value record for the Select options, + // including selectedKind if it's unknown - but allows the selectedKind to get clobbered by the + // more proper catalog kind if it exists. + let availableKinds = allKinds; + if (allowedKinds) { + availableKinds = availableKinds.filter(k => + allowedKinds.some( + a => a.toLocaleLowerCase('en-US') === k.toLocaleLowerCase('en-US'), + ), + ); + } + if ( + forcedKinds && + !allKinds.some( + a => + a.toLocaleLowerCase('en-US') === forcedKinds.toLocaleLowerCase('en-US'), + ) + ) { + availableKinds = availableKinds.concat([forcedKinds]); + } + + const kindsMap = availableKinds.sort().reduce((acc, kind) => { + acc[kind.toLocaleLowerCase('en-US')] = kind; + return acc; + }, {} as Record); + + return kindsMap; +}