diff --git a/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.tsx b/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.tsx
index 4cfd141509..774d07c544 100644
--- a/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.tsx
+++ b/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.tsx
@@ -14,41 +14,115 @@
* limitations under the License.
*/
-import React, { useEffect, useState } from 'react';
-import { Alert } from '@material-ui/lab';
-import { useEntityList } from '../../hooks';
+import { useApi } from '@backstage/core-plugin-api';
+import {
+ Box,
+ Checkbox,
+ FormControlLabel,
+ makeStyles,
+ TextField,
+ Typography,
+} from '@material-ui/core';
+import CheckBoxIcon from '@material-ui/icons/CheckBox';
+import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import { Autocomplete } from '@material-ui/lab';
+import React, { useEffect, useMemo, useState } from 'react';
+import useAsync from 'react-use/lib/useAsync';
+import { catalogApiRef } from '../../api';
import { EntityKindFilter } from '../../filters';
+import { useEntityList } from '../../hooks';
-/**
- * Props for {@link EntityKindPicker}.
- *
- * @public
- */
-export interface EntityKindPickerProps {
- initialFilter?: string;
- hidden: boolean;
-}
+const useStyles = makeStyles(
+ {
+ input: {},
+ },
+ {
+ name: 'CatalogReactEntityKindPicker',
+ },
+);
+
+const icon = ;
+const checkedIcon = ;
/** @public */
-export const EntityKindPicker = (props: EntityKindPickerProps) => {
- const { initialFilter, hidden } = props;
-
+export const EntityKindPicker = () => {
+ const classes = useStyles();
const {
updateFilters,
- queryParameters: { kind: kindParameter },
+ filters,
+ queryParameters: { kind: kindsParameter },
} = useEntityList();
- const [selectedKind] = useState([kindParameter].flat()[0] ?? initialFilter);
+
+ const catalogApi = useApi(catalogApiRef);
+ const { value: availableKinds } = useAsync(async () => {
+ const facet = 'kind';
+ const { facets } = await catalogApi.getEntityFacets({
+ facets: [facet],
+ });
+
+ return facets[facet].map(({ value }) => value);
+ }, [filters.kind]);
+
+ const queryParamKinds = useMemo(
+ () => [kindsParameter].flat().filter(Boolean) as string[],
+ [kindsParameter],
+ );
+
+ const [selectedKinds, setSelectedKinds] = useState(
+ queryParamKinds.length ? queryParamKinds : filters.kind?.getKinds() ?? [],
+ );
+
+ // Set selected kinds on query parameter updates; this happens at initial page load and from
+ // external updates to the page location.
+ useEffect(() => {
+ if (queryParamKinds.length) {
+ setSelectedKinds(queryParamKinds);
+ }
+ }, [queryParamKinds]);
useEffect(() => {
updateFilters({
- kind: selectedKind ? new EntityKindFilter(selectedKind) : undefined,
+ kind: selectedKinds.length
+ ? new EntityKindFilter(selectedKinds)
+ : undefined,
});
- }, [selectedKind, updateFilters]);
+ }, [selectedKinds, updateFilters]);
- if (hidden) return null;
+ if (!availableKinds?.length) return null;
- // TODO(timbonicus): This should load available kinds from the catalog-backend, similar to
- // EntityTypePicker.
-
- return Kind filter not yet available;
+ return (
+
+
+ Kinds
+ setSelectedKinds(value)}
+ renderOption={(option, { selected }) => (
+
+ }
+ label={option}
+ />
+ )}
+ size="small"
+ popupIcon={}
+ renderInput={params => (
+
+ )}
+ />
+
+
+ );
};
diff --git a/plugins/catalog-react/src/filters.ts b/plugins/catalog-react/src/filters.ts
index 056b3b92c1..efa10a8e19 100644
--- a/plugins/catalog-react/src/filters.ts
+++ b/plugins/catalog-react/src/filters.ts
@@ -28,14 +28,19 @@ import { getEntityRelations } from './utils';
* @public
*/
export class EntityKindFilter implements EntityFilter {
- constructor(readonly value: string) {}
+ constructor(readonly value: string | string[]) {}
- getCatalogFilters(): Record {
- return { kind: this.value };
+ // Simplify `string | string[]` for consumers, always returns an array
+ getKinds(): string[] {
+ return Array.isArray(this.value) ? this.value : [this.value];
}
- toQueryValue(): string {
- return this.value;
+ getCatalogFilters(): Record {
+ return { kind: this.getKinds() };
+ }
+
+ toQueryValue(): string[] {
+ return this.getKinds();
}
}
diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx
index 39c19d717a..3f34a950be 100644
--- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx
+++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx
@@ -34,6 +34,7 @@ import {
EntityTypePicker,
UserListFilterKind,
UserListPicker,
+ EntityKindPicker,
} from '@backstage/plugin-catalog-react';
import React from 'react';
import { createComponentRouteRef } from '../../routes';
@@ -83,6 +84,7 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) {
+
diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx
index 6bc18d7a90..5a7f8aabbb 100644
--- a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx
+++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx
@@ -70,7 +70,12 @@ export const CatalogTable = (props: CatalogTableProps) => {
const defaultColumns: TableColumn[] = useMemo(() => {
return [
columnFactories.createTitleColumn({ hidden: true }),
- columnFactories.createNameColumn({ defaultKind: filters.kind?.value }),
+ columnFactories.createNameColumn({
+ defaultKind:
+ filters.kind?.getKinds()?.length === 1
+ ? filters.kind?.getKinds()[0]
+ : undefined,
+ }),
...createEntitySpecificColumns(),
columnFactories.createMetadataDescriptionColumn(),
columnFactories.createTagsColumn(),
@@ -100,7 +105,7 @@ export const CatalogTable = (props: CatalogTableProps) => {
];
}
}
- }, [filters.kind?.value]);
+ }, [filters.kind]);
const showTypeColumn = filters.type === undefined;
// TODO(timbonicus): remove the title from the CatalogTable once using EntitySearchBar