Skip to content

Apply validation functions to mapping.#192

Merged
rossjones merged 19 commits into
mainfrom
validate-mapping
Apr 29, 2025
Merged

Apply validation functions to mapping.#192
rossjones merged 19 commits into
mainfrom
validate-mapping

Conversation

@rossjones
Copy link
Copy Markdown
Contributor

@rossjones rossjones commented Apr 7, 2025

Use the attribute-types to ensure that rows are validated according to the type and required fields when performing the validation. This should generate errors and warnings for the review page.

In addition to these changes, the warning/errors are defined such that validation failures are errors, but structural errors (such as missing rows, or mismatched row lengths) are recorded as warnings. For errors, it is now possible to request the row data in code for any errors, which in future will allow the review page to show exactly where the errors occur. To achieve this the column index will need to be available to the frontend in the same way that the row index is, currently there's no simple way to map the column name where the error occurred to the index in the error data (see #199)

Also resolves #191 as it now shows an error summary when a required field is not used in the mapping step.

@rossjones rossjones requested a review from simonwo April 22, 2025 14:38
Copy link
Copy Markdown
Member

@simonwo simonwo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good so far, I haven't been able to see the review page yet.

Comment thread prototypes/basic/app/views/review.html Outdated
<th scope="col" class="govuk-table__header">Error</th>
</tr>
</thead>
<tbody class="govuk-table__body"></tbody>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<tbody class="govuk-table__body"></tbody>
<tbody class="govuk-table__body">

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8ebbd5b

Comment thread lib/importer/src/index.js
Comment on lines +313 to +318
if (required_fields.length > 0) {
request.session.data[IMPORTER_ERROR_KEY] = "The following fields are required"
request.session.data[IMPORTER_ERROR_EXTRA_KEY] = required_fields
response.redirect(request.get('Referrer'));
return;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we hit this, we lose all of the user's previous entries on the mapping page. I get that we aren't rendering the template here so can't push the previous entries onto the page, but could we be storing them in the session for the mapping macro to pick up?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in f2cbe70 but not super-happy with it as it doesn't feel generic enough to be re-usable elsewhere, but workable for now until we have that need.

<ul class="govuk-list govuk-error-summary__list">
{% for e in error.extra %}
<li>
<a href="#">{{ e }}</a>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the anchor here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in the design system it's intended to jump to the anchor where the error occurs, but I think I just forgot to go back and implement that by adding ids to the fields. Will sort it..

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e3ad256 but not sure scrolling down the page without a visual indicator on the erroring row is that helpful, but not sure I know how to visually indicate the error in a table.

Comment thread lib/importer/src/index.js
Comment on lines +313 to +318
if (required_fields.length > 0) {
request.session.data[IMPORTER_ERROR_KEY] = "The following fields are required"
request.session.data[IMPORTER_ERROR_EXTRA_KEY] = required_fields
response.redirect(request.get('Referrer'));
return;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, this does not clear the error in the case where length == 0, meaning that returning to the mapping page continues to show an error.

Copy link
Copy Markdown
Contributor Author

@rossjones rossjones Apr 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The errors are cleaned up on each request so any request after an error will remove it from the session. The redirect here is working as we the referrer is a user provided url rather than a data-importer route

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

THat's not what I'm observing – if you go to the mapping page and don't map all the required fields, you see an error. If you then map the required fields you can progress. If you THEN use the breadcrumbs to go back to the mapping page, the error is still visible, even when refreshing?

Copy link
Copy Markdown
Contributor Author

@rossjones rossjones Apr 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah, if you don't hit an importer route and then go back that's the behaviour. I think I've got a fix, will give it a test in 666d10d

Comment on lines -83 to +99
exports.typeFromName = (name) => {
if (!name) return null
exports.mapperForField = (field) => {
if (!field) return null

switch (name.toLowerCase()) {
let m = exports.basicStringType;

switch (field.type.toLowerCase()) {
case "number":
return exports.basicNumberType
m = exports.basicNumberType
break
default:
return exports.basicStringType
m = exports.basicStringType
}

if (field.required) {
return exports.requiredType(m)
}

return exports.optionalType(m)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something here doesn't seem to be working. If I have config:

{
  "serviceName": "Upload monthly pension return",
  "fields": [
    {
      "name": "Title",
      "type": "text",
      "required": false
    },
    {
      "name": "First name",
      "type": "text",
      "required": false
    },
    {
      "name": "Surname",
      "type": "text",
      "required": false
    },
    {
      "name": "Employee number",
      "type": "text",
      "required": true
    },
    {
      "name": "Employment start date",
      "type": "text",
      "required": false
    },
    {
      "name": "Salary",
      "type": "text",
      "required": true
    },
    {
      "name": "Contribution percentage",
      "type": "text",
      "required": true
    },
    {
      "name": "Payment date",
      "type": "text",
      "required": false
    }
  ],
  "uploadPath": ""
}

and I upload this CSV and map the columns in the obvious way:

Employee number,Title,First name,Surname,Employment start date,Salary,Contribution percentage,Payment date
1,Mr,Jon,Arbuckle,2025-01-01,,,2025-04-01
2,Mr,Odie,Arbuckle,2025-02-01,123,12%,2025-04-01

Then I am told that I have uploaded two rows and there are no errors. But there should be errors because one of the rows is missing values for required fields.

image

More tests needed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in 7e82f2d, tests to follow.

Previously fields that were not present (and had no value) where not
being processed by the validation which iterated over the keys present
in the object to decide what to validate.
When we submit values, if there is an error we currently end up with
blank selections. This change will remember the previous submission and
pre-select the values as they were submitted when there is an error.
@rossjones rossjones merged commit 6dd45ba into main Apr 29, 2025
5 checks passed
@rossjones rossjones deleted the validate-mapping branch April 29, 2025 08:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Apply 'required' check to mapping setup

2 participants