Skip to content

Commit 2c55366

Browse files
authored
Merge pull request #27 from workfloworchestrator/1713-add-list-field
add list field
2 parents 2cdec65 + 7bb38d1 commit 2c55366

File tree

7 files changed

+87
-10
lines changed

7 files changed

+87
-10
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ __pycache__/
1919
test
2020
.idea
2121
todo.md
22-
venv
22+
venv/
23+
.venv/

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ $ npm run dev
3131

3232
Visit [http://127.0.0.1:3000][5] to view the generated form
3333

34+
to also regenerate the pydantic forms ui package, also perform those steps in `pydantic-forms-ui/frontend/packages/pydantic-forms/`
35+
3436
## Contributing
3537

3638
When setting up this repo to contribute initialize the pre-commit hooks using [pre-commit][6] (eq. `brew install pre-commit`).

backend/main.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,25 @@ class MultiCheckBoxChoices(Choice):
102102
_4 = ("4", "Option 4")
103103

104104

105+
class ListChoices(Choice):
106+
_0 = ("0", "Option 0")
107+
_1 = ("1", "Option 1")
108+
_2 = ("2", "Option 2")
109+
_3 = ("3", "Option 3")
110+
_4 = ("4", "Option 4")
111+
_5 = ("5", "Option 5")
112+
_6 = ("6", "Option 6")
113+
114+
105115
@app.post("/form")
106116
async def form(form_data: list[dict] = []):
107117
def form_generator(state: State):
108118
class TestForm(FormPage):
109119
model_config = ConfigDict(title="Form Title")
110120

111-
number: NumberExample
121+
number: NumberExample = 3
112122
text: Annotated[str, Field(min_length=3, max_length=12)] = "Default text"
113-
textArea: LongText
123+
textArea: LongText = "Default text area"
114124
divider: Divider
115125
label: Label = "Label"
116126
hidden: Hidden = "Hidden"
@@ -119,7 +129,9 @@ class TestForm(FormPage):
119129
# When there are <= 3 choices a radio group will be rendered
120130
radio: RadioChoices = "3"
121131
checkbox: bool = True
122-
multicheckbox: choice_list(MultiCheckBoxChoices, min_items=3)
132+
# When there are <= 5 choices in a list a set of checkboxes are rendered
133+
multicheckbox: choice_list(MultiCheckBoxChoices) = ["1", "2"]
134+
list: choice_list(ListChoices) = [0, 1]
123135

124136
form_data_1 = yield TestForm
125137

frontend/packages/pydantic-forms/src/components/defaultComponentMatchers.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
HiddenField,
1111
IntegerField,
1212
LabelField,
13+
ListField,
1314
MultiCheckboxField,
1415
RadioField,
1516
TextAreaField,
@@ -133,15 +134,25 @@ const defaultComponentMatchers: PydanticComponentMatcher[] = [
133134
isControlledElement: true,
134135
},
135136
matcher(field) {
136-
// Use this component when we have multiple boolean options (5 or more)
137137
return (
138138
field.type === PydanticFormFieldType.ARRAY &&
139139
field.options.length <= 5
140140
);
141141
},
142142
validator: zodValidationPresets.array,
143143
},
144+
{
145+
id: 'list',
146+
ElementMatch: {
147+
Element: ListField,
148+
isControlledElement: true,
149+
},
150+
matcher(field) {
151+
return field.type === PydanticFormFieldType.ARRAY;
152+
},
153+
validator: zodValidationPresets.array,
154+
},
144155
];
145156

146-
// If nothing matches, it defaults to Text field in the mapToComponent function
157+
// If nothing matches, it defaults to Text field in the mapToComponent function
147158
export default defaultComponentMatchers;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* Pydantic Forms
3+
*
4+
* List component for multiple choice items
5+
*/
6+
import React, { useState } from 'react';
7+
8+
import {
9+
PydanticFormControlledElementProps,
10+
PydanticFormFieldOption,
11+
} from '@/types';
12+
13+
export const ListField = ({
14+
value,
15+
onChange,
16+
onBlur,
17+
disabled,
18+
pydanticFormField,
19+
}: PydanticFormControlledElementProps & {
20+
options?: Array<{ value: string; label: string }>;
21+
}) => {
22+
const [listItems, setListItems] = useState(value || []);
23+
24+
return (
25+
<div>
26+
<select
27+
onBlur={onBlur}
28+
disabled={disabled}
29+
value={listItems}
30+
onChange={(e) => {
31+
const selectedValues = Array.from(
32+
e.currentTarget.selectedOptions,
33+
(option) => option.value,
34+
);
35+
setListItems(selectedValues);
36+
onChange(selectedValues);
37+
}}
38+
multiple
39+
>
40+
{pydanticFormField.options.map(
41+
(option: PydanticFormFieldOption) => (
42+
<option key={option.value} value={option.value}>
43+
{option.label}
44+
</option>
45+
),
46+
)}
47+
</select>
48+
</div>
49+
);
50+
};

frontend/packages/pydantic-forms/src/components/fields/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ export * from './HiddenField';
1010
export * from './DropdownField';
1111
export * from './RadioField';
1212
export * from './MultiCheckboxField';
13+
export * from './ListField';

frontend/packages/pydantic-forms/src/components/zodValidations.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,22 +113,22 @@ export const zodValidationPresets: PydanticFormZodValidationPresets = {
113113
array: (field) => {
114114
const { minimum, maximum } = field?.validation ?? {};
115115

116-
let arraySchema = z.array(z.boolean());
116+
let validationRule = z.array(z.boolean());
117117

118118
if (minimum) {
119-
arraySchema = arraySchema.min(
119+
validationRule = validationRule.min(
120120
minimum,
121121
`Dit veld heeft een minimum waarde van ${minimum}`,
122122
);
123123
}
124124

125125
if (maximum) {
126-
arraySchema = arraySchema.max(
126+
validationRule = validationRule.max(
127127
maximum,
128128
`Dit veld heeft een maximum waarde van ${maximum}`,
129129
);
130130
}
131131

132-
return arraySchema;
132+
return validationRule;
133133
},
134134
};

0 commit comments

Comments
 (0)