Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions frontend/.changeset/big-dingos-follow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'pydantic-forms': patch
---

Fixes resetting formdata with forms that have no properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
*
* We will search for the first field that returns a positive match
*/
import _ from 'lodash';

import {
ArrayField,
CheckboxField,
Expand Down Expand Up @@ -101,6 +103,7 @@ const defaultComponentMatchers: PydanticComponentMatcher[] = [
// We are looking for a single value from a set list of options. With less than 4 options, use radio buttons.
return (
field.type === PydanticFormFieldType.STRING &&
_.isArray(field.options) &&
field.options?.length > 0 &&
field.options?.length <= 3
);
Expand All @@ -116,6 +119,7 @@ const defaultComponentMatchers: PydanticComponentMatcher[] = [
// We are looking for a single value from a set list of options. With more than 3 options, use a dropdown.
return (
field.type === PydanticFormFieldType.STRING &&
_.isArray(field.options) &&
field.options?.length >= 4
);
},
Expand All @@ -139,6 +143,7 @@ const defaultComponentMatchers: PydanticComponentMatcher[] = [
matcher(field) {
return (
field.type === PydanticFormFieldType.ARRAY &&
_.isArray(field.options) &&
field.options?.length > 0 &&
field.options?.length <= 5
);
Expand All @@ -153,6 +158,7 @@ const defaultComponentMatchers: PydanticComponentMatcher[] = [
},
matcher(field) {
return (
_.isArray(field.options) &&
field.options?.length > 0 &&
field.type === PydanticFormFieldType.ARRAY
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import React from 'react';

import _ from 'lodash';

import type { PydanticFormControlledElementProps } from '@/types';
import { getFormFieldIdWithPath } from '@/utils';

export const IntegerField = ({
value,
Expand All @@ -9,6 +12,14 @@ export const IntegerField = ({
disabled,
pydanticFormField,
}: PydanticFormControlledElementProps) => {
// If the field is part of an array the value is passed in as an object with the field name as key
// this is imposed by react-hook-form. We try to detect this and extract the actual value
const fieldName = getFormFieldIdWithPath(pydanticFormField.id);
const fieldValue =
_.isObject(value) && _.has(value, fieldName)
? _.get(value, fieldName)
: value;

return (
<input
data-testid={pydanticFormField.id}
Expand All @@ -18,7 +29,7 @@ export const IntegerField = ({
onChange(value);
}}
disabled={disabled}
value={value}
value={fieldValue}
type="number"
style={{
padding: '8px',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const MultiCheckboxField = ({

return (
<div>
{options.map((option: PydanticFormFieldOption) => {
{options?.map((option: PydanticFormFieldOption) => {
// Extract the unique ID for this option
const optionId = `${id}-${option.value}`;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const MultiSelectField = ({
}}
multiple
>
{pydanticFormField.options.map(
{pydanticFormField.options?.map(
(option: PydanticFormFieldOption) => (
<option key={option.value} value={option.value}>
{option.label}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const RadioField = ({

return (
<div>
{options.map((option, key) => (
{options?.map((option, key) => (
<div key={key}>
<input
data-testid={`${id}-${option.value}`}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,40 @@
*/
import React from 'react';

import _ from 'lodash';

import { PydanticFormControlledElementProps } from '@/types';
import { getFormFieldIdWithPath } from '@/utils';

export const TextField = ({
value,
onChange,
onBlur,
disabled,
pydanticFormField,
}: PydanticFormControlledElementProps) => (
<input
data-testid={pydanticFormField.id}
onBlur={onBlur}
onChange={(t) => {
onChange(t.currentTarget.value);
}}
disabled={disabled}
value={value}
type="text"
style={{
padding: '8px',
margin: '8px 0',
}}
/>
);
}: PydanticFormControlledElementProps) => {
// If the field is part of an array the value is passed in as an object with the field name as key
// this is imposed by react-hook-form. We try to detect this and extract the actual value
const fieldName = getFormFieldIdWithPath(pydanticFormField.id);
const fieldValue =
_.isObject(value) && _.has(value, fieldName)
? _.get(value, fieldName)
: value;

return (
<input
data-testid={pydanticFormField.id}
onBlur={onBlur}
onChange={(t) => {
onChange(t.currentTarget.value);
}}
disabled={disabled}
value={fieldValue}
type="text"
style={{
padding: '8px',
margin: '8px 0',
}}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ export function useApiProvider(
}
if (
request.status &&
(request.status === 200 || request.status === 201)
request.status >= 200 &&
request.status < 300
) {
return {
type: PydanticFormApiResponseType.SUCCESS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,6 @@ const getPydanticFormField = (
)
: '';

const addConstValue =
typeof flatSchema.const === 'undefined' ? false : true;

const arrayItem = flatSchema.items
? getPydanticFormField(
flatSchema.items,
Expand All @@ -87,6 +84,14 @@ const getPydanticFormField = (
)
: undefined;

const addConstValue =
typeof flatSchema.const === 'undefined' ? false : true;

// Don't add options to array items if they have an arrayItem where they live
const addOptions = !(
flatSchema.type === PydanticFormFieldType.ARRAY && arrayItem
);

//TODO: I think object properties should never be required only their properties are or aren't. Should we fix this in the backend?
const required =
flatSchema.type === PydanticFormFieldType.OBJECT
Expand All @@ -100,7 +105,7 @@ const getPydanticFormField = (
arrayItem,
format: flatSchema.format || PydanticFormFieldFormat.DEFAULT,
type: flatSchema.type || PydanticFormFieldType.STRING,
options: options,
...toOptionalObjectProperty({ options }, addOptions),
default: flatSchema.default,
attributes: attributes,
schema: propertySchema,
Expand Down
2 changes: 1 addition & 1 deletion frontend/packages/pydantic-forms/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export interface PydanticFormField {
description?: string;
type: PydanticFormFieldType;
format: PydanticFormFieldFormat;
options: PydanticFormFieldOption[];
options?: PydanticFormFieldOption[];
disabledOptions?: string[];
default?: PydanticFormFieldValue;
required: boolean;
Expand Down
2 changes: 1 addition & 1 deletion frontend/packages/pydantic-forms/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export function getFormFieldValue(
*/
export function getFormFieldIdWithPath(
pydanticFormFieldId: PydanticFormField['id'],
fieldName: string,
fieldName?: string,
): string {
const pathToParent = pydanticFormFieldId.split('.');
pathToParent.pop();
Expand Down