Skip to content

Commit 0a7e8e1

Browse files
Image reading annotations update (#134)
Changes after usability testing: Remove conditional free text from each abnormality type Add new comment box (optional) in their place Make validation of marking locations only require one images to be marked Change text in level of concern select
1 parent 53527c4 commit 0a7e8e1

File tree

5 files changed

+105
-85
lines changed

5 files changed

+105
-85
lines changed

app/assets/sass/_misc.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,8 @@
5858
@include nhsuk-responsive-margin(5, "top");
5959

6060
}
61+
62+
63+
.app-page-width--wide .nhsuk-width-container {
64+
max-width: 1200px;
65+
}

app/assets/sass/main.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
2+
$nhsuk-page-width: 1260px;
3+
14
// Import NHS.UK frontend library
25
@forward 'nhsuk-frontend/dist/nhsuk/nhsuk';
36

@@ -32,6 +35,8 @@
3235
@forward 'typography';
3336
@forward 'utils';
3437

38+
$nhsuk-page-width: 1260px;
39+
3540

3641
///////////////////////////////////////////
3742
// Add your custom CSS/Sass styles below...

app/routes/reading.js

Lines changed: 63 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -405,14 +405,16 @@ router.post('/reading/batch/:batchId/events/:eventId/annotation/save', (req, res
405405
const errors = []
406406
const annotationTemp = data.imageReadingTemp?.annotationTemp
407407

408+
console.log(`annotation temp: ${JSON.stringify(annotationTemp)}`)
409+
408410
if (!annotationTemp) {
409411
return res.redirect(`/reading/batch/${batchId}/events/${eventId}/recall-for-assessment-details`)
410412
}
411413

412414
// Validate that marker positions are set for both views
413415
if (!annotationTemp.markerPositions || annotationTemp.markerPositions === '{}' || annotationTemp.markerPositions === '') {
414416
errors.push({
415-
text: `Mark the location on both ${annotationTemp.side} breast views`,
417+
text: `Mark the location on at least one ${annotationTemp.side} breast view`,
416418
name: 'markerPositions',
417419
href: '#mammogram-section'
418420
})
@@ -425,37 +427,38 @@ router.post('/reading/batch/:batchId/events/:eventId/annotation/save', (req, res
425427

426428
if (!positions || Object.keys(positions).length === 0) {
427429
errors.push({
428-
text: `Mark the location on both ${annotationTemp.side} breast views`,
430+
text: `Mark the location on at least one ${annotationTemp.side} breast view`,
429431
name: 'markerPositions',
430432
href: '#mammogram-section'
431433
})
432-
} else {
433-
// Check we have markers for both image-0 and image-1 (both views)
434-
const hasImage0 = positions['image-0']
435-
const hasImage1 = positions['image-1']
436-
437-
if (!hasImage0 && !hasImage1) {
438-
errors.push({
439-
text: `Mark the location on both ${annotationTemp.side} breast views`,
440-
name: 'markerPositions',
441-
href: '#mammogram-section'
442-
})
443-
} else if (!hasImage0) {
444-
const viewName = annotationTemp.side === 'right' ? 'RMLO' : 'LMLO'
445-
errors.push({
446-
text: `Mark the location on the ${annotationTemp.side} ${viewName} view`,
447-
name: 'markerPositions',
448-
href: '#mammogram-section'
449-
})
450-
} else if (!hasImage1) {
451-
const viewName = annotationTemp.side === 'right' ? 'RCC' : 'LCC'
452-
errors.push({
453-
text: `Mark the location on the ${annotationTemp.side} ${viewName} view`,
454-
name: 'markerPositions',
455-
href: '#mammogram-section'
456-
})
457-
}
458434
}
435+
// else {
436+
// // Check we have markers for both image-0 and image-1 (both views)
437+
// const hasImage0 = positions['image-0']
438+
// const hasImage1 = positions['image-1']
439+
440+
// if (!hasImage0 && !hasImage1) {
441+
// errors.push({
442+
// text: `Mark the location on both ${annotationTemp.side} breast views`,
443+
// name: 'markerPositions',
444+
// href: '#mammogram-section'
445+
// })
446+
// } else if (!hasImage0) {
447+
// const viewName = annotationTemp.side === 'right' ? 'RMLO' : 'LMLO'
448+
// errors.push({
449+
// text: `Mark the location on the ${annotationTemp.side} ${viewName} view`,
450+
// name: 'markerPositions',
451+
// href: '#mammogram-section'
452+
// })
453+
// } else if (!hasImage1) {
454+
// const viewName = annotationTemp.side === 'right' ? 'RCC' : 'LCC'
455+
// errors.push({
456+
// text: `Mark the location on the ${annotationTemp.side} ${viewName} view`,
457+
// name: 'markerPositions',
458+
// href: '#mammogram-section'
459+
// })
460+
// }
461+
// }
459462
} catch (e) {
460463
errors.push({
461464
text: `Mark the location on both ${annotationTemp.side} breast views`,
@@ -466,13 +469,15 @@ router.post('/reading/batch/:batchId/events/:eventId/annotation/save', (req, res
466469
}
467470

468471
// Validate required fields
469-
if (!annotationTemp.location || annotationTemp.location.trim() === '') {
470-
errors.push({
471-
text: 'Enter the location of the abnormality',
472-
name: 'imageReadingTemp[annotationTemp][location]',
473-
href: '#location'
474-
})
475-
}
472+
473+
// Text location not in use
474+
// if (!annotationTemp.location || annotationTemp.location.trim() === '') {
475+
// errors.push({
476+
// text: 'Enter the location of the abnormality',
477+
// name: 'imageReadingTemp[annotationTemp][location]',
478+
// href: '#location'
479+
// })
480+
// }
476481

477482
if (!annotationTemp.abnormalityType || annotationTemp.abnormalityType.length === 0) {
478483
errors.push({
@@ -506,27 +511,27 @@ router.post('/reading/batch/:batchId/events/:eventId/annotation/save', (req, res
506511
}
507512

508513
// Check other conditional fields using the same camelCase logic as the template
509-
const conditionalTypes = [
510-
'Mass well-defined',
511-
'Mass ill-defined',
512-
'Architectural distortion',
513-
'Asymetric density',
514-
'Microcalcification outside a mass',
515-
'Clinical abnormality',
516-
'Lymph node abnormality'
517-
]
518-
519-
if (conditionalTypes.includes(type)) {
520-
const detailsFieldName = camelCase(type) + 'Details'
521-
522-
if (!annotationTemp[detailsFieldName] || annotationTemp[detailsFieldName].trim() === '') {
523-
errors.push({
524-
text: `Provide details for ${type.toLowerCase()}`,
525-
name: `imageReadingTemp[annotationTemp][${detailsFieldName}]`,
526-
href: `#${detailsFieldName}`
527-
})
528-
}
529-
}
514+
// const conditionalTypes = [
515+
// 'Mass well-defined',
516+
// 'Mass ill-defined',
517+
// 'Architectural distortion',
518+
// 'Asymetric density',
519+
// 'Microcalcification outside a mass',
520+
// 'Clinical abnormality',
521+
// 'Lymph node abnormality'
522+
// ]
523+
524+
// if (conditionalTypes.includes(type)) {
525+
// const detailsFieldName = camelCase(type) + 'Details'
526+
527+
// if (!annotationTemp[detailsFieldName] || annotationTemp[detailsFieldName].trim() === '') {
528+
// errors.push({
529+
// text: `Provide details for ${type.toLowerCase()}`,
530+
// name: `imageReadingTemp[annotationTemp][${detailsFieldName}]`,
531+
// href: `#${detailsFieldName}`
532+
// })
533+
// }
534+
// }
530535
})
531536
}
532537

@@ -539,6 +544,7 @@ router.post('/reading/batch/:batchId/events/:eventId/annotation/save', (req, res
539544
// Continue with existing save logic...
540545
if (data.imageReadingTemp?.annotationTemp) {
541546
const side = annotationTemp.side
547+
const comment = annotationTemp.comment
542548
const isNewAnnotation = !annotationTemp.id
543549

544550
if (!side) {
@@ -569,6 +575,7 @@ router.post('/reading/batch/:batchId/events/:eventId/annotation/save', (req, res
569575
const annotation = {
570576
id: annotationTemp.id || generateId(),
571577
side: side,
578+
comment: comment,
572579
location: annotationTemp.location,
573580
abnormalityType: annotationTemp.abnormalityType,
574581
levelOfConcern: annotationTemp.levelOfConcern,

app/views/_templates/layout-app.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
{% extends "layout.html" %}
33

4-
{% set bodyClasses = "app-dark-mode" if data.settings.darkMode == 'true' %}
4+
{% set bodyClasses = bodyClasses + (" app-dark-mode" if data.settings.darkMode == 'true') %}
55

66
{% block beforeContent %}
77
{% if not hideBackLink %}

app/views/reading/annotation.html

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -53,29 +53,20 @@ <h2 class="nhsuk-label nhsuk-label--m" id="mammogram-section">Mark the location<
5353

5454
<div class="app-image-two-up nhsuk-u-margin-bottom-6">
5555
{% for view in views %}
56-
<div class="app-mammogram-container">
57-
<img draggable="false" class="nhsuk-image__img app-mammogram-image" src="/images/mammogram-diagrams/{{ view | lower }}.png" alt="">
58-
</div>
59-
56+
<div class="app-mammogram-container">
57+
<img draggable="false" class="nhsuk-image__img app-mammogram-image" src="/images/mammogram-diagrams/{{ view | lower }}.png" alt="">
58+
</div>
6059
{% endfor %}
6160
</div>
6261

63-
6462
</div>
6563

66-
67-
68-
69-
70-
71-
72-
7364
</div>
7465
</div>
7566

7667
<div class="nhsuk-grid-row">
7768
<div class="nhsuk-grid-column-two-thirds">
78-
{{ input({
69+
{# {{ input({
7970
id: "location",
8071
name: "imageReadingTemp[annotationTemp][location]",
8172
value: data.imageReadingTemp.annotationTemp.location,
@@ -87,11 +78,11 @@ <h2 class="nhsuk-label nhsuk-label--m" id="mammogram-section">Mark the location<
8778
text: "For example, upper right quadrant"
8879
},
8980
classes: "nhsuk-u-width-two-thirds"
90-
} | populateErrors) }}
81+
} | populateErrors) }} #}
9182

9283
{% set checkboxItems = [] %}
9384

94-
{% macro makeCheckboxConditionalItem(params) %}
85+
{# {% macro makeCheckboxConditionalItem(params) %}
9586
{{ input({
9687
name: "imageReadingTemp[annotationTemp][" + params.value + "Details]",
9788
value: data.imageReadingTemp.annotationTemp[params.value + "Details"],
@@ -101,7 +92,7 @@ <h2 class="nhsuk-label nhsuk-label--m" id="mammogram-section">Mark the location<
10192
},
10293
classes: "nhsuk-u-width-two-thirds"
10394
} | populateErrors) }}
104-
{% endmacro %}
95+
{% endmacro %} #}
10596

10697
{% set abnormalityList = [
10798
"Mass well-defined",
@@ -116,13 +107,14 @@ <h2 class="nhsuk-label nhsuk-label--m" id="mammogram-section">Mark the location<
116107
{% for abnormality in abnormalityList %}
117108
{% set checkboxItems = checkboxItems | push({
118109
value: abnormality,
119-
text: abnormality,
120-
conditional: {
121-
html: makeCheckboxConditionalItem({value: abnormality | camelCase})
122-
}
110+
text: abnormality
123111
}) %}
124112
{% endfor %}
125113

114+
{# conditional: {
115+
html: makeCheckboxConditionalItem({value: abnormality | camelCase})
116+
} #}
117+
126118
{% set otherTextInputHtml %}
127119
{{ input({
128120
name: "imageReadingTemp[annotationTemp][otherDetails]",
@@ -174,28 +166,39 @@ <h2 class="nhsuk-label nhsuk-label--m" id="mammogram-section">Mark the location<
174166
selected: true if not data.imageReadingTemp.annotationTemp.levelOfConcern
175167
},
176168
{
177-
value: "1",
169+
value: "Normal",
178170
text: "1 - Normal"
179171
},
180172
{
181-
value: "2",
173+
value: "Benign",
182174
text: "2 - Benign"
183175
},
184176
{
185-
value: "3",
186-
text: "3 - Probably benign"
177+
value: "Indeterminatef",
178+
text: "3 - Indeterminate"
187179
},
188180
{
189-
value: "4",
190-
text: "4 - Probably cancerous"
181+
value: "Suspicious",
182+
text: "4 - Suspicious"
191183
},
192184
{
193-
value: "5",
194-
text: "5 - Likely cancerous"
185+
value: "Highly suspicious",
186+
text: "5 - Highly suspicious"
195187
}
196188
]
197189
} | populateErrors) }}
198190

191+
{{ input({
192+
id: "comment",
193+
name: "imageReadingTemp[annotationTemp][comment]",
194+
value: data.imageReadingTemp.annotationTemp.comment,
195+
label: {
196+
text: "Comment about this abnormality (optional)",
197+
classes: "nhsuk-label--s"
198+
},
199+
classes: "nhsuk-u-width-two-thirds"
200+
} | populateErrors) }}
201+
199202
<div class="nhsuk-button-group nhsuk-u-margin-top-7">
200203
{{ button({
201204
text: "Save and close",

0 commit comments

Comments
 (0)