Too many changes :(

This commit is contained in:
Ross
2025-07-29 09:20:58 +01:00
parent ad4be1e9a6
commit 4460545442
20 changed files with 361 additions and 81 deletions
+20
View File
@@ -183,6 +183,8 @@ class CaseTable(tables.Table):
)
sequence = ("view", )
order_by = "-created_date"
attrs = {"class": "table row-selector"}
class PopupLinkColumn(tables.Column):
@@ -231,6 +233,8 @@ class SeriesTable(tables.Table):
)
sequence = ("view", "popup", "images", "case")
order_by = "-created_date"
attrs = {"class": "table row-selector"}
def __init__(self, data=None, *args, **kwargs):
super().__init__(
@@ -271,6 +275,8 @@ class ConditionTable(tables.Table):
template_name = "django_tables2/bootstrap4.html"
fields = ("primary", "subspecialty", "rcr_curriculum_map", "rcr_curriculum")
sequence = ("name",)
attrs = {"class": "table row-selector"}
def __init__(self, data=None, *args, **kwargs):
super().__init__(
@@ -307,6 +313,8 @@ class FindingTable(tables.Table):
template_name = "django_tables2/bootstrap4.html"
fields = ("name", "primary")
sequence = ("name",)
attrs = {"class": "table row-selector"}
def render_synonym(self, value, record):
return format_html(record.get_synonym_link())
@@ -334,6 +342,8 @@ class StructureTable(tables.Table):
template_name = "django_tables2/bootstrap4.html"
fields = ("name", "primary")
sequence = ("name",)
attrs = {"class": "table row-selector"}
def render_synonym(self, value, record):
return format_html(record.get_synonym_link())
@@ -360,6 +370,8 @@ class PresentationTable(tables.Table):
template_name = "django_tables2/bootstrap4.html"
fields = ("name",)
sequence = ("name",)
attrs = {"class": "table row-selector"}
class PathologicalProcessTable(tables.Table):
@@ -381,6 +393,8 @@ class PathologicalProcessTable(tables.Table):
template_name = "django_tables2/bootstrap4.html"
fields = ("name",)
sequence = ("name",)
attrs = {"class": "table row-selector"}
class SubspecialtyTable(tables.Table):
@@ -402,6 +416,8 @@ class SubspecialtyTable(tables.Table):
template_name = "django_tables2/bootstrap4.html"
fields = ()
sequence = ("name",)
attrs = {"class": "table row-selector"}
def render_synonym(self, value, record):
return format_html(record.get_synonym_link())
@@ -436,6 +452,8 @@ class CaseCollectionTable(tables.Table):
"author",
)
sequence = ("view", )#, "series")
attrs = {"class": "table row-selector"}
def __init__(self, data=None, *args, **kwargs):
super().__init__(
@@ -463,6 +481,8 @@ class QuestionSchemaTable(tables.Table):
model = QuestionSchema
template_name = "django_tables2/bootstrap4.html"
fields = ("name", "description", "schema")
attrs = {"class": "table row-selector"}
def render_schema(self, value, record):
return format_html("<details><summary>Schema</summary>{}</details>", value)
+38
View File
@@ -20,7 +20,45 @@
</div>
View my <a href='{% url "atlas:case_view" %}?author={{request.user.id}}'>cases</a>.
</details>
<form>
<details id="actions-detail" class="mt-3">
<summary>
<strong>Actions</strong>
</summary>
<div class="row mb-2">
<div class="col-auto">
<select id="collection-select" name="collection_id" class="form-select form-select-sm">
<!-- Dynamically load collection options via HTMX -->
<option value="">Loading collections...</option>
<option hx-trigger="every 1s[document.getElementById('actions-detail').open] once" hx-get="{% url 'atlas:collection_options' %}" hx-target="#collection-select" hx-swap="innerHTML"></option>
</select>
</div>
<div class="col-auto">
<button id="add-to-collection-btn"
class="btn btn-sm btn-outline-primary"
hx-post="{% url 'atlas:add_cases_to_collection' %}"
hx-include="[name='selection']:checked, #collection-select"
hx-target="#action-result"
hx-swap="innerHTML"
>
Add selected cases to collection
</button>
<button id="remove-from-collection-btn"
class="btn btn-sm btn-outline-danger ms-2"
hx-post="{% url 'atlas:remove_cases_from_collection' %}"
hx-include="[name='selection']:checked, #collection-select"
hx-target="#action-result"
hx-swap="innerHTML"
>
Remove selected cases from collection
</button>
<span id="action-result"></span>
</div>
</div>
</details>
{% render_table table %}
</form>
</div>
<div id="exam-options"></div>
@@ -0,0 +1,5 @@
{% for collection in collections %}
<option value="{{ collection.pk }}">{{ collection.name }}</option>
{% empty %}
<option value="">No collections available</option>
{% endfor %}
+1 -39
View File
@@ -21,7 +21,7 @@
<details class="mt-3">
<summary>
<strong>Extra options</strong>
<strong>Actions</strong>
</summary>
<form id="bulk-delete-form" method="post" action="{% url 'atlas:series_bulk_delete' %}">
{% csrf_token %}
@@ -62,34 +62,6 @@ document.getElementById('bulk-delete-form').addEventListener('submit', function(
{% block js %}
<script>
document.addEventListener('DOMContentLoaded', function() {
// Delegate click event to all table rows
document.querySelectorAll('.table tbody tr').forEach(function(row) {
row.addEventListener('click', function(e) {
// Ignore clicks on links or checkboxes
if (e.target.tagName === 'A' || e.target.tagName === 'INPUT') return;
// Find the checkbox in this row
const checkbox = row.querySelector('input[name="selection"]');
if (checkbox) {
checkbox.checked = !checkbox.checked;
row.classList.toggle('selected', checkbox.checked);
}
});
// Keep row visually in sync with checkbox state (e.g. after page reload)
const checkbox = row.querySelector('input[name="selection"]');
if (checkbox && checkbox.checked) {
row.classList.add('selected');
}
// Also toggle row selection when checkbox is clicked directly
if (checkbox) {
checkbox.addEventListener('click', function(e) {
row.classList.toggle('selected', checkbox.checked);
// Prevent row click event from firing
e.stopPropagation();
});
}
});
});
</script>
{% endblock %}
@@ -97,16 +69,6 @@ document.addEventListener('DOMContentLoaded', function() {
{% block css %}
<style>
/* Highlight row on hover */
.table tbody tr:hover {
background-color: darkblue;
cursor: pointer;
}
/* Highlight selected row */
.table tbody tr.selected {
background-color: #b3d7ff !important;
color: #333;
}
</style>
{% endblock css %}
+15
View File
@@ -101,6 +101,21 @@ urlpatterns = [
views.collection_history,
name="collection_history",
),
path(
"collection/add_cases",
views.add_cases_to_collection,
name="add_cases_to_collection",
),
path(
"collection/remove_cases",
views.remove_cases_from_collection,
name="remove_cases_from_collection",
),
path(
"collection/options",
views.collection_options,
name="collection_options",
),
path(
"collection/<int:exam_id>/history/<int:user_pk>/user",
views.collection_history_user,
+41 -1
View File
@@ -633,6 +633,46 @@ def user_collections(request):
return render(request, "atlas/user_collections.html", {"collections": collections})
@login_required
def collection_options(request):
if not request.htmx:
return Http404
collections = CaseCollection.objects.filter(author=request.user).order_by("name")
html = render_to_string("atlas/partials/collection_options.html", {"collections": collections}, request=request)
return HttpResponse(html)
@login_required
def remove_cases_from_collection(request):
if not request.htmx:
return Http404
case_ids = request.POST.getlist('selection')
collection_id = request.POST.get('collection_id')
if not case_ids or not collection_id:
return HttpResponse("No cases selected or collection ID provided.")
collection = get_object_or_404(CaseCollection, pk=collection_id)
if request.user not in collection.author.all():
return HttpResponse("You do not have permission to remove cases from this collection.")
cases = Case.objects.filter(pk__in=case_ids)
for case_ in cases:
collection.cases.remove(case_)
return HttpResponse(f"Removed {len(cases)} cases from collection {collection.name} (refresh to see)")
@login_required
def add_cases_to_collection(request):
if not request.htmx:
return Http404
case_ids = request.POST.getlist('selection')
collection_id = request.POST.get('collection_id')
if not case_ids or not collection_id:
return HttpResponse("No cases selected or collection ID provided.")
collection = get_object_or_404(CaseCollection, pk=collection_id)
if request.user not in collection.author.all():
return HttpResponse("You do not have permission to add cases to this collection.")
cases = Case.objects.filter(pk__in=case_ids)
for case_ in cases:
collection.cases.add(case_)
return HttpResponse(f"Added {len(cases)} cases to collection {collection.name} (refresh to see)")
def add_case_to_collection(request, collection_id):
if not request.htmx:
@@ -1905,7 +1945,7 @@ def collection_detail(request, pk):
return render(
request,
"atlas/collection_detail.html",
{"collection": collection, "casesdetails": casedetails, "can_edit": True},
{"collection": collection, "casesdetails": casedetails, "can_edit": True, "exam": collection},
)