refactor: convert EntityPicker to use ScaffolderField component

Signed-off-by: Toby Harradine <tobyh@canva.com>
This commit is contained in:
Toby Harradine
2025-04-16 20:38:42 +10:00
parent d7da01d98b
commit 97f7592ea9
2 changed files with 8 additions and 69 deletions
@@ -28,13 +28,6 @@ import { EntityPickerProps } from './schema';
import { ScaffolderRJSFFieldProps as FieldProps } from '@backstage/plugin-scaffolder-react';
import { DefaultEntityPresentationApi } from '@backstage/plugin-catalog';
import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils';
import * as backstageCore from '@backstage/core-components';
// Mock MarkdownContent to test that it's called with the right props
jest.mock('@backstage/core-components', () => ({
...jest.requireActual('@backstage/core-components'),
MarkdownContent: jest.fn(() => null),
}));
const makeEntity = (kind: string, namespace: string, name: string): Entity => ({
apiVersion: 'scaffolder.backstage.io/v1beta3',
@@ -819,39 +812,4 @@ describe('<EntityPicker />', () => {
expect(onChange).toHaveBeenCalledWith(undefined);
});
});
describe('with markdown description', () => {
beforeEach(() => {
jest.clearAllMocks();
uiSchema = { 'ui:options': {} };
props = {
onChange,
schema: {
description: '**Bold text** and *italic text*',
},
required,
uiSchema,
rawErrors,
formData,
} as unknown as FieldProps;
catalogApi.getEntities.mockResolvedValue({ items: entities });
});
it('renders description as markdown', async () => {
await renderInTestApp(
<Wrapper>
<EntityPicker {...props} />
</Wrapper>,
);
expect(backstageCore.MarkdownContent).toHaveBeenCalledWith(
expect.objectContaining({
content: '**Bold text** and *italic text*',
linkTarget: '_blank',
}),
expect.anything(),
);
});
});
});
@@ -29,10 +29,7 @@ import {
catalogApiRef,
entityPresentationApiRef,
} from '@backstage/plugin-catalog-react';
import { MarkdownContent } from '@backstage/core-components';
import TextField from '@material-ui/core/TextField';
import FormControl from '@material-ui/core/FormControl';
import { makeStyles } from '@material-ui/core/styles';
import Autocomplete, {
AutocompleteChangeReason,
createFilterOptions,
@@ -48,21 +45,10 @@ import {
import { VirtualizedListbox } from '../VirtualizedListbox';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
import { scaffolderTranslationRef } from '../../../translation';
import { ScaffolderField } from '@backstage/plugin-scaffolder-react/alpha';
export { EntityPickerSchema } from './schema';
const useStyles = makeStyles(theme => ({
markdownDescription: {
fontSize: theme.typography.caption.fontSize,
margin: 0,
color: theme.palette.text.secondary,
'& :first-child': {
margin: 0,
marginTop: '3px', // to keep the standard browser padding
},
},
}));
/**
* The underlying component that is rendered in the form for the `EntityPicker`
* field extension.
@@ -71,7 +57,6 @@ const useStyles = makeStyles(theme => ({
*/
export const EntityPicker = (props: EntityPickerProps) => {
const { t } = useTranslationRef(scaffolderTranslationRef);
const classes = useStyles();
const {
onChange,
schema: {
@@ -83,6 +68,7 @@ export const EntityPicker = (props: EntityPickerProps) => {
rawErrors,
formData,
idSchema,
errors,
} = props;
const catalogFilter = buildCatalogFilter(uiSchema);
const defaultKind = uiSchema['ui:options']?.defaultKind;
@@ -194,10 +180,12 @@ export const EntityPicker = (props: EntityPickerProps) => {
}, [entities, onChange, selectedEntity, required, allowArbitraryValues]);
return (
<FormControl
margin="normal"
<ScaffolderField
rawErrors={rawErrors}
rawDescription={description}
required={required}
error={rawErrors?.length > 0 && !formData}
disabled={isDisabled}
errors={errors}
>
<Autocomplete
disabled={
@@ -239,14 +227,7 @@ export const EntityPicker = (props: EntityPickerProps) => {
})}
ListboxComponent={VirtualizedListbox}
/>
{description && (
<MarkdownContent
content={description}
linkTarget="_blank"
className={classes.markdownDescription}
/>
)}
</FormControl>
</ScaffolderField>
);
};