diff --git a/src/openforms/js/compiled-lang/en.json b/src/openforms/js/compiled-lang/en.json index 35e9958410..790c4a6d3e 100644 --- a/src/openforms/js/compiled-lang/en.json +++ b/src/openforms/js/compiled-lang/en.json @@ -6427,6 +6427,12 @@ "value": "Variable" } ], + "xBb5YI": [ + { + "type": 0, + "value": "Select an object type and version before you can pick a source path." + } + ], "xI6md8": [ { "type": 0, diff --git a/src/openforms/js/compiled-lang/nl.json b/src/openforms/js/compiled-lang/nl.json index 2c2060d55b..e354b6c13e 100644 --- a/src/openforms/js/compiled-lang/nl.json +++ b/src/openforms/js/compiled-lang/nl.json @@ -6449,6 +6449,12 @@ "value": "Variabele" } ], + "xBb5YI": [ + { + "type": 0, + "value": "Select an object type and version before you can pick a source path." + } + ], "xI6md8": [ { "type": 0, diff --git a/src/openforms/js/components/admin/form_design/RegistrationFields.stories.js b/src/openforms/js/components/admin/form_design/RegistrationFields.stories.js index 0d28050491..726b9cc2fa 100644 --- a/src/openforms/js/components/admin/form_design/RegistrationFields.stories.js +++ b/src/openforms/js/components/admin/form_design/RegistrationFields.stories.js @@ -6,6 +6,7 @@ import { mockCataloguesGet as mockObjectsApiCataloguesGet, mockObjecttypeVersionsGet, mockObjecttypesGet, + mockTargetPathsPost, } from 'components/admin/form_design/registrations/objectsapi/mocks'; import { mockCaseTypesGet, @@ -512,6 +513,15 @@ export default { ]), mockObjectsApiCataloguesGet(), mockDocumentTypesGet(), + mockTargetPathsPost({ + string: [ + { + targetPath: ['path', 'to.the', 'target'], + isRequired: true, + jsonSchema: {type: 'string'}, + }, + ], + }), ], zgwMocks: [ mockZGWApisCataloguesGet(), diff --git a/src/openforms/js/components/admin/form_design/registrations/objectsapi/AddressNlObjectsApiVariableConfigurationEditor.js b/src/openforms/js/components/admin/form_design/registrations/objectsapi/AddressNlObjectsApiVariableConfigurationEditor.js index 7f9265580b..f6b5f624c4 100644 --- a/src/openforms/js/components/admin/form_design/registrations/objectsapi/AddressNlObjectsApiVariableConfigurationEditor.js +++ b/src/openforms/js/components/admin/form_design/registrations/objectsapi/AddressNlObjectsApiVariableConfigurationEditor.js @@ -1,6 +1,5 @@ -import {FieldArray, useFormikContext} from 'formik'; +import {useFormikContext} from 'formik'; import isEqual from 'lodash/isEqual'; -import PropTypes from 'prop-types'; import React, {useContext} from 'react'; import {FormattedMessage} from 'react-intl'; import {useAsync, useToggle} from 'react-use'; @@ -11,11 +10,12 @@ import Field from 'components/admin/forms/Field'; import Fieldset from 'components/admin/forms/Fieldset'; import FormRow from 'components/admin/forms/FormRow'; import {Checkbox} from 'components/admin/forms/Inputs'; -import Select, {LOADING_OPTION} from 'components/admin/forms/Select'; -import {TargetPathDisplay} from 'components/admin/forms/objects_api'; +import {TargetPathSelect} from 'components/admin/forms/objects_api'; import ErrorMessage from 'components/errors/ErrorMessage'; import {post} from 'utils/fetch'; +import {MappedVariableTargetPathSelect} from './GenericObjectsApiVariableConfigurationEditor'; + const ADDRESSNL_NESTED_PROPERTIES = { postcode: {type: 'string'}, houseLetter: {type: 'string'}, @@ -58,16 +58,17 @@ export const AddressNlEditor = ({ objecttypeVersion, }) => { const {csrftoken} = useContext(APIContext); - const {values, setFieldValue} = useFormikContext(); + const {setValues} = useFormikContext(); + + const hasSpecificOptions = Object.values(mappedVariable?.options ?? {}).some( + targetPath => targetPath && targetPath.length + ); + const [specificTargetPaths, toggleSpecificTargetPaths] = useToggle(hasSpecificOptions); const [jsonSchemaVisible, toggleJsonSchemaVisible] = useToggle(false); - const {specificTargetPaths} = values; - const isSpecificTargetPaths = - specificTargetPaths || - (mappedVariable.options && Object.keys(mappedVariable.options).length > 0); const deriveAddress = components[variable?.key]['deriveAddress']; - // // Load all the possible target paths (obect,string and number types) in parallel and only once + // Load all the possible target paths (obect,string and number types) in parallel and only once const { loading, value: targetPaths, @@ -90,20 +91,6 @@ export const AddressNlEditor = ({ const [objectTypeTargetPaths = [], stringTypeTargetPaths = [], numberTypeTargetPaths = []] = targetPaths || []; - const choicesTypes = { - object: objectTypeTargetPaths, - string: stringTypeTargetPaths, - number: numberTypeTargetPaths, - }; - - const getChoices = type => - loading || error - ? LOADING_OPTION - : choicesTypes[type].map(t => [ - JSON.stringify(t.targetPath), - , - ]); - const getTargetPath = pathSegment => objectTypeTargetPaths.find(t => isEqual(t.targetPath, pathSegment)); @@ -118,18 +105,31 @@ export const AddressNlEditor = ({ ); const onSpecificTargetPathsChange = event => { - setFieldValue('specificTargetPaths', event.target.checked); + const makeSpecific = event.target.checked; + toggleSpecificTargetPaths(makeSpecific); - if (event.target.checked) { - setFieldValue(`${namePrefix}.targetPath`, undefined); - } else { - setFieldValue(`${namePrefix}.options.postcode`, undefined); - setFieldValue(`${namePrefix}.options.houseLetter`, undefined); - setFieldValue(`${namePrefix}.options.houseNumber`, undefined); - setFieldValue(`${namePrefix}.options.houseNumberAddition`, undefined); - setFieldValue(`${namePrefix}.options.city`, undefined); - setFieldValue(`${namePrefix}.options.streetName`, undefined); - } + setValues(prevValues => { + const newVariablesMapping = [...prevValues.variablesMapping]; + const newMappedVariable = { + ...(newVariablesMapping[index] ?? mappedVariable), + // clear targetPath if we're switching to specific subfields + targetPath: makeSpecific ? undefined : mappedVariable.targetPath, + // prepare the options structure if we're switching to specific subfields, + // otherwise remove it entirely + options: makeSpecific + ? { + postcode: undefined, + houseLetter: undefined, + houseNumber: undefined, + houseNumberAddition: undefined, + city: undefined, + streetName: undefined, + } + : undefined, + }; + newVariablesMapping[index] = newMappedVariable; + return {...prevValues, variablesMapping: newVariablesMapping}; + }); }; return ( @@ -150,7 +150,7 @@ export const AddressNlEditor = ({ defaultMessage="Whether to map the specific subfield of addressNl component" /> } - checked={isSpecificTargetPaths} + checked={specificTargetPaths} onChange={onSpecificTargetPathsChange} /> @@ -164,18 +164,19 @@ export const AddressNlEditor = ({ description="'JSON Schema object target' label" /> } - disabled={isSpecificTargetPaths} + disabled={specificTargetPaths} > - - {isSpecificTargetPaths && ( + {specificTargetPaths && (
} required + noManageChildProps > @@ -207,13 +207,12 @@ export const AddressNlEditor = ({ /> } required + noManageChildProps > @@ -226,13 +225,12 @@ export const AddressNlEditor = ({ description="'Objects registration variable mapping, addressNL component: 'options.houseLetter schema target' label" /> } + noManageChildProps > @@ -245,13 +243,12 @@ export const AddressNlEditor = ({ description="Objects registration variable mapping, addressNL component: 'options.houseNumberAddition schema target' label" /> } + noManageChildProps > @@ -265,14 +262,13 @@ export const AddressNlEditor = ({ /> } disabled={!deriveAddress} + noManageChildProps > @@ -286,20 +282,19 @@ export const AddressNlEditor = ({ /> } disabled={!deriveAddress} + noManageChildProps >
)} - {!isSpecificTargetPaths && ( + {!specificTargetPaths && (
e.preventDefault() || toggleJsonSchemaVisible()}> ); }; - -const TargetPathSelect = ({id, name, index, choices, mappedVariable, disabled}) => { - // To avoid having an incomplete variable mapping added in the `variablesMapping` array, - // It is added only when an actual target path is selected. This way, having the empty - // option selected means the variable is unmapped (hence the `arrayHelpers.remove` call below). - const { - values: {variablesMapping}, - getFieldProps, - setFieldValue, - } = useFormikContext(); - const props = getFieldProps(name); - const isNew = variablesMapping.length === index; - - return ( - ( - { - if (event.target.value === '') { - arrayHelpers.remove(index); - } else { - if (isNew) { - arrayHelpers.push({...mappedVariable, targetPath: JSON.parse(event.target.value)}); - } else { - setFieldValue(name, JSON.parse(event.target.value)); - } - } - }} - /> - )} + o.value === JSON.stringify(value)) : null} + components={{ + Option: props => ( + + + + ), + }} + onChange={newValue => { + setFieldValue(name, newValue ? newValue.targetPath : undefined); + }} + {...props} /> ); }; TargetPathSelect.propTypes = { name: PropTypes.string.isRequired, - index: PropTypes.number.isRequired, - choices: PropTypes.array.isRequired, - mappedVariable: PropTypes.object, + isLoading: PropTypes.bool, + targetPaths: PropTypes.arrayOf(TargetPathType), + isDisabled: PropTypes.bool, }; export default TargetPathSelect; diff --git a/src/openforms/js/components/admin/forms/objects_api/TargetPathSelect.stories.js b/src/openforms/js/components/admin/forms/objects_api/TargetPathSelect.stories.js new file mode 100644 index 0000000000..e7106c0c55 --- /dev/null +++ b/src/openforms/js/components/admin/forms/objects_api/TargetPathSelect.stories.js @@ -0,0 +1,43 @@ +import {FormikDecorator} from 'components/admin/form_design/story-decorators'; + +import TargetPathSelect from './TargetPathSelect'; + +export default { + title: 'Form design / TargetPathSelect', + component: TargetPathSelect, + decorators: [FormikDecorator], + args: { + name: 'someTarget', + isLoading: false, + targetPaths: [ + { + targetPath: ['root', 'child'], + isRequired: false, + }, + { + targetPath: ['root', 'other child'], + isRequired: true, + }, + ], + isDisabled: false, + }, + parameters: { + formik: { + initialValues: { + someTarget: null, + }, + }, + }, +}; + +export const Default = {}; + +export const ValueSelected = { + parameters: { + formik: { + initialValues: { + someTarget: ['root', 'other child'], + }, + }, + }, +}; diff --git a/src/openforms/js/components/admin/forms/objects_api/index.js b/src/openforms/js/components/admin/forms/objects_api/index.js index 4040eaf192..a1ace2bede 100644 --- a/src/openforms/js/components/admin/forms/objects_api/index.js +++ b/src/openforms/js/components/admin/forms/objects_api/index.js @@ -2,5 +2,4 @@ export {default as AuthAttributePath} from './AuthAttributePath'; export {default as ObjectsAPIGroup} from './ObjectsAPIGroup'; export {default as ObjectTypeSelect} from './ObjectTypeSelect'; export {default as ObjectTypeVersionSelect} from './ObjectTypeVersionSelect'; -export {default as TargetPathDisplay} from './TargetPathDisplay'; -export {default as TargetPathSelect} from './TargetPathSelect'; +export {default as TargetPathSelect, TargetPathDisplay} from './TargetPathSelect'; diff --git a/src/openforms/js/lang/en.json b/src/openforms/js/lang/en.json index 8eea60e6ca..9b023b43d0 100644 --- a/src/openforms/js/lang/en.json +++ b/src/openforms/js/lang/en.json @@ -3029,6 +3029,11 @@ "description": "Price variable label", "originalDefault": "Variable" }, + "xBb5YI": { + "defaultMessage": "Select an object type and version before you can pick a source path.", + "description": "Object type target path selection for auth attribute message for missing options because no object type has been selected.", + "originalDefault": "Select an object type and version before you can pick a source path." + }, "xJBMaf": { "defaultMessage": "Submission confirmation template", "description": "Submission confirmation fieldset title", diff --git a/src/openforms/js/lang/nl.json b/src/openforms/js/lang/nl.json index 032d9496bd..14da689daa 100644 --- a/src/openforms/js/lang/nl.json +++ b/src/openforms/js/lang/nl.json @@ -3050,6 +3050,11 @@ "description": "Price variable label", "originalDefault": "Variable" }, + "xBb5YI": { + "defaultMessage": "Select an object type and version before you can pick a source path.", + "description": "Object type target path selection for auth attribute message for missing options because no object type has been selected.", + "originalDefault": "Select an object type and version before you can pick a source path." + }, "xJBMaf": { "defaultMessage": "Sjabloon bevestigingspagina", "description": "Submission confirmation fieldset title",