Fix loading sequence for PUI form fields (#7678)

- Ensure that "existing" values are honored
- Change hook execution ordering
- Delay field display until all fields are loaded
This commit is contained in:
Oliver 2024-07-18 14:16:30 +10:00 committed by GitHub
parent ecec81ead0
commit c6d310caf7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 35 additions and 22 deletions

View File

@ -139,6 +139,7 @@ export function OptionsApiForm({
if (!props.ignorePermissionCheck) {
fields = extractAvailableFields(response, props.method);
}
return fields;
},
throwOnError: (error: any) => {
@ -183,7 +184,7 @@ export function OptionsApiForm({
<ApiForm
id={id}
props={formProps}
optionsLoading={optionsQuery.isFetching}
optionsLoading={optionsQuery.isFetching || !optionsQuery.data}
/>
);
}
@ -206,9 +207,6 @@ export function ApiForm({
const [fields, setFields] = useState<ApiFormFieldSet>(
() => props.fields ?? {}
);
useEffect(() => {
setFields(props.fields ?? {});
}, [props.fields]);
const defaultValues: FieldValues = useMemo(() => {
let defaultValuesMap = mapFields(fields ?? {}, (_path, field) => {
@ -314,11 +312,24 @@ export function ApiForm({
} catch (error) {
console.error('ERR: Error fetching initial data:', error);
// Re-throw error to allow react-query to handle error
throw error;
return {};
}
}
});
useEffect(() => {
let _fields = props.fields ?? {};
// Ensure default values override initial field spec
for (const k of Object.keys(_fields)) {
if (defaultValues[k]) {
_fields[k].value = defaultValues[k];
}
}
setFields(_fields);
}, [props.fields, defaultValues, initialDataQuery.data]);
// Fetch initial data on form load
useEffect(() => {
// Fetch initial data if the fetchInitialData property is set
@ -559,21 +570,23 @@ export function ApiForm({
)}
</Boundary>
<Boundary label={`ApiForm-${id}-FormContent`}>
<FormProvider {...form}>
<Stack gap="xs">
{!optionsLoading &&
Object.entries(fields).map(([fieldName, field]) => (
<ApiFormField
key={fieldName}
fieldName={fieldName}
definition={field}
control={form.control}
url={url}
setFields={setFields}
/>
))}
</Stack>
</FormProvider>
{!isLoading && (
<FormProvider {...form}>
<Stack gap="xs">
{!optionsLoading &&
Object.entries(fields).map(([fieldName, field]) => (
<ApiFormField
key={fieldName}
fieldName={fieldName}
definition={field}
control={form.control}
url={url}
setFields={setFields}
/>
))}
</Stack>
</FormProvider>
)}
</Boundary>
<Boundary label={`ApiForm-${id}-PostFormContent`}>
{props.postFormContent}

View File

@ -149,7 +149,7 @@ export function ApiFormField({
label: hideLabels ? undefined : definition.label,
description: hideLabels ? undefined : definition.description
};
}, [definition]);
}, [hideLabels, definition]);
// pull out onValueChange as this can cause strange errors when passing the
// definition to the input components via spread syntax
@ -202,7 +202,7 @@ export function ApiFormField({
}
return val;
}, [value]);
}, [definition.field_type, value]);
// Coerce the value to a (stringified) boolean value
const booleanValue: boolean = useMemo(() => {