Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions manage_breast_screening/participants/models/appointment.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ def filter_counts_for_clinic(cls, clinic):
counts[filter] = clinic.appointments.for_filter(filter).count()
return counts

@classmethod
def with_study(cls):
return cls.objects.filter(study__isnull=False)

@property
def provider(self):
return self.clinic_slot.provider
Expand Down
1 change: 1 addition & 0 deletions manage_breast_screening/reading/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@


class ReadingConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "manage_breast_screening.reading"
76 changes: 36 additions & 40 deletions manage_breast_screening/reading/jinja2/read_image.jinja
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{% extends "layout-app.jinja" %}
{% from "django_form_helpers.jinja" import form_error_summary %}
{% from "nhsuk/components/button/macro.jinja" import button %}
{% from "nhsuk/components/inset-text/macro.jinja" import insetText %}
{% from "nhsuk/components/summary-list/macro.jinja" import summaryList %}
Expand All @@ -26,8 +25,6 @@
{% block page_content %}
<div class="nhsuk-grid-row">
<div class="nhsuk-grid-column-full">
{{ form_error_summary(form) }}

<div class="nhsuk-grid-row app-header">
<div class="nhsuk-grid-column-two-thirds app-header">
<h1 class="nhsuk-heading-l">
Expand Down Expand Up @@ -59,51 +56,50 @@
</div>
</div>

<form method="post" novalidate>
{{ csrf_input }}

<div class="nhsuk-grid-row">
<div class="nhsuk-grid-column-one-third nhsuk-u-margin-bottom-4">
<h2 class="nhsuk-heading-s">Image thumbnails ({{ images | length }})</h2>
<div class="app-mammogram-thumbnails">
{% for image in images %}
<div class="app-mammogram-thumbnail {{ image.class }}">
<div class="app-mammogram-thumbnail__image-wrapper">
<span class="app-mammogram-thumbnail__label">{{ image.name }}</span>
<img class="app-mammogram-thumbnail__image app-mammogram-thumbnail__image--diagram"
src="{{ image.url }}" alt="{{ image.name }} view">
</div>
<div class="nhsuk-grid-row">
<div class="nhsuk-grid-column-one-third nhsuk-u-margin-bottom-4">
<h2 class="nhsuk-heading-s">Image thumbnails ({{ images | length }})</h2>
<div class="app-mammogram-thumbnails">
{% for image in images %}
<div class="app-mammogram-thumbnail {{ image.class }}">
<div class="app-mammogram-thumbnail__image-wrapper">
<span class="app-mammogram-thumbnail__label">{{ image.name }}</span>
<img class="app-mammogram-thumbnail__image app-mammogram-thumbnail__image--diagram"
src="{{ image.url }}" alt="{{ image.name }} view">
</div>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
</div>

<div class="nhsuk-grid-column-two-thirds">
<h2 class="nhsuk-heading-m">What is your opinion of these images?</h2>
<div class="nhsuk-grid-column-two-thirds">
<h2 class="nhsuk-heading-m">What is your opinion of these images?</h2>

<div class="nhsuk-u-margin-bottom-4">
<button class="nhsuk-button nhsuk-u-width-full nhsuk-u-margin-bottom-3">
Normal <span class="app-shortcut-hint">(N)</span>
</button>
<p class="nhsuk-u-margin-bottom-4">
<a class="nhsuk-link nhsuk-link--no-visited-state" href="#">Normal, but add details</a>
</p>
</div>
<div class="nhsuk-u-margin-bottom-4">
<button class="nhsuk-button nhsuk-u-width-full nhsuk-u-margin-bottom-3">
Normal <span class="app-shortcut-hint">(N)</span>
</button>
<p class="nhsuk-u-margin-bottom-4">
<a class="nhsuk-link nhsuk-link--no-visited-state" href="#">Normal, but add details</a>
</p>
</div>

<div class="nhsuk-u-margin-bottom-4">
<button class="nhsuk-button nhsuk-button--secondary nhsuk-u-width-full nhsuk-u-margin-bottom-3">
Technical recall <span class="app-shortcut-hint">(T)</span>
</button>
</div>
<div class="nhsuk-u-margin-bottom-4">
<a href="{{ url('reading:add_technical_recall', kwargs={'session_pk': view.kwargs.session_pk, 'read_pk': view.kwargs.pk}) }}"
role="button"
draggable="false"
class="nhsuk-button nhsuk-button--secondary nhsuk-u-width-full nhsuk-u-margin-bottom-3">
Technical recall <span class="app-shortcut-hint">(T)</span>
</a>
</div>

<div class="nhsuk-u-margin-bottom-4">
<button class="nhsuk-button nhsuk-button--warning nhsuk-u-width-full">
Recall for assessment <span class="app-shortcut-hint">(R)</span>
</button>
</div>
<div class="nhsuk-u-margin-bottom-4">
<button class="nhsuk-button nhsuk-button--warning nhsuk-u-width-full">
Recall for assessment <span class="app-shortcut-hint">(R)</span>
</button>
</div>
</div>
</form>
</div>

{% if notes_for_reader %}
{% set inset_html %}
Expand Down
101 changes: 101 additions & 0 deletions manage_breast_screening/reading/jinja2/reading/technical_recall.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
{% extends "layout-app.jinja" %}
{% from "nhsuk/components/button/macro.jinja" import button %}
{% from "nhsuk/components/checkboxes/macro.jinja" import checkboxes %}

{% macro recall_fields(prefix) %}
<div class="nhsuk-form-group">
<label class="nhsuk-label" for="{{ prefix }}_reason">Reason for recall</label>
<select class="nhsuk-select" id="{{ prefix }}_reason" name="{{ prefix }}_reason">
<option value="" selected disabled>Select a reason</option>
<option value="breast_positioning">Breast positioning</option>
<option value="incorrect_exposure">Incorrect exposure</option>
<option value="image_obscured">Image obscured</option>
<option value="image_blurred">Image blurred</option>
<option value="image_missing">Image missing</option>
<option value="other_reason">Other reason</option>
</select>
</div>
<div class="nhsuk-form-group">
<label class="nhsuk-label nhsuk-label--s" for="{{ prefix }}_details">Additional details (optional)</label>
<input class="nhsuk-input" id="{{ prefix }}_details" name="{{ prefix }}_details" type="text">
</div>
{% endmacro %}

{% block page_content %}
<div class="nhsuk-grid-row">
<div class="nhsuk-grid-column-full">
<span class="nhsuk-caption-l">Erin Sauer</span>
<h1 class="nhsuk-heading-l">Technical recall</h1>

<form action="{{ request.path }}" method="post" novalidate>
{{ csrf_input }}

<h2 class="nhsuk-heading-m">Which views need to be retaken?</h2>

<div class="nhsuk-grid-row">
<div class="nhsuk-grid-column-one-half">
<h3 class="nhsuk-heading-s">Right breast</h3>

{% set rcc_conditional = recall_fields("rcc") %}
{{ checkboxes({
"idPrefix": "rcc",
"name": "rcc",
"items": [
{
"value": "rcc",
"text": "RCC",
"conditional": {"html": rcc_conditional}
}
]
}) }}

{% set rmlo_conditional = recall_fields("rmlo") %}
{{ checkboxes({
"idPrefix": "rmlo",
"name": "rmlo",
"items": [
{
"value": "rmlo",
"text": "RMLO",
"conditional": {"html": rmlo_conditional}
}
]
}) }}
</div>

<div class="nhsuk-grid-column-one-half">
<h3 class="nhsuk-heading-s">Left breast</h3>

{% set lcc_conditional = recall_fields("lcc") %}
{{ checkboxes({
"idPrefix": "lcc",
"name": "lcc",
"items": [
{
"value": "lcc",
"text": "LCC",
"conditional": {"html": lcc_conditional}
}
]
}) }}

{% set lmlo_conditional = recall_fields("lmlo") %}
{{ checkboxes({
"idPrefix": "lmlo",
"name": "lmlo",
"items": [
{
"value": "lmlo",
"text": "LMLO",
"conditional": {"html": lmlo_conditional}
}
]
}) }}
</div>
</div>

{{ button({"text": "Continue"}) }}
</form>
</div>
</div>
{% endblock %}
7 changes: 6 additions & 1 deletion manage_breast_screening/reading/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
path("", views.show_reading_dashboard_view, name="show_reading_dashboard"),
path(
"sessions/<uuid:session_pk>/reads/<uuid:pk>/",
views.ReadImageView.as_view(),
views.ShowImageReadView.as_view(),
name="image_read",
),
path(
"sessions/<uuid:session_pk>/reads/<uuid:read_pk>/technical-recall/",
views.AddTechnicalRecallView.as_view(),
name="add_technical_recall",
),
]
36 changes: 28 additions & 8 deletions manage_breast_screening/reading/views.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
from logging import getLogger

from django.contrib.auth.decorators import permission_required
from django.forms import Form
from django.shortcuts import render
from django.views.decorators.http import require_http_methods
from django.views.generic import FormView
from django.views.generic import TemplateView
from rules.contrib.views import PermissionRequiredMixin

from manage_breast_screening.auth.models import Permission
from manage_breast_screening.mammograms.presenters.medical_history.check_medical_information_presenter import (
CheckMedicalInformationPresenter,
)
from manage_breast_screening.mammograms.views.mixins import AppointmentMixin
from manage_breast_screening.participants.models import Appointment

logger = getLogger(__name__)


@require_http_methods(["GET"])
Expand All @@ -18,25 +21,28 @@
return render(request, "show_readings.jinja")


class ReadImageView(PermissionRequiredMixin, AppointmentMixin, FormView):
form_class = Form
class ShowImageReadView(PermissionRequiredMixin, TemplateView):
template_name = "read_image.jinja"
permission_required = Permission.READ_IMAGES

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)

# TODO: dummy data — replace once retrieval of the appropriate Reading object is implemented.

Check warning on line 31 in manage_breast_screening/reading/views.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this "TODO" comment.

See more on https://sonarcloud.io/project/issues?id=NHSDigital_dtos-manage-breast-screening&issues=AZ3UFuIEXVW2Rep05dBO&open=AZ3UFuIEXVW2Rep05dBO&pullRequest=1382
appointment = Appointment.with_study().first()
participant = appointment.participant

images = []

context.update(
{
"heading": self.participant.full_name,
"heading": participant.full_name,
"caption": "Review images",
"images": images,
"presented_medical_information": CheckMedicalInformationPresenter(
self.appointment
appointment
),
"notes_for_reader": self.appointment.study.additional_details,
"notes_for_reader": appointment.study.additional_details,
"is_urgent": True,
"is_second_read": True,
"is_previously_skipped": True,
Expand All @@ -61,3 +67,17 @@
)

return images


class AddTechnicalRecallView(TemplateView):
template_name = "reading/technical_recall.jinja"

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update(
{
"page_title": "Technical recall",
"back_link_params": {"href": "#"},
}
)
return context
Loading