|
import React, { useCallback, useEffect } from 'react'; |
|
import { useApi } from '@backstage/core-plugin-api'; |
|
import { |
|
catalogApiRef, |
|
humanizeEntityRef, |
|
} from '@backstage/plugin-catalog-react'; |
|
import useAsync from 'react-use/lib/useAsync'; |
|
import { |
|
createScaffolderFieldExtension, |
|
FieldExtensionComponentProps, scaffolderPlugin, |
|
} from '@backstage/plugin-scaffolder'; |
|
import { TextField } from '@material-ui/core'; |
|
import FormControl from '@material-ui/core/FormControl'; |
|
import Autocomplete from '@material-ui/lab/Autocomplete'; |
|
|
|
/** |
|
* The input props that can be specified under `ui:options` for the |
|
* `EntityPicker` field extension. |
|
* |
|
* @public |
|
*/ |
|
export interface EntityPickerUiOptions { |
|
allowedKinds?: string[]; |
|
defaultKind?: string; |
|
allowedTypes?: string[]; |
|
allowArbitraryValues?: boolean; |
|
defaultNamespace?: string | false; |
|
} |
|
|
|
export const CustomEntityPicker = ( |
|
props: FieldExtensionComponentProps<string, EntityPickerUiOptions>, |
|
) => { |
|
const { |
|
onChange, |
|
schema: { title = 'Entity', description = 'An entity from the catalog' }, |
|
required, |
|
uiSchema, |
|
rawErrors, |
|
formData, |
|
idSchema, |
|
} = props; |
|
const allowedKinds = uiSchema['ui:options']?.allowedKinds; |
|
const defaultKind = uiSchema['ui:options']?.defaultKind; |
|
const allowedTypes = uiSchema['ui:options']?.allowedTypes; |
|
|
|
const defaultNamespace = uiSchema['ui:options']?.defaultNamespace; |
|
|
|
const catalogApi = useApi(catalogApiRef); |
|
|
|
const { value: entities, loading } = useAsync(() => |
|
catalogApi.getEntities( |
|
allowedKinds ? { filter: { 'spec.type': allowedTypes!, kind: allowedKinds } } : undefined, |
|
), |
|
); |
|
|
|
const entityRefs = entities?.items.map(e => |
|
humanizeEntityRef(e, { defaultKind, defaultNamespace }), |
|
); |
|
|
|
const onSelect = useCallback( |
|
(_: any, value: string | null) => { |
|
onChange(value ?? undefined); |
|
}, |
|
[onChange], |
|
); |
|
|
|
useEffect(() => { |
|
if (entityRefs?.length === 1) { |
|
onChange(entityRefs[0]); |
|
} |
|
}, [entityRefs, onChange]); |
|
|
|
return ( |
|
<FormControl |
|
margin="normal" |
|
required={required} |
|
error={rawErrors?.length > 0 && !formData} |
|
> |
|
<Autocomplete |
|
disabled={entityRefs?.length === 1} |
|
id={idSchema?.$id} |
|
value={(formData as string) || ''} |
|
loading={loading} |
|
onChange={onSelect} |
|
options={entityRefs || []} |
|
autoSelect |
|
freeSolo={uiSchema['ui:options']?.allowArbitraryValues ?? true} |
|
renderInput={params => ( |
|
<TextField |
|
{...params} |
|
label={title} |
|
margin="dense" |
|
helperText={description} |
|
FormHelperTextProps={{ margin: 'dense', style: { marginLeft: 0 } }} |
|
variant="outlined" |
|
required={required} |
|
InputProps={params.InputProps} |
|
/> |
|
)} |
|
/> |
|
</FormControl> |
|
); |
|
}; |
|
|
|
export const CustomEntityPickerExtension = scaffolderPlugin.provide( |
|
createScaffolderFieldExtension({ |
|
name: 'CustomEntityPicker', |
|
component: CustomEntityPicker, |
|
}), |
|
); |