From bdb7b653b63c26452d0cb9dfd0480d95c8192605 Mon Sep 17 00:00:00 2001 From: Ross Date: Sun, 8 Feb 2026 22:42:14 +0000 Subject: [PATCH] Add modal for viewing display set details and update URLs and views --- atlas/templates/atlas/case_display_block.html | 41 +++++++++++ .../atlas/case_displayset_modal.html | 71 +++++++++++++++++++ atlas/urls.py | 1 + atlas/views.py | 7 ++ 4 files changed, 120 insertions(+) create mode 100644 atlas/templates/atlas/case_displayset_modal.html diff --git a/atlas/templates/atlas/case_display_block.html b/atlas/templates/atlas/case_display_block.html index 2f24ec38..1facf43a 100755 --- a/atlas/templates/atlas/case_display_block.html +++ b/atlas/templates/atlas/case_display_block.html @@ -373,6 +373,7 @@ {% endif %} View Display Set +
Findings: @@ -493,6 +494,22 @@ {% include 'question_notes.html' %}
+

Checked by: {% for verified in case.verified.all %} {{verified}}, {% endfor %}

@@ -773,6 +790,30 @@ }); }); + // Display Set modal handler + const dsModal = new bootstrap.Modal(document.getElementById("displaysetModal")); + const dsModalBody = document.getElementById("displaysetModalBody"); + + document.querySelectorAll(".view-displayset-modal").forEach(button => { + button.addEventListener("click", function () { + const url = this.getAttribute("data-url"); + dsModalBody.innerHTML = "

Loading...

"; + fetch(url) + .then(response => response.text()) + .then(html => { + dsModalBody.innerHTML = html; + setTimeout(function () { + try { window.mountDicomViewers(); } catch (e) { console.warn('mountDicomViewers not available', e); } + }, 200); + }) + .catch(error => { + console.error("Error loading display set details:", error); + dsModalBody.innerHTML = "

Failed to load display set.

"; + }); + dsModal.show(); + }); + }); + }); diff --git a/atlas/templates/atlas/case_displayset_modal.html b/atlas/templates/atlas/case_displayset_modal.html new file mode 100644 index 00000000..664ac9eb --- /dev/null +++ b/atlas/templates/atlas/case_displayset_modal.html @@ -0,0 +1,71 @@ +
+
+
{{ ds.name }}
+ {% if ds.description %} +
{{ ds.description }}
+ {% endif %} +
+ + {% if ds.viewerstate and ds.annotations %} +
+ +
+ {% endif %} + +
+ Findings: + {% if ds.findings.all %} +
    + {% for finding in ds.findings.all %} +
  • {{ finding }}
  • + {% endfor %} +
+ {% else %} + None + {% endif %} +
+ +
+ Structures: + {% if ds.structures.all %} +
    + {% for structure in ds.structures.all %} +
  • {{ structure }}
  • + {% endfor %} +
+ {% else %} + None + {% endif %} +
+ +
+ Conditions: + {% if ds.conditions.all %} +
    + {% for condition in ds.conditions.all %} +
  • {{ condition }}
  • + {% endfor %} +
+ {% else %} + None + {% endif %} +
+ +
+
+ Show advanced (viewer state & annotations) +
+ Viewer State: +
{{ ds.viewerstate|default:"{}" }}
+
+
+ Annotations: +
{{ ds.annotations|default:"{}" }}
+
+
+
+
diff --git a/atlas/urls.py b/atlas/urls.py index dcc25810..a40a538a 100755 --- a/atlas/urls.py +++ b/atlas/urls.py @@ -380,6 +380,7 @@ urlpatterns = [ path("case//display_sets/add", views.case_displaysets_add, name="case_displaysets_add"), path("/display_sets/edit", views.case_displaysets_edit, name="case_displaysets_edit"), path("/display_sets/detail", views.case_displaysets_detail, name="case_displaysets_detail"), + path("/display_sets/modal", views.case_displaysets_modal, name="case_displaysets_modal"), path("/display_sets/delete", views.case_displaysets_delete, name="case_displaysets_delete"), path( "case//dicom_json", diff --git a/atlas/views.py b/atlas/views.py index 02129413..a2c67b2c 100755 --- a/atlas/views.py +++ b/atlas/views.py @@ -540,6 +540,13 @@ def case_displaysets_detail(request, pk): # Redirect to the case_displaysets page with ?displayset= return redirect(f"{reverse('atlas:case_displaysets', args=[case.pk])}?displayset={pk}") + +@login_required +def case_displaysets_modal(request, pk): + """Return HTML fragment for a CaseDisplaySet to be shown inside a modal.""" + displayset = get_object_or_404(CaseDisplaySet, pk=pk) + return render(request, 'atlas/case_displayset_modal.html', {'ds': displayset}) + def case_displaysets_delete(request, pk): try: displayset = CaseDisplaySet.objects.get(pk=pk)