Fix the scaffolder validator for arrays when the item is a field in the object
Signed-off-by: Bogdan Nechyporenko <bnechyporenko@bol.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': minor
|
||||
---
|
||||
|
||||
Fix the scaffolder validator for arrays when the item is a field in the object
|
||||
@@ -19,6 +19,12 @@ import { CustomFieldValidator } from '@backstage/plugin-scaffolder-react';
|
||||
import { ApiHolder } from '@backstage/core-plugin-api';
|
||||
import { FieldValidation, FormValidation } from '@rjsf/core';
|
||||
|
||||
type CustomLinkType = {
|
||||
url: string;
|
||||
title: string;
|
||||
icon: string;
|
||||
};
|
||||
|
||||
describe('createValidator', () => {
|
||||
const validators: Record<string, undefined | CustomFieldValidator<unknown>> =
|
||||
{
|
||||
@@ -31,6 +37,23 @@ describe('createValidator', () => {
|
||||
fieldValidation.addError('Error !');
|
||||
}
|
||||
},
|
||||
CustomLink: (
|
||||
values: unknown,
|
||||
fieldValidation: FieldValidation,
|
||||
_context: { apiHolder: ApiHolder },
|
||||
) => {
|
||||
const input = values as CustomLinkType[];
|
||||
for (const item of input) {
|
||||
const validGitlabUrlRegex =
|
||||
/gitlab\.(?:stg\.)?spotify\.com\?owner=.*&repo=.*/;
|
||||
|
||||
if (!item || !validGitlabUrlRegex.test(item.url)) {
|
||||
fieldValidation.addError(
|
||||
`Make sure to put in a valid gitlab clone url.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
TagPicker: (
|
||||
values: unknown,
|
||||
fieldValidation: FieldValidation,
|
||||
@@ -123,4 +146,53 @@ describe('createValidator', () => {
|
||||
expect(result).not.toBeNull();
|
||||
expect(result.tags.addError).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should call validator for array object property from a custom field extension', () => {
|
||||
/* GIVEN */
|
||||
const rootSchema = {
|
||||
title: 'My links',
|
||||
properties: {
|
||||
links: {
|
||||
title: 'Links',
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
required: ['url', 'title', 'icon'],
|
||||
properties: {
|
||||
url: {
|
||||
title: 'url',
|
||||
description: 'url',
|
||||
type: 'object',
|
||||
'ui:field': 'CustomLink',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const validator = createValidator(rootSchema, validators, context);
|
||||
|
||||
const formData = {
|
||||
links: [
|
||||
{
|
||||
url: 'http://gitlab.spotify.nl/owener=me&repo=test',
|
||||
icon: 'subject',
|
||||
title: 'My repository for testing features',
|
||||
} as CustomLinkType,
|
||||
],
|
||||
};
|
||||
const errors = {
|
||||
addError: jest.fn(),
|
||||
links: {
|
||||
addError: jest.fn(),
|
||||
} as unknown as FormValidation,
|
||||
} as unknown as FormValidation;
|
||||
|
||||
/* WHEN */
|
||||
const result = validator(formData, errors);
|
||||
|
||||
/* THEN */
|
||||
expect(result).not.toBeNull();
|
||||
expect(result.links.addError).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -50,40 +50,42 @@ export const createValidator = (
|
||||
for (const [key, propData] of Object.entries(formData)) {
|
||||
const propValidation = errors[key];
|
||||
|
||||
const propSchemaProps = schemaProps[key];
|
||||
if (isObject(propData)) {
|
||||
if (isObject(propSchemaProps)) {
|
||||
validate(
|
||||
propSchemaProps,
|
||||
propData as JsonObject,
|
||||
propValidation as FormValidation,
|
||||
);
|
||||
const doValidate = (item: JsonValue | undefined) => {
|
||||
if (item && isObject(item)) {
|
||||
const fieldName = item['ui:field'] as string;
|
||||
if (fieldName && typeof validators[fieldName] === 'function') {
|
||||
validators[fieldName]!(
|
||||
propData as JsonObject[],
|
||||
propValidation,
|
||||
context,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const propSchemaProps = schemaProps[key];
|
||||
if (isObject(propData) && isObject(propSchemaProps)) {
|
||||
validate(
|
||||
propSchemaProps,
|
||||
propData as JsonObject,
|
||||
propValidation as FormValidation,
|
||||
);
|
||||
} else if (isArray(propData)) {
|
||||
if (isObject(propSchemaProps)) {
|
||||
const { items } = propSchemaProps;
|
||||
if (isObject(items)) {
|
||||
const fieldName = items['ui:field'] as string;
|
||||
if (fieldName && typeof validators[fieldName] === 'function') {
|
||||
validators[fieldName]!(
|
||||
propData as JsonObject[],
|
||||
propValidation,
|
||||
context,
|
||||
);
|
||||
if (items.type === 'object') {
|
||||
const properties = (items?.properties ?? []) as JsonObject[];
|
||||
for (const [, value] of Object.entries(properties)) {
|
||||
doValidate(value);
|
||||
}
|
||||
} else {
|
||||
doValidate(items);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const fieldName =
|
||||
isObject(propSchemaProps) &&
|
||||
(propSchemaProps['ui:field'] as string);
|
||||
if (fieldName && typeof validators[fieldName] === 'function') {
|
||||
validators[fieldName]!(
|
||||
propData as JsonValue,
|
||||
propValidation,
|
||||
context,
|
||||
);
|
||||
}
|
||||
doValidate(propSchemaProps);
|
||||
}
|
||||
}
|
||||
} else if (customObject) {
|
||||
|
||||
Reference in New Issue
Block a user