diff --git a/.changeset/sharp-bottles-tan.md b/.changeset/sharp-bottles-tan.md new file mode 100644 index 0000000000..1fcd3dd380 --- /dev/null +++ b/.changeset/sharp-bottles-tan.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +- Reworking the `FieldExtensionComponentType` so we can export the `ui:schema:options` props in the `api-report.md`. +- Exporting all of the `UiOptions` types for the `FieldExtensions` so we can see them in the `api-report.md`. +- Removing the redundant type in the `CustomFieldValidator` union. diff --git a/.changeset/wise-jars-reflect.md b/.changeset/wise-jars-reflect.md new file mode 100644 index 0000000000..e23542cb17 --- /dev/null +++ b/.changeset/wise-jars-reflect.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder': minor +--- + +- **BREAKING** - Removed the `plugin` export, use `scaffolderPlugin` instead. +- **BREAKING** - Removed the `TextValuePicker` component export, you can inline this component instead as it's a simple wrapper around a `TextField` from `@material-ui/core`. diff --git a/packages/app/src/components/scaffolder/customScaffolderExtensions.tsx b/packages/app/src/components/scaffolder/customScaffolderExtensions.tsx index 1c96e9325c..61407e2918 100644 --- a/packages/app/src/components/scaffolder/customScaffolderExtensions.tsx +++ b/packages/app/src/components/scaffolder/customScaffolderExtensions.tsx @@ -13,14 +13,44 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +import React from 'react'; import type { FieldValidation } from '@rjsf/core'; import { createScaffolderFieldExtension, - TextValuePicker, + FieldExtensionComponentProps, scaffolderPlugin, } from '@backstage/plugin-scaffolder'; +import { TextField } from '@material-ui/core'; + +const TextValuePicker = (props: FieldExtensionComponentProps) => { + const { + onChange, + required, + schema: { title, description }, + rawErrors, + formData, + uiSchema: { 'ui:autofocus': autoFocus }, + idSchema, + placeholder, + } = props; + + return ( + onChange(value)} + margin="normal" + error={rawErrors?.length > 0 && !formData} + inputProps={{ autoFocus }} + /> + ); +}; + export const LowerCaseValuePickerFieldExtension = scaffolderPlugin.provide( createScaffolderFieldExtension({ name: 'LowerCaseValuePicker', diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index 0a9145c780..fb3fd830f7 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -32,28 +32,21 @@ import { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common'; // Warning: (ae-missing-release-tag) "createScaffolderFieldExtension" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export function createScaffolderFieldExtension( - options: FieldExtensionOptions, +export function createScaffolderFieldExtension< + TReturnValue = unknown, + TInputProps = unknown, +>( + options: FieldExtensionOptions, ): Extension<() => null>; // @public -export type CustomFieldValidator = - | ((data: T, field: FieldValidation) => void) - | (( - data: T, - field: FieldValidation, - context: { - apiHolder: ApiHolder; - }, - ) => void); - -// Warning: (ae-missing-release-tag) "EntityNamePicker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const EntityNamePicker: ({ - schema: { title, description }, - ...props -}: FieldProps) => JSX.Element; +export type CustomFieldValidator = ( + data: TFieldReturnValue, + field: FieldValidation, + context: { + apiHolder: ApiHolder; + }, +) => void; // Warning: (ae-missing-release-tag) "EntityNamePickerFieldExtension" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -62,32 +55,46 @@ export const EntityNamePickerFieldExtension: () => null; // Warning: (ae-missing-release-tag) "EntityPicker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -export const EntityPicker: ({ - onChange, - schema: { title, description }, - required, - uiSchema, - rawErrors, - formData, - idSchema, -}: FieldProps) => JSX.Element; +// @public +export const EntityPicker: ( + props: FieldExtensionComponentProps, +) => JSX.Element; // Warning: (ae-missing-release-tag) "EntityPickerFieldExtension" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export const EntityPickerFieldExtension: () => null; +// Warning: (ae-missing-release-tag) "EntityPickerUiOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface EntityPickerUiOptions { + // (undocumented) + allowArbitraryValues?: boolean; + // (undocumented) + allowedKinds?: string[]; + // (undocumented) + defaultKind?: string; +} + +// Warning: (ae-missing-release-tag) "EntityTagsPicker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public -export const EntityTagsPicker: ({ - formData, - onChange, - uiSchema, -}: FieldProps) => JSX.Element; +export const EntityTagsPicker: ( + props: FieldExtensionComponentProps, +) => JSX.Element; // @public export const EntityTagsPickerFieldExtension: () => null; +// Warning: (ae-missing-release-tag) "EntityTagsPickerUiOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface EntityTagsPickerUiOptions { + // (undocumented) + kinds?: string[]; +} + // Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "FavouriteTemplate" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -96,57 +103,81 @@ export const FavouriteTemplate: (props: Props) => JSX.Element; // @public export interface FieldExtensionComponentProps< - ReturnValue, - UiOptions extends {} = {}, -> extends FieldProps { + TFieldReturnValue, + TUiOptions extends {} = {}, +> extends FieldProps { // (undocumented) - uiSchema: { - 'ui:options'?: UiOptions; + uiSchema: FieldProps['uiSchema'] & { + 'ui:options'?: TUiOptions; }; } // @public -export type FieldExtensionOptions = { +export type FieldExtensionOptions< + TFieldReturnValue = unknown, + TProps = FieldProps, +> = { name: string; - component: (props: FieldProps) => JSX.Element | null; - validation?: CustomFieldValidator; + component: (props: TProps) => JSX.Element | null; + validation?: CustomFieldValidator; }; // Warning: (ae-missing-release-tag) "OwnedEntityPicker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -export const OwnedEntityPicker: ({ - onChange, - schema: { title, description }, - required, - uiSchema, - rawErrors, - formData, - idSchema, -}: FieldProps) => JSX.Element; +// @public +export const OwnedEntityPicker: ( + props: FieldExtensionComponentProps, +) => JSX.Element; // Warning: (ae-missing-release-tag) "OwnedEntityPickerFieldExtension" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export const OwnedEntityPickerFieldExtension: () => null; -// Warning: (ae-missing-release-tag) "OwnerPicker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "OwnedEntityPickerUiOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const OwnerPicker: ({ - schema: { title, description }, - uiSchema, - ...props -}: FieldProps) => JSX.Element; +export interface OwnedEntityPickerUiOptions { + // (undocumented) + allowedKinds?: string[]; + // (undocumented) + defaultKind?: string; +} + +// Warning: (ae-missing-release-tag) "OwnerPicker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export const OwnerPicker: ( + props: FieldExtensionComponentProps, +) => JSX.Element; // Warning: (ae-missing-release-tag) "OwnerPickerFieldExtension" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export const OwnerPickerFieldExtension: () => null; -// Warning: (ae-missing-release-tag) "RepoUrlPicker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "OwnerPickerUiOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) +export interface OwnerPickerUiOptions { + // (undocumented) + allowedKinds?: string[]; +} + +// Warning: (ae-missing-release-tag) "repoPickerValidation" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const repoPickerValidation: ( + value: string, + validation: FieldValidation, + context: { + apiHolder: ApiHolder; + }, +) => void; + +// Warning: (ae-missing-release-tag) "RepoUrlPicker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public export const RepoUrlPicker: ( props: FieldExtensionComponentProps, ) => JSX.Element; @@ -276,7 +307,7 @@ export const ScaffolderPage: ({ // Warning: (ae-missing-release-tag) "scaffolderPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -const scaffolderPlugin: BackstagePlugin< +export const scaffolderPlugin: BackstagePlugin< { root: RouteRef; }, @@ -284,8 +315,6 @@ const scaffolderPlugin: BackstagePlugin< registerComponent: ExternalRouteRef; } >; -export { scaffolderPlugin as plugin }; -export { scaffolderPlugin }; // @public export const TaskPage: ({ loadingText }: TaskPageProps) => JSX.Element; @@ -324,20 +353,6 @@ export type TemplateListProps = { // @public (undocumented) export const TemplateTypePicker: () => JSX.Element | null; -// Warning: (ae-missing-release-tag) "TextValuePicker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const TextValuePicker: ({ - onChange, - required, - schema: { title, description }, - rawErrors, - formData, - uiSchema: { 'ui:autofocus': autoFocus }, - idSchema, - placeholder, -}: FieldProps) => JSX.Element; - // @public export const useTemplateSecrets: () => { setSecret: (input: Record) => void; diff --git a/plugins/scaffolder/src/components/fields/EntityNamePicker/EntityNamePicker.tsx b/plugins/scaffolder/src/components/fields/EntityNamePicker/EntityNamePicker.tsx index 8e7c0b0bea..802135a863 100644 --- a/plugins/scaffolder/src/components/fields/EntityNamePicker/EntityNamePicker.tsx +++ b/plugins/scaffolder/src/components/fields/EntityNamePicker/EntityNamePicker.tsx @@ -14,12 +14,38 @@ * limitations under the License. */ import React from 'react'; -import { FieldProps } from '@rjsf/core'; -import { TextValuePicker } from '../TextValuePicker'; +import { FieldExtensionComponentProps } from '../../../extensions'; +import { TextField } from '@material-ui/core'; -export const EntityNamePicker = ({ - schema: { title = 'Name', description = 'Unique name of the component' }, - ...props -}: FieldProps) => ( - -); +/** + * EntityName Picker + */ +export const EntityNamePicker = ( + props: FieldExtensionComponentProps, +) => { + const { + onChange, + required, + schema: { title = 'Name', description = 'Unique name of the component' }, + rawErrors, + formData, + uiSchema: { 'ui:autofocus': autoFocus }, + idSchema, + placeholder, + } = props; + + return ( + onChange(value)} + margin="normal" + error={rawErrors?.length > 0 && !formData} + inputProps={{ autoFocus }} + /> + ); +}; diff --git a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx index 82f12ac0a3..942eef9d82 100644 --- a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx @@ -18,9 +18,9 @@ import { Entity } from '@backstage/catalog-model'; import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { FieldProps } from '@rjsf/core'; -import userEvent from '@testing-library/user-event'; +import { fireEvent } from '@testing-library/react'; import React from 'react'; -import { EntityPicker, allowArbitraryValues } from './EntityPicker'; +import { EntityPicker } from './EntityPicker'; const makeEntity = (kind: string, namespace: string, name: string): Entity => ({ apiVersion: 'backstage.io/v1beta1', @@ -92,15 +92,16 @@ describe('', () => { }); it('updates even if there is not an exact match', async () => { - const { getByLabelText } = await renderInTestApp( + const { getByRole } = await renderInTestApp( , ); - const input = getByLabelText('Entity'); - userEvent.type(input, 'squ'); - input.blur(); + const input = getByRole('textbox'); + + fireEvent.change(input, { target: { value: 'squ' } }); + fireEvent.blur(input); expect(onChange).toHaveBeenCalledWith('squ'); }); @@ -136,37 +137,3 @@ describe('', () => { }); }); }); - -describe('allowArbitraryValues', () => { - describe('without ui:options', () => { - it('defaults to true', () => { - const uiSchema = {}; - const result = allowArbitraryValues(uiSchema); - expect(result).toBe(true); - }); - }); - - describe('without ui:options.allowArbitraryValues', () => { - it('defaults to true', () => { - const uiSchema = { 'ui:options': {} }; - const result = allowArbitraryValues(uiSchema); - expect(result).toBe(true); - }); - }); - - describe('with ui:options.allowArbitraryValues set to true', () => { - it('is true', () => { - const uiSchema = { 'ui:options': { allowArbitraryValues: true } }; - const result = allowArbitraryValues(uiSchema); - expect(result).toBe(true); - }); - }); - - describe('with ui:options.allowArbitraryValues set to false', () => { - it('is false', () => { - const uiSchema = { 'ui:options': { allowArbitraryValues: false } }; - const result = allowArbitraryValues(uiSchema); - expect(result).toBe(false); - }); - }); -}); diff --git a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx index 959e7883c0..31c44bfe97 100644 --- a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx @@ -21,24 +21,34 @@ import { import { TextField } from '@material-ui/core'; import FormControl from '@material-ui/core/FormControl'; import Autocomplete from '@material-ui/lab/Autocomplete'; -import { FieldProps, UiSchema } from '@rjsf/core'; import React, { useCallback, useEffect } from 'react'; import useAsync from 'react-use/lib/useAsync'; +import { FieldExtensionComponentProps } from '../../../extensions'; -export const allowArbitraryValues = (uiSchema: UiSchema): boolean => - (uiSchema['ui:options']?.allowArbitraryValues as boolean) ?? true; +export interface EntityPickerUiOptions { + allowedKinds?: string[]; + defaultKind?: string; + allowArbitraryValues?: boolean; +} + +/** + * Entity Picker + */ +export const EntityPicker = ( + props: FieldExtensionComponentProps, +) => { + 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; -export const EntityPicker = ({ - onChange, - schema: { title = 'Entity', description = 'An entity from the catalog' }, - required, - uiSchema, - rawErrors, - formData, - idSchema, -}: FieldProps) => { - const allowedKinds = uiSchema['ui:options']?.allowedKinds as string[]; - const defaultKind = uiSchema['ui:options']?.defaultKind as string | undefined; const catalogApi = useApi(catalogApiRef); const { value: entities, loading } = useAsync(() => @@ -78,7 +88,7 @@ export const EntityPicker = ({ onChange={onSelect} options={entityRefs || []} autoSelect - freeSolo={allowArbitraryValues(uiSchema)} + freeSolo={uiSchema['ui:options']?.allowArbitraryValues ?? true} renderInput={params => ( ) => { +export const EntityTagsPicker = ( + props: FieldExtensionComponentProps, +) => { + const { formData, onChange, uiSchema } = props; const catalogApi = useApi(catalogApiRef); const [inputValue, setInputValue] = useState(''); const [inputError, setInputError] = useState(false); const tagValidator = makeValidator().isValidTag; - const kinds = uiSchema['ui:options']?.kinds as string[]; + const kinds = uiSchema['ui:options']?.kinds; const { loading, value: existingTags } = useAsync(async () => { const tagsRequest: GetEntitiesRequest = { fields: ['metadata.tags'] }; diff --git a/plugins/scaffolder/src/components/fields/EntityTagsPicker/index.ts b/plugins/scaffolder/src/components/fields/EntityTagsPicker/index.ts index 09f4d5c519..3ba36a2409 100644 --- a/plugins/scaffolder/src/components/fields/EntityTagsPicker/index.ts +++ b/plugins/scaffolder/src/components/fields/EntityTagsPicker/index.ts @@ -14,3 +14,4 @@ * limitations under the License. */ export { EntityTagsPicker } from './EntityTagsPicker'; +export type { EntityTagsPickerUiOptions } from './EntityTagsPicker'; diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx index 3c2fc2b495..80f63efaf9 100644 --- a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx @@ -20,20 +20,33 @@ import { import { TextField } from '@material-ui/core'; import FormControl from '@material-ui/core/FormControl'; import Autocomplete from '@material-ui/lab/Autocomplete'; -import { FieldProps } from '@rjsf/core'; import React from 'react'; -export const OwnedEntityPicker = ({ - onChange, - schema: { title = 'Entity', description = 'An entity from the catalog' }, - required, - uiSchema, - rawErrors, - formData, - idSchema, -}: FieldProps) => { - const allowedKinds = uiSchema['ui:options']?.allowedKinds as string[]; - const defaultKind = uiSchema['ui:options']?.defaultKind as string | undefined; +import { FieldExtensionComponentProps } from '../../../extensions'; + +export interface OwnedEntityPickerUiOptions { + allowedKinds?: string[]; + defaultKind?: string; +} + +/** + * Owned Entity Picker + */ +export const OwnedEntityPicker = ( + props: FieldExtensionComponentProps, +) => { + 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 { ownedEntities, loading } = useOwnedEntities(allowedKinds); const entityRefs = ownedEntities?.items diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/index.ts b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/index.ts index 7cf5add6eb..125f6fdef0 100644 --- a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/index.ts +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/index.ts @@ -14,3 +14,4 @@ * limitations under the License. */ export { OwnedEntityPicker } from './OwnedEntityPicker'; +export type { OwnedEntityPickerUiOptions } from './OwnedEntityPicker'; diff --git a/plugins/scaffolder/src/components/fields/OwnerPicker/OwnerPicker.tsx b/plugins/scaffolder/src/components/fields/OwnerPicker/OwnerPicker.tsx index dd02622ae9..9012ed149e 100644 --- a/plugins/scaffolder/src/components/fields/OwnerPicker/OwnerPicker.tsx +++ b/plugins/scaffolder/src/components/fields/OwnerPicker/OwnerPicker.tsx @@ -13,15 +13,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { FieldProps } from '@rjsf/core'; import React from 'react'; import { EntityPicker } from '../EntityPicker'; +import { FieldExtensionComponentProps } from '../../../extensions'; + +export interface OwnerPickerUiOptions { + allowedKinds?: string[]; +} + +/** + * Owner Picker + */ +export const OwnerPicker = ( + props: FieldExtensionComponentProps, +) => { + const { + schema: { title = 'Owner', description = 'The owner of the component' }, + uiSchema, + ...restProps + } = props; -export const OwnerPicker = ({ - schema: { title = 'Owner', description = 'The owner of the component' }, - uiSchema, - ...props -}: FieldProps) => { const ownerUiSchema = { ...uiSchema, 'ui:options': { @@ -35,7 +46,7 @@ export const OwnerPicker = ({ return ( diff --git a/plugins/scaffolder/src/components/fields/OwnerPicker/index.ts b/plugins/scaffolder/src/components/fields/OwnerPicker/index.ts index 801ed59c93..b8cb97eb97 100644 --- a/plugins/scaffolder/src/components/fields/OwnerPicker/index.ts +++ b/plugins/scaffolder/src/components/fields/OwnerPicker/index.ts @@ -14,3 +14,4 @@ * limitations under the License. */ export { OwnerPicker } from './OwnerPicker'; +export type { OwnerPickerUiOptions } from './OwnerPicker'; diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx index 1ccaed4e86..fe7c4b18a4 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx @@ -44,6 +44,9 @@ export interface RepoUrlPickerUiOptions { }; } +/** + * Repo Url Picker + */ export const RepoUrlPicker = ( props: FieldExtensionComponentProps, ) => { diff --git a/plugins/scaffolder/src/components/fields/TextValuePicker/TextValuePicker.tsx b/plugins/scaffolder/src/components/fields/TextValuePicker/TextValuePicker.tsx deleted file mode 100644 index 7bed7eedb9..0000000000 --- a/plugins/scaffolder/src/components/fields/TextValuePicker/TextValuePicker.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 { TextField } from '@material-ui/core'; -import { FieldProps } from '@rjsf/core'; -import React from 'react'; - -export const TextValuePicker = ({ - onChange, - required, - schema: { title, description }, - rawErrors, - formData, - uiSchema: { 'ui:autofocus': autoFocus }, - idSchema, - placeholder, -}: FieldProps) => ( - onChange(value)} - margin="normal" - error={rawErrors?.length > 0 && !formData} - inputProps={{ autoFocus }} - /> -); diff --git a/plugins/scaffolder/src/components/fields/TextValuePicker/index.ts b/plugins/scaffolder/src/components/fields/TextValuePicker/index.ts deleted file mode 100644 index 8ab810b6ed..0000000000 --- a/plugins/scaffolder/src/components/fields/TextValuePicker/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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 { TextValuePicker } from './TextValuePicker'; diff --git a/plugins/scaffolder/src/components/fields/index.ts b/plugins/scaffolder/src/components/fields/index.ts index ecde218029..6358934025 100644 --- a/plugins/scaffolder/src/components/fields/index.ts +++ b/plugins/scaffolder/src/components/fields/index.ts @@ -13,10 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export * from './EntityNamePicker'; export * from './EntityPicker'; export * from './OwnerPicker'; export * from './RepoUrlPicker'; -export * from './TextValuePicker'; export * from './OwnedEntityPicker'; export * from './EntityTagsPicker'; diff --git a/plugins/scaffolder/src/extensions/default.ts b/plugins/scaffolder/src/extensions/default.ts index 820cc0e6d3..10c0746e41 100644 --- a/plugins/scaffolder/src/extensions/default.ts +++ b/plugins/scaffolder/src/extensions/default.ts @@ -27,31 +27,32 @@ import { import { FieldExtensionOptions } from './types'; import { OwnedEntityPicker } from '../components/fields/OwnedEntityPicker'; -export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS: FieldExtensionOptions[] = [ - { - component: EntityPicker, - name: 'EntityPicker', - }, - { - component: EntityNamePicker, - name: 'EntityNamePicker', - validation: entityNamePickerValidation, - }, - { - component: EntityTagsPicker, - name: 'EntityTagsPicker', - }, - { - component: RepoUrlPicker, - name: 'RepoUrlPicker', - validation: repoPickerValidation, - }, - { - component: OwnerPicker, - name: 'OwnerPicker', - }, - { - component: OwnedEntityPicker, - name: 'OwnedEntityPicker', - }, -]; +export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS: FieldExtensionOptions[] = + [ + { + component: EntityPicker, + name: 'EntityPicker', + }, + { + component: EntityNamePicker, + name: 'EntityNamePicker', + validation: entityNamePickerValidation, + }, + { + component: EntityTagsPicker, + name: 'EntityTagsPicker', + }, + { + component: RepoUrlPicker, + name: 'RepoUrlPicker', + validation: repoPickerValidation, + }, + { + component: OwnerPicker, + name: 'OwnerPicker', + }, + { + component: OwnedEntityPicker, + name: 'OwnedEntityPicker', + }, + ]; diff --git a/plugins/scaffolder/src/extensions/index.tsx b/plugins/scaffolder/src/extensions/index.tsx index f9c167a6b0..fd816681ea 100644 --- a/plugins/scaffolder/src/extensions/index.tsx +++ b/plugins/scaffolder/src/extensions/index.tsx @@ -25,8 +25,13 @@ import { Extension, attachComponentData } from '@backstage/core-plugin-api'; export const FIELD_EXTENSION_WRAPPER_KEY = 'scaffolder.extensions.wrapper.v1'; export const FIELD_EXTENSION_KEY = 'scaffolder.extensions.field.v1'; -export function createScaffolderFieldExtension( - options: FieldExtensionOptions, +export function createScaffolderFieldExtension< + TReturnValue = unknown, + TInputProps = unknown, +>( + options: FieldExtensionOptions, + // TODO: need know how to embed these types nicely so the api report looks nice. + // then we can remove the export of the components ): Extension<() => null> { return { expose() { diff --git a/plugins/scaffolder/src/extensions/types.ts b/plugins/scaffolder/src/extensions/types.ts index e1da9889e7..574ce7ea64 100644 --- a/plugins/scaffolder/src/extensions/types.ts +++ b/plugins/scaffolder/src/extensions/types.ts @@ -21,13 +21,11 @@ import { FieldValidation, FieldProps } from '@rjsf/core'; * * @public */ -export type CustomFieldValidator = - | ((data: T, field: FieldValidation) => void) - | (( - data: T, - field: FieldValidation, - context: { apiHolder: ApiHolder }, - ) => void); +export type CustomFieldValidator = ( + data: TFieldReturnValue, + field: FieldValidation, + context: { apiHolder: ApiHolder }, +) => void; /** * Type for the Custom Field Extension with the @@ -35,10 +33,13 @@ export type CustomFieldValidator = * * @public */ -export type FieldExtensionOptions = { +export type FieldExtensionOptions< + TFieldReturnValue = unknown, + TProps = FieldProps, +> = { name: string; - component: (props: FieldProps) => JSX.Element | null; - validation?: CustomFieldValidator; + component: (props: TProps) => JSX.Element | null; + validation?: CustomFieldValidator; }; /** @@ -48,10 +49,10 @@ export type FieldExtensionOptions = { * @public */ export interface FieldExtensionComponentProps< - ReturnValue, - UiOptions extends {} = {}, -> extends FieldProps { - uiSchema: { - 'ui:options'?: UiOptions; + TFieldReturnValue, + TUiOptions extends {} = {}, +> extends FieldProps { + uiSchema: FieldProps['uiSchema'] & { + 'ui:options'?: TUiOptions; }; } diff --git a/plugins/scaffolder/src/index.ts b/plugins/scaffolder/src/index.ts index adb2aab035..34091b3fea 100644 --- a/plugins/scaffolder/src/index.ts +++ b/plugins/scaffolder/src/index.ts @@ -39,18 +39,9 @@ export { OwnedEntityPickerFieldExtension, RepoUrlPickerFieldExtension, ScaffolderPage, - scaffolderPlugin as plugin, scaffolderPlugin, } from './plugin'; -export { - EntityNamePicker, - EntityPicker, - EntityTagsPicker, - OwnerPicker, - RepoUrlPicker, - TextValuePicker, - OwnedEntityPicker, -} from './components/fields'; +export * from './components/fields'; export type { RepoUrlPickerUiOptions } from './components/fields'; export { FavouriteTemplate } from './components/FavouriteTemplate'; export { TemplateList } from './components/TemplateList';