mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-26 01:15:08 +00:00
fix(ui): json schema form field validation (#11867)
* fix(ui): json schema form field validation * address comment * fix: duplicate key issue * add unit test
This commit is contained in:
parent
ce9a10dd32
commit
cec1c295a7
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Collate.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { FieldErrorProps } from '@rjsf/utils';
|
||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { FieldErrorTemplate } from './FieldErrorTemplate';
|
||||||
|
|
||||||
|
describe('FieldErrorTemplate', () => {
|
||||||
|
it('renders error list correctly', () => {
|
||||||
|
const errors = ['Error 1', 'Error 2'];
|
||||||
|
const schema = { $id: 'schema-id' };
|
||||||
|
const idSchema = { $id: 'id-schema-id' };
|
||||||
|
|
||||||
|
const { container } = render(
|
||||||
|
<FieldErrorTemplate
|
||||||
|
errors={errors}
|
||||||
|
idSchema={idSchema as FieldErrorProps['idSchema']}
|
||||||
|
registry={{} as FieldErrorProps['registry']}
|
||||||
|
schema={schema}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const errorItems = container.querySelectorAll(
|
||||||
|
'.ant-form-item-explain-error'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(errorItems).toHaveLength(errors.length);
|
||||||
|
|
||||||
|
errorItems.forEach((item, index) => {
|
||||||
|
expect(item.textContent).toBe(errors[index]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders null when errors are empty', () => {
|
||||||
|
const errors: string[] = [];
|
||||||
|
const schema = { $id: 'schema-id' };
|
||||||
|
const idSchema = { $id: 'id-schema-id' };
|
||||||
|
|
||||||
|
const { container } = render(
|
||||||
|
<FieldErrorTemplate
|
||||||
|
errors={errors}
|
||||||
|
idSchema={idSchema as FieldErrorProps['idSchema']}
|
||||||
|
registry={{} as FieldErrorProps['registry']}
|
||||||
|
schema={schema}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const errorItems = container.querySelectorAll(
|
||||||
|
'.ant-form-item-explain-error'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(errorItems).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Collate.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { FieldErrorProps } from '@rjsf/utils';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
|
import React, { FC } from 'react';
|
||||||
|
|
||||||
|
export const FieldErrorTemplate: FC<FieldErrorProps> = (props) => {
|
||||||
|
const errorList = [...new Set(props.errors ?? [])];
|
||||||
|
|
||||||
|
if (isEmpty(errorList)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ul>
|
||||||
|
{errorList.map((error) => (
|
||||||
|
<li
|
||||||
|
className="ant-form-item-explain-error"
|
||||||
|
key={`${props.schema.$id}-${props.idSchema.$id}`}>
|
||||||
|
{error}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -17,6 +17,7 @@ import { Button } from 'antd';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { ArrayFieldTemplate } from 'components/JSONSchemaTemplate/ArrayFieldTemplate';
|
import { ArrayFieldTemplate } from 'components/JSONSchemaTemplate/ArrayFieldTemplate';
|
||||||
import DescriptionFieldTemplate from 'components/JSONSchemaTemplate/DescriptionFieldTemplate';
|
import DescriptionFieldTemplate from 'components/JSONSchemaTemplate/DescriptionFieldTemplate';
|
||||||
|
import { FieldErrorTemplate } from 'components/JSONSchemaTemplate/FieldErrorTemplate/FieldErrorTemplate';
|
||||||
import { ObjectFieldTemplate } from 'components/JSONSchemaTemplate/ObjectFieldTemplate';
|
import { ObjectFieldTemplate } from 'components/JSONSchemaTemplate/ObjectFieldTemplate';
|
||||||
import PasswordWidget from 'components/JsonSchemaWidgets/PasswordWidget';
|
import PasswordWidget from 'components/JsonSchemaWidgets/PasswordWidget';
|
||||||
import { ServiceCategory } from 'enums/service.enum';
|
import { ServiceCategory } from 'enums/service.enum';
|
||||||
@ -123,6 +124,7 @@ const FormBuilder: FunctionComponent<Props> = ({
|
|||||||
ArrayFieldTemplate: ArrayFieldTemplate,
|
ArrayFieldTemplate: ArrayFieldTemplate,
|
||||||
ObjectFieldTemplate: ObjectFieldTemplate,
|
ObjectFieldTemplate: ObjectFieldTemplate,
|
||||||
DescriptionFieldTemplate: DescriptionFieldTemplate,
|
DescriptionFieldTemplate: DescriptionFieldTemplate,
|
||||||
|
FieldErrorTemplate: FieldErrorTemplate,
|
||||||
}}
|
}}
|
||||||
transformErrors={transformErrors}
|
transformErrors={transformErrors}
|
||||||
uiSchema={uiSchema}
|
uiSchema={uiSchema}
|
||||||
|
@ -192,7 +192,15 @@ export const generateFormFields = (fields: FieldProp[]) => {
|
|||||||
export const transformErrors: ErrorTransformer = (errors) => {
|
export const transformErrors: ErrorTransformer = (errors) => {
|
||||||
const errorRet = errors.map((error) => {
|
const errorRet = errors.map((error) => {
|
||||||
const { property } = error;
|
const { property } = error;
|
||||||
const id = 'root' + property?.replaceAll('.', '/');
|
|
||||||
|
/**
|
||||||
|
* For nested fields we have to check if it's property start with "."
|
||||||
|
* else we will just prepend the root to property
|
||||||
|
*/
|
||||||
|
const id = property?.startsWith('.')
|
||||||
|
? 'root' + property?.replaceAll('.', '/')
|
||||||
|
: `root/${property}`;
|
||||||
|
|
||||||
// If element is not present in DOM, ignore error
|
// If element is not present in DOM, ignore error
|
||||||
if (document.getElementById(id)) {
|
if (document.getElementById(id)) {
|
||||||
const fieldName = error.params?.missingProperty;
|
const fieldName = error.params?.missingProperty;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user