Skip to content

Commit 90ad4d7

Browse files
authored
Error view for review page (#273)
Introduces an error view macro (importerErrorView) which shows users any errors of warnings encountered during the mapping process. The data representation for erros and warnings is now grouped by the error itself, showing the rows and fields where it occurs. { message: "An error", meta: { first: 1, count: 1, }, fields: ["A"], rows: [] } rows in the structure above contains all of the rows containing errors along with the previous and following rows for extra context. The specific cells containing the error in each row has a new tag, error: true to show that the cell contains an error.
1 parent a855708 commit 90ad4d7

26 files changed

Lines changed: 535 additions & 217 deletions

lib/importer/assets/css/error.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.validation-error-message {
2+
color: #d4351c !important;
3+
}

lib/importer/assets/css/selectable_table.css

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,3 +345,25 @@ table.selectable thead tr[data-key=text]>*:empty::after {
345345
height: calc((18px) + (4em))
346346
}
347347
}
348+
349+
/* Validation errors */
350+
table.selectable td.validation-error {
351+
text-decoration: #d4351c wavy underline;
352+
}
353+
354+
table.selectable tr.validation-error::before,
355+
table.selectable tr.validation-error th[scope=row] {
356+
background-color: lightpink;
357+
}
358+
359+
table.selectable tr.validation-error:last-child::before {
360+
border-bottom-left-radius: 10px;
361+
}
362+
363+
/* Don't rely on coloured elements to distinguish rows, as this isn't accessible
364+
to people with some vision impairments. So display a dot next to invalid rows.
365+
*/
366+
table.selectable tr.validation-error::before {
367+
content: "•";
368+
padding-top: 3px;
369+
}

lib/importer/assets/docs/component-sheet-selector.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<meta name="viewport" content="width=device-width, initial-scale=1" />
77
<title>Sheet selector – Data Upload Design Kit by Register Dynamics</title>
88
<link href="/public/stylesheets/application.css" rel="stylesheet" type="text/css" />
9+
<link href="../css/error.css" rel="stylesheet" type="text/css" />
910
<link href="../css/sheet_selector.css" rel="stylesheet" type="text/css" />
1011
<link href="../css/selectable_table.css" rel="stylesheet" type="text/css" />
1112
<link href="./docs.css" rel="stylesheet" type="text/css" />

lib/importer/assets/js/selectable_table.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ window.addEventListener("load", function() {
721721

722722
const headerRowCellCount = table.querySelectorAll('th[scope="col"]').length
723723
const headerRowCount = table.querySelectorAll('thead tr').length
724-
const headerRowOffset = headerRowCellCount > 0 ? headerRowCount : 0;
724+
const headerRowOffset = headerRowCellCount > 0 ? headerRowCount : 1;
725725
var columnOffset = 0;
726726

727727
// If there are row numbers, the column numbers will be off as it includes the

lib/importer/govuk-prototype-kit.config.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"/assets/js/selectable_table.js"
5353
],
5454
"stylesheets": [
55+
"/assets/css/error.css",
5556
"/assets/css/sheet_selector.css",
5657
"/assets/css/range_selector.css",
5758
"/assets/css/selectable_table.css"
@@ -87,6 +88,10 @@
8788
{
8889
"macroName": "tableView",
8990
"importFrom": "importer/macros/table_view.njk"
91+
},
92+
{
93+
"macroName": "importerErrorView",
94+
"importFrom": "importer/macros/error_view.njk"
9095
}
9196
]
9297
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
{% from "importer/macros/table_view.njk" import tableView %}
2+
3+
{#
4+
importerErrorView displays errors from the result of a mapping attempt.
5+
6+
These errors are grouped so that similar errors in the same column are
7+
shown together, and each side of the error there should also be a single
8+
row of non-erroring data for context where possible.
9+
10+
The expected error/warning structure from the API is as follows:
11+
12+
[
13+
{
14+
message: "An error occurred",
15+
fields: ["A"],
16+
rows: [["A", "B", "C"]] }
17+
},
18+
{
19+
message: "A warning is necessary",
20+
fields: ["B"],
21+
rows: [["A"]]
22+
}
23+
]
24+
25+
#}
26+
{% macro importerErrorView(session, results ) %}
27+
{% set tableHeaders = importerHeaderRowDisplay(session, "source") %}
28+
29+
<p class="govuk-body">
30+
During import there were <strong>{{results.errorCount}}</strong> errors and <strong>{{results.warningCount}}</strong> warnings.
31+
</p>
32+
33+
{% if results.errors.length > 0 %}
34+
<h2 class="govuk-heading-m">Errors</h2>
35+
{% for error in results.errors %}
36+
<div class="govuk-form-group govuk-form-group--error">
37+
<h2 class="govuk-heading-m validation-error-message">{{error.message}}</h2>
38+
<p class="govuk-body">This error occurs {{error.meta.count | count_string}} in your data. The first time at row {{ error.meta.first}}:</p>
39+
40+
{{ tableView( {
41+
caption: false,
42+
showHeaders: true,
43+
headers: tableHeaders,
44+
showRowNumbers: true,
45+
rows: error.rows,
46+
moreRowsCount: 0
47+
} )
48+
}}
49+
</div>
50+
{% endfor %}
51+
{% endif %}
52+
53+
{% if results.warnings.length > 0 %}
54+
<h2 class="govuk-heading-m">Warnings</h2>
55+
{% for warning in results.warnings %}
56+
<div class="govuk-form-group govuk-form-group--error">
57+
<h2 class="govuk-heading-m validation-error-message">{{warning.message}}</h2>
58+
<p class="govuk-body">This warning occurs {{warning.meta.count | count_string}} in your data. The first time at row {{ warning.meta.first}}:</p>
59+
60+
61+
{{ tableView( {
62+
caption: false,
63+
showHeaders: true,
64+
headers: tableHeaders,
65+
showRowNumbers: true,
66+
rows: warning.rows,
67+
moreRowsCount: 0
68+
} )
69+
}}
70+
</div>
71+
{% endfor %}
72+
{% endif %}
73+
74+
{% endmacro %}
75+
76+

lib/importer/nunjucks/importer/macros/footer_selector.njk

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,5 @@
55
{% set rows = importerGetTrailingRows(data, count) %}
66
{% set caption = importerGetTableCaption(data, "Last", count) %}
77

8-
{% set tableHeaders = importerHeaderRowDisplay(data, "source") %}
9-
10-
{{ importerRangeSelector(rows, caption, tableHeaders, true) }}
8+
{{ importerRangeSelector(rows, caption, false, true) }}
119
{% endmacro %}

lib/importer/nunjucks/importer/macros/header_selector.njk

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
{% macro importerHeaderSelector(data, start, count=10) %}
55
{% set rows = importerGetRows(data, start, count) %}
66
{% set caption = importerGetTableCaption(data, "First", count) %}
7-
{% set tableHeaders = importerHeaderRowDisplay(data, "index") %}
87

9-
{{ importerRangeSelector(rows, caption, tableHeaders, true) }}
8+
{{ importerRangeSelector(rows, caption, false, true) }}
109
{% endmacro %}

lib/importer/nunjucks/importer/macros/range_selector.njk

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
{% if showRowNumbers %}
4444
<th scope="row" class="rowIndex">{{ rowObj.index }}</th>
4545
{% endif %}
46-
4746
{% for cell in rowObj.row %}
4847
<td aria-selected="false"
4948
{% if cell.colspan %}

lib/importer/nunjucks/importer/macros/table_view.njk

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Renders a table view using the provided parameters to determine what is being sh
2626
* moreRowsCount - How many more rows are available but now shown, useful when showing only n of many.
2727
#}
2828
{% macro tableView(params) %}
29+
2930
<table class="selectable govuk-body" data-persist-selection="true">
3031
{% if params.caption %}
3132
<caption class="govuk-table__caption govuk-table__caption--m">{{params.caption}}</caption>
@@ -44,8 +45,9 @@ Renders a table view using the provided parameters to determine what is being sh
4445
{% endif %}
4546
<tbody>
4647
{% for rowObj in params.rows %}
47-
<tr>
48-
{% if showRowNumbers %}
48+
<tr class="govuk-table__row {% if importerRowHasHeader(rowObj) %}
49+
validation-error{%endif%}">
50+
{% if params.showRowNumbers %}
4951
<th scope="row" class="rowIndex">{{ rowObj.index }}</th>
5052
{% endif %}
5153
{% for cell in rowObj.row %}
@@ -56,6 +58,10 @@ Renders a table view using the provided parameters to determine what is being sh
5658
{% if cell.rowspan %}
5759
rowspan="{{ cell.rowspan }}"
5860
{% endif %}
61+
62+
{% if cell.error %}
63+
class="validation-error"
64+
{% endif %}
5965
>{{cell.value }}</td>
6066
{% endfor %}
6167
</tr>

0 commit comments

Comments
 (0)