Skip to content

Commit 5287526

Browse files
authored
Merge pull request #114 from workfloworchestrator/1954-get-value-in-field
1954 get value in field
2 parents 34fd7c2 + f002aba commit 5287526

File tree

4 files changed

+153
-1
lines changed

4 files changed

+153
-1
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'pydantic-forms': patch
3+
---
4+
5+
Adds getFormFieldValue function

frontend/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import type { FieldValues } from 'react-hook-form';
2+
3+
import type { PydanticFormField } from './types';
4+
import { PydanticFormFieldFormat, PydanticFormFieldType } from './types';
5+
import { getFormFieldValue, insertItemAtIndex } from './utils';
6+
7+
const getPydanticFormFieldDummy = (
8+
props: Partial<PydanticFormField>,
9+
): PydanticFormField => {
10+
return {
11+
id: 'dummy',
12+
type: PydanticFormFieldType.STRING,
13+
format: PydanticFormFieldFormat.LONG,
14+
title: 'Dummy Field',
15+
required: false,
16+
properties: {},
17+
options: [],
18+
isEnumField: false,
19+
columns: 1,
20+
schema: {
21+
type: PydanticFormFieldType.OBJECT,
22+
format: PydanticFormFieldFormat.DEFAULT,
23+
},
24+
validations: {},
25+
attributes: {},
26+
...props,
27+
};
28+
};
29+
30+
describe('insertItemAtIndex', () => {
31+
const fieldA = getPydanticFormFieldDummy({ id: 'a' });
32+
const fieldB = getPydanticFormFieldDummy({ id: 'b' });
33+
const fieldC = getPydanticFormFieldDummy({ id: 'c' });
34+
const newField = getPydanticFormFieldDummy({ id: 'new' });
35+
36+
it('inserts at the beginning when anchorIndex is 0', () => {
37+
const result = insertItemAtIndex([fieldA, fieldB], newField, 0);
38+
expect(result).toEqual([newField, fieldA, fieldB]);
39+
});
40+
41+
it('inserts at the end when anchorIndex is equal to array length', () => {
42+
const result = insertItemAtIndex([fieldA, fieldB], newField, 2);
43+
expect(result).toEqual([fieldA, fieldB, newField]);
44+
});
45+
46+
it('inserts in the middle', () => {
47+
const result = insertItemAtIndex([fieldA, fieldB, fieldC], newField, 1);
48+
expect(result).toEqual([fieldA, newField, fieldB, fieldC]);
49+
});
50+
51+
it('inserts into an empty array', () => {
52+
const result = insertItemAtIndex([], newField, 0);
53+
expect(result).toEqual([newField]);
54+
});
55+
56+
it('does not mutate the original array', () => {
57+
const fields = [fieldA, fieldB];
58+
const copy = [...fields];
59+
insertItemAtIndex(fields, newField, 1);
60+
expect(fields).toEqual(copy);
61+
});
62+
});
63+
64+
describe('getFormFieldValue', () => {
65+
const formValues: FieldValues = {
66+
name: 'John Doe',
67+
age: 30,
68+
isActive: true,
69+
};
70+
it('gets the value by fieldName', () => {
71+
const field = getPydanticFormFieldDummy({ id: 'name' });
72+
const fieldName = 'name';
73+
const value = getFormFieldValue(fieldName, formValues, field);
74+
expect(value).toBe('John Doe');
75+
});
76+
77+
it('returns undefined for unknown fields', () => {
78+
const field = getPydanticFormFieldDummy({ id: 'name' });
79+
const fieldName = 'UNKNOWN_FIELD';
80+
const value = getFormFieldValue(fieldName, formValues, field);
81+
expect(value).toBe(undefined);
82+
});
83+
84+
it('gets the value at the right level ', () => {
85+
const complexValues = {
86+
company: {
87+
name: 'John Deer',
88+
age: 30,
89+
contactPersons: [
90+
{
91+
name: 'Jane Smith',
92+
age: 25,
93+
licenses: ['A', 'B'],
94+
},
95+
{
96+
name: 'Alice Johnson',
97+
age: 28,
98+
licenses: ['C'],
99+
},
100+
],
101+
},
102+
};
103+
104+
const field = getPydanticFormFieldDummy({
105+
id: 'company.contactPersons.0.name',
106+
});
107+
const value = getFormFieldValue('age', complexValues, field);
108+
expect(value).toEqual(25);
109+
110+
const field2 = getPydanticFormFieldDummy({
111+
id: 'company.contactPersons.1.name',
112+
});
113+
114+
const value2 = getFormFieldValue('licenses', complexValues, field2);
115+
expect(value2).toEqual(['C']);
116+
});
117+
});

frontend/packages/pydantic-forms/src/utils.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { FieldValues } from 'react-hook-form';
2+
13
import type { Properties, PydanticFormField } from '@/types';
24
import { PydanticFormFieldType } from '@/types';
35

@@ -91,3 +93,31 @@ export const itemizeArrayItem = (
9193
const itemId = `${item.id}.${arrayIndex}`;
9294
return itemize(item, itemId);
9395
};
96+
97+
/**
98+
* This functions returns a fields value but taking into account the position
99+
* of the field in any tree it might be in. For example when requesting the
100+
* 'age' field it will return the sibling field called 'age'. This is relevant
101+
* if the field is part of an array or object where there might be more 'age'
102+
* fields on other levels
103+
* */
104+
export function getFormFieldValue(
105+
fieldName: string,
106+
formValues: FieldValues,
107+
field: PydanticFormField,
108+
) {
109+
const pathToParent = field.id.split('.').slice(0, -1);
110+
let current: FieldValues = { ...formValues };
111+
112+
for (const segment of pathToParent) {
113+
// Convert numeric strings to numbers for array indexing
114+
const key = isNaN(Number(segment)) ? segment : Number(segment);
115+
if (current && key in current) {
116+
current = current[key];
117+
} else {
118+
return undefined;
119+
}
120+
}
121+
122+
return current?.[fieldName];
123+
}

0 commit comments

Comments
 (0)