diff --git a/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.test.ts b/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.test.ts index fe8b41a9f3..3c4442afea 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.test.ts +++ b/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.test.ts @@ -272,4 +272,59 @@ describe('createAsyncValidators', () => { }, }); }); + + it('should call a validator for array property from a custom field extension', async () => { + const schema: JsonObject = { + type: 'object', + properties: { + tags: { + title: 'Tags', + type: 'array', + items: { + type: 'string', + 'ui:field': 'TagField', + }, + }, + }, + }; + + const validators = { TagField: jest.fn() }; + + const validate = createAsyncValidators(schema, validators, { + apiHolder: { get: jest.fn() }, + }); + + await validate({ + tags: ['tag-1', 'tag-2'], + }); + + expect(validators.TagField).toHaveBeenCalled(); + }); + + it('should does not call a validator if no ui field specified', async () => { + const schema: JsonObject = { + type: 'object', + properties: { + tags: { + title: 'Tags', + type: 'array', + items: { + type: 'string', + }, + }, + }, + }; + + const validators = { TagField: jest.fn() }; + + const validate = createAsyncValidators(schema, validators, { + apiHolder: { get: jest.fn() }, + }); + + await validate({ + tags: ['asd', 'asd$'], + }); + + expect(validators.TagField).not.toHaveBeenCalled(); + }); }); diff --git a/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.ts b/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.ts index 86b7619b34..b524944719 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.ts +++ b/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.ts @@ -15,7 +15,7 @@ */ import { FieldValidation } from '@rjsf/utils'; -import type { JsonObject } from '@backstage/types'; +import type { JsonObject, JsonValue } from '@backstage/types'; import { ApiHolder } from '@backstage/core-plugin-api'; import { Draft07 as JSONSchema } from 'json-schema-library'; import { createFieldValidation } from '../../lib'; @@ -44,20 +44,38 @@ export const createAsyncValidators = ( const parsedSchema = new JSONSchema(rootSchema); const formValidation: FormValidation = {}; + const validateForm = async ( + validatorName: string, + key: string, + value: JsonValue | undefined, + ) => { + const validator = validators[validatorName]; + if (validator) { + const fieldValidation = createFieldValidation(); + try { + await validator(value, fieldValidation, { ...context, formData }); + } catch (ex) { + fieldValidation.addError(ex.message); + } + formValidation[key] = fieldValidation; + } + }; + for (const [key, value] of Object.entries(current)) { const path = `${pathPrefix}/${key}`; const definitionInSchema = parsedSchema.getSchema(path, formData); if (definitionInSchema && 'ui:field' in definitionInSchema) { - const validator = validators[definitionInSchema['ui:field']]; - if (validator) { - const fieldValidation = createFieldValidation(); - try { - await validator(value, fieldValidation, { ...context, formData }); - } catch (ex) { - fieldValidation.addError(ex.message); - } - formValidation[key] = fieldValidation; + if ('ui:field' in definitionInSchema) { + await validateForm(definitionInSchema['ui:field'], key, value); + } + } else if ( + definitionInSchema && + definitionInSchema.items && + 'ui:field' in definitionInSchema.items + ) { + if ('ui:field' in definitionInSchema.items) { + await validateForm(definitionInSchema.items['ui:field'], key, value); } } else if (isObject(value)) { formValidation[key] = await validate(formData, path, value); diff --git a/plugins/scaffolder/src/components/TemplatePage/createValidator.test.ts b/plugins/scaffolder/src/components/TemplatePage/createValidator.test.ts index 777de0cc36..f5be77811a 100644 --- a/plugins/scaffolder/src/components/TemplatePage/createValidator.test.ts +++ b/plugins/scaffolder/src/components/TemplatePage/createValidator.test.ts @@ -57,7 +57,7 @@ describe('createValidator', () => { apiHolder: apiHolderMock, }; - it('Should call validator for object property from a custom field extension', () => { + it('should call validator for object property from a custom field extension', () => { /* GIVEN */ const rootSchema = { title: 'Title', @@ -89,7 +89,7 @@ describe('createValidator', () => { expect(result.p1.addError).toHaveBeenCalledTimes(1); }); - it('Should call validator for array property from a custom field extension', () => { + it('should call validator for array property from a custom field extension', () => { /* GIVEN */ const rootSchema = { title: 'My form',