django-unfold 0.27.0__py3-none-any.whl → 0.28.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. {django_unfold-0.27.0.dist-info → django_unfold-0.28.1.dist-info}/METADATA +64 -9
  2. {django_unfold-0.27.0.dist-info → django_unfold-0.28.1.dist-info}/RECORD +30 -27
  3. unfold/admin.py +1 -0
  4. unfold/contrib/forms/widgets.py +2 -0
  5. unfold/contrib/import_export/forms.py +21 -7
  6. unfold/contrib/import_export/templates/admin/import_export/change_list_export.html +5 -0
  7. unfold/contrib/import_export/templates/admin/import_export/export.html +1 -1
  8. unfold/contrib/simple_history/templates/simple_history/object_history.html +3 -5
  9. unfold/contrib/simple_history/templates/simple_history/{_object_history_list.html → object_history_list.html} +49 -11
  10. unfold/dataclasses.py +2 -0
  11. unfold/fields.py +9 -1
  12. unfold/static/unfold/css/styles.css +1 -1
  13. unfold/styles.css +1 -2
  14. unfold/templates/admin/login.html +4 -0
  15. unfold/templates/admin/submit_line.html +1 -1
  16. unfold/templates/unfold/helpers/attrs.html +1 -0
  17. unfold/templates/unfold/helpers/boolean.html +1 -1
  18. unfold/templates/unfold/helpers/field_readonly_value.html +1 -1
  19. unfold/templates/unfold/helpers/fieldset_row.html +2 -2
  20. unfold/templates/unfold/helpers/navigation.html +1 -1
  21. unfold/templates/unfold/helpers/search_results.html +10 -10
  22. unfold/templates/unfold/layouts/base.html +11 -0
  23. unfold/templates/unfold/layouts/base_simple.html +7 -1
  24. unfold/templates/unfold/widgets/clearable_file_input_small.html +1 -1
  25. unfold/templates/unfold/widgets/split_datetime.html +7 -7
  26. unfold/utils.py +21 -1
  27. unfold/views.py +18 -6
  28. unfold/widgets.py +12 -1
  29. {django_unfold-0.27.0.dist-info → django_unfold-0.28.1.dist-info}/LICENSE.md +0 -0
  30. {django_unfold-0.27.0.dist-info → django_unfold-0.28.1.dist-info}/WHEEL +0 -0
@@ -1,23 +1,23 @@
1
- <div class="datetime flex flex-col max-w-2xl lg:flex-row">
2
- <div class="basis-1/2 flex flex-col flex-wrap mb-4 lg:mb-0 lg:mr-2">
3
- <div class="font-medium mb-2 text-gray-500 text-sm dark:text-gray-400">
1
+ <div class="datetime flex flex-col gap-2 max-w-2xl lg:flex-row group-[.field-row]:flex-row group-[.field-row]:items-center">
2
+ <div class="basis-1/2 flex flex-col flex-wrap mb-4 lg:mb-0 group-[.field-row]:flex-row group-[.field-row]:gap-2">
3
+ <div class="font-medium mb-2 text-gray-500 text-sm dark:text-gray-400 group-[.field-row]:mb-0 group-[.field-row]:flex group-[.field-row]:items-center">
4
4
  {{ date_label }}
5
5
  </div>
6
6
 
7
7
  {% with widget=widget.subwidgets.0 %}
8
- <div class="flex flex-col relative">
8
+ <div class="flex flex-col relative group-[.field-row]:flex-grow">
9
9
  {% include widget.template_name %}
10
10
  </div>
11
11
  {% endwith %}
12
12
  </div>
13
13
 
14
- <div class="basis-1/2 flex flex-col flex-wrap lg:ml-auto mt-3 md:mt-0">
15
- <div class="font-medium mb-2 text-gray-500 text-sm dark:text-gray-400">
14
+ <div class="basis-1/2 flex flex-col flex-wrap lg:ml-auto mt-3 md:mt-0 group-[.field-row]:flex-row group-[.field-row]:gap-2">
15
+ <div class="font-medium mb-2 text-gray-500 text-sm dark:text-gray-400 group-[.field-row]:mb-0 group-[.field-row]:flex group-[.field-row]:items-center">
16
16
  {{ time_label }}
17
17
  </div>
18
18
 
19
19
  {% with widget=widget.subwidgets.1 %}
20
- <div class="flex flex-col relative">
20
+ <div class="flex flex-col relative group-[.field-row]:flex-grow">
21
21
  {% include widget.template_name %}
22
22
  </div>
23
23
  {% endwith %}
unfold/utils.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import datetime
2
2
  import decimal
3
3
  import json
4
- from typing import Any, Iterable, List
4
+ from typing import Any, Iterable, List, Optional
5
5
 
6
6
  from django.db import models
7
7
  from django.template.loader import render_to_string
@@ -121,3 +121,23 @@ def hex_to_rgb(hex_color: str) -> List[int]:
121
121
  b = int(hex_color[4:6], 16)
122
122
 
123
123
  return (r, g, b)
124
+
125
+
126
+ def prettify_json(data: Any) -> Optional[str]:
127
+ try:
128
+ from pygments import highlight
129
+ from pygments.formatters import HtmlFormatter
130
+ from pygments.lexers import JsonLexer
131
+ except ImportError:
132
+ return None
133
+
134
+ def format_response(response: str, theme: str) -> str:
135
+ formatter = HtmlFormatter(style=theme, noclasses=True, nobackground=True)
136
+ return highlight(response, JsonLexer(), formatter)
137
+
138
+ response = json.dumps(data, sort_keys=True, indent=4)
139
+
140
+ return mark_safe(
141
+ f'<div class="block dark:hidden">{format_response(response, "colorful")}</div>'
142
+ f'<div class="hidden dark:block">{format_response(response, "monokai")}</div>'
143
+ )
unfold/views.py CHANGED
@@ -10,13 +10,25 @@ class UnfoldModelAdminViewMixin(PermissionRequiredMixin):
10
10
  Prepares views to be displayed in admin
11
11
  """
12
12
 
13
- def get_context_data(self, **kwargs) -> Dict[str, Any]:
14
- if "model_admin" not in self.kwargs:
13
+ model_admin = None
14
+
15
+ def __init__(self, model_admin, **kwargs):
16
+ self.model_admin = model_admin
17
+ super().__init__(**kwargs)
18
+
19
+ def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
20
+ if not hasattr(self, "model_admin"):
15
21
  raise UnfoldException(
16
22
  "UnfoldModelAdminViewMixin was not provided with 'model_admin' argument"
17
23
  )
18
- model_admin = self.kwargs["model_admin"]
19
- context_data = super().get_context_data(
20
- **kwargs, **model_admin.admin_site.each_context(self.request)
24
+
25
+ if not hasattr(self, "title"):
26
+ raise UnfoldException(
27
+ "UnfoldModelAdminViewMixin was not provided with 'title' attribute"
28
+ )
29
+
30
+ return super().get_context_data(
31
+ **kwargs,
32
+ **self.model_admin.admin_site.each_context(self.request),
33
+ **{"title": self.title},
21
34
  )
22
- return context_data
unfold/widgets.py CHANGED
@@ -288,7 +288,18 @@ class FileFieldMixin:
288
288
  def get_context(self, name, value, attrs):
289
289
  widget = super().get_context(name, value, attrs)
290
290
  widget["widget"].update(
291
- {"class": " ".join([*CHECKBOX_CLASSES, *["form-check-input"]])}
291
+ {
292
+ "class": " ".join([*CHECKBOX_CLASSES, *["form-check-input"]]),
293
+ "file_input_class": " ".join(
294
+ [
295
+ self.attrs.get("class", ""),
296
+ *[
297
+ "opacity-0",
298
+ "pointer-events-none",
299
+ ],
300
+ ]
301
+ ),
302
+ }
292
303
  )
293
304
  return widget
294
305