Merge pull request #16619 from backstage/blam/ui-schema-in-ctx

scaffolder/next: Move `uiSchema` from `schema` into it's own property
This commit is contained in:
Ben Lambert
2023-02-28 10:55:38 +01:00
committed by GitHub
6 changed files with 65 additions and 20 deletions
+16 -7
View File
@@ -66,13 +66,17 @@ export type FormProps = Pick<
>;
// @alpha
export type NextCustomFieldValidator<TFieldReturnValue> = (
export type NextCustomFieldValidator<
TFieldReturnValue,
TUiOptions = unknown,
> = (
data: TFieldReturnValue,
field: FieldValidation,
context: {
apiHolder: ApiHolder;
formData: JsonObject;
schema: JsonObject;
uiSchema?: NextFieldExtensionUiSchema<TFieldReturnValue, TUiOptions>;
},
) => void | Promise<void>;
@@ -82,24 +86,29 @@ export interface NextFieldExtensionComponentProps<
TUiOptions = {},
> extends PropsWithChildren<FieldProps<TFieldReturnValue>> {
// (undocumented)
uiSchema?: UiSchema<TFieldReturnValue> & {
'ui:options'?: TUiOptions & UIOptionsType;
};
uiSchema?: NextFieldExtensionUiSchema<TFieldReturnValue, TUiOptions>;
}
// @alpha
export type NextFieldExtensionOptions<
TFieldReturnValue = unknown,
TInputProps = unknown,
TUiOptions = unknown,
> = {
name: string;
component: (
props: NextFieldExtensionComponentProps<TFieldReturnValue, TInputProps>,
props: NextFieldExtensionComponentProps<TFieldReturnValue, TUiOptions>,
) => JSX.Element | null;
validation?: NextCustomFieldValidator<TFieldReturnValue>;
validation?: NextCustomFieldValidator<TFieldReturnValue, TUiOptions>;
schema?: CustomFieldExtensionSchema;
};
// @alpha
export interface NextFieldExtensionUiSchema<TFieldReturnValue, TUiOptions>
extends UiSchema<TFieldReturnValue> {
// (undocumented)
'ui:options'?: TUiOptions & UIOptionsType;
}
// @alpha
export interface ParsedTemplateSchema {
// (undocumented)
@@ -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: {},
},
}),
);
});
@@ -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<string, undefined | NextCustomFieldValidator<unknown>>,
validators: Record<
string,
undefined | NextCustomFieldValidator<unknown, unknown>
>,
context: {
apiHolder: ApiHolder;
},
@@ -49,6 +53,7 @@ export const createAsyncValidators = (
key: string,
value: JsonValue | undefined,
schema: JsonObject,
uiSchema: NextFieldExtensionUiSchema<unknown, unknown>,
) => {
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)) {
@@ -18,6 +18,7 @@ import {
NextCustomFieldValidator,
NextFieldExtensionOptions,
NextFieldExtensionComponentProps,
NextFieldExtensionUiSchema,
} from './types';
import { Extension, attachComponentData } from '@backstage/core-plugin-api';
import { UIOptionsType } from '@rjsf/utils';
@@ -54,4 +55,5 @@ export type {
NextCustomFieldValidator,
NextFieldExtensionOptions,
NextFieldExtensionComponentProps,
NextFieldExtensionUiSchema,
};
@@ -33,9 +33,17 @@ export interface NextFieldExtensionComponentProps<
TFieldReturnValue,
TUiOptions = {},
> extends PropsWithChildren<FieldPropsV5<TFieldReturnValue>> {
uiSchema?: UiSchemaV5<TFieldReturnValue> & {
'ui:options'?: TUiOptions & UIOptionsType;
};
uiSchema?: NextFieldExtensionUiSchema<TFieldReturnValue, TUiOptions>;
}
/**
* Type for Field Extension UiSchema
*
* @alpha
*/
export interface NextFieldExtensionUiSchema<TFieldReturnValue, TUiOptions>
extends UiSchemaV5<TFieldReturnValue> {
'ui:options'?: TUiOptions & UIOptionsType;
}
/**
@@ -43,13 +51,17 @@ export interface NextFieldExtensionComponentProps<
*
* @alpha
*/
export type NextCustomFieldValidator<TFieldReturnValue> = (
export type NextCustomFieldValidator<
TFieldReturnValue,
TUiOptions = unknown,
> = (
data: TFieldReturnValue,
field: FieldValidationV5,
context: {
apiHolder: ApiHolder;
formData: JsonObject;
schema: JsonObject;
uiSchema?: NextFieldExtensionUiSchema<TFieldReturnValue, TUiOptions>;
},
) => void | Promise<void>;
@@ -61,12 +73,12 @@ export type NextCustomFieldValidator<TFieldReturnValue> = (
*/
export type NextFieldExtensionOptions<
TFieldReturnValue = unknown,
TInputProps = unknown,
TUiOptions = unknown,
> = {
name: string;
component: (
props: NextFieldExtensionComponentProps<TFieldReturnValue, TInputProps>,
props: NextFieldExtensionComponentProps<TFieldReturnValue, TUiOptions>,
) => JSX.Element | null;
validation?: NextCustomFieldValidator<TFieldReturnValue>;
validation?: NextCustomFieldValidator<TFieldReturnValue, TUiOptions>;
schema?: CustomFieldExtensionSchema;
};