|
1 | 1 | {% extends 'tom_common/base.html' %} |
2 | | -{% load bootstrap4 targets_extras dataproduct_extras %} |
| 2 | +{% load bootstrap4 targets_extras dataproduct_extras dataservices_extras %} |
| 3 | +{% load render_table from django_tables2 %} |
| 4 | +{% load i18n %} |
| 5 | +{% load crispy_forms_tags %} |
| 6 | + |
3 | 7 | {% block title %}Targets{% endblock %} |
| 8 | + |
4 | 9 | {% block content %} |
5 | 10 | <div class="row content"> |
6 | | - <div class="col-md-10"> |
| 11 | + <div class="col-md-12"> |
7 | 12 | <div class="row"> |
8 | 13 | <div class="col-md-12"> |
9 | 14 | <span class="float-right"> |
10 | | - {{ target_count }} Targets |
| 15 | + {{ target_count }} Target{{ target_count|pluralize }} |
11 | 16 | <button class="btn btn-primary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> |
12 | 17 | Create Targets |
13 | 18 | </button> |
|
16 | 21 | <a class="dropdown-item" href="{% url 'targets:import' %}" title="Import Targets">Import Targets</a> |
17 | 22 | <a class="dropdown-item" href="{% url 'tom_catalogs:query' %}" title="Catalog Search">Catalog Search</a> |
18 | 23 | </div> |
| 24 | + {% catalog_query_menu %} |
| 25 | + |
19 | 26 | {% update_broker_data_button %} |
20 | | - <button onclick="document.getElementById('invisible-export-button').click()" class="btn btn-primary">Export Filtered Targets</button> |
21 | | - <!-- use an invisible button, because the key "Enter" event will triggered the first submit button and we want the default action to be applying filter --> |
| 27 | + |
| 28 | + <!-- Export Filtered Targets button (gets current filter form values for export list)--> |
| 29 | + <button type="button" class="btn btn-primary" title="Export Filtered Targets" |
| 30 | + onclick="const queryString = new URLSearchParams(new FormData(document.querySelector('form.mb-3'))).toString(); window.location.href = '{% url 'targets:export' %}?' + queryString;"> |
| 31 | + Export Filtered Targets |
| 32 | + </button> |
22 | 33 | </span> |
23 | 34 | </div> |
24 | 35 | </div> |
25 | 36 | <div class="row"> |
26 | | - <div class="col-md-6"> |
27 | | - {% aladin_skymap object_list %} |
| 37 | + <div class="col-md-6"> |
| 38 | + {# Aladin skymap -- initialized once on page load (Moon/Sun computed here). #} |
| 39 | + {# On HTMX filter updates, only the target markers are updated via OOB swap #} |
| 40 | + {# into the aladin-targets-data div below (see target_table_partial.html). #} |
| 41 | + {% aladin_skymap skymap_objects %} |
| 42 | + |
| 43 | + {# Placeholder for OOB target data updates from HTMX #} |
| 44 | + <div id="aladin-targets-data"></div> |
28 | 45 | </div> |
| 46 | + |
29 | 47 | <div class="col-md-6"> |
30 | | - <label id="displaySelected"></label> |
31 | | - <button id="optionSelectAll" type="button" class="btn btn-link" onClick="select_all({{ target_count }})"></button> |
32 | | - <form id="grouping-form" action="{% url 'targets:add-remove-grouping' %}" method="POST"> |
33 | | - {% csrf_token %} |
34 | | - <div class="d-flex flex-row align-items-baseline"> |
| 48 | + |
| 49 | + <form id="grouping-form" action="{% url 'targets:add-remove-grouping' %}" method="POST"> |
| 50 | + {% csrf_token %} |
| 51 | + <div class="d-flex flex-row align-items-baseline"> |
35 | 52 | <label>Merge duplicate targets</label> |
36 | 53 | <button type="submit" class="btn btn-outline-success ml-1" name="merge">Merge</button> |
37 | | - </div> |
38 | | - <div class="form-group d-flex justify-content-end align-items-baseline"> |
39 | | - <label>Add/Remove from grouping</label> |
40 | | - <select name="grouping" class="form-control w-25 ml-1"> |
41 | | - {% for grouping in groupings %} |
42 | | - <option value="{{ grouping.id }}">{{ grouping.name }}</option> |
43 | | - {% endfor %} |
44 | | - </select> |
45 | | - <input type="hidden" value="{{ query_string }}" name="query_string"> |
46 | | - <input type="hidden" value="False" id="isSelectAll" name="isSelectAll"> |
47 | | - <button type="submit" class="btn btn-outline-primary ml-1" name="add">Add</button> |
48 | | - <button type="submit" class="btn btn-outline-primary ml-1" name="move">Move</button> |
49 | | - <button type="submit" class="btn btn-outline-danger ml-1" name="remove">Remove</button> |
50 | | - </div> |
51 | | - {% bootstrap_pagination page_obj extra=request.GET.urlencode %} |
52 | | - {% target_table object_list %} |
53 | | - {% bootstrap_pagination page_obj extra=request.GET.urlencode %} |
54 | | - </form> |
55 | 54 | </div> |
56 | | - </div> |
57 | | - </div> |
58 | | - {% select_target_js %} |
| 55 | + <div class="form-group d-flex flex-row align-items-baseline"> |
| 56 | + <label>Add/Remove from grouping</label> |
| 57 | + <select name="grouping" class="form-control w-25 ml-1"> |
| 58 | + {% for grouping in groupings %} |
| 59 | + <option value="{{ grouping.id }}">{{ grouping.name }}</option> |
| 60 | + {% endfor %} |
| 61 | + </select> |
| 62 | + <input type="hidden" value="{{ query_string }}" name="query_string"> |
| 63 | + <input type="hidden" value="False" id="isSelectAll" name="isSelectAll"> |
| 64 | + <button type="submit" class="btn btn-outline-primary ml-1" name="add">Add</button> |
| 65 | + <button type="submit" class="btn btn-outline-primary ml-1" name="move">Move</button> |
| 66 | + <button type="submit" class="btn btn-outline-danger ml-1" name="remove">Remove</button> |
| 67 | + </div> |
| 68 | + </form> |
59 | 69 |
|
60 | | - {{ filter.fields }} |
61 | | - <div class="col-md-2"> |
62 | | - <form action="" method="get" class="form"> |
63 | | - {% bootstrap_form filter.form %} |
64 | | - {% buttons %} |
65 | | - <button type="submit" class="btn btn-primary"> |
66 | | - Filter |
67 | | - </button> |
68 | | - <a href="{% url 'targets:list' %}" class="btn btn-secondary" title="Reset">Reset</a> |
69 | | - <button type="submit" formaction="{% url 'targets:export' %}" id="invisible-export-button" style="display:none"></button> |
70 | | - {% endbuttons %} |
| 70 | + {% block target_table_content %} |
| 71 | + <hr> |
| 72 | + {# Search form (we refer to this id="filter-form" in the TargetTable.Meta.attrs) #} |
| 73 | + <form id="filter-form" class="mb-3" |
| 74 | + hx-get="{% url 'tom_targets:list' %}" |
| 75 | + hx-target="div.table-container" |
| 76 | + hx-swap="outerHTML" |
| 77 | + hx-indicator=".progress"> |
| 78 | + {% crispy filter.form %} |
71 | 79 | </form> |
| 80 | + |
| 81 | + {# Progress indicator #} |
| 82 | + <div class="progress"> |
| 83 | + <div class="indeterminate"></div> |
| 84 | + </div> |
| 85 | + |
| 86 | + {# The actual table #} |
| 87 | + <div class="table-container"> |
| 88 | + {% include "tom_targets/partials/target_table_partial.html" %} |
| 89 | + </div> |
| 90 | + |
| 91 | + <hr> |
| 92 | + {% endblock target_table_content %} |
72 | 93 | </div> |
73 | | -</div> |
74 | | -{% endblock %} |
| 94 | + </div> |
| 95 | + </div> |
| 96 | + |
| 97 | + <script> |
| 98 | + document.body.addEventListener('change', function(e) { |
| 99 | + // This eventListener toggles all the checkboxes when the header-checkbox is toggled. |
| 100 | + |
| 101 | + // Check if the source of the change event is our header checkbox |
| 102 | + if (e.target && e.target.classList.contains('header-checkbox')) { |
| 103 | + |
| 104 | + // Find all checkboxes with the specific name used in the rows |
| 105 | + const checkboxes = document.querySelectorAll('input[name="selected-target"]'); |
| 106 | + |
| 107 | + // Set their state to match the header checkbox |
| 108 | + checkboxes.forEach(cb => cb.checked = e.target.checked); |
| 109 | + } |
| 110 | + }); |
| 111 | + </script> |
| 112 | +{% endblock content %} |
0 commit comments