Skip to content

Commit

Permalink
fix(ui): client should add back default values for valid and passesCo…
Browse files Browse the repository at this point in the history
…ndition form field properties
  • Loading branch information
AlessioGr committed Jan 21, 2025
1 parent 2a98c84 commit 021601b
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 23 deletions.
28 changes: 24 additions & 4 deletions packages/ui/src/forms/Form/fieldReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,20 +284,40 @@ export function fieldReducer(state: FormState, action: FieldAction): FormState {
// ..
// This is a performance enhancement for saving
// large documents with hundreds of fields
const newState = {}
const newState: FormState = {}

Object.entries(action.state).forEach(([path, field]) => {
for (const path in action.state) {
const oldField = state[path]
const newField = field
const newField = action.state[path]

if (newField.valid !== false) {
newField.valid = true
}
if (newField.passesCondition !== false) {
newField.passesCondition = true
}

if (!dequal(oldField, newField)) {
newState[path] = newField
} else if (oldField) {
newState[path] = oldField
}
})
}

return newState
}

if (action.sanitize) {
for (const path in action.state) {
const field = action.state[path]
if (field.valid !== false) {
field.valid = true
}
if (field.passesCondition !== false) {
field.passesCondition = true
}
}
}
// If we're not optimizing, just set the state to the new state
return action.state
}
Expand Down
7 changes: 6 additions & 1 deletion packages/ui/src/forms/Form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,12 @@ export const Form: React.FC<FormProps> = (props) => {
useEffect(() => {
if (initialState) {
contextRef.current = { ...initContextState } as FormContextType
dispatchFields({ type: 'REPLACE_STATE', optimize: false, state: initialState })
dispatchFields({
type: 'REPLACE_STATE',
optimize: false,
sanitize: true,
state: initialState,
})
}
}, [initialState, dispatchFields])

Expand Down
45 changes: 27 additions & 18 deletions packages/ui/src/forms/Form/mergeServerFormState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,31 @@ export const mergeServerFormState = ({
existingState,
incomingState,
}: Args): { changed: boolean; newState: FormState } => {
const serverPropsToAccept = [
'passesCondition',
'valid',
'errorMessage',
'rows',
'customComponents',
'requiresRender',
]

if (acceptValues) {
serverPropsToAccept.push('value')
}

let changed = false

const newState = {}

if (existingState) {
Object.entries(existingState).forEach(([path, newFieldState]) => {
const serverPropsToAccept = [
'passesCondition',
'valid',
'errorMessage',
'rows',
'customComponents',
'requiresRender',
]

if (acceptValues) {
serverPropsToAccept.push('value')
}

for (const path in existingState) {
if (!incomingState[path]) {
return
}

const newFieldState = existingState[path]

/**
* Handle error paths
*/
Expand Down Expand Up @@ -87,18 +89,25 @@ export const mergeServerFormState = ({
}
})

if (newFieldState.valid !== false) {
newFieldState.valid = true
}
if (newFieldState.passesCondition !== false) {
newFieldState.passesCondition = true
}

// Conditions don't work if we don't memcopy the new state, as the object references would otherwise be the same
newState[path] = { ...newFieldState }
})
newState[path] = changed ? { ...newFieldState } : newFieldState
}

// Now loop over values that are part of incoming state but not part of existing state, and add them to the new state.
// This can happen if a new array row was added. In our local state, we simply add out stubbed `array` and `array.[index].id` entries to the local form state.
// However, all other array sub-fields are not added to the local state - those will be added by the server and may be incoming here.

for (const [path, newFieldState] of Object.entries(incomingState)) {
for (const path in incomingState) {
if (!existingState[path]) {
changed = true
newState[path] = newFieldState
newState[path] = incomingState[path]
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions packages/ui/src/forms/Form/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ export type Reset = (data: unknown) => Promise<void>

export type REPLACE_STATE = {
optimize?: boolean
/**
* If `sanitize` is true, default values will be set for form field properties that are not present in the incoming state.
* For example, `valid` will be set to true if it is not present in the incoming state.
*/
sanitize?: boolean
state: FormState
type: 'REPLACE_STATE'
}
Expand Down

0 comments on commit 021601b

Please sign in to comment.