Enhance Admin: Add Dropdown Date Range Filter for Parcels
This commit is contained in:
parent
7f5da18a24
commit
82b68976c5
@ -17,6 +17,9 @@ from rangefilter.filters import DateRangeFilter
|
|||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
import weasyprint
|
import weasyprint
|
||||||
|
|
||||||
|
class DropdownDateRangeFilter(DateRangeFilter):
|
||||||
|
template = 'admin/dropdown_date_range_filter.html'
|
||||||
|
|
||||||
class ProfileInline(admin.StackedInline):
|
class ProfileInline(admin.StackedInline):
|
||||||
model = Profile
|
model = Profile
|
||||||
can_delete = False
|
can_delete = False
|
||||||
@ -98,7 +101,7 @@ class ParcelAdmin(admin.ModelAdmin):
|
|||||||
list_filter = (
|
list_filter = (
|
||||||
'status',
|
'status',
|
||||||
'payment_status',
|
'payment_status',
|
||||||
('created_at', DateRangeFilter),
|
('created_at', DropdownDateRangeFilter),
|
||||||
)
|
)
|
||||||
search_fields = ('tracking_number', 'shipper__username', 'receiver_name', 'carrier__username')
|
search_fields = ('tracking_number', 'shipper__username', 'receiver_name', 'carrier__username')
|
||||||
actions = ['export_as_csv', 'print_parcels', 'export_pdf']
|
actions = ['export_as_csv', 'print_parcels', 'export_pdf']
|
||||||
|
|||||||
213
core/templates/admin/dropdown_date_range_filter.html
Normal file
213
core/templates/admin/dropdown_date_range_filter.html
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
{% load i18n rangefilter_compat static %}
|
||||||
|
<h3>{{ title }}</h3>
|
||||||
|
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/widgets.css' %}">
|
||||||
|
<style nonce="{{ spec.request.csp_nonce }}">
|
||||||
|
{% default_css_vars_if_needed %}
|
||||||
|
.admindatefilter .button, .admindatefilter input[type=submit], .admindatefilter input[type=button], .admindatefilter .submit-row input, .admindatefilter a.button,
|
||||||
|
.admindatefilter .button, .admindatefilter input[type=reset] {
|
||||||
|
background: var(--button-bg);
|
||||||
|
padding: 4px 5px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--button-fg);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.admindatefilter {
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
.admindatefilter p {
|
||||||
|
padding-left: 0px;
|
||||||
|
line-height: 0;
|
||||||
|
}
|
||||||
|
.admindatefilter p.datetime {
|
||||||
|
line-height: 0;
|
||||||
|
}
|
||||||
|
.admindatefilter .timezonewarning {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.admindatefilter .datetimeshortcuts a:first-child {
|
||||||
|
margin-right: 4px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.calendarbox {
|
||||||
|
z-index: 1100;
|
||||||
|
}
|
||||||
|
.clockbox {
|
||||||
|
z-index: 1100;
|
||||||
|
margin-left: -8em !important;
|
||||||
|
margin-top: 5em !important;
|
||||||
|
}
|
||||||
|
.admindatefilter .datetimeshortcuts {
|
||||||
|
font-size: 0;
|
||||||
|
float: right;
|
||||||
|
position: absolute;
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
.admindatefilter a {
|
||||||
|
color: #999;
|
||||||
|
position: absolute;
|
||||||
|
padding-top: 3px;
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
.range-preset-select {
|
||||||
|
width: 95%;
|
||||||
|
margin: 10px 0 10px 15px;
|
||||||
|
padding: 6px;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: var(--body-bg);
|
||||||
|
color: var(--body-fg);
|
||||||
|
}
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.calendarbox {
|
||||||
|
margin-left: -16em !important;
|
||||||
|
margin-top: 9em !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.calendarbox {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script>
|
||||||
|
<script type="text/javascript" nonce="{{ spec.request.csp_nonce }}">
|
||||||
|
function embedScript(url) {
|
||||||
|
return new Promise(function pr(resolve, reject) {
|
||||||
|
var newScript = document.createElement("script");
|
||||||
|
newScript.type = "text/javascript";
|
||||||
|
newScript.src = url;
|
||||||
|
newScript.onload = resolve;
|
||||||
|
if ("{{ spec.request.csp_nonce }}" !== "") {
|
||||||
|
newScript.setAttribute("nonce", "{{ spec.request.csp_nonce }}");
|
||||||
|
}
|
||||||
|
document.head.appendChild(newScript);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
django.jQuery(window).on('load', function () {
|
||||||
|
if (!('DateTimeShortcuts' in window)) {
|
||||||
|
var promiseList = [];
|
||||||
|
{% for m in spec.form.js %}
|
||||||
|
promiseList.push(embedScript("{{ m }}"));
|
||||||
|
{% endfor %}
|
||||||
|
Promise.all(promiseList).then(function() {
|
||||||
|
django.jQuery('.datetimeshortcuts').remove();
|
||||||
|
if ('DateTimeShortcuts' in window) {
|
||||||
|
window.DateTimeShortcuts.init();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
django.jQuery('document').ready(function () {
|
||||||
|
// Original logic for submit/reset
|
||||||
|
django.jQuery('.admindatefilter #{{ choices.0.system_name }}-form input[type="submit"]').click(function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var form = django.jQuery(this).closest('div.admindatefilter').find('form');
|
||||||
|
var query_string = django.jQuery('input#{{ choices.0.system_name }}-query-string').val();
|
||||||
|
var form_data = form.serialize();
|
||||||
|
var amp = query_string === "?" ? "" : "&";
|
||||||
|
window.location = window.location.pathname + query_string + amp + form_data;
|
||||||
|
});
|
||||||
|
|
||||||
|
django.jQuery('.admindatefilter #{{ choices.0.system_name }}-form input[type="reset"]').click(function() {
|
||||||
|
var form = django.jQuery(this).closest('div.admindatefilter').find('form');
|
||||||
|
var query_string = form.find('input#{{ choices.0.system_name }}-query-string').val();
|
||||||
|
window.location = window.location.pathname + query_string;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Custom Dropdown Logic
|
||||||
|
var $ = django.jQuery;
|
||||||
|
var formId = '#{{ choices.0.system_name }}-form';
|
||||||
|
var $form = $(formId);
|
||||||
|
var $container = $form.closest('.admindatefilter');
|
||||||
|
|
||||||
|
// Build Select
|
||||||
|
var $select = $('<select class="range-preset-select">' +
|
||||||
|
'<option value="all">{% trans "Any Date" %}</option>' +
|
||||||
|
'<option value="today">{% trans "Today" %}</option>' +
|
||||||
|
'<option value="7days">{% trans "Last 7 Days" %}</option>' +
|
||||||
|
'<option value="month">{% trans "This Month" %}</option>' +
|
||||||
|
'<option value="year">{% trans "This Year" %}</option>' +
|
||||||
|
'<option value="custom">{% trans "Custom Range..." %}</option>' +
|
||||||
|
'</select>');
|
||||||
|
|
||||||
|
$container.before($select);
|
||||||
|
|
||||||
|
var $gte = $form.find('input[name$="__gte"]');
|
||||||
|
var $lte = $form.find('input[name$="__lte"]');
|
||||||
|
var $submit = $form.find('input[type="submit"]');
|
||||||
|
|
||||||
|
function formatDate(d) {
|
||||||
|
var year = d.getFullYear();
|
||||||
|
var month = ('0' + (d.getMonth() + 1)).slice(-2);
|
||||||
|
var day = ('0' + d.getDate()).slice(-2);
|
||||||
|
return year + '-' + month + '-' + day;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check initial state
|
||||||
|
if ($gte.val() || $lte.val()) {
|
||||||
|
$select.val('custom');
|
||||||
|
$container.show();
|
||||||
|
} else {
|
||||||
|
$select.val('all');
|
||||||
|
$container.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
$select.on('change', function() {
|
||||||
|
var val = $(this).val();
|
||||||
|
var today = new Date();
|
||||||
|
|
||||||
|
if (val === 'custom') {
|
||||||
|
$container.slideDown();
|
||||||
|
} else {
|
||||||
|
// If not custom, calculate and submit
|
||||||
|
if (val === 'all') {
|
||||||
|
// Reset
|
||||||
|
$form.find('input[type="reset"]').click();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var startStr = '';
|
||||||
|
var endStr = formatDate(today); // Default end is today
|
||||||
|
|
||||||
|
if (val === 'today') {
|
||||||
|
startStr = formatDate(today);
|
||||||
|
} else if (val === '7days') {
|
||||||
|
var past = new Date();
|
||||||
|
past.setDate(today.getDate() - 7);
|
||||||
|
startStr = formatDate(past);
|
||||||
|
} else if (val === 'month') {
|
||||||
|
var firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||||
|
startStr = formatDate(firstDay);
|
||||||
|
} else if (val === 'year') {
|
||||||
|
var firstDay = new Date(today.getFullYear(), 0, 1);
|
||||||
|
startStr = formatDate(firstDay);
|
||||||
|
}
|
||||||
|
|
||||||
|
$gte.val(startStr);
|
||||||
|
$lte.val(endStr);
|
||||||
|
|
||||||
|
// Trigger submit
|
||||||
|
$submit.click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="admindatefilter">
|
||||||
|
<form method="GET" action="." id="{{ choices.0.system_name }}-form">
|
||||||
|
{{ spec.form.as_p }}
|
||||||
|
{% for choice in choices %}
|
||||||
|
<input type="hidden" id="{{ choice.system_name }}-query-string" value="{{ choice.query_string }}">
|
||||||
|
{% endfor %}
|
||||||
|
<div class="controls">
|
||||||
|
<input type="submit" class="button" value="{% trans "Search" %}">
|
||||||
|
<input type="reset" class="button" value="{% trans "Reset" %}">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
Loading…
x
Reference in New Issue
Block a user