From 4dc54873e29a455784f601a16c200d32b13c395a Mon Sep 17 00:00:00 2001 From: Jonathan Roebuck Date: Fri, 25 Oct 2024 15:41:59 +0100 Subject: [PATCH] Add new core component Autocomplete and use for entity pickers Signed-off-by: Jonathan Roebuck --- packages/core-components/report.api.md | 14 ++ .../Autocomplete/Autocomplete.stories.tsx | 33 ++++ .../Autocomplete/Autocomplete.test.tsx | 117 ++++++++++++ .../components/Autocomplete/Autocomplete.tsx | 171 +++++++++++++++++ .../src/components/Autocomplete/index.tsx | 16 ++ .../core-components/src/components/index.ts | 1 + plugins/catalog-react/report.api.md | 2 +- .../EntityAutocompletePicker.tsx | 60 +++--- .../EntityAutocompletePickerInput.tsx | 43 ----- .../EntityOwnerPicker/EntityOwnerPicker.tsx | 172 ++++++++---------- .../EntityProcessingStatusPicker.tsx | 90 ++++----- 11 files changed, 479 insertions(+), 240 deletions(-) create mode 100644 packages/core-components/src/components/Autocomplete/Autocomplete.stories.tsx create mode 100644 packages/core-components/src/components/Autocomplete/Autocomplete.test.tsx create mode 100644 packages/core-components/src/components/Autocomplete/Autocomplete.tsx create mode 100644 packages/core-components/src/components/Autocomplete/index.tsx delete mode 100644 plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePickerInput.tsx diff --git a/packages/core-components/report.api.md b/packages/core-components/report.api.md index c3f7cf9a6a..5298ac9816 100644 --- a/packages/core-components/report.api.md +++ b/packages/core-components/report.api.md @@ -6,6 +6,7 @@ /// import { ApiRef } from '@backstage/core-plugin-api'; +import { AutocompleteProps } from '@material-ui/lab/Autocomplete'; import { BackstageIdentityApi } from '@backstage/core-plugin-api'; import { BackstagePalette } from '@backstage/theme'; import { BackstageUserIdentity } from '@backstage/core-plugin-api'; @@ -33,6 +34,7 @@ import { MaterialTableProps } from '@material-table/core'; import { NavLinkProps } from 'react-router-dom'; import { Options } from 'react-markdown'; import { Options as Options_2 } from '@material-table/core'; +import { OutlinedTextFieldProps } from '@material-ui/core/TextField'; import { Overrides } from '@material-ui/core/styles/overrides'; import { ProfileInfo } from '@backstage/core-plugin-api'; import { ProfileInfoApi } from '@backstage/core-plugin-api'; @@ -76,6 +78,18 @@ export type AppIconProps = IconComponentProps & { Fallback?: IconComponent; }; +// Warning: (ae-forgotten-export) The symbol "AutocompleteComponentProps" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export function Autocomplete< + T, + Multiple extends boolean | undefined = undefined, + DisableClearable extends boolean | undefined = undefined, + FreeSolo extends boolean | undefined = undefined, +>( + props: AutocompleteComponentProps, +): React_2.JSX.Element; + // @public export const AutoLogout: (props: AutoLogoutProps) => JSX.Element | null; diff --git a/packages/core-components/src/components/Autocomplete/Autocomplete.stories.tsx b/packages/core-components/src/components/Autocomplete/Autocomplete.stories.tsx new file mode 100644 index 0000000000..7aed709125 --- /dev/null +++ b/packages/core-components/src/components/Autocomplete/Autocomplete.stories.tsx @@ -0,0 +1,33 @@ +/* + * Copyright 2024 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 { AutocompleteComponent as Autocomplete } from './Autocomplete'; + +export default { + title: 'Inputs/Autocomplete', + component: Autocomplete, +}; + +export const Default = (args: any) => { + return ; +}; + +Default.args = { + multiple: true, + label: 'Default', + name: 'default', + options: ['test 1', 'test 2', 'test 3'], +}; diff --git a/packages/core-components/src/components/Autocomplete/Autocomplete.test.tsx b/packages/core-components/src/components/Autocomplete/Autocomplete.test.tsx new file mode 100644 index 0000000000..fff83eb26d --- /dev/null +++ b/packages/core-components/src/components/Autocomplete/Autocomplete.test.tsx @@ -0,0 +1,117 @@ +/* + * Copyright 2024 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 { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { AutocompleteComponent as Autocomplete } from './Autocomplete'; + +describe('Autocomplete', () => { + const user = userEvent.setup(); + const mockOptions = ['Option 1', 'Option 2', 'Option 3']; + + it('renders without exploding', () => { + render( + , + ); + expect(screen.getByRole('textbox')).toBeInTheDocument(); + }); + + it('renders the expand icon', () => { + render( + , + ); + const expandIcon = screen.getByTestId('test-autocomplete-expand'); + expect(expandIcon).toBeInTheDocument(); + }); + + it('displays options when clicked', () => { + render( + , + ); + + const input = screen.getByRole('textbox'); + user.click(input); + + mockOptions.forEach(option => { + expect(screen.getByText(option)).toBeInTheDocument(); + }); + }); + + it('supports required input', () => { + render( + , + ); + + const input = screen.getByRole('textbox'); + expect(input).toBeRequired(); + }); + + it('displays helper text when provided', () => { + render( + , + ); + + expect(screen.getByText('Helper text')).toBeInTheDocument(); + }); + + it('renders without label', () => { + render(); + + const input = screen.getByRole('textbox'); + expect(input).toBeInTheDocument(); + }); + + it('displays correct option on selection', () => { + render( + , + ); + + const input = screen.getByRole('textbox'); + user.click(input); + + const optionToSelect = screen.getByText('Option 1'); + user.click(optionToSelect); + + expect(input).toHaveValue('Option 1'); + }); +}); diff --git a/packages/core-components/src/components/Autocomplete/Autocomplete.tsx b/packages/core-components/src/components/Autocomplete/Autocomplete.tsx new file mode 100644 index 0000000000..dd0c936c14 --- /dev/null +++ b/packages/core-components/src/components/Autocomplete/Autocomplete.tsx @@ -0,0 +1,171 @@ +/* + * Copyright 2024 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 Box from '@material-ui/core/Box'; +import Typography from '@material-ui/core/Typography'; +import Paper, { PaperProps } from '@material-ui/core/Paper'; +import Popper, { PopperProps } from '@material-ui/core/Popper'; +import TextField, { OutlinedTextFieldProps } from '@material-ui/core/TextField'; +import Grow from '@material-ui/core/Grow'; +import { + createStyles, + makeStyles, + Theme, + withStyles, +} from '@material-ui/core/styles'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import Autocomplete, { AutocompleteProps } from '@material-ui/lab/Autocomplete'; +import React, { ReactNode } from 'react'; + +const useStyles = makeStyles( + theme => ({ + root: {}, + label: { + position: 'relative', + fontWeight: 'bold', + fontSize: theme.typography.body2.fontSize, + fontFamily: theme.typography.fontFamily, + color: theme.palette.text.primary, + '& > span': { + top: 0, + left: 0, + position: 'absolute', + }, + }, + input: {}, + }), + { name: 'BackstageAutocomplete' }, +); + +const BootstrapAutocomplete = withStyles( + (theme: Theme) => + createStyles({ + root: {}, + paper: { + margin: 0, + }, + hasClearIcon: {}, + hasPopupIcon: {}, + focused: {}, + inputRoot: { + marginTop: 24, + backgroundColor: theme.palette.background.paper, + '$root$hasClearIcon$hasPopupIcon &': { + padding: `${theme.spacing(0.75, 7, 0.75, 1.5)}`, + }, + '$root$focused &': { + outline: 'none', + }, + '$root &:hover > fieldset': { + borderColor: '#ced4da', + }, + '$root$focused & > fieldset': { + borderWidth: 1, + borderColor: theme.palette.primary.main, + }, + }, + popupIndicator: { + padding: 0, + margin: 0, + color: theme.palette.text.primary, + '& [class*="MuiTouchRipple-root"]': { + display: 'none', + }, + }, + endAdornment: { + '$root$hasClearIcon$hasPopupIcon &': { + right: 4, + }, + }, + input: { + '$root$hasClearIcon$hasPopupIcon &': { + height: 32, + fontSize: theme.typography.body1.fontSize, + padding: 0, + }, + }, + }), + { name: 'BackstageAutocompleteBase' }, +)(Autocomplete) as typeof Autocomplete; + +const PopperComponent = (props: PopperProps) => ( + + {({ TransitionProps }) => ( + + {props.children as ReactNode} + + )} + +); + +const PaperComponent = (props: PaperProps) => ( + +); + +export type AutocompleteComponentProps< + T, + Multiple extends boolean | undefined = undefined, + DisableClearable extends boolean | undefined = undefined, + FreeSolo extends boolean | undefined = undefined, +> = { + name: string; + label?: string; + inputProps?: Omit; +} & Omit< + AutocompleteProps, + 'PopperComponent' | 'PaperComponent' | 'renderInput' | 'size' | 'popupIcon' +>; + +/** @public */ +export function AutocompleteComponent< + T, + Multiple extends boolean | undefined = undefined, + DisableClearable extends boolean | undefined = undefined, + FreeSolo extends boolean | undefined = undefined, +>(props: AutocompleteComponentProps) { + const { label, name, inputProps, ...rest } = props; + const classes = useStyles(); + const autocomplete = ( + } + PaperComponent={PaperComponent} + PopperComponent={PopperComponent} + renderInput={params => ( + + )} + /> + ); + + return ( + + {label ? ( + + {label} + {autocomplete} + + ) : ( + autocomplete + )} + + ); +} diff --git a/packages/core-components/src/components/Autocomplete/index.tsx b/packages/core-components/src/components/Autocomplete/index.tsx new file mode 100644 index 0000000000..bf4681db8e --- /dev/null +++ b/packages/core-components/src/components/Autocomplete/index.tsx @@ -0,0 +1,16 @@ +/* + * Copyright 2024 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 { AutocompleteComponent as Autocomplete } from './Autocomplete'; diff --git a/packages/core-components/src/components/index.ts b/packages/core-components/src/components/index.ts index 828df3ec03..6fcbe2e9a9 100644 --- a/packages/core-components/src/components/index.ts +++ b/packages/core-components/src/components/index.ts @@ -16,6 +16,7 @@ export * from './AlertDisplay'; export * from './AutoLogout'; +export * from './Autocomplete'; export * from './Avatar'; export * from './LinkButton'; export * from './CodeSnippet'; diff --git a/plugins/catalog-react/report.api.md b/plugins/catalog-react/report.api.md index af5102176d..107fbeb0c0 100644 --- a/plugins/catalog-react/report.api.md +++ b/plugins/catalog-react/report.api.md @@ -205,7 +205,7 @@ export type EntityAutocompletePickerProps< Filter: { new (values: string[]): NonNullable; }; - InputProps?: TextFieldProps; + InputProps?: TextFieldProps['InputProps']; initialSelectedOptions?: string[]; filtersForAvailableValues?: Array; }; diff --git a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx b/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx index fd88a7a31e..d4f978fce5 100644 --- a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx +++ b/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx @@ -16,21 +16,18 @@ import Box from '@material-ui/core/Box'; import { TextFieldProps } from '@material-ui/core/TextField'; -import Typography from '@material-ui/core/Typography'; import { makeStyles } from '@material-ui/core/styles'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; -import Autocomplete from '@material-ui/lab/Autocomplete'; -import React, { useEffect, useMemo, useState, ReactNode } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import { useApi } from '@backstage/core-plugin-api'; import useAsync from 'react-use/esm/useAsync'; import { catalogApiRef } from '../../api'; import { EntityAutocompletePickerOption } from './EntityAutocompletePickerOption'; -import { EntityAutocompletePickerInput } from './EntityAutocompletePickerInput'; import { DefaultEntityFilters, useEntityList, } from '../../hooks/useEntityListProvider'; import { EntityFilter } from '../../types'; +import { Autocomplete } from '@backstage/core-components'; import { reduceBackendCatalogFilters } from '../../utils/filters'; /** @public */ @@ -52,7 +49,7 @@ export type EntityAutocompletePickerProps< path: string; showCounts?: boolean; Filter: { new (values: string[]): NonNullable }; - InputProps?: TextFieldProps; + InputProps?: TextFieldProps['InputProps']; initialSelectedOptions?: string[]; filtersForAvailableValues?: Array; }; @@ -82,11 +79,9 @@ export function EntityAutocompletePicker< path, showCounts, Filter, - InputProps, initialSelectedOptions = [], filtersForAvailableValues = ['kind'], } = props; - const classes = useStyles(); const { @@ -152,36 +147,25 @@ export function EntityAutocompletePicker< return ( - - {label} - - PopperComponent={popperProps => ( -
{popperProps.children as ReactNode}
- )} - multiple - disableCloseOnSelect - options={availableOptions} - value={selectedOptions} - onChange={(_event: object, options: string[]) => - setSelectedOptions(options) - } - renderOption={(option, { selected }) => ( - - )} - size="small" - popupIcon={ - - } - renderInput={params => ( - - )} - /> -
+ + multiple + disableCloseOnSelect + label={label} + name={`${String(name)}-picker`} + options={availableOptions} + value={selectedOptions} + onChange={(_event: object, options: string[]) => + setSelectedOptions(options) + } + renderOption={(option, { selected }) => ( + + )} + />
); } diff --git a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePickerInput.tsx b/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePickerInput.tsx deleted file mode 100644 index 133024330c..0000000000 --- a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePickerInput.tsx +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 TextField, { TextFieldProps } from '@material-ui/core/TextField'; -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'; -import React from 'react'; -import classnames from 'classnames'; - -const useStyles = makeStyles( - (theme: Theme) => - createStyles({ - input: { - backgroundColor: theme.palette.background.paper, - }, - }), - { - name: 'CatalogReactEntityAutocompletePickerInput', - }, -); - -export function EntityAutocompletePickerInput(params: TextFieldProps) { - const classes = useStyles(); - - return ( - - ); -} diff --git a/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.tsx b/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.tsx index ecbdae1d63..bf8db5f627 100644 --- a/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.tsx +++ b/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.tsx @@ -22,15 +22,13 @@ import { import Box from '@material-ui/core/Box'; import Checkbox from '@material-ui/core/Checkbox'; import FormControlLabel from '@material-ui/core/FormControlLabel'; -import TextField from '@material-ui/core/TextField'; import Typography from '@material-ui/core/Typography'; import Tooltip from '@material-ui/core/Tooltip'; -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'; +import { makeStyles } from '@material-ui/core/styles'; 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/Autocomplete'; -import React, { useEffect, useMemo, useState, ReactNode } from 'react'; +import { Autocomplete } from '@backstage/core-components'; +import React, { useEffect, useMemo, useState } from 'react'; import { useEntityList } from '../../hooks/useEntityListProvider'; import { EntityOwnerFilter } from '../../filters'; import { useDebouncedEffect } from '@react-hookz/web'; @@ -42,29 +40,20 @@ import { withStyles } from '@material-ui/core/styles'; import { useEntityPresentation } from '../../apis'; import { catalogReactTranslationRef } from '../../translation'; import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; -import { PopperProps } from '@material-ui/core/Popper'; /** @public */ export type CatalogReactEntityOwnerPickerClassKey = 'input'; const useStyles = makeStyles( - (theme: Theme) => - createStyles({ - root: {}, - label: { - textTransform: 'none', - fontWeight: 'bold', - }, - input: { - backgroundColor: theme.palette.background.paper, - }, - fullWidth: { width: '100%' }, - boxLabel: { - width: '100%', - textOverflow: 'ellipsis', - overflow: 'hidden', - }, - }), + { + root: {}, + fullWidth: { width: '100%' }, + boxLabel: { + width: '100%', + textOverflow: 'ellipsis', + overflow: 'hidden', + }, + }, { name: 'CatalogReactEntityOwnerPicker' }, ); @@ -147,7 +136,7 @@ export const EntityOwnerPicker = (props?: EntityOwnerPickerProps) => { [ownersParameter], ); - const [selectedOwners, setSelectedOwners] = useState( + const [selectedOwners, setSelectedOwners] = useState( queryParamOwners.length ? queryParamOwners : filters.owners?.values ?? [], ); @@ -186,84 +175,67 @@ export const EntityOwnerPicker = (props?: EntityOwnerPickerProps) => { return ( - - {t('entityOwnerPicker.title')} - { - if (typeof v === 'string') { - return stringifyEntityRef(o) === v; - } - return o === v; - }} - getOptionLabel={o => { - const entity = - typeof o === 'string' - ? cache.getEntity(o) || - parseEntityRef(o, { - defaultKind: 'group', - defaultNamespace: 'default', - }) - : o; - return humanizeEntity(entity, humanizeEntityRef(entity)); - }} - onChange={(_: object, owners) => { - setText(''); - setSelectedOwners( - owners.map(e => { - const entityRef = - typeof e === 'string' ? e : stringifyEntityRef(e); + + label={t('entityOwnerPicker.title')} + multiple + disableCloseOnSelect + loading={loading} + options={availableOwners} + value={selectedOwners as unknown as Entity[]} + getOptionSelected={(o, v) => { + if (typeof v === 'string') { + return stringifyEntityRef(o) === v; + } + return o === v; + }} + getOptionLabel={o => { + const entity = + typeof o === 'string' + ? cache.getEntity(o) || + parseEntityRef(o, { + defaultKind: 'group', + defaultNamespace: 'default', + }) + : o; + return humanizeEntity(entity, humanizeEntityRef(entity)); + }} + onChange={(_: object, owners) => { + setText(''); + setSelectedOwners( + owners.map(e => { + const entityRef = + typeof e === 'string' ? e : stringifyEntityRef(e); - if (typeof e !== 'string') { - cache.setEntity(e); - } - return entityRef; - }), - ); - }} - filterOptions={x => x} - renderOption={(entity, { selected }) => { - return ; - }} - size="small" - popupIcon={} - renderInput={params => ( - { - setText(e.currentTarget.value); - }} - variant="outlined" - /> - )} - ListboxProps={{ - onScroll: (e: React.MouseEvent) => { - const element = e.currentTarget; - const hasReachedEnd = - Math.abs( - element.scrollHeight - - element.clientHeight - - element.scrollTop, - ) < 1; - - if (hasReachedEnd && value?.cursor) { - handleFetch({ items: value.items, cursor: value.cursor }); + if (typeof e !== 'string') { + cache.setEntity(e); } - }, - 'data-testid': 'owner-picker-listbox', - }} - /> - + return entityRef; + }), + ); + }} + filterOptions={x => x} + renderOption={(entity, { selected }) => { + return ; + }} + name="owner-picker" + onInputChange={(_e, inputValue) => { + setText(inputValue); + }} + ListboxProps={{ + onScroll: (e: React.MouseEvent) => { + const element = e.currentTarget; + const hasReachedEnd = + Math.abs( + element.scrollHeight - element.clientHeight - element.scrollTop, + ) < 1; + + if (hasReachedEnd && value?.cursor) { + handleFetch({ items: value.items, cursor: value.cursor }); + } + }, + 'data-testid': 'owner-picker-listbox', + }} + /> ); }; - -function Popper({ children }: PopperProps) { - return
{children as ReactNode}
; -} diff --git a/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.tsx b/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.tsx index a2f0c8f729..02d1ddc238 100644 --- a/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.tsx +++ b/plugins/catalog-react/src/components/EntityProcessingStatusPicker/EntityProcessingStatusPicker.tsx @@ -18,15 +18,12 @@ import { EntityErrorFilter, EntityOrphanFilter } from '../../filters'; import Box from '@material-ui/core/Box'; import Checkbox from '@material-ui/core/Checkbox'; import FormControlLabel from '@material-ui/core/FormControlLabel'; -import TextField from '@material-ui/core/TextField'; -import Typography from '@material-ui/core/Typography'; -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'; +import { makeStyles } from '@material-ui/core/styles'; import CheckBoxIcon from '@material-ui/icons/CheckBox'; import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; -import React, { useState, ReactNode } from 'react'; +import React, { useState } from 'react'; import { useEntityList } from '../../hooks'; -import Autocomplete from '@material-ui/lab/Autocomplete'; +import { Autocomplete } from '@backstage/core-components'; import { catalogReactTranslationRef } from '../../translation'; import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; @@ -34,17 +31,9 @@ import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; export type CatalogReactEntityProcessingStatusPickerClassKey = 'input'; const useStyles = makeStyles( - (theme: Theme) => - createStyles({ - root: {}, - input: { - backgroundColor: theme.palette.background.paper, - }, - label: { - textTransform: 'none', - fontWeight: 'bold', - }, - }), + { + root: {}, + }, { name: 'CatalogReactEntityProcessingStatusPickerPicker' }, ); @@ -77,47 +66,32 @@ export const EntityProcessingStatusPicker = () => { return ( - - {t('entityProcessingStatusPicker.title')} - - PopperComponent={popperProps => ( -
{popperProps.children as ReactNode}
- )} - multiple - disableCloseOnSelect - options={availableAdvancedItems} - value={selectedAdvancedItems} - onChange={(_: object, value: string[]) => { - setSelectedAdvancedItems(value); - orphanChange(value.includes('Is Orphan')); - errorChange(value.includes('Has Error')); - }} - renderOption={(option, { selected }) => ( - - } - onClick={event => event.preventDefault()} - label={option} - /> - )} - size="small" - popupIcon={ - - } - renderInput={params => ( - - )} - /> -
+ + label={t('entityProcessingStatusPicker.title')} + multiple + disableCloseOnSelect + options={availableAdvancedItems} + value={selectedAdvancedItems} + onChange={(_: object, value: string[]) => { + setSelectedAdvancedItems(value); + orphanChange(value.includes('Is Orphan')); + errorChange(value.includes('Has Error')); + }} + renderOption={(option, { selected }) => ( + + } + onClick={event => event.preventDefault()} + label={option} + /> + )} + name="processing-status-picker" + />
); };