Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

742a htmx for name select choice field #1004

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ django-extensions = "~3"
django-filter = ">=23,<25"
django-gravatar2 = "~1"
django-guardian = "~2"
django-htmx = "~1"
fits2image = "~0.4"
markdown = "<4"
pillow = ">9.2,<11.0"
Expand Down
2 changes: 2 additions & 0 deletions tom_setup/templates/tom_setup/settings.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ INSTALLED_APPS = [
'rest_framework.authtoken',
'django_filters',
'django_gravatar',
'django_htmx',
'tom_targets',
'tom_alerts',
'tom_catalogs',
Expand All @@ -72,6 +73,7 @@ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django_htmx.middleware.HtmxMiddleware',
'tom_common.middleware.Raise403Middleware',
'tom_common.middleware.ExternalServiceMiddleware',
'tom_common.middleware.AuthStrategyMiddleware',
Expand Down
16 changes: 13 additions & 3 deletions tom_targets/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,20 @@ def __init__(self, *args, **kwargs):
self.fields['share_destination'].choices = get_sharing_destination_options()




class TargetMergeForm(forms.Form):
"""
Form for merging two duplicate targets with a primary target and secondary target
"""
name_select= forms.ChoiceField(required=True, choices=[], label="Select Primary Target")
name_select = forms.ChoiceField(
label="Select Primary Target",
required=True,
choices=[],
# Select is the default widget for a ChoiceField, but we need to set htmx attributes.
widget=forms.Select(
# set up attributes to trigger folder dropdown update when this field changes
attrs={
'hx-get': '', # send GET request to the source URL's get method
'hx-trigger': 'change', # when this happens
'hx-target': '#id_target_merge_fields', # replace name_select element
})
)
2 changes: 1 addition & 1 deletion tom_targets/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,4 +257,4 @@ def move_selected_to_grouping(targets_ids, grouping_object, request):
.format(len(warning_targets), grouping_object.name, ', '.join(warning_targets)))
for failure_target in failure_targets:
messages.error(request, "Failed to move target with id={} to group '{}'; {}"
.format(failure_target[0], grouping_object.name, failure_target[1]))
.format(failure_target[0], grouping_object.name, failure_target[1]))
3 changes: 2 additions & 1 deletion tom_targets/merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
def merge_error_message(request):
messages.warning(request, "Please select two targets to merge!")


def target_merge(primary_target, secondary_target):
"""
"""
Expand All @@ -19,4 +20,4 @@ def target_merge(primary_target, secondary_target):

secondary_target.delete()

return primary_target
return primary_target
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@



<table class="table table-bordered table-striped table-sm">
<table id="id_target_merge_fields" class="table table-bordered table-striped table-sm">
<thead class="table-secondary">
<tr>
<th>Property</th>
Expand Down
13 changes: 3 additions & 10 deletions tom_targets/templates/tom_targets/target_merge.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,12 @@
{% block title %}Merge Targets{% endblock %}

{% block content %}
{% bootstrap_form form %}


<div>
<form method="post" action="">
{% csrf_token %}
{% bootstrap_form form %}
<button type="submit" class="btn btn-outline-primary float-right" name="submit">Update Table</button>
</form>
</div>

<!-- display the target fields table -->
{% target_fields target1 target2 %}

<button type="submit" class="btn btn-outline-danger float-right btn-lg" name="submit"><a href="{% url 'targets:list' %}" style="color: rgb(167, 11, 11)">Cancel</a></button>
<button type="submit" class="btn btn-outline-primary float-right btn-lg" name="submit">Confirm</button>

{% endblock %}
{% endblock %}
7 changes: 6 additions & 1 deletion tom_targets/templatetags/targets_extras.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime, timedelta
import logging

from astroplan import moon_illumination
from astropy import units as u
Expand All @@ -19,6 +20,9 @@

register = template.Library()

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)


@register.inclusion_tag('tom_targets/partials/recent_targets.html', takes_context=True)
def recent_targets(context, limit=10):
Expand Down Expand Up @@ -284,6 +288,7 @@ def aladin_skymap(targets):
context = {'targets': target_list}
return context


@register.inclusion_tag('tom_targets/partials/target_fields.html')
def target_fields(target1, target2):
"""
Expand All @@ -307,9 +312,9 @@ def target_fields(target1, target2):
'target2_data': target2_data,
'combined_target_data': combined_target_data
}

return context


@register.inclusion_tag('tom_targets/partials/aladin_skymap.html')
def target_distribution(targets):
"""
Expand Down
8 changes: 2 additions & 6 deletions tom_targets/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1745,7 +1745,7 @@ def test_merge_targets(self):
# print(model_to_dict(self.st1))
result = target_merge(self.st1, self.st2)
result_dictionary = model_to_dict(result)
st1_dictionary = model_to_dict(self.st1)
st1_dictionary = model_to_dict(self.st1)
st2_dictionary = model_to_dict(self.st2)
for param in st1_dictionary:
# print(param)
Expand All @@ -1755,6 +1755,7 @@ def test_merge_targets(self):
else:
self.assertEqual(result_dictionary[param], st2_dictionary[param])


def test_merge_names(self):
"""
This test makes sure that the secondary targets name has been saved as an alias for the primary target
Expand Down Expand Up @@ -1794,8 +1795,3 @@ def test_merge_data(self):
def test_merge_target_list(self):
pass






3 changes: 2 additions & 1 deletion tom_targets/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

from .views import TargetCreateView, TargetUpdateView, TargetDetailView, TargetNameSearchView
from .views import TargetDeleteView, TargetListView, TargetImportView, TargetExportView, TargetShareView
from .views import TargetGroupingView, TargetGroupingDeleteView, TargetGroupingCreateView, TargetAddRemoveGroupingView, TargetMergeView
from .views import (TargetGroupingView, TargetGroupingDeleteView, TargetGroupingCreateView,
TargetAddRemoveGroupingView, TargetMergeView)
from .views import TargetGroupingShareView, TargetHermesPreloadView, TargetGroupingHermesPreloadView

from .api_views import TargetViewSet, TargetExtraViewSet, TargetNameViewSet, TargetListViewSet
Expand Down
53 changes: 47 additions & 6 deletions tom_targets/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,19 @@
from django.core.management import call_command
from django.db import transaction
from django.db.models import Q
from django_filters.views import FilterView
from django.http import HttpResponse
from django.http import HttpResponseRedirect, QueryDict, StreamingHttpResponse, HttpResponseBadRequest
from django.forms import HiddenInput
from django.shortcuts import redirect
from django.template.loader import render_to_string
from django.urls import reverse_lazy, reverse
from django.utils.text import slugify
from django.utils.safestring import mark_safe
from django.views.generic.edit import CreateView, UpdateView, DeleteView, FormView
from django.views.generic.detail import DetailView, SingleObjectMixin
from django.views.generic.list import ListView
from django.views.generic import RedirectView, TemplateView, View
from django_filters.views import FilterView

from guardian.mixins import PermissionListMixin
from guardian.shortcuts import get_objects_for_user, get_groups_with_perms, assign_perm
Expand All @@ -44,11 +46,13 @@
)
from tom_targets.merge import (merge_error_message)
from tom_targets.models import Target, TargetList
from tom_targets.templatetags.targets_extras import target_fields
from tom_targets.utils import import_targets, export_targets
from tom_dataproducts.alertstreams.hermes import BuildHermesMessage, preload_to_hermes


logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)


class TargetListView(PermissionListMixin, FilterView):
Expand Down Expand Up @@ -561,6 +565,7 @@ def render_to_response(self, context, **response_kwargs):
response['Content-Disposition'] = 'attachment; filename="{}"'.format(filename)
return response


class TargetMergeView(FormView):
"""
View that handles choosing the primary target in the process of merging targets
Expand Down Expand Up @@ -603,30 +608,66 @@ def get_context_data(self, *args, **kwargs):
def get_form_class(self):

return TargetMergeForm

def post(self, request, *args, **kwargs):
form = TargetMergeForm(request.POST)

first_target_id = int(self.kwargs.get('pk1', None))
second_target_id = int(self.kwargs.get('pk2', None))
# let the form name_select field know what it's choices are
# these were determined at run time
form.fields['name_select'].choices = self.get_name_select_choices(first_target_id, second_target_id)
print(f'just set the name_select choices to {form.fields["name_select"].choices}')
form.fields['name_select'].choices = self.get_name_select_choices(
first_target_id, second_target_id)

if form.is_valid():
primary_target_id = int(form.cleaned_data['name_select'])
if primary_target_id == first_target_id:
secondary_target_id = second_target_id
else:
secondary_target_id = first_target_id
return redirect('tom_targets:merge',
pk1=primary_target_id, pk2=secondary_target_id)
return redirect('tom_targets:merge', pk1=primary_target_id, pk2=secondary_target_id)
else:
messages.warning(request, form.errors)
return redirect('tom_targets:merge',
pk1=first_target_id, pk2=second_target_id)

def get(self, request, *args, **kwargs):
"""When called as a result of the Primary Target name_select field being
changed, request.htmx will be True and this should update the
target_field inclusiontag/partial (via render_to_string) according to
the selected target.

If this is not an HTMX request, just call super().get.
"""
if request.htmx:
pk1 = int(self.kwargs.get('pk1', None))
pk2 = int(self.kwargs.get('pk2', None))

# get the target_id of the selected target: it's the primary
primary_target_id = int(request.GET.get('name_select', None))

# decide which of pk1 or pk2 is primary (i.e. it matches name_select)
if pk1 == primary_target_id: # first is primary, so
secondary_target_id = pk2
else: # second is primary, so
secondary_target_id = pk1

# get the actual Target instances for these target_ids
primary_target = Target.objects.get(id=primary_target_id)
secondary_target = Target.objects.get(id=secondary_target_id)

# render the table with those targets via the inclusiontag
target_table_html = render_to_string(
'tom_targets/partials/target_fields.html',
context=target_fields(primary_target, secondary_target))

# replace the old target_field table with the newly rendered one
return HttpResponse(target_table_html)
else:
# not an HTMX request
return super().get(request, *args, **kwargs)


class TargetAddRemoveGroupingView(LoginRequiredMixin, View):
"""
View that handles addition and removal of targets to target groups. Requires authentication.
Expand Down
Loading