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 196bae0255..38543b2148 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.test.ts +++ b/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.test.ts @@ -100,10 +100,12 @@ describe('createAsyncValidators', () => { expect.objectContaining({ schema: { type: 'string', + pattern: 'lols', + }, + uiSchema: { 'ui:options': { bob: true, }, - pattern: 'lols', 'ui:field': 'NameField', }, }), @@ -115,7 +117,6 @@ describe('createAsyncValidators', () => { expect.objectContaining({ schema: { type: 'object', - 'ui:field': 'AddressField', properties: { street: { type: 'string', @@ -125,6 +126,11 @@ describe('createAsyncValidators', () => { }, }, }, + uiSchema: { + 'ui:field': 'AddressField', + street: {}, + postcode: {}, + }, }), ); }); diff --git a/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.ts b/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.ts index 111f3a0f1f..31185d1c12 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.ts +++ b/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.ts @@ -18,9 +18,10 @@ import { FieldValidation } from '@rjsf/utils'; 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'; +import { createFieldValidation, extractSchemaFromStep } from '../../lib'; import { NextCustomFieldValidator } from '../../extensions'; import { isObject } from './utils'; +import { NextFieldExtensionUiSchema } from '../../extensions/types'; /** * @internal @@ -31,7 +32,10 @@ export type FormValidation = { export const createAsyncValidators = ( rootSchema: JsonObject, - validators: Record>, + validators: Record< + string, + undefined | NextCustomFieldValidator + >, context: { apiHolder: ApiHolder; }, @@ -49,6 +53,7 @@ export const createAsyncValidators = ( key: string, value: JsonValue | undefined, schema: JsonObject, + uiSchema: NextFieldExtensionUiSchema, ) => { const validator = validators[validatorName]; if (validator) { @@ -58,6 +63,7 @@ export const createAsyncValidators = ( ...context, formData, schema, + uiSchema, }); } catch (ex) { fieldValidation.addError(ex.message); @@ -69,6 +75,7 @@ export const createAsyncValidators = ( for (const [key, value] of Object.entries(current)) { const path = `${pathPrefix}/${key}`; const definitionInSchema = parsedSchema.getSchema(path, formData); + const { schema, uiSchema } = extractSchemaFromStep(definitionInSchema); if (definitionInSchema && 'ui:field' in definitionInSchema) { if ('ui:field' in definitionInSchema) { @@ -76,7 +83,8 @@ export const createAsyncValidators = ( definitionInSchema['ui:field'], key, value, - definitionInSchema, + schema, + uiSchema, ); } } else if ( @@ -85,11 +93,14 @@ export const createAsyncValidators = ( 'ui:field' in definitionInSchema.items ) { if ('ui:field' in definitionInSchema.items) { + const { schema: itemsSchema, uiSchema: itemsUiSchema } = + extractSchemaFromStep(definitionInSchema.items); await validateForm( definitionInSchema.items['ui:field'], key, value, - definitionInSchema.items, + itemsSchema, + itemsUiSchema, ); } } else if (isObject(value)) { diff --git a/plugins/scaffolder-react/src/next/extensions/types.ts b/plugins/scaffolder-react/src/next/extensions/types.ts index 0917efe85d..803dcb2be6 100644 --- a/plugins/scaffolder-react/src/next/extensions/types.ts +++ b/plugins/scaffolder-react/src/next/extensions/types.ts @@ -33,9 +33,17 @@ export interface NextFieldExtensionComponentProps< TFieldReturnValue, TUiOptions = {}, > extends PropsWithChildren> { - uiSchema?: UiSchemaV5 & { - 'ui:options'?: TUiOptions & UIOptionsType; - }; + uiSchema?: NextFieldExtensionUiSchema; +} + +/** + * Type for Field Extension UiSchema + * + * @alpha + */ +export interface NextFieldExtensionUiSchema + extends UiSchemaV5 { + 'ui:options'?: TUiOptions & UIOptionsType; } /** @@ -43,13 +51,17 @@ export interface NextFieldExtensionComponentProps< * * @alpha */ -export type NextCustomFieldValidator = ( +export type NextCustomFieldValidator< + TFieldReturnValue, + TUiOptions = unknown, +> = ( data: TFieldReturnValue, field: FieldValidationV5, context: { apiHolder: ApiHolder; formData: JsonObject; schema: JsonObject; + uiSchema?: NextFieldExtensionUiSchema; }, ) => void | Promise; @@ -61,12 +73,12 @@ export type NextCustomFieldValidator = ( */ export type NextFieldExtensionOptions< TFieldReturnValue = unknown, - TInputProps = unknown, + TUiOptions = unknown, > = { name: string; component: ( - props: NextFieldExtensionComponentProps, + props: NextFieldExtensionComponentProps, ) => JSX.Element | null; - validation?: NextCustomFieldValidator; + validation?: NextCustomFieldValidator; schema?: CustomFieldExtensionSchema; };