mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	A nicer look for the documents listing
This change includes a filthy hack around how Django handles change_list_results.html -- I'm not thrilled with it, but it's as elegant as I could come up with. I'm happy to field alternative ideas. More details can be found in `documents/templatetags/hacks.py` Specifically, this merge includes a significant facelift to the documents listing page, moving away from the tabular layout and toward a tileset look. I tried fiddling with the colours, but I just don't have any skills in that area, so we're all stuck with Django'd default colours until someone with an eye for colour can submit a better CSS.
This commit is contained in:
		| @@ -1,6 +1,15 @@ | |||||||
| Changelog | Changelog | ||||||
| ######### | ######### | ||||||
|  |  | ||||||
|  | * 0.3.5 | ||||||
|  |   * A serious facelift for the documents listing page wherein we drop the | ||||||
|  |     tabular layout in favour of a tiled interface. | ||||||
|  |   * Users can now configure the number of items per page. | ||||||
|  |   * Fix for `#171`_: Allow users to specify their own ``SECRET_KEY`` value. | ||||||
|  |   * Moved the dotenv loading to the top of settings.py | ||||||
|  |   * Fix for `#112`_: Added checks for binaries required for document | ||||||
|  |     consumption. | ||||||
|  |  | ||||||
| * 0.3.4 | * 0.3.4 | ||||||
|   * Removal of django-suit due to a licensing conflict I bumped into in 0.3.3. |   * Removal of django-suit due to a licensing conflict I bumped into in 0.3.3. | ||||||
|     Note that you *can* use Django Suit with Paperless, but only in a |     Note that you *can* use Django Suit with Paperless, but only in a | ||||||
| @@ -42,7 +51,8 @@ Changelog | |||||||
|     ``paperless.conf``. |     ``paperless.conf``. | ||||||
|   * `#148`_: The database location (sqlite) is now a variable you can set in |   * `#148`_: The database location (sqlite) is now a variable you can set in | ||||||
|     ``paperless.conf``. |     ``paperless.conf``. | ||||||
|   * `#146`_: Fixed a bug that allowed unauthorised access to the `/fetch` URL. |   * `#146`_: Fixed a bug that allowed unauthorised access to the ``/fetch`` | ||||||
|  |     URL. | ||||||
|   * `#131`_: Document files are now automatically removed from disk when |   * `#131`_: Document files are now automatically removed from disk when | ||||||
|     they're deleted in Paperless. |     they're deleted in Paperless. | ||||||
|   * `#121`_: Fixed a bug where Paperless wasn't setting document creation time |   * `#121`_: Fixed a bug where Paperless wasn't setting document creation time | ||||||
| @@ -168,10 +178,12 @@ Changelog | |||||||
| .. _#89: https://github.com/danielquinn/paperless/issues/89 | .. _#89: https://github.com/danielquinn/paperless/issues/89 | ||||||
| .. _#94: https://github.com/danielquinn/paperless/issues/94 | .. _#94: https://github.com/danielquinn/paperless/issues/94 | ||||||
| .. _#98: https://github.com/danielquinn/paperless/issues/98 | .. _#98: https://github.com/danielquinn/paperless/issues/98 | ||||||
|  | .. _#112: https://github.com/danielquinn/paperless/issues/112 | ||||||
| .. _#121: https://github.com/danielquinn/paperless/issues/121 | .. _#121: https://github.com/danielquinn/paperless/issues/121 | ||||||
| .. _#131: https://github.com/danielquinn/paperless/issues/131 | .. _#131: https://github.com/danielquinn/paperless/issues/131 | ||||||
| .. _#146: https://github.com/danielquinn/paperless/issues/146 | .. _#146: https://github.com/danielquinn/paperless/issues/146 | ||||||
| .. _#148: https://github.com/danielquinn/paperless/pull/148 | .. _#148: https://github.com/danielquinn/paperless/pull/148 | ||||||
| .. _#150: https://github.com/danielquinn/paperless/pull/150 | .. _#150: https://github.com/danielquinn/paperless/pull/150 | ||||||
|  | .. _#171: https://github.com/danielquinn/paperless/issues/171 | ||||||
| .. _#172: https://github.com/danielquinn/paperless/issues/172 | .. _#172: https://github.com/danielquinn/paperless/issues/172 | ||||||
| .. _#179: https://github.com/danielquinn/paperless/pull/179 | .. _#179: https://github.com/danielquinn/paperless/pull/179 | ||||||
|   | |||||||
| @@ -1,18 +1,18 @@ | |||||||
| Django==1.10.4 | Django==1.10.5 | ||||||
| Pillow>=3.1.1 | Pillow>=3.1.1 | ||||||
| django-crispy-forms>=1.6.0 | django-crispy-forms>=1.6.1 | ||||||
| django-extensions>=1.6.1 | django-extensions>=1.7.6 | ||||||
| django-filter>=1.0 | django-filter>=1.0 | ||||||
| djangorestframework>=3.4.4 | django-flat-responsive>=1.2.0 | ||||||
|  | djangorestframework>=3.5.3 | ||||||
| filemagic>=1.6 | filemagic>=1.6 | ||||||
| langdetect>=1.0.5 | langdetect>=1.0.7 | ||||||
| pyocr>=0.3.1 | pyocr>=0.4.6 | ||||||
| python-dateutil>=2.4.2 | python-dateutil>=2.6.0 | ||||||
| python-dotenv>=0.3.0 | python-dotenv>=0.6.2 | ||||||
| python-gnupg>=0.3.8 | python-gnupg>=0.3.9 | ||||||
| pytz>=2015.7 | pytz>=2016.10 | ||||||
| gunicorn==19.6.0 | gunicorn==19.6.0 | ||||||
| django-flat-responsive==1.2.0 |  | ||||||
|  |  | ||||||
| # For the tests | # For the tests | ||||||
| pytest | pytest | ||||||
|   | |||||||
| @@ -58,7 +58,7 @@ class DocumentAdmin(CommonAdmin): | |||||||
|         } |         } | ||||||
|  |  | ||||||
|     search_fields = ("correspondent__name", "title", "content") |     search_fields = ("correspondent__name", "title", "content") | ||||||
|     list_display = ("created", "title", "thumbnail", "correspondent", "tags_") |     list_display = ("title", "created", "thumbnail", "correspondent", "tags_") | ||||||
|     list_filter = ("tags", "correspondent", MonthListFilter) |     list_filter = ("tags", "correspondent", MonthListFilter) | ||||||
|     ordering = ["-created", "correspondent"] |     ordering = ["-created", "correspondent"] | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								src/documents/templates/admin/change_list_results.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/documents/templates/admin/change_list_results.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | {% load hacks %} | ||||||
|  |  | ||||||
|  | {# See documents.templatetags.hacks.change_list_results for an explanation #} | ||||||
|  |  | ||||||
|  | {% change_list_results %} | ||||||
|  |  | ||||||
| @@ -0,0 +1,167 @@ | |||||||
|  | {% load i18n %} | ||||||
|  |  | ||||||
|  | <style> | ||||||
|  |   .grid *, .grid *:after, .grid *:before { | ||||||
|  |     -webkit-box-sizing: border-box; | ||||||
|  |     -moz-box-sizing: border-box; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |   } | ||||||
|  |   .box { | ||||||
|  |     width: 12.5%; | ||||||
|  |     padding: 1em; | ||||||
|  |     float: left; | ||||||
|  |     opacity: 0.7; | ||||||
|  |     transition: all 0.5s; | ||||||
|  |   } | ||||||
|  |   .box:hover { | ||||||
|  |     opacity: 1; | ||||||
|  |     transition: all 0.5s; | ||||||
|  |   } | ||||||
|  |   .box:last-of-type { | ||||||
|  |     padding-right: 0; | ||||||
|  |   } | ||||||
|  |   .result { | ||||||
|  |     border: 1px solid #cccccc; | ||||||
|  |     border-radius: 2%; | ||||||
|  |     overflow: hidden; | ||||||
|  |     height: 300px; | ||||||
|  |   } | ||||||
|  |   .result .header { | ||||||
|  |     padding: 5px; | ||||||
|  |     background-color: #79AEC8; | ||||||
|  |     height: 6em; | ||||||
|  |   } | ||||||
|  |   .result .header .checkbox { | ||||||
|  |     margin-right: 5px; | ||||||
|  |   } | ||||||
|  |   .result .header .checkbox{ | ||||||
|  |     width: 5%; | ||||||
|  |     float: left; | ||||||
|  |   } | ||||||
|  |   .result .header .info { | ||||||
|  |     width: 90%; | ||||||
|  |     float: left; | ||||||
|  |   } | ||||||
|  |   .result .header a, | ||||||
|  |   .result a.tag { | ||||||
|  |     color: #ffffff; | ||||||
|  |   } | ||||||
|  |   .result .date { | ||||||
|  |     padding: 5px; | ||||||
|  |   } | ||||||
|  |   .result .tags { | ||||||
|  |     float: left; | ||||||
|  |   } | ||||||
|  |   .result .tags a.tag { | ||||||
|  |     padding: 2px 5px; | ||||||
|  |     border-radius: 2px; | ||||||
|  |     display: inline-block; | ||||||
|  |     margin: 2px; | ||||||
|  |   } | ||||||
|  |   .result .date { | ||||||
|  |     float: right; | ||||||
|  |     color: #cccccc; | ||||||
|  |   } | ||||||
|  |   .result .image img { | ||||||
|  |     width: 100%; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .grid { | ||||||
|  |     margin-right: 260px; | ||||||
|  |   } | ||||||
|  |   .grid:after { | ||||||
|  |     content: ""; | ||||||
|  |     display: table; | ||||||
|  |     clear: both; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @media (max-width: 1600px) { | ||||||
|  |     .box { | ||||||
|  |       width: 25% | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @media (max-width: 991px) { | ||||||
|  |     .grid { | ||||||
|  |       margin-right: 220px; | ||||||
|  |     } | ||||||
|  |     .box { | ||||||
|  |       width: 50% | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @media (max-width: 767px) { | ||||||
|  |     .grid { | ||||||
|  |       margin-right: 0; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @media (max-width: 500px) { | ||||||
|  |     .box { | ||||||
|  |       width: 100% | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | </style> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | {# This is just copypasta from the parent change_list_results.html file #} | ||||||
|  | <table id="result_list"> | ||||||
|  | <thead> | ||||||
|  | <tr> | ||||||
|  | {% for header in result_headers %} | ||||||
|  | <th scope="col" {{ header.class_attrib }}> | ||||||
|  |    {% if header.sortable %} | ||||||
|  |      {% if header.sort_priority > 0 %} | ||||||
|  |        <div class="sortoptions"> | ||||||
|  |          <a class="sortremove" href="{{ header.url_remove }}" title="{% trans "Remove from sorting" %}"></a> | ||||||
|  |          {% if num_sorted_fields > 1 %}<span class="sortpriority" title="{% blocktrans with priority_number=header.sort_priority %}Sorting priority: {{ priority_number }}{% endblocktrans %}">{{ header.sort_priority }}</span>{% endif %} | ||||||
|  |          <a href="{{ header.url_toggle }}" class="toggle {% if header.ascending %}ascending{% else %}descending{% endif %}" title="{% trans "Toggle sorting" %}"></a> | ||||||
|  |        </div> | ||||||
|  |      {% endif %} | ||||||
|  |    {% endif %} | ||||||
|  |    <div class="text">{% if header.sortable %}<a href="{{ header.url_primary }}">{{ header.text|capfirst }}</a>{% else %}<span>{{ header.text|capfirst }}</span>{% endif %}</div> | ||||||
|  |    <div class="clear"></div> | ||||||
|  | </th>{% endfor %} | ||||||
|  | </tr> | ||||||
|  | </thead> | ||||||
|  | </table> | ||||||
|  | {# /copypasta #} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | <div class="grid"> | ||||||
|  |   {% for result in results %} | ||||||
|  |     {# 0: Checkbox #} | ||||||
|  |     {# 1: Title #} | ||||||
|  |     {# 2: Date #} | ||||||
|  |     {# 3: Image #} | ||||||
|  |     {# 4: Correspondent #} | ||||||
|  |     {# 5: Tags #} | ||||||
|  |     <div class="box"> | ||||||
|  |       <div class="result"> | ||||||
|  |         <div class="header"> | ||||||
|  |           <div class="checkbox">{{ result.0 }}</div> | ||||||
|  |           <div class="info"> | ||||||
|  |             {{ result.4 }}<br /> | ||||||
|  |             {{ result.1 }} | ||||||
|  |           </div> | ||||||
|  |           <div style="clear: both;"></div> | ||||||
|  |         </div> | ||||||
|  |         <div class="tags">{{ result.5 }}</div> | ||||||
|  |         <div class="date">{{ result.2 }}</div> | ||||||
|  |         <div style="clear: both;"></div> | ||||||
|  |         <div class="image">{{ result.3 }}</div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   {% endfor %} | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  |   // We nee to re-build the select-all functionality as the old logic pointed | ||||||
|  |   // to a table and we're using divs now. | ||||||
|  |   django.jQuery("#action-toggle").on("change", function(){ | ||||||
|  |     django.jQuery(".grid .box .result .checkbox input") | ||||||
|  |       .prop("checked", this.checked); | ||||||
|  |   }); | ||||||
|  | </script> | ||||||
							
								
								
									
										0
									
								
								src/documents/templatetags/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/documents/templatetags/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										41
									
								
								src/documents/templatetags/hacks.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/documents/templatetags/hacks.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | import os | ||||||
|  |  | ||||||
|  | from django.contrib import admin | ||||||
|  | from django.template import Library | ||||||
|  | from django.template.loader import get_template | ||||||
|  |  | ||||||
|  | from ..models import Document | ||||||
|  |  | ||||||
|  |  | ||||||
|  | register = Library() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @register.simple_tag(takes_context=True) | ||||||
|  | def change_list_results(context): | ||||||
|  |     """ | ||||||
|  |     Django has a lot of places where you can override defaults, but | ||||||
|  |     unfortunately, `change_list_results.html` is not one of them.  In fact, | ||||||
|  |     it's a downright pain in the ass to override this file on a per-model basis | ||||||
|  |     and this is the cleanest way I could come up with. | ||||||
|  |  | ||||||
|  |     Basically all we've done here is defined `change_list_results.html` in an | ||||||
|  |     `admin` directory which globally overrides that file for *every* model. | ||||||
|  |     That template however simply loads this templatetag which determines | ||||||
|  |     whether we're currently looking at a `Document` listing or something else | ||||||
|  |     and loads the appropriate file in each case. | ||||||
|  |  | ||||||
|  |     Better work arounds for this are welcome as I hate this myself, but at the | ||||||
|  |     moment, it's all I could come up with. | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     path = os.path.join( | ||||||
|  |         os.path.dirname(admin.__file__), | ||||||
|  |         "templates", | ||||||
|  |         "admin", | ||||||
|  |         "change_list_results.html" | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     if context["cl"].model == Document: | ||||||
|  |         path = "admin/documents/document/change_list_results.html" | ||||||
|  |  | ||||||
|  |     return get_template(path).render(context) | ||||||
| @@ -52,18 +52,19 @@ if _allowed_hosts: | |||||||
|  |  | ||||||
| INSTALLED_APPS = [ | INSTALLED_APPS = [ | ||||||
|  |  | ||||||
|     'flat_responsive', |     "django.contrib.auth", | ||||||
|     'django.contrib.admin', |     "django.contrib.contenttypes", | ||||||
|     'django.contrib.auth', |     "django.contrib.sessions", | ||||||
|     'django.contrib.contenttypes', |     "django.contrib.messages", | ||||||
|     'django.contrib.sessions', |     "django.contrib.staticfiles", | ||||||
|     'django.contrib.messages', |  | ||||||
|     'django.contrib.staticfiles', |  | ||||||
|  |  | ||||||
|     "django_extensions", |     "django_extensions", | ||||||
|  |  | ||||||
|     "documents.apps.DocumentsConfig", |     "documents.apps.DocumentsConfig", | ||||||
|  |  | ||||||
|  |     "flat_responsive", | ||||||
|  |     "django.contrib.admin", | ||||||
|  |  | ||||||
|     "rest_framework", |     "rest_framework", | ||||||
|     "crispy_forms", |     "crispy_forms", | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1 +1 @@ | |||||||
| __version__ = (0, 3, 4) | __version__ = (0, 3, 5) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Daniel Quinn
					Daniel Quinn