Improve validation error display text in scaffolder UI
Signed-off-by: Stephen Glass <stephen@stephen.glass>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-react': minor
|
||||
---
|
||||
|
||||
Improve validation error display text in scaffolder
|
||||
+81
-18
@@ -19,25 +19,88 @@ import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { ErrorListProps } from '@rjsf/utils';
|
||||
|
||||
describe('Error List Template', () => {
|
||||
const errorList = {
|
||||
errors: [
|
||||
{
|
||||
stack: 'Test error 1',
|
||||
},
|
||||
{
|
||||
stack: 'Test error 2',
|
||||
},
|
||||
],
|
||||
errorSchema: {},
|
||||
} as Partial<ErrorListProps> as ErrorListProps;
|
||||
describe('should render the error messages', () => {
|
||||
it('no properties', async () => {
|
||||
const errorList = {
|
||||
errors: [
|
||||
{
|
||||
stack: 'Test error 1',
|
||||
},
|
||||
{
|
||||
stack: 'Test error 2',
|
||||
},
|
||||
],
|
||||
errorSchema: {},
|
||||
} as Partial<ErrorListProps> as ErrorListProps;
|
||||
|
||||
it('should render the error messages', async () => {
|
||||
const { getByText } = await renderInTestApp(
|
||||
<ErrorListTemplate {...errorList} />,
|
||||
);
|
||||
const { getByText } = await renderInTestApp(
|
||||
<ErrorListTemplate {...errorList} />,
|
||||
);
|
||||
|
||||
for (const error of errorList.errors) {
|
||||
expect(getByText(error.stack)).toBeInTheDocument();
|
||||
}
|
||||
for (const error of errorList.errors) {
|
||||
expect(getByText(error.stack)).toBeInTheDocument();
|
||||
}
|
||||
});
|
||||
|
||||
it('properties no title', async () => {
|
||||
const errorList = {
|
||||
errors: [
|
||||
{
|
||||
property: '.foo',
|
||||
stack: 'Test error 1',
|
||||
message: 'Test error 1',
|
||||
},
|
||||
{
|
||||
property: '.anExampleTitle',
|
||||
stack: 'Test error 2',
|
||||
message: 'Test error 2',
|
||||
},
|
||||
],
|
||||
errorSchema: {},
|
||||
schema: {},
|
||||
} as Partial<ErrorListProps> as ErrorListProps;
|
||||
|
||||
const { getByText } = await renderInTestApp(
|
||||
<ErrorListTemplate {...errorList} />,
|
||||
);
|
||||
|
||||
expect(getByText("'Foo' Test error 1")).toBeInTheDocument();
|
||||
expect(getByText("'An Example Title' Test error 2")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('properties with title', async () => {
|
||||
const errorList = {
|
||||
errors: [
|
||||
{
|
||||
property: '.foo',
|
||||
stack: 'Test error 1',
|
||||
message: 'Test error 1',
|
||||
},
|
||||
{
|
||||
property: '.bar',
|
||||
stack: 'Test error 2',
|
||||
message: 'Test error 2',
|
||||
},
|
||||
],
|
||||
errorSchema: {},
|
||||
schema: {
|
||||
properties: {
|
||||
foo: {
|
||||
title: 'Hello',
|
||||
},
|
||||
bar: {
|
||||
title: 'Example Title',
|
||||
},
|
||||
},
|
||||
},
|
||||
} as Partial<ErrorListProps> as ErrorListProps;
|
||||
|
||||
const { getByText } = await renderInTestApp(
|
||||
<ErrorListTemplate {...errorList} />,
|
||||
);
|
||||
|
||||
expect(getByText("'Hello' Test error 1")).toBeInTheDocument();
|
||||
expect(getByText("'Example Title' Test error 2")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+23
-3
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { ErrorListProps } from '@rjsf/utils';
|
||||
import { ErrorListProps, RJSFValidationError } from '@rjsf/utils';
|
||||
import List from '@material-ui/core/List';
|
||||
import ListItem from '@material-ui/core/ListItem';
|
||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||
@@ -22,6 +22,7 @@ import ListItemText from '@material-ui/core/ListItemText';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import { Theme, createStyles, makeStyles } from '@material-ui/core/styles';
|
||||
import ErrorIcon from '@material-ui/icons/Error';
|
||||
import startCase from 'lodash/startCase';
|
||||
|
||||
const useStyles = makeStyles((_theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -39,9 +40,28 @@ const useStyles = makeStyles((_theme: Theme) =>
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const ErrorListTemplate = ({ errors }: ErrorListProps) => {
|
||||
export const ErrorListTemplate = ({ errors, schema }: ErrorListProps) => {
|
||||
const classes = useStyles();
|
||||
|
||||
function formatErrorMessage(error: RJSFValidationError) {
|
||||
if (error.property && error.message) {
|
||||
const propertyName = error.property.startsWith('.')
|
||||
? error.property.substring(1)
|
||||
: error.property;
|
||||
if (schema.properties && propertyName in schema.properties) {
|
||||
const property = schema.properties[propertyName];
|
||||
|
||||
if (typeof property === 'object' && 'title' in property) {
|
||||
return `'${property.title}' ${error.message}`;
|
||||
}
|
||||
}
|
||||
// fall back to property name
|
||||
return `'${startCase(propertyName)}' ${error.message}`;
|
||||
}
|
||||
// fall back if property does not exist
|
||||
return error.stack;
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper>
|
||||
<List dense className={classes.list}>
|
||||
@@ -52,7 +72,7 @@ export const ErrorListTemplate = ({ errors }: ErrorListProps) => {
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
classes={{ primary: classes.text }}
|
||||
primary={error.stack}
|
||||
primary={formatErrorMessage(error)}
|
||||
/>
|
||||
</ListItem>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user