fix some templates
This commit is contained in:
@@ -17,6 +17,13 @@ Django-based radiology education platform. Multi-app, HTMX-driven, PostgreSQL +
|
||||
- Partials must be standalone fragments — no `{% extends %}`.
|
||||
- HTMX detection via `django_htmx` middleware (`request.htmx`).
|
||||
|
||||
#### HTMX input
|
||||
- When using htmx input for autoupdating search/other triggers triggers do not use changed in the hx-trigger. Using input is sufficient.
|
||||
e.g. instead of
|
||||
hx-trigger="input changed delay:300ms, focus"
|
||||
use
|
||||
hx-trigger="input delay:300ms, focus"
|
||||
|
||||
### API
|
||||
- Django Ninja (not DRF). Routers in `{app}/api.py`, registered in `rad/api.py` at `/api/v1/`.
|
||||
- Use `ModelSchema` with explicit `Meta.fields` lists (avoid `"__all__"` on public endpoints).
|
||||
|
||||
@@ -89,48 +89,51 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% if collection.show_results_sharing_information and sharing_summary %}
|
||||
<section class="take-start-card mt-3">
|
||||
<div class="fw-semibold mb-2 small text-body-secondary text-uppercase" style="letter-spacing:.05em;">Who can see your results</div>
|
||||
<ul class="list-unstyled mb-0 small">
|
||||
<li class="mb-1">
|
||||
<span class="badge bg-secondary me-1">You</span>
|
||||
Always visible to you.
|
||||
</li>
|
||||
{% for u in sharing_summary.always_visible_to %}
|
||||
{% partialdef sharing-info inline %}
|
||||
{% if collection.show_results_sharing_information and sharing_summary %}
|
||||
<section class="take-start-card mt-3">
|
||||
<div class="fw-semibold mb-2 small text-body-secondary text-uppercase" style="letter-spacing:.05em;">Who can see your results</div>
|
||||
<ul class="list-unstyled mb-0 small">
|
||||
<li class="mb-1">
|
||||
<span class="badge bg-secondary me-1">Author/Marker</span>
|
||||
{{ u.get_full_name|default:u.username }}
|
||||
{% if u.email %}<span class="text-muted"><{{ u.email }}></span>{% endif %}
|
||||
<span class="badge bg-secondary me-1">You</span>
|
||||
Always visible to you.
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% if sharing_summary.supervisor_always %}
|
||||
<li class="mb-1">
|
||||
<span class="badge bg-info text-dark me-1">Supervisor</span>
|
||||
{% if sharing_summary.supervisor %}
|
||||
{{ sharing_summary.supervisor.get_full_name|default:sharing_summary.supervisor.username }}
|
||||
(always shared - collection setting)
|
||||
{% else %}
|
||||
Your supervisor, if one is linked to your profile (collection setting always on).
|
||||
{% endif %}
|
||||
</li>
|
||||
{% elif sharing_summary.supervisor_opt_in %}
|
||||
<li class="mb-1">
|
||||
<span class="badge bg-outline-secondary me-1" style="border:1px solid var(--bs-secondary);color:var(--bs-secondary);">Supervisor</span>
|
||||
{% if sharing_summary.supervisor %}
|
||||
{{ sharing_summary.supervisor.get_full_name|default:sharing_summary.supervisor.username }}
|
||||
- you can choose to share with them after starting.
|
||||
{% else %}
|
||||
You have a supervisor linked but they do not have a login account yet.
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if not sharing_summary.always_visible_to and not sharing_summary.supervisor_always and not sharing_summary.supervisor_opt_in %}
|
||||
<li class="text-muted fst-italic">Only you can see your results for this collection.</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% for u in sharing_summary.always_visible_to %}
|
||||
<li class="mb-1">
|
||||
<span class="badge bg-secondary me-1">Author/Marker</span>
|
||||
{{ u.get_full_name|default:u.username }}
|
||||
{% if u.email %}<span class="text-muted"><{{ u.email }}></span>{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% if sharing_summary.supervisor_always %}
|
||||
<li class="mb-1">
|
||||
<span class="badge bg-info text-dark me-1">Supervisor</span>
|
||||
{% if sharing_summary.supervisor %}
|
||||
{{ sharing_summary.supervisor.get_full_name|default:sharing_summary.supervisor.username }}
|
||||
(always shared – collection setting)
|
||||
{% else %}
|
||||
Your supervisor, if one is linked to your profile (collection setting always on).
|
||||
{% endif %}
|
||||
</li>
|
||||
{% elif sharing_summary.supervisor_opt_in %}
|
||||
<li class="mb-1">
|
||||
<span class="badge bg-outline-secondary me-1" style="border:1px solid var(--bs-secondary);color:var(--bs-secondary);">Supervisor</span>
|
||||
{% if sharing_summary.supervisor %}
|
||||
{{ sharing_summary.supervisor.get_full_name|default:sharing_summary.supervisor.username }}
|
||||
— you can choose to share with them after starting.
|
||||
{% else %}
|
||||
You have a supervisor linked but they don't have a login account yet.
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if not sharing_summary.always_visible_to and not sharing_summary.supervisor_always and not sharing_summary.supervisor_opt_in %}
|
||||
<li class="text-muted fst-italic">Only you can see your results for this collection.</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
{% endpartialdef %}
|
||||
{% else %}
|
||||
<section class="take-start-card">
|
||||
<p class="mb-0">
|
||||
|
||||
@@ -91,49 +91,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# ---- Who can see your results ---- #}
|
||||
{% if collection.show_results_sharing_information and sharing_summary %}
|
||||
<section class="take-start-card mt-3">
|
||||
<div class="fw-semibold mb-2 small text-body-secondary text-uppercase" style="letter-spacing:.05em;">Who can see your results</div>
|
||||
<ul class="list-unstyled mb-0 small">
|
||||
<li class="mb-1">
|
||||
<span class="badge bg-secondary me-1">You</span>
|
||||
Always visible to you.
|
||||
</li>
|
||||
{% for u in sharing_summary.always_visible_to %}
|
||||
<li class="mb-1">
|
||||
<span class="badge bg-secondary me-1">Author/Marker</span>
|
||||
{{ u.get_full_name|default:u.username }}
|
||||
{% if u.email %}<span class="text-muted"><{{ u.email }}></span>{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% if sharing_summary.supervisor_always %}
|
||||
<li class="mb-1">
|
||||
<span class="badge bg-info text-dark me-1">Supervisor</span>
|
||||
{% if sharing_summary.supervisor %}
|
||||
{{ sharing_summary.supervisor.get_full_name|default:sharing_summary.supervisor.username }}
|
||||
(always shared – collection setting)
|
||||
{% else %}
|
||||
Your supervisor, if one is linked to your profile (collection setting always on).
|
||||
{% endif %}
|
||||
</li>
|
||||
{% elif sharing_summary.supervisor_opt_in %}
|
||||
<li class="mb-1">
|
||||
<span class="badge bg-outline-secondary me-1" style="border:1px solid var(--bs-secondary);color:var(--bs-secondary);">Supervisor</span>
|
||||
{% if sharing_summary.supervisor %}
|
||||
{{ sharing_summary.supervisor.get_full_name|default:sharing_summary.supervisor.username }}
|
||||
— you can choose to share with them after starting.
|
||||
{% else %}
|
||||
You have a supervisor linked but they don't have a login account yet.
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if not sharing_summary.always_visible_to and not sharing_summary.supervisor_always and not sharing_summary.supervisor_opt_in %}
|
||||
<li class="text-muted fst-italic">Only you can see your results for this collection.</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% include "atlas/collection_review_start.html#sharing-info" %}
|
||||
{% else %}
|
||||
<section class="take-start-card">
|
||||
<p class="mb-3">
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{% load django_htmx %}
|
||||
{# Sharing panel for a CidUserExam attempt.
|
||||
{% comment %} Sharing panel for a CidUserExam attempt.
|
||||
Context:
|
||||
cid_user_exam – CidUserExam instance
|
||||
sharing_info – dict from cid_user_exam.get_sharing_info()
|
||||
is_owner – bool: current user is the attempt owner
|
||||
#}
|
||||
{% endcomment %}
|
||||
<div id="sharing-panel-{{ cid_user_exam.pk }}" class="card border-secondary mt-3">
|
||||
<div class="card-header py-2 px-3 d-flex justify-content-between align-items-center">
|
||||
<span class="fw-semibold small">Result Sharing</span>
|
||||
@@ -107,7 +107,7 @@
|
||||
name="q"
|
||||
autocomplete="off"
|
||||
hx-get="{% url 'atlas:collection_exam_user_search' cid_user_exam.pk %}"
|
||||
hx-trigger="input changed delay:300ms, focus"
|
||||
hx-trigger="input delay:300ms, focus"
|
||||
hx-target="#sharing-search-results-{{ cid_user_exam.pk }}"
|
||||
hx-swap="innerHTML">
|
||||
<div id="sharing-search-results-{{ cid_user_exam.pk }}" class="mt-1"></div>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
{% if collection.show_results_sharing_information and sharing_summary %}
|
||||
<section class="take-start-card mt-3">
|
||||
<div class="fw-semibold mb-2 small text-body-secondary text-uppercase" style="letter-spacing:.05em;">Who can see your results</div>
|
||||
<ul class="list-unstyled mb-0 small">
|
||||
<li class="mb-1">
|
||||
<span class="badge bg-secondary me-1">You</span>
|
||||
Always visible to you.
|
||||
</li>
|
||||
{% for u in sharing_summary.always_visible_to %}
|
||||
<li class="mb-1">
|
||||
<span class="badge bg-secondary me-1">Author/Marker</span>
|
||||
{{ u.get_full_name|default:u.username }}
|
||||
{% if u.email %}<span class="text-muted"><{{ u.email }}></span>{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% if sharing_summary.supervisor_always %}
|
||||
<li class="mb-1">
|
||||
<span class="badge bg-info text-dark me-1">Supervisor</span>
|
||||
{% if sharing_summary.supervisor %}
|
||||
{{ sharing_summary.supervisor.get_full_name|default:sharing_summary.supervisor.username }}
|
||||
(always shared - collection setting)
|
||||
{% else %}
|
||||
Your supervisor, if one is linked to your profile (collection setting always on).
|
||||
{% endif %}
|
||||
</li>
|
||||
{% elif sharing_summary.supervisor_opt_in %}
|
||||
<li class="mb-1">
|
||||
<span class="badge bg-outline-secondary me-1" style="border:1px solid var(--bs-secondary);color:var(--bs-secondary);">Supervisor</span>
|
||||
{% if sharing_summary.supervisor %}
|
||||
{{ sharing_summary.supervisor.get_full_name|default:sharing_summary.supervisor.username }}
|
||||
- you can choose to share with them after starting.
|
||||
{% else %}
|
||||
You have a supervisor linked but they do not have a login account yet.
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if not sharing_summary.always_visible_to and not sharing_summary.supervisor_always and not sharing_summary.supervisor_opt_in %}
|
||||
<li class="text-muted fst-italic">Only you can see your results for this collection.</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</section>
|
||||
{% endif %}
|
||||
@@ -12,7 +12,7 @@
|
||||
hx-get="{% url 'atlas:case_search' %}"
|
||||
hx-include="closest .case-search-widget"
|
||||
hx-target="#{{ target_id }}"
|
||||
hx-trigger="keyup changed delay:400ms"
|
||||
hx-trigger="input delay:400ms"
|
||||
autocomplete="off">
|
||||
|
||||
<div id="{{ target_id }}" class="mt-2">
|
||||
|
||||
@@ -1,80 +1,8 @@
|
||||
on the case details page when mananging series clicking on a select button launches the series popup when it shouldn't.
|
||||
1. the time / date filters on the logs viewing viewer should be labeled and better organised
|
||||
|
||||
when building the series / stack description for the dv3d viewer we should take into account the plane and contrast if they are defined on the series model.
|
||||
2. on the Unused Media Cleanup page we need to shown loading dialogs when the preview unused files and delete unused files buttons are pressed. please also check the recovered space size calculations as it does not match with what actually happens.
|
||||
|
||||
when importing cases we currently get the following error:
|
||||
web-1 | 2026-06-03 20:20:04.612 | ERROR | atlas.views:uploads_import_htmx:3578 - Error during uploads import
|
||||
web-1 | Traceback (most recent call last):
|
||||
web-1 | File "/usr/src/app/atlas/views.py", line 3576, in uploads_import_htmx
|
||||
web-1 | imported = import_dicoms_helper(request, case_id=case_id, dicoms=dicoms)
|
||||
web-1 | File "/usr/src/app/atlas/api.py", line 280, in import_dicoms_helper
|
||||
web-1 | series_image.save()
|
||||
web-1 | File "/usr/src/app/generic/models.py", line 390, in save
|
||||
web-1 | super().save(*args, **kwargs) # Call the "real" save() method.
|
||||
web-1 | File "/opt/venv/lib/python3.14/site-packages/django/db/models/base.py", line 874, in save
|
||||
web-1 | self.save_base(
|
||||
web-1 | File "/opt/venv/lib/python3.14/site-packages/django/db/models/base.py", line 981, in save_base
|
||||
web-1 | post_save.send(
|
||||
web-1 | File "/opt/venv/lib/python3.14/site-packages/django/dispatch/dispatcher.py", line 209, in send
|
||||
web-1 | response = receiver(signal=self, sender=sender, **named)
|
||||
web-1 | File "/usr/src/app/atlas/models.py", line 1382, in _populate_case_study_date_on_series_image_save
|
||||
web-1 | tags = instance.basic_dicom_tags or {}
|
||||
web-1 | AttributeError: 'SeriesImage' object has no attribute 'basic_dicom_tags'
|
||||
web-1 | Internal Server Error: /atlas/uploads/import/case/241
|
||||
|
||||
please add a unit test that demostrates the failure and then fix the bug and confirm that the unit test then passes.
|
||||
|
||||
please also check why when I add the
|
||||
logger.exception("Error during uploads import")
|
||||
error in production this does not seem to get shown anywhere. The only log just showed
|
||||
ERROR 03/Jun/2026 11:52:50 django.request:249
|
||||
Internal Server Error: /atlas/uploads/import
|
||||
the online local settings are
|
||||
DEBUG = False
|
||||
INTERNAL_IPS = ["82.69.88.125", "217.155.198.96"]
|
||||
#SECURE_SSL_REDIRECT = False
|
||||
#SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'http')
|
||||
#REMOTE_URL = "http://46.101.13.46:8123"
|
||||
#
|
||||
#MEDIA_ROOT = '/home/django/rad/media/'
|
||||
STATIC_ROOT = '/home/ross/web/static/'
|
||||
|
||||
#EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
||||
|
||||
if not DEBUG:
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'formatters': {
|
||||
'verbose': {
|
||||
'format' : "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
|
||||
'datefmt' : "%d/%b/%Y %H:%M:%S"
|
||||
},
|
||||
'simple': {
|
||||
'format': '%(levelname)s %(message)s'
|
||||
},
|
||||
},
|
||||
'handlers': {
|
||||
'file': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'logging.FileHandler',
|
||||
'filename': 'log.txt',
|
||||
'formatter': 'verbose'
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'django': {
|
||||
'handlers':['file'],
|
||||
'propagate': True,
|
||||
'level':'DEBUG',
|
||||
},
|
||||
'atlas': {
|
||||
'handlers': ['file'],
|
||||
'level': 'DEBUG',
|
||||
},
|
||||
#"django.core.mail": {"handlers": ["console"], "level": "DEBUG", "propagate": False},
|
||||
#"smtplib": {"handlers": ["console"], "level": "DEBUG", "propagate": False},
|
||||
}
|
||||
}
|
||||
3. on the series tools page we are able to generate reconstructions of selected series. currently the process works but the created dicoms do not align correctly with the original soruce (in terms of 3d volume space) indicating that there is a bug in the reconstruction code. in an ideal setting we would have an option to define /manually set the reconstruction alignment to generate the reconstructions from to account for scans where the patient is not corrcetly aligned with the x,y,z axis. this would be possible by making use of the crosshairs tools in the cornerstone3d library (https://www.cornerstonejs.org/live-examples/crosshairs) to extend the dv3d viewer in a way that allows setting the desired reconstruction planes, projection (min/max/average) mode and slab thickness. please look at fixing the 3d volume space of the current implemenatation and adding a new advanced page that implements the new dv3d implementation (leavving both in place).
|
||||
i have added a dicom series into the folder temp/recon that you can use to test if required.
|
||||
|
||||
4. search widgets such as case-search-widget should show a loading indicator whilst awaiting htmx responses.
|
||||
Reference in New Issue
Block a user