Skip to content

Commit

Permalink
Merge pull request #6 from digital-land/errorsPage
Browse files Browse the repository at this point in the history
Added an errors page
  • Loading branch information
GeorgeGoodall authored Nov 9, 2023
2 parents 337ce01 + 91f57a3 commit b9f36ff
Show file tree
Hide file tree
Showing 14 changed files with 583 additions and 21 deletions.
3 changes: 2 additions & 1 deletion config/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ logs:
app: false
error: false
api: {
url: http://localhost:3000/api
url: http://127.0.0.1:8082,
validationEndpoint: /api/dataset/validate/file/request/
}
79 changes: 79 additions & 0 deletions src/assets/scss/_scrollable-container.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
.app-scrollable-container {

table {
margin-bottom: 20px;
th, td {
white-space: nowrap;
}

td.app-wrap {
// white-space: unset;
max-width: 500px;
overflow: hidden;
text-overflow: ellipsis;

.app-inset-text__value {
overflow: hidden;
text-overflow: ellipsis;
}
}
}

max-height: 500px;
@include govuk-responsive-margin(6, $direction: "bottom");
padding-left: 15px;
padding-right: 15px;
overflow-x: auto;
border: 1px solid rgb(169, 169, 169);
background-image:
// Shadows
linear-gradient(to right, white, white),
linear-gradient(to right, white, white),

// Shadow covers
linear-gradient(to right, rgba(0,0,0,.25), rgba(255,255,255,0)),
linear-gradient(to left, rgba(0,0,0,.25), rgba(255,255,255,0));

background-position: left center, right center, left center, right center;
background-repeat: no-repeat;
background-color: white;
background-size: 20px 100%, 20px 100%, 10px 100%, 10px 100%;

/* Opera doesn't support this in the shorthand */
background-attachment: local, local, scroll, scroll;

scrollbar-width: thin;
scrollbar-color: #8A8A8A #DFE9EB;

/* Chrome, Edge and Safari */
&::-webkit-scrollbar {
height: 10px;
width: 10px;
}
&::-webkit-scrollbar-track {
border-radius: 5px;
background-color: #e8e8e8;
}

&::-webkit-scrollbar-track:hover {
background-color: #B8C0C2;
}

&::-webkit-scrollbar-track:active {
background-color: #B8C0C2;
}

&::-webkit-scrollbar-thumb {
border-radius: 0px;
background-color: $govuk-border-colour;
}

&::-webkit-scrollbar-thumb:hover {
background-color: #5F5F5F;
}

&::-webkit-scrollbar-thumb:active {
background-color: #474D54;
}

}
37 changes: 36 additions & 1 deletion src/assets/scss/index.scss
Original file line number Diff line number Diff line change
@@ -1,2 +1,37 @@
@import "node_modules/govuk-frontend/govuk/all";
@import "node_modules/@x-govuk/govuk-prototype-components/x-govuk/all";
@import "node_modules/@x-govuk/govuk-prototype-components/x-govuk/all";
@import "src/assets/scss/_scrollable-container.scss";

.app-inset-text---error {
border-left: 5px solid govuk-colour('red');
padding: govuk-spacing(1) govuk-spacing(2);
margin: 0;

.app-inset-text__value {
margin-bottom: govuk-spacing(1);
}

.app-inset-text__error {
color: govuk-colour('red');
font-weight: bold;
}


}

.app-inset-text---warning {
border-left: 5px solid govuk-colour('blue');
padding: govuk-spacing(1) govuk-spacing(2);
margin: 0;

.app-inset-text__value {
margin-bottom: govuk-spacing(1);
}

.app-inset-text__warning {
color: govuk-colour('blue');
font-weight: bold;
}


}
56 changes: 56 additions & 0 deletions src/controllers/errorsController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
'use strict'

const { Controller } = require('hmpo-form-wizard')

class ErrorsController extends Controller {
get (req, res, next) {
const json = req.sessionModel.get('validationResult')

const aggregatedIssues = {}
const issueCounts = {}

json['issue-log'].forEach(issue => {
const entryNumber = issue['entry-number']

const rowColumns = json['converted-csv'][issue['line-number'] - 1]
if (!(entryNumber in aggregatedIssues)) {
aggregatedIssues[entryNumber] = Object.keys(rowColumns).reduce((acc, key) => {
acc[key] = {
error: false,
value: rowColumns[key]
}
return acc
}, {})
}

if (entryNumber in aggregatedIssues) {
aggregatedIssues[entryNumber][issue.field] = {
error: this.lookupIssueType(issue['issue-type']),
value: rowColumns[issue.field]
}
issueCounts[issue.field] = issueCounts[issue.field] ? issueCounts[issue.field] + 1 : 1
}
})

const rows = Object.keys(aggregatedIssues).map(key => {
return {
entryNumber: key,
columns: aggregatedIssues[key]
}
})

req.form.options.rows = rows
req.form.options.issueCounts = issueCounts
req.form.options.dataset = req.sessionModel.get('dataset')
req.form.options.dataSubject = req.sessionModel.get('data-subject')

super.get(req, res, next)
}

lookupIssueType (issueType) {
// this needs to be implemented once we know what the issue types are
return issueType
}
}

module.exports = ErrorsController
10 changes: 5 additions & 5 deletions src/controllers/uploadController.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ const { Controller } = require('hmpo-form-wizard')
const { readFile } = require('node:fs/promises')
const { lookup } = require('mime-types')

const apiRoute = 'http://127.0.0.1:8082/api/dataset/validate/file/request/'
const config = require('../../config')

const apiRoute = config.api.url + config.api.validationEndpoint

class UploadController extends Controller {
middlewareSetup () {
Expand Down Expand Up @@ -35,10 +37,8 @@ class UploadController extends Controller {

const json = await result.json()

console.log(json)

// send the response back to the user
res.send(json)
req.sessionModel.set('validationResult', json)
super.post(req, res, next)
} catch (e) {
res.send(e)
}
Expand Down
3 changes: 3 additions & 0 deletions src/routes/form-wizard/fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@ module.exports = {
},
datafile: {
validate: 'required'
},
validationResult: {
validate: 'required'
}
}
7 changes: 5 additions & 2 deletions src/routes/form-wizard/steps.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ module.exports = {
},
'/upload': {
controller: require('../../controllers/uploadController'),
fields: ['datafile', 'path'],
next: 'done'
next: 'errors'
},
'/errors': {
controller: require('../../controllers/errorsController'),
next: 'transformations'
}
}
141 changes: 141 additions & 0 deletions src/views/errors.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
{% extends "layouts/main.html" %}

{% from 'govuk/components/back-link/macro.njk' import govukBackLink %}
{% from 'govuk/components/button/macro.njk' import govukButton %}
{% from 'govuk/components/radios/macro.njk' import govukRadios %}
{% from 'govuk/components/inset-text/macro.njk' import govukInsetText %}

{% set pageName = 'There’s a problem with your data' %}

{% block beforeContent %}
{{ govukBackLink({
text: "Back",
href: "javascript:window.history.back()"
}) }}
{% endblock %}

{% block content %}

<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<span class="govuk-caption-l">
{% if options.dataset %}
{{options.dataset}}
{% else %}
{{options.dataSubject}}
{% endif %}
</span>
<h1 class="govuk-heading-l">
{{pageName}}
</h1>

<ul class="govuk-list govuk-list--bullet">
{% for issue, count in options.issueCounts %}
<li>{{count}} issue, relating to {{issue}}</li>
{% endfor %}
</ul>
</div>
</div>

<div class="govuk-grid-row">
<div class="govuk-grid-column-full">
<h2 class="govuk-heading-m">
Records with errors
</h2>

<div class="app-scrollable-container">
<table class="govuk-table">
<thead class="govuk-table__head">
<tr class="govuk-table__row">
<th scope="col" class="govuk-table__header">Reference</th>
<th scope="col" class="govuk-table__header">Name</th>
<th scope="col" class="govuk-table__header">Geometry</th>
<th scope="col" class="govuk-table__header">Start date</th>
<th scope="col" class="govuk-table__header">Legislation</th>
<th scope="col" class="govuk-table__header">Notes</th>
<th scope="col" class="govuk-table__header">Point</th>
<th scope="col" class="govuk-table__header">End date</th>
<th scope="col" class="govuk-table__header">Document URL</th>
</tr>
</thead>
<tbody class="govuk-table__body">
{% for row in options.rows %}
<tr class="govuk-table__row">
<td class="govuk-table__cell">
{% if row.columns.Reference.error %}
{{ govukInsetText({
classes: "app-inset-text---error",
html: '<p class="app-inset-text__error">Reference is missing</p>'
}) }}
{% else %}
{{row.columns.Reference.value}}
{% endif %}
</td>
<td class="govuk-table__cell">{{row.columns.Name.value}}</td>
<td class="govuk-table__cell app-wrap">
{% if row.columns.Geometry.error %}
{{ govukInsetText({
classes: "app-inset-text---error",
html: '<p class="app-inset-text__value">'+row.columns.Geometry.value+'</p> <p class="app-inset-text__error">'+row.columns.Geometry.error +'</p>'
}) }}
{% else %}
{{row.columns.Geometry.value}}
{% endif %}
</td>
<td class="govuk-table__cell">
{% if row.columns['Start date'].error %}
{{ govukInsetText({
classes: "app-inset-text---error",
html: '<p class="app-inset-text__value">'+row.columns['Start date'].value+'</p> <p class="app-inset-text__error">'+row.columns['Start date'].error +'</p>'
}) }}
{% else %}
{{row.columns['Start date'].value}}
{% endif %}
</td>
<td class="govuk-table__cell">{{row.columns.Legisliation.value}}</td>
<td class="govuk-table__cell">{{row.columns.Notes.value}}</td>
<td class="govuk-table__cell app-wrap">{{row.columns.Point.value}}</td>
<td class="govuk-table__cell">{{row.columns['End date'].value}}</td>
<td class="govuk-table__cell">{{row.columns['Document URL'].value}}</td>
</tr>
{% endfor %}

</tbody>
</table>
</div>
</div>
</div>

<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<form novalidate method="post">

{{ govukRadios({
name: "check[fixErrors]",
fieldset: {
legend: {
text: "Do you want to fix the errors before you publish the data?",
classes: "govuk-fieldset__legend--m"
}
},
value: data.check.fixErrors,
items: [
{
value: "Yes",
text: "Yes"
},
{
value: "No",
text: "No, publish the valid data and I’ll fix the invalid data later"
}
]
}) }}

{{ govukButton({
text: "Continue"
}) }}
</form>

</div>
</div>
{% endblock %}
3 changes: 2 additions & 1 deletion test/acceptance/upload_data.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { test } from '@playwright/test'

test('Upload data', async ({ page }) => {
test('Enter form information', async ({ page }) => {
await page.goto('/')
await page.getByRole('button', { name: 'Start now' }).click()

Expand All @@ -20,5 +20,6 @@ test('Upload data', async ({ page }) => {
await page.getByText('Upload data').click()
const fileChooser = await fileChooserPromise
await fileChooser.setFiles('test/testData/conservation-area.csv')

await page.getByRole('button', { name: 'Continue' }).click()
})
Loading

0 comments on commit b9f36ff

Please sign in to comment.