diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 88845b402b..c02b63f761 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -51,6 +51,7 @@ "humanize-duration": "^3.25.1", "immer": "^9.0.1", "json-schema": "^0.3.0", + "lodash": "^4.17.21", "luxon": "^1.25.0", "react": "^16.13.1", "react-dom": "^16.13.1", diff --git a/plugins/scaffolder/src/components/TemplateTypePicker/TemplateTypePicker.test.tsx b/plugins/scaffolder/src/components/TemplateTypePicker/TemplateTypePicker.test.tsx new file mode 100644 index 0000000000..fa74b34717 --- /dev/null +++ b/plugins/scaffolder/src/components/TemplateTypePicker/TemplateTypePicker.test.tsx @@ -0,0 +1,134 @@ +/* + * 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 from 'react'; +import { fireEvent, render, waitFor } from '@testing-library/react'; +import { capitalize } from 'lodash'; +import { CatalogApi } from '@backstage/catalog-client'; +import { Entity } from '@backstage/catalog-model'; +import { EntityTypePicker } from './EntityTypePicker'; +import { MockEntityListContextProvider } from '../../testUtils/providers'; +import { catalogApiRef } from '../../api'; +import { EntityKindFilter, EntityTypeFilter } from '../../filters'; + +import { AlertApi, alertApiRef } from '@backstage/core-plugin-api'; +import { ApiProvider, ApiRegistry } from '@backstage/core-app-api'; + +const entities: Entity[] = [ + { + apiVersion: '1', + kind: 'Component', + metadata: { + name: 'component-1', + }, + spec: { + type: 'service', + }, + }, + { + apiVersion: '1', + kind: 'Component', + metadata: { + name: 'component-2', + }, + spec: { + type: 'website', + }, + }, + { + apiVersion: '1', + kind: 'Component', + metadata: { + name: 'component-3', + }, + spec: { + type: 'library', + }, + }, +]; + +const apis = ApiRegistry.from([ + [ + catalogApiRef, + ({ + getEntities: jest + .fn() + .mockImplementation(() => Promise.resolve({ items: entities })), + } as unknown) as CatalogApi, + ], + [ + alertApiRef, + ({ + post: jest.fn(), + } as unknown) as AlertApi, + ], +]); + +describe('', () => { + it('renders available entity types', async () => { + const rendered = render( + + + + + , + ); + expect(rendered.getByText('Type')).toBeInTheDocument(); + + const input = rendered.getByTestId('select'); + fireEvent.click(input); + + await waitFor(() => rendered.getByText('Service')); + + entities.forEach(entity => { + expect( + rendered.getByText(capitalize(entity.spec!.type as string)), + ).toBeInTheDocument(); + }); + }); + + it('sets the selected type filter', async () => { + const updateFilters = jest.fn(); + const rendered = render( + + + + + , + ); + const input = rendered.getByTestId('select'); + fireEvent.click(input); + + await waitFor(() => rendered.getByText('Service')); + fireEvent.click(rendered.getByText('Service')); + + expect(updateFilters).toHaveBeenLastCalledWith({ + type: new EntityTypeFilter('service'), + }); + + fireEvent.click(input); + fireEvent.click(rendered.getByText('All')); + + expect(updateFilters).toHaveBeenLastCalledWith({ type: undefined }); + }); +}); diff --git a/plugins/scaffolder/src/components/TemplateTypePicker/TemplateTypePicker.tsx b/plugins/scaffolder/src/components/TemplateTypePicker/TemplateTypePicker.tsx new file mode 100644 index 0000000000..780f9d2d1e --- /dev/null +++ b/plugins/scaffolder/src/components/TemplateTypePicker/TemplateTypePicker.tsx @@ -0,0 +1,97 @@ +/* + * 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 from 'react'; +import { + Typography, + List, + ListItem, + makeStyles, + Theme, + Checkbox, + ListItemText, +} from '@material-ui/core'; +import { useEntityTypeFilter } from '@backstage/plugin-catalog-react'; +import { alertApiRef, useApi } from '@backstage/core-plugin-api'; + +const useStyles = makeStyles(theme => ({ + checkbox: { + padding: theme.spacing(0, 1, 0, 1), + }, +})); + +export const TemplateTypePicker = () => { + const classes = useStyles(); + const alertApi = useApi(alertApiRef); + // TODO(timbonicus): Use new setTypes returned from the hook + const { error, types, selectedType } = useEntityTypeFilter(); + + if (!types) return null; + + if (error) { + alertApi.post({ + message: `Failed to load entity types`, + severity: 'error', + }); + return null; + } + + return ( + <> + Categories + + {types.map(type => { + const labelId = `checkbox-list-label-${type}`; + return ( + {}} + // TODO(timbonicus): Update to use setTypes + // setSelectedCategories( + // selectedCategories.includes(type) + // ? selectedCategories.filter( + // selectedCategory => selectedCategory !== type, + // ) + // : [...selectedCategories, type], + // ) + // } + > + + + + ); + })} + + + ); +}; diff --git a/plugins/scaffolder/src/components/TemplateTypePicker/index.ts b/plugins/scaffolder/src/components/TemplateTypePicker/index.ts new file mode 100644 index 0000000000..2dcd091311 --- /dev/null +++ b/plugins/scaffolder/src/components/TemplateTypePicker/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export { TemplateTypePicker } from './TemplateTypePicker';