From 15915ef5c0218be56912878b80c9ed3e878b5cdb Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 13 Nov 2023 13:23:33 +0000 Subject: [PATCH] Add htmx autocomplete and allow merging of conditions --- atlas/forms.py | 20 ++++++- atlas/templates/atlas/condition_detail.html | 24 ++++++++- atlas/templates/atlas/condition_options.html | 6 +++ atlas/urls.py | 5 ++ atlas/views.py | 55 ++++++++++++++++++++ rad/settings.py | 1 + rad/urls.py | 8 +++ requirements.txt | 3 +- 8 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 atlas/templates/atlas/condition_options.html diff --git a/atlas/forms.py b/atlas/forms.py index 3c24d386..e9c3405a 100755 --- a/atlas/forms.py +++ b/atlas/forms.py @@ -47,6 +47,8 @@ from tinymce.widgets import TinyMCE from dal import autocomplete +from autocomplete import widgets as htmx_widgets + import logging class ConditionForm(ModelForm): @@ -603,4 +605,20 @@ class UncategorisedDicomForm(ModelForm): fields = ["image"]#, "user"] -#UncategorisedDicomFormset = formset_factory(UncategorisedDicomForm) \ No newline at end of file +#UncategorisedDicomFormset = formset_factory(UncategorisedDicomForm) + +#class ConditionAutocompleteFormModel(forms.ModelForm): +# class Meta: +# model = Condition +# fields = ["name"] +# widgets = { +# 'members': widgets.Autocomplete( +# name='members', +# options=dict(multiselect=True, model=Condition) +# ) +# } + +class ConditionAutocompleteForm(Form): + condition = ModelChoiceField(queryset=Condition.objects.all(), widget=htmx_widgets.Autocomplete( + name="conditions", options=dict(model=Condition) + )) diff --git a/atlas/templates/atlas/condition_detail.html b/atlas/templates/atlas/condition_detail.html index 8208b8dd..b9f4a2e9 100755 --- a/atlas/templates/atlas/condition_detail.html +++ b/atlas/templates/atlas/condition_detail.html @@ -56,12 +56,34 @@ {% endif %} + + {% if not condition.rcr_curriculum %} + + +
Merge +Merge this condition into another. This will transfer all associated cases (and differential) but will not transfer synonymns / parents or children. +
+ {% csrf_token %} + + {{ form.as_table }} +
+ +
+
+
+ {% endif %} + {% endblock %} {% block js %} diff --git a/atlas/templates/atlas/condition_options.html b/atlas/templates/atlas/condition_options.html new file mode 100644 index 00000000..20217876 --- /dev/null +++ b/atlas/templates/atlas/condition_options.html @@ -0,0 +1,6 @@ + +{% for condition in conditions %} + + + +{% endfor %} diff --git a/atlas/urls.py b/atlas/urls.py index 39133fe0..d7aba142 100755 --- a/atlas/urls.py +++ b/atlas/urls.py @@ -159,6 +159,11 @@ urlpatterns = [ views.ConditionUpdate.as_view(), name="condition_update", ), + path( + "condition//merge/", + views.condition_merge, + name="condition_merge", + ), path("subspecialty/", views.SubspecialtyView.as_view(), name="subspecialty_view"), path( "subspecialty/", views.subspecialty_detail, name="subspecialty_detail" diff --git a/atlas/views.py b/atlas/views.py index 68536a17..ef8e57f4 100755 --- a/atlas/views.py +++ b/atlas/views.py @@ -36,6 +36,7 @@ from .forms import ( CaseForm, CidReportAnswerForm, CidReportAnswerMarkForm, + ConditionAutocompleteForm, ConditionForm, FindingForm, SelfReviewForm, @@ -53,6 +54,7 @@ from .models import ( CaseDetail, CidReportAnswer, Condition, + Differential, PathologicalProcess, Presentation, SelfReview, @@ -92,6 +94,9 @@ from .filters import ( from django_tables2 import SingleTableView, SingleTableMixin from django_filters.views import FilterView +from autocomplete import HTMXAutoComplete + + from .decorators import ( user_is_author_or_atlas_editor, user_is_author_or_atlas_editor_or_atlas_marker, @@ -186,15 +191,65 @@ def series_detail(request, pk, finding_pk=None): def condition_detail(request, pk): condition = get_object_or_404(Condition, pk=pk) + form = ConditionAutocompleteForm() + # logging.debug(atlas.subspecialty.first().name.all()) return render( request, "atlas/condition_detail.html", { "condition": condition, + "form": form }, ) +#class GetConditionAutocomplete(HTMXAutoComplete): +# name = "conditions" +# multiselect = False +# +# class Meta: +# model = Condition + +@login_required +@user_is_atlas_editor +def condition_merge(request, pk_to_merge): + if not request.htmx: + raise Http404 + + condition_to_merge = get_object_or_404(Condition, pk=pk_to_merge) + #condition_to_merge_into = get_object_or_404(Condition, pk=pk_to_merge_into) + + print(condition_to_merge.case_set) + if condition_to_merge.rcr_curriculum: + return HttpResponse("You cannot merge rcr curriculum items") + + condition_to_merge_into = request.POST.get("conditions") + + if not condition_to_merge_into: + return HttpResponse("You need to select a condition to merge into.") + + condition_to_merge_into = get_object_or_404(Condition, pk=condition_to_merge_into) + + if condition_to_merge == condition_to_merge_into: + return HttpResponse("You cannot merge into the same condition.") + + + # move all relevant relationships + cases = condition_to_merge.case_set.all().values_list("id", flat=True) + condition_to_merge_into.case_set.add(cases) + #cases = Case.objects.filter(condition=condition_to_merge) + #cases.update(condition=condition_to_merge_into) + + differentials = Differential.objects.filter(condition=condition_to_merge) + differentials.update(condition=condition_to_merge_into) + + return HttpResponse("Merged") + + #conditions = Condition.objects.all() + + #return render(request, "atlas/condition_options.html", {"conditions": conditions}) + + @login_required @user_is_atlas_editor diff --git a/rad/settings.py b/rad/settings.py index 1511c90c..dfe6e2d7 100644 --- a/rad/settings.py +++ b/rad/settings.py @@ -75,6 +75,7 @@ INSTALLED_APPS = [ "django_htmx", "crispy_forms", "crispy_bootstrap4", + "autocomplete" ] MIDDLEWARE = [ diff --git a/rad/urls.py b/rad/urls.py index bce089b0..db75605e 100644 --- a/rad/urls.py +++ b/rad/urls.py @@ -34,6 +34,7 @@ from rest_framework import routers from django.conf.urls import handler400, handler403, handler404, handler500 from .api import api +from autocomplete import HTMXAutoComplete router_drf = routers.DefaultRouter() @@ -73,6 +74,12 @@ urlpatterns = [ path( "accounts/create/", generic_views.create_user, name="create_user" ), + path( + "accounts/trainees/", generic_views.trainees, name="trainees" + ), + path( + "accounts/trainees//", generic_views.trainees, name="trainees_grade" + ), path( "accounts/update//", views.UpdateUserView.as_view(), @@ -152,6 +159,7 @@ urlpatterns = [ #path("cookies/", include("cookie_consent.urls")), path("privacy/", views.privacy_view, name="privacy"), # path('select2/', include('select2.urls')), + *HTMXAutoComplete.url_dispatcher('ac'), ] # handler400 = 'my_app.views.bad_request' diff --git a/requirements.txt b/requirements.txt index 593eb29c..e547baf6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -37,4 +37,5 @@ django-crispy-forms django-ninja crispy-bootstrap4 django-rich -ipython \ No newline at end of file +ipython +django-htmx-autocomplete \ No newline at end of file