Merge pull request #9752 from backstage/blam/deprecations/scaffolder/frontend
🧹 some tidying up in the `scaffolder` plugin
This commit is contained in:
@@ -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.
|
||||
@@ -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`.
|
||||
@@ -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<string>) => {
|
||||
const {
|
||||
onChange,
|
||||
required,
|
||||
schema: { title, description },
|
||||
rawErrors,
|
||||
formData,
|
||||
uiSchema: { 'ui:autofocus': autoFocus },
|
||||
idSchema,
|
||||
placeholder,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<TextField
|
||||
id={idSchema?.$id}
|
||||
label={title}
|
||||
placeholder={placeholder}
|
||||
helperText={description}
|
||||
required={required}
|
||||
value={formData ?? ''}
|
||||
onChange={({ target: { value } }) => onChange(value)}
|
||||
margin="normal"
|
||||
error={rawErrors?.length > 0 && !formData}
|
||||
inputProps={{ autoFocus }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const LowerCaseValuePickerFieldExtension = scaffolderPlugin.provide(
|
||||
createScaffolderFieldExtension({
|
||||
name: 'LowerCaseValuePicker',
|
||||
|
||||
@@ -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<T = any>(
|
||||
options: FieldExtensionOptions<T>,
|
||||
export function createScaffolderFieldExtension<
|
||||
TReturnValue = unknown,
|
||||
TInputProps = unknown,
|
||||
>(
|
||||
options: FieldExtensionOptions<TReturnValue, TInputProps>,
|
||||
): Extension<() => null>;
|
||||
|
||||
// @public
|
||||
export type CustomFieldValidator<T> =
|
||||
| ((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<string>) => JSX.Element;
|
||||
export type CustomFieldValidator<TFieldReturnValue> = (
|
||||
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<string>) => JSX.Element;
|
||||
// @public
|
||||
export const EntityPicker: (
|
||||
props: FieldExtensionComponentProps<string, EntityPickerUiOptions>,
|
||||
) => 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<string[]>) => JSX.Element;
|
||||
export const EntityTagsPicker: (
|
||||
props: FieldExtensionComponentProps<string[], EntityTagsPickerUiOptions>,
|
||||
) => 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<ReturnValue> {
|
||||
TFieldReturnValue,
|
||||
TUiOptions extends {} = {},
|
||||
> extends FieldProps<TFieldReturnValue> {
|
||||
// (undocumented)
|
||||
uiSchema: {
|
||||
'ui:options'?: UiOptions;
|
||||
uiSchema: FieldProps['uiSchema'] & {
|
||||
'ui:options'?: TUiOptions;
|
||||
};
|
||||
}
|
||||
|
||||
// @public
|
||||
export type FieldExtensionOptions<T = any> = {
|
||||
export type FieldExtensionOptions<
|
||||
TFieldReturnValue = unknown,
|
||||
TProps = FieldProps<TFieldReturnValue>,
|
||||
> = {
|
||||
name: string;
|
||||
component: (props: FieldProps<T>) => JSX.Element | null;
|
||||
validation?: CustomFieldValidator<T>;
|
||||
component: (props: TProps) => JSX.Element | null;
|
||||
validation?: CustomFieldValidator<TFieldReturnValue>;
|
||||
};
|
||||
|
||||
// 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<string>) => JSX.Element;
|
||||
// @public
|
||||
export const OwnedEntityPicker: (
|
||||
props: FieldExtensionComponentProps<string, OwnedEntityPickerUiOptions>,
|
||||
) => 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<string>) => 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<string, OwnerPickerUiOptions>,
|
||||
) => 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<string, RepoUrlPickerUiOptions>,
|
||||
) => 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<undefined>;
|
||||
},
|
||||
@@ -284,8 +315,6 @@ const scaffolderPlugin: BackstagePlugin<
|
||||
registerComponent: ExternalRouteRef<undefined, true>;
|
||||
}
|
||||
>;
|
||||
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<string>) => JSX.Element;
|
||||
|
||||
// @public
|
||||
export const useTemplateSecrets: () => {
|
||||
setSecret: (input: Record<string, string>) => void;
|
||||
|
||||
@@ -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<string>) => (
|
||||
<TextValuePicker schema={{ title, description }} {...props} />
|
||||
);
|
||||
/**
|
||||
* EntityName Picker
|
||||
*/
|
||||
export const EntityNamePicker = (
|
||||
props: FieldExtensionComponentProps<string>,
|
||||
) => {
|
||||
const {
|
||||
onChange,
|
||||
required,
|
||||
schema: { title = 'Name', description = 'Unique name of the component' },
|
||||
rawErrors,
|
||||
formData,
|
||||
uiSchema: { 'ui:autofocus': autoFocus },
|
||||
idSchema,
|
||||
placeholder,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<TextField
|
||||
id={idSchema?.$id}
|
||||
label={title}
|
||||
placeholder={placeholder}
|
||||
helperText={description}
|
||||
required={required}
|
||||
value={formData ?? ''}
|
||||
onChange={({ target: { value } }) => onChange(value)}
|
||||
margin="normal"
|
||||
error={rawErrors?.length > 0 && !formData}
|
||||
inputProps={{ autoFocus }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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('<EntityPicker />', () => {
|
||||
});
|
||||
|
||||
it('updates even if there is not an exact match', async () => {
|
||||
const { getByLabelText } = await renderInTestApp(
|
||||
const { getByRole } = await renderInTestApp(
|
||||
<Wrapper>
|
||||
<EntityPicker {...props} />
|
||||
</Wrapper>,
|
||||
);
|
||||
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('<EntityPicker />', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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<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;
|
||||
|
||||
export const EntityPicker = ({
|
||||
onChange,
|
||||
schema: { title = 'Entity', description = 'An entity from the catalog' },
|
||||
required,
|
||||
uiSchema,
|
||||
rawErrors,
|
||||
formData,
|
||||
idSchema,
|
||||
}: FieldProps<string>) => {
|
||||
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 => (
|
||||
<TextField
|
||||
{...params}
|
||||
|
||||
@@ -14,3 +14,4 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { EntityPicker } from './EntityPicker';
|
||||
export type { EntityPickerUiOptions } from './EntityPicker';
|
||||
|
||||
@@ -22,22 +22,23 @@ import { useApi } from '@backstage/core-plugin-api';
|
||||
import { catalogApiRef } from '@backstage/plugin-catalog-react';
|
||||
import { FormControl, TextField } from '@material-ui/core';
|
||||
import { Autocomplete } from '@material-ui/lab';
|
||||
import { FieldProps } from '@rjsf/core';
|
||||
import { FieldExtensionComponentProps } from '../../../extensions';
|
||||
|
||||
export interface EntityTagsPickerUiOptions {
|
||||
kinds?: string[];
|
||||
}
|
||||
/**
|
||||
* EntityTagsPicker
|
||||
* @public
|
||||
*/
|
||||
export const EntityTagsPicker = ({
|
||||
formData,
|
||||
onChange,
|
||||
uiSchema,
|
||||
}: FieldProps<string[]>) => {
|
||||
export const EntityTagsPicker = (
|
||||
props: FieldExtensionComponentProps<string[], EntityTagsPickerUiOptions>,
|
||||
) => {
|
||||
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'] };
|
||||
|
||||
@@ -14,3 +14,4 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { EntityTagsPicker } from './EntityTagsPicker';
|
||||
export type { EntityTagsPickerUiOptions } from './EntityTagsPicker';
|
||||
|
||||
@@ -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<string>) => {
|
||||
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<string, OwnedEntityPickerUiOptions>,
|
||||
) => {
|
||||
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
|
||||
|
||||
@@ -14,3 +14,4 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { OwnedEntityPicker } from './OwnedEntityPicker';
|
||||
export type { OwnedEntityPickerUiOptions } from './OwnedEntityPicker';
|
||||
|
||||
@@ -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<string, OwnerPickerUiOptions>,
|
||||
) => {
|
||||
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<string>) => {
|
||||
const ownerUiSchema = {
|
||||
...uiSchema,
|
||||
'ui:options': {
|
||||
@@ -35,7 +46,7 @@ export const OwnerPicker = ({
|
||||
|
||||
return (
|
||||
<EntityPicker
|
||||
{...props}
|
||||
{...restProps}
|
||||
schema={{ title, description }}
|
||||
uiSchema={ownerUiSchema}
|
||||
/>
|
||||
|
||||
@@ -14,3 +14,4 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { OwnerPicker } from './OwnerPicker';
|
||||
export type { OwnerPickerUiOptions } from './OwnerPicker';
|
||||
|
||||
@@ -44,6 +44,9 @@ export interface RepoUrlPickerUiOptions {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Repo Url Picker
|
||||
*/
|
||||
export const RepoUrlPicker = (
|
||||
props: FieldExtensionComponentProps<string, RepoUrlPickerUiOptions>,
|
||||
) => {
|
||||
|
||||
@@ -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<string>) => (
|
||||
<TextField
|
||||
id={idSchema?.$id}
|
||||
label={title}
|
||||
placeholder={placeholder}
|
||||
helperText={description}
|
||||
required={required}
|
||||
value={formData ?? ''}
|
||||
onChange={({ target: { value } }) => onChange(value)}
|
||||
margin="normal"
|
||||
error={rawErrors?.length > 0 && !formData}
|
||||
inputProps={{ autoFocus }}
|
||||
/>
|
||||
);
|
||||
@@ -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';
|
||||
@@ -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';
|
||||
|
||||
@@ -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<any>[] =
|
||||
[
|
||||
{
|
||||
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',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -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<T = any>(
|
||||
options: FieldExtensionOptions<T>,
|
||||
export function createScaffolderFieldExtension<
|
||||
TReturnValue = unknown,
|
||||
TInputProps = unknown,
|
||||
>(
|
||||
options: FieldExtensionOptions<TReturnValue, TInputProps>,
|
||||
// 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() {
|
||||
|
||||
@@ -21,13 +21,11 @@ import { FieldValidation, FieldProps } from '@rjsf/core';
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CustomFieldValidator<T> =
|
||||
| ((data: T, field: FieldValidation) => void)
|
||||
| ((
|
||||
data: T,
|
||||
field: FieldValidation,
|
||||
context: { apiHolder: ApiHolder },
|
||||
) => void);
|
||||
export type CustomFieldValidator<TFieldReturnValue> = (
|
||||
data: TFieldReturnValue,
|
||||
field: FieldValidation,
|
||||
context: { apiHolder: ApiHolder },
|
||||
) => void;
|
||||
|
||||
/**
|
||||
* Type for the Custom Field Extension with the
|
||||
@@ -35,10 +33,13 @@ export type CustomFieldValidator<T> =
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type FieldExtensionOptions<T = any> = {
|
||||
export type FieldExtensionOptions<
|
||||
TFieldReturnValue = unknown,
|
||||
TProps = FieldProps<TFieldReturnValue>,
|
||||
> = {
|
||||
name: string;
|
||||
component: (props: FieldProps<T>) => JSX.Element | null;
|
||||
validation?: CustomFieldValidator<T>;
|
||||
component: (props: TProps) => JSX.Element | null;
|
||||
validation?: CustomFieldValidator<TFieldReturnValue>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -48,10 +49,10 @@ export type FieldExtensionOptions<T = any> = {
|
||||
* @public
|
||||
*/
|
||||
export interface FieldExtensionComponentProps<
|
||||
ReturnValue,
|
||||
UiOptions extends {} = {},
|
||||
> extends FieldProps<ReturnValue> {
|
||||
uiSchema: {
|
||||
'ui:options'?: UiOptions;
|
||||
TFieldReturnValue,
|
||||
TUiOptions extends {} = {},
|
||||
> extends FieldProps<TFieldReturnValue> {
|
||||
uiSchema: FieldProps['uiSchema'] & {
|
||||
'ui:options'?: TUiOptions;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user