give the ability to supply a transformErrors function to the Stepper form

Signed-off-by: Paul Cowan <paul.cowan@cutting.scot>
This commit is contained in:
Paul Cowan
2022-11-16 14:18:34 +00:00
parent 50704338f2
commit adb1b01e32
5 changed files with 72 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': minor
---
give the ability to supply a transform errors function to the Stepper form
@@ -30,6 +30,7 @@ import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
import { TemplateGroupFilter } from '../TemplateListPage/TemplateGroups';
import { nextSelectedTemplateRouteRef } from '../../routes';
import { SecretsContextProvider } from '../../components/secrets/SecretsContext';
import type { ErrorTransformer } from '@rjsf/utils';
/**
* The Props for the Scaffolder Router
@@ -44,6 +45,7 @@ export type NextRouterProps = {
TaskPageComponent?: React.ComponentType<{}>;
};
groups?: TemplateGroupFilter[];
transformErrors?: ErrorTransformer;
};
/**
@@ -18,6 +18,7 @@ import { TemplateParameterSchema } from '../../../types';
import { Stepper } from './Stepper';
import { renderInTestApp } from '@backstage/test-utils';
import { act, fireEvent } from '@testing-library/react';
import type { RJSFValidationError } from '@rjsf/utils';
describe('Stepper', () => {
it('should render the step titles for each step of the manifest', async () => {
@@ -140,4 +141,50 @@ describe('Stepper', () => {
expect(getByText('im a custom field extension')).toBeInTheDocument();
});
it('should transform default error message', async () => {
const manifest: TemplateParameterSchema = {
steps: [
{
title: 'Step 1',
schema: {
properties: {
postcode: {
type: 'string',
pattern: '[A-Z][0-9][A-Z] [0-9][A-Z][0-9]',
},
},
},
},
],
title: 'transformErrors Form Test',
};
const transformErrors = (errors: RJSFValidationError[]) => {
return errors.map(err =>
err.property === '.postcode'
? { ...err, message: 'invalid postcode' }
: err,
);
};
const { getByText, getByRole } = await renderInTestApp(
<Stepper
manifest={manifest}
extensions={[]}
onComplete={jest.fn()}
transformErrors={transformErrors}
/>,
);
await fireEvent.change(getByRole('textbox', { name: 'postcode' }), {
target: { value: 'invalid' },
});
await act(async () => {
await fireEvent.click(getByRole('button', { name: 'Review' }));
});
expect(getByText('invalid postcode')).toBeInTheDocument();
});
});
@@ -36,6 +36,7 @@ import { useTemplateSchema } from './useTemplateSchema';
import { ReviewState } from './ReviewState';
import validator from '@rjsf/validator-ajv8';
import { selectedTemplateRouteRef } from '../../../routes';
import type { ErrorTransformer } from '@rjsf/utils';
const useStyles = makeStyles(theme => ({
backButton: {
@@ -56,6 +57,7 @@ export interface StepperProps {
manifest: TemplateParameterSchema;
extensions: NextFieldExtensionOptions<any, any>[];
onComplete: (values: Record<string, JsonValue>) => Promise<void>;
transformErrors?: ErrorTransformer;
}
// TODO(blam): We require here, as the types in this package depend on @rjsf/core explicitly
@@ -149,6 +151,19 @@ export const Stepper = (props: StepperProps) => {
onSubmit={handleNext}
fields={extensions}
showErrorList={false}
transformErrors={props.transformErrors}
// this is needed because handleNext is really triggering the validation
// which only happens onSubmit
onChange={({ formData, schema }) => {
if (props.transformErrors) {
validator.validateFormData(
formData,
schema,
undefined,
props.transformErrors,
);
}
}}
>
<div className={styles.footer}>
<Button
@@ -44,9 +44,11 @@ import {
} from '../../routes';
import { SecretsContext } from '../../components/secrets/SecretsContext';
import { JsonValue } from '@backstage/types';
import type { ErrorTransformer } from '@rjsf/utils';
export interface TemplateWizardPageProps {
customFieldExtensions: NextFieldExtensionOptions<any, any>[];
transformErrors?: ErrorTransformer;
}
const useStyles = makeStyles<BackstageTheme>(() => ({
@@ -137,6 +139,7 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => {
manifest={manifest}
extensions={props.customFieldExtensions}
onComplete={onComplete}
transformErrors={props.transformErrors}
/>
</InfoCard>
)}