Skip to content

Commit

Permalink
👽 [#4693] Integrate Objects API prefill modal with backend
Browse files Browse the repository at this point in the history
  • Loading branch information
stevenbal committed Oct 28, 2024
1 parent 2cfc111 commit 5147a2a
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 44 deletions.
12 changes: 5 additions & 7 deletions src/openforms/forms/api/serializers/form_variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,15 +205,13 @@ def validate(self, attrs):
}
)

if (prefill_plugin and not prefill_attribute) or (
not prefill_plugin and prefill_attribute
if (prefill_plugin and not (prefill_attribute or prefill_options)) or (
not prefill_plugin and (prefill_attribute or prefill_options)
):
raise ValidationError(
{
"prefill_attribute": _(
"Prefill plugin and attribute must both be specified."
),
}
_(
"Prefill plugin must be specified with either prefill attribute or prefill options."
)
)

# check the specific validation options of the prefill plugin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ const VARIABLES = [
initialValue: [],
prefillOptions: {
objectsApiGroup: 1,
objecttype: '2c77babf-a967-4057-9969-0200320d23f2',
objecttypeUuid: '2c77babf-a967-4057-9969-0200320d23f2',
objecttypeVersion: 1,
variablesMapping: [{formVariable: 'formioComponent', prefillProperty: ['firstName']}],
variablesMapping: [{variableKey: 'formioComponent', targetPath: ['firstName']}],
},
},
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,11 +162,12 @@ const EditableVariableRow = ({index, variable, onDelete, onChange, onFieldChange
identifierRole={variable.prefillIdentifierRole}
errors={variable.errors}
options={variable.prefillOptions}
onChange={({plugin, attribute, identifierRole}) =>
onChange={({plugin, attribute, identifierRole, prefillOptions}) =>
onChange(variable.key, '', {
prefillPlugin: plugin,
prefillAttribute: attribute,
prefillIdentifierRole: identifierRole,
prefillOptions: prefillOptions,
})
}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,18 @@ const PLUGIN_ID = 'objects_api';
*/
const onApiGroupChange = prevValues => ({
...prevValues,
options: {
...prevValues.options,
objecttype: '',
prefillOptions: {
...prevValues.prefillOptions,
objecttypeUuid: '',
objecttypeVersion: undefined,
variablesMapping: [],
},
});

// Load the possible prefill properties
// XXX: this would benefit from client-side caching
const getProperties = async (objectsApiGroup, objecttype, objecttypeVersion) => {
const endpoint = `/api/v2/prefill/plugins/objects-api/objecttypes/${objecttype}/versions/${objecttypeVersion}/properties`;
const getProperties = async (objectsApiGroup, objecttypeUuid, objecttypeVersion) => {
const endpoint = `/api/v2/prefill/plugins/objects-api/objecttypes/${objecttypeUuid}/versions/${objecttypeVersion}/properties`;
// XXX: clean up error handling here at some point...
const response = await get(endpoint, {objects_api_group: objectsApiGroup});
if (!response.ok) throw response.data;
Expand All @@ -56,7 +56,7 @@ const ObjectsAPIFields = ({errors}) => {
const {
values: {
plugin,
options: {objecttype, objecttypeVersion, objectsApiGroup},
prefillOptions: {objecttypeUuid, objecttypeVersion, objectsApiGroup, variablesMapping},
},
setFieldValue,
} = useFormikContext();
Expand All @@ -74,13 +74,13 @@ const ObjectsAPIFields = ({errors}) => {
value = [],
error,
} = useAsync(async () => {
if (!plugin || !objecttype || !objecttypeVersion || !objectsApiGroup) return [];
if (!plugin || !objecttypeUuid || !objecttypeVersion || !objectsApiGroup) return [];
try {
return await getProperties(objectsApiGroup, objecttype, objecttypeVersion);
return await getProperties(objectsApiGroup, objecttypeUuid, objecttypeVersion);
} catch (e) {
throw e;
}
}, [plugin, objecttype, objecttypeVersion, objectsApiGroup]);
}, [plugin, objecttypeUuid, objecttypeVersion, objectsApiGroup]);

// throw errors to the nearest error boundary
if (error) throw error;
Expand All @@ -92,7 +92,7 @@ const ObjectsAPIFields = ({errors}) => {
<ObjectsAPIGroup
apiGroupChoices={apiGroups}
onChangeCheck={() => {
if (values.options.variablesMapping.length === 0) return true;
if (variablesMapping.length === 0) return true;
const confirmSwitch = window.confirm(
intl.formatMessage({
description:
Expand All @@ -102,14 +102,16 @@ const ObjectsAPIFields = ({errors}) => {
})
);
if (!confirmSwitch) return false;
setFieldValue('options.variablesMapping', []);
setFieldValue('prefillOptions.variablesMapping', []);
return true;
}}
name="options.objectsApiGroup"
name="prefillOptions.objectsApiGroup"
onApiGroupChange={onApiGroupChange}
/>

<ErrorBoundary
// Ensure the error resets when the API group is changed
key={objectsApiGroup}
errorMessage={
<FormattedMessage
description="Objects API registrations options: object type select error"
Expand All @@ -118,11 +120,11 @@ const ObjectsAPIFields = ({errors}) => {
}
>
<ObjectTypeSelect
name="options.objecttype"
apiGroupFieldName="options.objectsApiGroup"
versionFieldName="options.objecttypeVersion"
name="prefillOptions.objecttypeUuid"
apiGroupFieldName="prefillOptions.objectsApiGroup"
versionFieldName="prefillOptions.objecttypeVersion"
onChangeCheck={() => {
if (values.options.variablesMapping.length === 0) return true;
if (variablesMapping.length === 0) return true;
const confirmSwitch = window.confirm(
intl.formatMessage({
description:
Expand All @@ -132,7 +134,7 @@ const ObjectsAPIFields = ({errors}) => {
})
);
if (!confirmSwitch) return false;
setFieldValue('options.variablesMapping', []);
setFieldValue('prefillOptions.variablesMapping', []);
return true;
}}
/>
Expand All @@ -147,9 +149,9 @@ const ObjectsAPIFields = ({errors}) => {
}
>
<ObjectTypeVersionSelect
name="options.objecttypeVersion"
apiGroupFieldName="options.objectsApiGroup"
objectTypeFieldName="options.objecttype"
name="prefillOptions.objecttypeVersion"
apiGroupFieldName="prefillOptions.objectsApiGroup"
objectTypeFieldName="prefillOptions.objecttypeUuid"
/>
</ErrorBoundary>
</Fieldset>
Expand All @@ -164,10 +166,11 @@ const ObjectsAPIFields = ({errors}) => {
>
<FormRow>
<VariableMapping
name="options.variablesMapping"
name="prefillOptions.variablesMapping"
loading={loading}
directionIcon={<FAIcon icon="arrow-left-long" aria-hidden="true" />}
propertyName="prefillProperty"
variableName="variableKey"
propertyName="targetPath"
propertyChoices={prefillProperties}
propertyHeading={
<FormattedMessage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,28 @@ const PrefillConfigurationForm = ({
attribute = '',
identifierRole = 'main',
// TODO: find a better way to specify this based on the selected plugin
options = {
prefillOptions = {},
errors,
}) => {
const defaults = {
objectsApiGroup: '',
objecttype: '',
objecttypeUuid: '',
objecttypeVersion: null,
variablesMapping: [],
},
errors,
}) => {
};
prefillOptions = {...defaults, ...prefillOptions};
return (
<Formik
initialValues={{
plugin,
attribute,
identifierRole,
options,
prefillOptions,
}}
onSubmit={(values, actions) => {
// TODO should be implemented in https://github.com/open-formulieren/open-forms/issues/4693
console.log(values);
// TODO fix this in api
// if(!values.attribute) values.attribute = "foo"
onSubmit(values);
actions.setSubmitting(false);
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const PrefillSummary = ({
plugin={plugin}
attribute={attribute}
identifierRole={identifierRole}
options={options}
prefillOptions={options}
onSubmit={values => {
onChange(values);
setModalOpen(false);
Expand Down
26 changes: 22 additions & 4 deletions src/openforms/js/components/admin/forms/VariableMapping.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const VariableMappingRow = ({
prefix,
loading,
directionIcon,
variableName,
propertyName,
propertyChoices,
propertySelectLabel,
Expand Down Expand Up @@ -66,10 +67,10 @@ const VariableMappingRow = ({
return (
<tr>
<td>
<Field name={`${prefix}.formVariable`}>
<Field name={`${prefix}.${variableName}`}>
<VariableSelection
includeStaticVariables={includeStaticVariables}
{...getFieldProps(`${prefix}.formVariable`)}
{...getFieldProps(`${prefix}.${variableName}`)}
aria-label={intl.formatMessage({
description: 'Accessible label for (form) variable dropdown',
defaultMessage: 'Form variable',
Expand Down Expand Up @@ -118,7 +119,7 @@ const VariableMappingRow = ({

VariableMappingRow.propTypes = {
/**
* Prefix for the nested fields (formVariable, $propertyName) to its parent. Used to
* Prefix for the nested fields ($variableName, $propertyName) to its parent. Used to
* build the fully qualified names of individual form fields.
*/
prefix: PropTypes.string.isRequired,
Expand Down Expand Up @@ -153,6 +154,14 @@ VariableMappingRow.propTypes = {
*/
propertySelectLabel: PropTypes.string.isRequired,
onRemove: PropTypes.func.isRequired,

/**
* Name of the variable nested inside each mapping item.
*
* This is the form variable to which the property will be mapped.
*/
variableName: PropTypes.string.isRequired,

/**
* Indicates if static variables can be selected for the mapping or not. Assigning
* to static variables is not possible, but reading from them and assigning the value
Expand Down Expand Up @@ -185,6 +194,7 @@ const VariableMapping = ({
name,
loading,
directionIcon,
variableName = 'formVariable',
propertyName,
propertyChoices,
propertyHeading,
Expand Down Expand Up @@ -229,6 +239,7 @@ const VariableMapping = ({
loading={loading}
includeStaticVariables={includeStaticVariables}
propertyChoices={propertyChoices}
variableName={variableName}
propertyName={propertyName}
propertySelectLabel={propertySelectLabel}
alreadyMapped={alreadyMapped}
Expand All @@ -241,7 +252,7 @@ const VariableMapping = ({
<ButtonContainer
onClick={() => {
// TODO update
const initial = {formVariable: '', [propertyName]: ''};
const initial = {[variableName]: '', [propertyName]: ''};
const mapping = get(values, name);
arrayHelpers.insert(mapping.length, initial);
}}
Expand Down Expand Up @@ -274,6 +285,13 @@ VariableMapping.propTypes = {
*/
directionIcon: PropTypes.node,

/**
* Name of the variable nested inside each mapping item.
*
* This is the form variable to which the property will be mapped.
*/
variableName: PropTypes.string.isRequired,

/**
* Name of the property nested inside each mapping item.
*
Expand Down

0 comments on commit 5147a2a

Please sign in to comment.