Sfoglia il codice sorgente

Merge branch 'dev'

Denis K 8 anni fa
parent
commit
413db507cc

+ 13 - 0
CHANGELOG.rst

@@ -1,6 +1,19 @@
 Changelog
 =========
 
+1.0.3
+-----
+* PR-140: Added change message as tooltip to recent action dashboard module (thanks to michaelkuty for PR)
+* PR-130: Implement JET ui for django-admin-rangefilter (thanks to timur-orudzhov for PR)
+* PR-131: Use WSGIRequest resolver_match instead of resolve (thanks to m-vdb for PR)
+* PR-138: Fixed encoding error in jet_popup_response_data (thanks to michaelkuty for PR)
+* PR-137,138: Fixed UnicodeEncodeError in related popups (thanks to michaelkuty, Copperfield for PRs)
+* Issue-146: Fixed Django CMS plugin edit issue (thanks to bculpepper for report)
+* Issue-147: Fixed login for non superusers (thanks to gio82 for report)
+* Issue-147: Fixed RelatedFieldAjaxListFilter in Django 0.9+ (thanks to a1Gupta for report)
+* Issue-126: Fixed related popups for new items in tabular inlines (thanks to kmorey for report)
+
+
 1.0.2
 -----
 * PR-115: Removed mock request from get_model_queryset to fix 3rd party packages (thanks to imdario for PR)

+ 1 - 0
docs/configuration.rst

@@ -10,3 +10,4 @@ Contents:
    config_file
    autocomplete
    compact_inline
+   filters

+ 26 - 0
docs/filters.rst

@@ -0,0 +1,26 @@
+=======
+Filters
+=======
+
+RelatedFieldAjaxListFilter
+--------------------------
+
+See :doc:`autocomplete` documentation for details.
+
+django-admin-rangefilter
+------------------------
+
+In order to fix compatibility issues with ``django-admin-rangefilter`` package you should use JET's admin filter class
+``jet.filters.DateRangeFilter`` instead of ``rangefilter.filter.DateRangeFilter``.
+
+.. code:: python
+
+    #from rangefilter.filter import DateRangeFilter
+    from jet.filters import DateRangeFilter
+
+
+    class MyUserAdmin(UserAdmin):
+        ...
+        list_filter = (
+            ('date_joined', DateRangeFilter),
+        )

+ 1 - 1
jet/__init__.py

@@ -1 +1 @@
-VERSION = '1.0.2'
+VERSION = '1.0.3'

+ 3 - 3
jet/dashboard/templates/jet.dashboard/modules/recent_actions.html

@@ -1,4 +1,4 @@
-{% load i18n %}
+{% load i18n jet_dashboard_tags %}
 
 <ul>
     {% if not module.children %}
@@ -31,9 +31,9 @@
                     {% endif %}
 
                     {% if entry.is_deletion or not entry.get_admin_url %}
-                        {{ entry.object_repr }}
+                        <span class="tooltip" title="{{ entry|format_change_message }}">{{ entry.object_repr }}</span>
                     {% else %}
-                        <a href="{{ entry.get_admin_url }}">{{ entry.object_repr }}</a>
+                        <a title="{{ entry|format_change_message }}" class="tooltip" href="{{ entry.get_admin_url }}">{{ entry.object_repr }}</a>
                     {% endif %}
                 </div>
             </li>

+ 9 - 0
jet/dashboard/templatetags/jet_dashboard_tags.py

@@ -12,3 +12,12 @@ def get_dashboard(context, location):
     app_label = context['request'].resolver_match.kwargs.get('app_label')
 
     return dashboard_cls(context, app_label=app_label)
+
+
+@register.filter
+def format_change_message(log_entry):
+    # Django 1.10+
+    if hasattr(log_entry, 'get_change_message'):
+        return log_entry.get_change_message()
+    else:
+        return log_entry.change_message

+ 42 - 0
jet/filters.py

@@ -44,3 +44,45 @@ class RelatedFieldAjaxListFilter(RelatedFieldListFilter):
 
         queryset = model._default_manager.filter(**{rel_name: self.lookup_val}).all()
         return [(x._get_pk_val(), smart_text(x)) for x in queryset]
+
+
+try:
+    from collections import OrderedDict
+    from django import forms
+    from django.contrib.admin.widgets import AdminDateWidget
+    from rangefilter.filter import DateRangeFilter as OriginalDateRangeFilter
+    from django.utils.translation import ugettext as _
+
+
+    class DateRangeFilter(OriginalDateRangeFilter):
+        def get_template(self):
+            return 'rangefilter/date_filter.html'
+
+        def _get_form_fields(self):
+            # this is here, because in parent DateRangeFilter AdminDateWidget
+            # could be imported from django-suit
+            return OrderedDict((
+                (self.lookup_kwarg_gte, forms.DateField(
+                    label='',
+                    widget=AdminDateWidget(attrs={'placeholder': _('From date')}),
+                    localize=True,
+                    required=False
+                )),
+                (self.lookup_kwarg_lte, forms.DateField(
+                    label='',
+                    widget=AdminDateWidget(attrs={'placeholder': _('To date')}),
+                    localize=True,
+                    required=False
+                )),
+            ))
+
+        @staticmethod
+        def _get_media():
+            css = [
+                'style.css',
+            ]
+            return forms.Media(
+                css={'all': ['range_filter/css/%s' % path for path in css]}
+            )
+except ImportError:
+    pass

+ 1 - 1
jet/static/jet/css/_changeform.scss

@@ -404,7 +404,7 @@ body.popup .submit-row {
   border-radius: 4px 0 0 4px !important;
   border-right-width: 0 !important;
 
-  #changelist & {
+  .results & {
     border-radius: 4px !important;
     border-right-width: 1px !important;
   }

+ 21 - 0
jet/static/jet/css/_changelist.scss

@@ -180,6 +180,27 @@
   }
 }
 
+.changelist-filter-popup {
+  position: relative;
+
+  &-content {
+    display: none;
+    position: absolute;
+    top: 0;
+    right: 0;
+    left: 0;
+    min-width: 200px;
+    background: $content-background-color;
+    border-radius: 4px;
+    box-shadow: 0 0 4px 0 $input-shadow-color;
+    z-index: 1;
+
+    &.visible {
+      display: block;
+    }
+  }
+}
+
 /* FILTER COLUMN */
 
 #changelist-filter {

File diff suppressed because it is too large
+ 0 - 0
jet/static/jet/css/themes/default/base.css


File diff suppressed because it is too large
+ 0 - 0
jet/static/jet/css/themes/default/base.css.map


File diff suppressed because it is too large
+ 0 - 0
jet/static/jet/css/themes/green/base.css


File diff suppressed because it is too large
+ 0 - 0
jet/static/jet/css/themes/green/base.css.map


File diff suppressed because it is too large
+ 0 - 0
jet/static/jet/css/themes/light-blue/base.css


File diff suppressed because it is too large
+ 0 - 0
jet/static/jet/css/themes/light-blue/base.css.map


File diff suppressed because it is too large
+ 0 - 0
jet/static/jet/css/themes/light-gray/base.css


File diff suppressed because it is too large
+ 0 - 0
jet/static/jet/css/themes/light-gray/base.css.map


File diff suppressed because it is too large
+ 0 - 0
jet/static/jet/css/themes/light-green/base.css


File diff suppressed because it is too large
+ 0 - 0
jet/static/jet/css/themes/light-green/base.css.map


File diff suppressed because it is too large
+ 0 - 0
jet/static/jet/css/themes/light-violet/base.css


File diff suppressed because it is too large
+ 0 - 0
jet/static/jet/css/themes/light-violet/base.css.map


File diff suppressed because it is too large
+ 0 - 0
jet/static/jet/js/build/bundle.min.js


+ 26 - 0
jet/static/jet/js/src/layout-updaters/toolbar.js

@@ -74,6 +74,32 @@ ToolbarUpdater.prototype = {
                 }
 
                 filterName = null;
+            } else if ($element.hasClass('changelist-filter-popup')) {
+                var $toggle = $element.find('.changelist-filter-popup-toggle');
+                var $content = $element.find('.changelist-filter-popup-content');
+                var $wrapper = $('<span>')
+                    .addClass('changelist-filter-select-wrapper')
+                    .append($element);
+
+                if ($search.length) {
+                    $wrapper.insertAfter($search);
+                } else {
+                    $toolbar.append($wrapper);
+                }
+
+                $toggle.on('click', function(e) {
+                    e.preventDefault();
+                    e.stopPropagation();
+                    $content.toggleClass('visible');
+                });
+
+                $content.on('click', function(e) {
+                    e.stopPropagation();
+                });
+
+                $(document.body).on('click', function() {
+                    $content.removeClass('visible');
+                });
             }
         });
 

+ 15 - 0
jet/static/range_filter/css/style.css

@@ -0,0 +1,15 @@
+.admindatefilter fieldset.module {
+	padding: 10px;
+}
+
+.admindatefilter .form-row {
+	padding: 10px;
+}
+
+.admindatefilter .controls {
+	padding: 0 20px 20px 20px;
+}
+
+.admindatefilter .controls input[type="submit"] {
+	margin-bottom: 0 !important;
+}

+ 38 - 0
jet/templates/rangefilter/date_filter.html

@@ -0,0 +1,38 @@
+{% load i18n admin_static %}
+<h3>{% blocktrans with filter_title=title %} By {{ filter_title }} {% endblocktrans %}</h3>
+<script>
+    function datefilter_apply(event, qs_name, form_name){
+        event.preventDefault();
+        var query_string = django.jQuery('input#'+qs_name).val();
+        var form_data = django.jQuery('#'+form_name).serialize();
+        window.location = window.location.pathname + query_string + '&' + form_data;
+    }
+    function datefilter_reset(qs_name){
+        var query_string = django.jQuery('input#'+qs_name).val();
+        window.location = window.location.pathname + query_string;
+    }
+</script>
+<div class="changelist-filter-popup admindatefilter">
+    <input class="changelist-filter-popup-toggle" type="text" value="{% blocktrans with filter_title=title %} By {{ filter_title }} {% endblocktrans %}" readonly>
+    <div class="changelist-filter-popup-content">
+        <form method="GET" action="." id="{{ choices.0.system_name }}-form">
+            {{ spec.form.media }}
+            <fieldset class="module aligned">
+                {% for field in spec.form %}
+                    <div class="form-row {{ field.id }}">
+                        <div>
+                            {{ field }}
+                        </div>
+                    </div>
+                {% endfor %}
+            </fieldset>
+            {% for choice in choices %}
+                <input type="hidden" id="{{ choice.system_name }}-query-string" value="{{ choice.query_string }}">
+            {% endfor %}
+            <div class="controls">
+                <input type="button" value="{% trans "Search" %}" onclick="datefilter_apply(event, '{{ choices.0.system_name }}-query-string', '{{ choices.0.system_name }}-form')">
+                <input type="reset" class="button" value="{% trans "Reset" %}" onclick="datefilter_reset('{{ choices.0.system_name }}-query-string')">
+            </div>
+        </form>
+    </div>
+</div>

+ 8 - 1
jet/templatetags/jet_tags.py

@@ -92,7 +92,7 @@ def jet_get_menu(context):
     for app in app_list:
         if not current_found:
             for model in app['models']:
-                if context['request'].path.startswith(model['admin_url']):
+                if 'admin_url' in model and context['request'].path.startswith(model['admin_url']):
                     model['current'] = True
                     current_found = True
                     break
@@ -221,9 +221,16 @@ def jet_sibling_object_url(context, next):
     preserved_filters_plain = context.get('preserved_filters', '')
     preserved_filters = dict(parse_qsl(preserved_filters_plain))
     admin_site = get_admin_site(context)
+
+    if admin_site is None:
+        return
+
     request = context.get('request')
     queryset = get_model_queryset(admin_site, model, request, preserved_filters=preserved_filters)
 
+    if queryset is None:
+        return
+
     sibling_object = None
     object_pks = list(queryset.values_list('pk', flat=True))
 

+ 9 - 5
jet/utils.py

@@ -166,11 +166,15 @@ class SuccessMessageMixin(object):
 def get_model_queryset(admin_site, model, request, preserved_filters=None):
     model_admin = admin_site._registry.get(model)
 
-    changelist_url = urlresolvers.reverse('%s:%s_%s_changelist' % (
-        admin_site.name,
-        model._meta.app_label,
-        model._meta.model_name
-    ))
+    try:
+        changelist_url = urlresolvers.reverse('%s:%s_%s_changelist' % (
+            admin_site.name,
+            model._meta.app_label,
+            model._meta.model_name
+        ))
+    except NoReverseMatch:
+        return
+
     changelist_filters = None
 
     if preserved_filters:

Some files were not shown because too many files changed in this diff