Add modal for viewing display set details and update URLs and views
This commit is contained in:
@@ -373,6 +373,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<span>
|
<span>
|
||||||
<a href="{% url 'atlas:case_displaysets_detail' ds.pk %}">View Display Set</a>
|
<a href="{% url 'atlas:case_displaysets_detail' ds.pk %}">View Display Set</a>
|
||||||
|
<button type="button" class="btn btn-secondary btn-sm view-displayset-modal ms-2" data-ds-id="{{ ds.pk }}" data-url="{% url 'atlas:case_displaysets_modal' ds.pk %}">View in Modal</button>
|
||||||
</span>
|
</span>
|
||||||
<div>
|
<div>
|
||||||
<strong>Findings:</strong>
|
<strong>Findings:</strong>
|
||||||
@@ -493,6 +494,22 @@
|
|||||||
{% include 'question_notes.html' %}
|
{% include 'question_notes.html' %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="modal fade" id="displaysetModal" tabindex="-1" aria-labelledby="displaysetModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="displaysetModalLabel">Display Set Details</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body" id="displaysetModalBody">
|
||||||
|
<p>Loading...</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p><b>Checked by:</b> {% for verified in case.verified.all %} <a
|
<p><b>Checked by:</b> {% for verified in case.verified.all %} <a
|
||||||
href="{% url 'atlas:verified_detail' pk=verified.pk %}">{{verified}}</a>, {% endfor %}</p>
|
href="{% url 'atlas:verified_detail' pk=verified.pk %}">{{verified}}</a>, {% endfor %}</p>
|
||||||
@@ -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 = "<p>Loading...</p>";
|
||||||
|
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 = "<p>Failed to load display set.</p>";
|
||||||
|
});
|
||||||
|
dsModal.show();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
<div class="case-displayset-modal">
|
||||||
|
<div class="mb-3">
|
||||||
|
<h5>{{ ds.name }}</h5>
|
||||||
|
{% if ds.description %}
|
||||||
|
<div class="text-muted">{{ ds.description }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if ds.viewerstate and ds.annotations %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-primary"
|
||||||
|
onclick='importAnnotations_main_viewer({{ ds.annotations|safe }}); importViewerState_main_viewer({{ ds.viewerstate|safe }});'
|
||||||
|
>Load into viewer</button>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="mt-2">
|
||||||
|
<strong>Findings:</strong>
|
||||||
|
{% if ds.findings.all %}
|
||||||
|
<ul>
|
||||||
|
{% for finding in ds.findings.all %}
|
||||||
|
<li>{{ finding }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">None</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<strong>Structures:</strong>
|
||||||
|
{% if ds.structures.all %}
|
||||||
|
<ul>
|
||||||
|
{% for structure in ds.structures.all %}
|
||||||
|
<li>{{ structure }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">None</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<strong>Conditions:</strong>
|
||||||
|
{% if ds.conditions.all %}
|
||||||
|
<ul>
|
||||||
|
{% for condition in ds.conditions.all %}
|
||||||
|
<li>{{ condition }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">None</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-3">
|
||||||
|
<details>
|
||||||
|
<summary class="small text-muted" style="cursor:pointer;">Show advanced (viewer state & annotations)</summary>
|
||||||
|
<div>
|
||||||
|
<strong>Viewer State:</strong>
|
||||||
|
<pre class="small">{{ ds.viewerstate|default:"{}" }}</pre>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<strong>Annotations:</strong>
|
||||||
|
<pre class="small">{{ ds.annotations|default:"{}" }}</pre>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -380,6 +380,7 @@ urlpatterns = [
|
|||||||
path("case/<int:pk>/display_sets/add", views.case_displaysets_add, name="case_displaysets_add"),
|
path("case/<int:pk>/display_sets/add", views.case_displaysets_add, name="case_displaysets_add"),
|
||||||
path("<int:pk>/display_sets/edit", views.case_displaysets_edit, name="case_displaysets_edit"),
|
path("<int:pk>/display_sets/edit", views.case_displaysets_edit, name="case_displaysets_edit"),
|
||||||
path("<int:pk>/display_sets/detail", views.case_displaysets_detail, name="case_displaysets_detail"),
|
path("<int:pk>/display_sets/detail", views.case_displaysets_detail, name="case_displaysets_detail"),
|
||||||
|
path("<int:pk>/display_sets/modal", views.case_displaysets_modal, name="case_displaysets_modal"),
|
||||||
path("<int:pk>/display_sets/delete", views.case_displaysets_delete, name="case_displaysets_delete"),
|
path("<int:pk>/display_sets/delete", views.case_displaysets_delete, name="case_displaysets_delete"),
|
||||||
path(
|
path(
|
||||||
"case/<int:pk>/dicom_json",
|
"case/<int:pk>/dicom_json",
|
||||||
|
|||||||
@@ -540,6 +540,13 @@ def case_displaysets_detail(request, pk):
|
|||||||
# Redirect to the case_displaysets page with ?displayset=<pk>
|
# Redirect to the case_displaysets page with ?displayset=<pk>
|
||||||
return redirect(f"{reverse('atlas:case_displaysets', args=[case.pk])}?displayset={pk}")
|
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):
|
def case_displaysets_delete(request, pk):
|
||||||
try:
|
try:
|
||||||
displayset = CaseDisplaySet.objects.get(pk=pk)
|
displayset = CaseDisplaySet.objects.get(pk=pk)
|
||||||
|
|||||||
Reference in New Issue
Block a user