Skip to content

Commit

Permalink
Add form validation
Browse files Browse the repository at this point in the history
  • Loading branch information
danielfdsilva committed Dec 17, 2024
1 parent 93918f9 commit 22d8528
Show file tree
Hide file tree
Showing 7 changed files with 469 additions and 6 deletions.
6 changes: 5 additions & 1 deletion packages/client/src/pages/CollectionForm/EditForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useMemo, useState } from 'react';
import {
PluginBox,
useCollectionPlugins,
validatePluginsFieldsData,
WidgetRenderer
} from '@stac-manager/data-core';
import { Box, Button, ButtonGroup, Flex, Heading } from '@chakra-ui/react';
Expand Down Expand Up @@ -42,14 +43,17 @@ export function EditForm(props: {
<Flex direction='column' gap={4}>
<Formik
validateOnChange={false}
validateOnBlur={false}
enableReinitialize
initialValues={editorData}
onSubmit={(values, actions) => {
const exitData =
view === 'json' ? values.jsonData : toOutData(values);
return onSubmit(exitData, actions);
}}
validate={(values) => {
const [, error] = validatePluginsFieldsData(plugins, values);
if (error) return error;
}}
>
{({ handleSubmit, values, isSubmitting }) => (
<Flex
Expand Down
9 changes: 8 additions & 1 deletion packages/client/src/pages/CollectionForm/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';
import { Box, useToast } from '@chakra-ui/react';
import { FormikHelpers } from 'formik';
import { useParams } from 'react-router-dom';
import { useNavigate, useParams } from 'react-router-dom';
import { useCollection } from '@developmentseed/stac-react';
import { StacCollection } from 'stac-ts';

Expand All @@ -23,6 +23,7 @@ export function CollectionFormNew() {
usePageTitle('New collection');

const toast = useToast();
const navigate = useNavigate();

const onSubmit = async (data: any, formikHelpers: FormikHelpers<any>) => {
try {
Expand All @@ -42,6 +43,8 @@ export function CollectionFormNew() {
duration: 5000,
isClosable: true
});

navigate(`/collections/${data.id}`);
} catch (error: any) {
toast.update('collection-submit', {
title: 'Collection creation failed',
Expand All @@ -64,6 +67,8 @@ export function CollectionFormEdit(props: { id: string }) {

usePageTitle(collection ? `Edit collection ${id}` : 'Edit collection');

const navigate = useNavigate();

const toast = useToast();

useEffect(() => {
Expand Down Expand Up @@ -98,6 +103,8 @@ export function CollectionFormEdit(props: { id: string }) {
duration: 5000,
isClosable: true
});

navigate(`/collections/${data.id}`);
} catch (error: any) {
toast.update('collection-submit', {
title: 'Collection update failed',
Expand Down
1 change: 1 addition & 0 deletions packages/data-core/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './plugin-utils/plugin';
export * from './plugin-utils/validate';
export * from './plugin-utils/use-plugins-hook';
export * from './context/plugin-config';
export * from './config';
Expand Down
263 changes: 263 additions & 0 deletions packages/data-core/lib/plugin-utils/validate.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
import { Plugin, PluginEditSchema } from './plugin';
import { validatePluginsFieldsData } from './validate';

describe('validatePluginsFieldsData', () => {
test('No data', () => {
const plugins = [
{
name: 'Render Extension',
editSchema(): PluginEditSchema {
return {
type: 'root',
required: ['description', 'license'],
properties: {
description: {
label: 'Description',
type: 'string'
},
license: {
label: 'License',
type: 'string',
enum: [
['one', 'License One'],
['two', 'License Two'],
['three', 'License Three']
]
}
}
};
}
}
] as Plugin[];
const [, errors] = validatePluginsFieldsData(plugins, {});
expect(errors).toEqual({
description: 'Description is a required field',
license: 'License is a required field'
});
});

test('Invalid enum', () => {
const plugins = [
{
editSchema(): PluginEditSchema {
return {
type: 'root',
required: ['license'],
properties: {
license: {
label: 'License',
type: 'string',
enum: [
['one', 'License One'],
['two', 'License Two'],
['three', 'License Three']
]
}
}
};
}
}
] as Plugin[];
const data = {
license: 'invalid'
};
const [, errors] = validatePluginsFieldsData(plugins, data);
expect(errors).toEqual({
license: 'License value is invalid'
});
});

test('Invalid enum empty', () => {
const plugins = [
{
name: 'Render Extension',
editSchema(): PluginEditSchema {
return {
type: 'root',
required: ['license'],
properties: {
license: {
label: 'License',
type: 'string',
enum: [
['one', 'License One'],
['two', 'License Two'],
['three', 'License Three']
]
}
}
};
}
}
] as Plugin[];
const data = {
license: ''
};
const [, errors] = validatePluginsFieldsData(plugins, data);
expect(errors).toEqual({
license: 'License value is invalid'
});
});

test('Allowed empty enum', () => {
const plugins = [
{
name: 'Render Extension',
editSchema(): PluginEditSchema {
return {
type: 'root',
properties: {
type: {
label: 'Type',
type: 'string',
enum: [
['one', 'Type One'],
['two', 'Type Two'],
['three', 'Type Three']
]
}
}
};
}
}
] as Plugin[];
const data = {
type: ''
};
const [, errors] = validatePluginsFieldsData(plugins, data);
expect(errors).toEqual(null);
});

test('Allowed other enum', () => {
const plugins = [
{
name: 'Render Extension',
editSchema(): PluginEditSchema {
return {
type: 'root',
properties: {
type: {
label: 'Type',
type: 'string',
allowOther: {
type: 'string'
},
enum: [
['one', 'Type One'],
['two', 'Type Two'],
['three', 'Type Three']
]
}
}
};
}
}
] as Plugin[];
const data = {
type: 'special'
};
const [, errors] = validatePluginsFieldsData(plugins, data);
expect(errors).toEqual(null);
});

test('Missing nested', () => {
const plugins = [
{
name: 'Render Extension',
editSchema(): PluginEditSchema {
return {
type: 'root',
properties: {
providers: {
type: 'array',
label: 'Providers',
items: {
type: 'object',
required: ['name'],
properties: {
name: {
label: 'Name',
type: 'string'
}
}
}
}
}
};
}
}
] as Plugin[];
const data = {
providers: [
{
url: 'http://example.com'
}
]
};
const [, errors] = validatePluginsFieldsData(plugins, data);
expect(errors).toEqual({
providers: [{ name: 'Name is a required field' }]
});
});

test('Wrong array count', () => {
const plugins = [
{
name: 'Render Extension',
editSchema(): PluginEditSchema {
return {
type: 'root',
properties: {
spatial: {
label: 'Spatial Extent',
type: 'array',
minItems: 2,
items: {
type: 'number'
}
}
}
};
}
}
] as Plugin[];
const data = {
spatial: [1]
};
const [, errors] = validatePluginsFieldsData(plugins, data);
expect(errors).toEqual({
spatial: 'Spatial Extent field must have at least 2 items'
});
});

test('Wrong field type', () => {
const plugins = [
{
name: 'Render Extension',
editSchema(): PluginEditSchema {
return {
type: 'root',
required: ['description', 'license'],
properties: {
spatial: {
label: 'Spatial Extent',
type: 'array',
minItems: 2,
items: {
type: 'number'
}
}
}
};
}
}
] as Plugin[];
const data = {
spatial: ['one', 'two']
};
const [, errors] = validatePluginsFieldsData(plugins, data);
expect(errors).toEqual({
spatial: ['Value must be a number', 'Value must be a number']
});
});
});
Loading

0 comments on commit 22d8528

Please sign in to comment.