django-unfold 0.30.0__py3-none-any.whl → 0.32.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. {django_unfold-0.30.0.dist-info → django_unfold-0.32.0.dist-info}/METADATA +101 -31
  2. {django_unfold-0.30.0.dist-info → django_unfold-0.32.0.dist-info}/RECORD +76 -73
  3. unfold/admin.py +30 -11
  4. unfold/contrib/filters/templates/unfold/filters/filters_numeric_slider.html +3 -3
  5. unfold/contrib/forms/templates/unfold/forms/array.html +3 -1
  6. unfold/contrib/forms/templates/unfold/forms/helpers/toolbar.html +6 -6
  7. unfold/contrib/forms/templates/unfold/forms/wysiwyg.html +1 -1
  8. unfold/contrib/forms/widgets.py +22 -11
  9. unfold/contrib/guardian/templates/unfold/guardian/group_form.html +4 -4
  10. unfold/contrib/guardian/templates/unfold/guardian/user_form.html +4 -4
  11. unfold/contrib/import_export/templates/admin/import_export/change_form.html +1 -1
  12. unfold/contrib/import_export/templates/admin/import_export/import_errors.html +1 -1
  13. unfold/contrib/import_export/templates/admin/import_export/import_preview.html +3 -3
  14. unfold/contrib/import_export/templates/admin/import_export/import_validation.html +4 -4
  15. unfold/contrib/inlines/forms.py +1 -2
  16. unfold/contrib/simple_history/templates/simple_history/object_history_list.html +9 -9
  17. unfold/contrib/simple_history/templates/simple_history/submit_line.html +1 -1
  18. unfold/dataclasses.py +10 -1
  19. unfold/fields.py +1 -1
  20. unfold/settings.py +1 -0
  21. unfold/sites.py +39 -15
  22. unfold/static/unfold/css/styles.css +1 -1
  23. unfold/static/unfold/js/alpine.anchor.js +1 -0
  24. unfold/static/unfold/js/alpine.js +2 -2
  25. unfold/static/unfold/js/alpine.persist.js +1 -1
  26. unfold/static/unfold/js/app.js +26 -3
  27. unfold/styles.css +10 -10
  28. unfold/templates/admin/actions.html +1 -1
  29. unfold/templates/admin/app_list.html +1 -1
  30. unfold/templates/admin/base.html +4 -4
  31. unfold/templates/admin/change_list.html +2 -2
  32. unfold/templates/admin/change_list_results.html +2 -2
  33. unfold/templates/admin/delete_confirmation.html +4 -4
  34. unfold/templates/admin/delete_selected_confirmation.html +4 -4
  35. unfold/templates/admin/edit_inline/stacked.html +2 -2
  36. unfold/templates/admin/edit_inline/tabular.html +3 -3
  37. unfold/templates/admin/filter.html +2 -2
  38. unfold/templates/admin/includes/fieldset.html +1 -1
  39. unfold/templates/admin/includes/object_delete_summary.html +1 -1
  40. unfold/templates/admin/login.html +8 -8
  41. unfold/templates/admin/object_history.html +4 -4
  42. unfold/templates/admin/search_form.html +1 -1
  43. unfold/templates/admin/submit_line.html +7 -5
  44. unfold/templates/auth/widgets/read_only_password_hash.html +1 -1
  45. unfold/templates/registration/logged_out.html +1 -1
  46. unfold/templates/unfold/change_list_filter.html +9 -1
  47. unfold/templates/unfold/components/card.html +7 -3
  48. unfold/templates/unfold/components/icon.html +1 -0
  49. unfold/templates/unfold/components/separator.html +1 -1
  50. unfold/templates/unfold/components/table.html +31 -0
  51. unfold/templates/unfold/helpers/account_links.html +2 -2
  52. unfold/templates/unfold/helpers/actions_row.html +4 -4
  53. unfold/templates/unfold/helpers/app_list.html +48 -38
  54. unfold/templates/unfold/helpers/app_list_default.html +4 -4
  55. unfold/templates/unfold/helpers/breadcrumb_item.html +1 -1
  56. unfold/templates/unfold/helpers/field_readonly_value.html +1 -1
  57. unfold/templates/unfold/helpers/fieldset_row.html +6 -6
  58. unfold/templates/unfold/helpers/fieldsets_tabs.html +2 -2
  59. unfold/templates/unfold/helpers/header.html +1 -1
  60. unfold/templates/unfold/helpers/help_text.html +1 -1
  61. unfold/templates/unfold/helpers/history.html +1 -1
  62. unfold/templates/unfold/helpers/label.html +2 -3
  63. unfold/templates/unfold/helpers/search.html +7 -4
  64. unfold/templates/unfold/helpers/search_results.html +2 -2
  65. unfold/templates/unfold/helpers/tab_action.html +1 -1
  66. unfold/templates/unfold/helpers/tab_list.html +27 -5
  67. unfold/templates/unfold/helpers/theme_switch.html +2 -2
  68. unfold/templates/unfold/layouts/skeleton.html +6 -1
  69. unfold/templates/unfold/widgets/clearable_file_input.html +14 -6
  70. unfold/templates/unfold/widgets/clearable_file_input_small.html +4 -4
  71. unfold/templates/unfold/widgets/split_datetime.html +2 -2
  72. unfold/templatetags/unfold.py +33 -12
  73. unfold/templatetags/unfold_list.py +16 -6
  74. unfold/widgets.py +2 -2
  75. {django_unfold-0.30.0.dist-info → django_unfold-0.32.0.dist-info}/LICENSE.md +0 -0
  76. {django_unfold-0.30.0.dist-info → django_unfold-0.32.0.dist-info}/WHEEL +0 -0
unfold/admin.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import copy
2
2
  from functools import update_wrapper
3
- from typing import Any, Callable, Dict, List, Optional, Tuple
3
+ from typing import Any, Callable, Dict, List, Optional, Tuple, Union
4
4
 
5
5
  from django import forms
6
6
  from django.contrib.admin import ModelAdmin as BaseModelAdmin
@@ -148,6 +148,7 @@ class ModelAdminMixin:
148
148
  else:
149
149
  kwargs["widget"] = UnfoldAdminSelectWidget()
150
150
 
151
+ if "choices" not in kwargs:
151
152
  kwargs["choices"] = db_field.get_choices(
152
153
  include_blank=db_field.blank, blank_choice=[("", _("Select value"))]
153
154
  )
@@ -229,6 +230,7 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
229
230
  add_fieldsets = ()
230
231
  list_horizontal_scrollbar_top = False
231
232
  list_filter_submit = False
233
+ list_fullwidth = False
232
234
  compressed_fields = False
233
235
  readonly_preprocess_fields = {}
234
236
  checks_class = UnfoldModelAdminChecks
@@ -255,7 +257,10 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
255
257
  return super().get_fieldsets(request, obj)
256
258
 
257
259
  def _filter_unfold_actions_by_permissions(
258
- self, request: HttpRequest, actions: List[UnfoldAction]
260
+ self,
261
+ request: HttpRequest,
262
+ actions: List[UnfoldAction],
263
+ object_id: Optional[Union[int, str]] = None,
259
264
  ) -> List[UnfoldAction]:
260
265
  """Filter out any Unfold actions that the user doesn't have access to."""
261
266
  filtered_actions = []
@@ -263,12 +268,22 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
263
268
  if not hasattr(action.method, "allowed_permissions"):
264
269
  filtered_actions.append(action)
265
270
  continue
271
+
266
272
  permission_checks = (
267
273
  getattr(self, f"has_{permission}_permission")
268
274
  for permission in action.method.allowed_permissions
269
275
  )
270
- if any(has_permission(request) for has_permission in permission_checks):
271
- filtered_actions.append(action)
276
+
277
+ if object_id:
278
+ if any(
279
+ has_permission(request, object_id)
280
+ for has_permission in permission_checks
281
+ ):
282
+ filtered_actions.append(action)
283
+ else:
284
+ if any(has_permission(request) for has_permission in permission_checks):
285
+ filtered_actions.append(action)
286
+
272
287
  return filtered_actions
273
288
 
274
289
  def get_actions_list(self, request: HttpRequest) -> List[UnfoldAction]:
@@ -282,9 +297,11 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
282
297
  """
283
298
  return [self.get_unfold_action(action) for action in self.actions_list or []]
284
299
 
285
- def get_actions_detail(self, request: HttpRequest) -> List[UnfoldAction]:
300
+ def get_actions_detail(
301
+ self, request: HttpRequest, object_id: int
302
+ ) -> List[UnfoldAction]:
286
303
  return self._filter_unfold_actions_by_permissions(
287
- request, self._get_base_actions_detail()
304
+ request, self._get_base_actions_detail(), object_id
288
305
  )
289
306
 
290
307
  def _get_base_actions_detail(self) -> List[UnfoldAction]:
@@ -304,9 +321,11 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
304
321
  """
305
322
  return [self.get_unfold_action(action) for action in self.actions_row or []]
306
323
 
307
- def get_actions_submit_line(self, request: HttpRequest) -> List[UnfoldAction]:
324
+ def get_actions_submit_line(
325
+ self, request: HttpRequest, object_id: int
326
+ ) -> List[UnfoldAction]:
308
327
  return self._filter_unfold_actions_by_permissions(
309
- request, self._get_base_actions_submit_line()
328
+ request, self._get_base_actions_submit_line(), object_id
310
329
  )
311
330
 
312
331
  def _get_base_actions_submit_line(self) -> List[UnfoldAction]:
@@ -404,7 +423,7 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
404
423
 
405
424
  actions = []
406
425
  if object_id:
407
- for action in self.get_actions_detail(request):
426
+ for action in self.get_actions_detail(request, object_id):
408
427
  actions.append(
409
428
  {
410
429
  "title": action.description,
@@ -418,7 +437,7 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
418
437
 
419
438
  extra_context.update(
420
439
  {
421
- "actions_submit_line": self.get_actions_submit_line(request),
440
+ "actions_submit_line": self.get_actions_submit_line(request, object_id),
422
441
  "actions_detail": actions,
423
442
  }
424
443
  )
@@ -485,7 +504,7 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
485
504
  ) -> None:
486
505
  super().save_model(request, obj, form, change)
487
506
 
488
- for action in self.get_actions_submit_line(request):
507
+ for action in self.get_actions_submit_line(request, obj.pk):
489
508
  if action.action_name not in request.POST:
490
509
  continue
491
510
 
@@ -9,11 +9,11 @@
9
9
 
10
10
  {% if choice.min is not None and choice.max is not None and choice.step %}
11
11
  <div class="admin-numeric-filter-slider-tooltips">
12
- <span class="admin-numeric-filter-slider-tooltip-from border cursor-not-allowed flex flex-grow flex-row items-center mr-auto rounded-md shadow-sm px-3 py-2 w-full dark:bg-gray-900 dark:border-gray-700 dark:text-gray-400">
12
+ <span class="admin-numeric-filter-slider-tooltip-from border cursor-not-allowed flex flex-grow flex-row items-center mr-auto rounded-md shadow-sm px-3 py-2 w-full dark:bg-gray-900 dark:border-gray-700 dark:text-gray-300">
13
13
  {{ choice.value_from }}
14
14
  </span>
15
15
 
16
- <span class="admin-numeric-filter-slider-tooltip-to border cursor-not-allowed flex flex-grow flex-row items-center rounded-md shadow-sm px-3 py-2 w-full dark:bg-gray-900 dark:border-gray-700 dark:text-gray-400">
16
+ <span class="admin-numeric-filter-slider-tooltip-to border cursor-not-allowed flex flex-grow flex-row items-center rounded-md shadow-sm px-3 py-2 w-full dark:bg-gray-900 dark:border-gray-700 dark:text-gray-300">
17
17
  {{ choice.value_to }}
18
18
  </span>
19
19
  </div>
@@ -25,7 +25,7 @@
25
25
  {{ choice.form.as_p }}
26
26
  </div>
27
27
  {% else %}
28
- <div class="admin-numeric-filter-slider-error dark:text-gray-400">
28
+ <div class="admin-numeric-filter-slider-error dark:text-gray-300">
29
29
  <p>
30
30
  {% trans 'Not enough data.' %}
31
31
  </p>
@@ -15,7 +15,9 @@
15
15
 
16
16
  <template x-for="(item, index) in items" :key="item.key">
17
17
  <div class="flex flex-row">
18
- {% include template.template_name with widget=template %}
18
+ {% with widget=template %}
19
+ {% include template.template_name %}
20
+ {% endwith %}
19
21
 
20
22
  <a x-on:click="items.splice(index, 1)" class="bg-white border cursor-pointer flex items-center h-9.5 justify-center ml-2 rounded shadow-sm shrink-0 text-red-600 text-sm w-9.5 dark:bg-gray-900 dark:border-gray-700 dark:text-red-500">
21
23
  <span class="material-symbols-outlined text-sm">delete</span>
@@ -2,7 +2,7 @@
2
2
 
3
3
  <template id="trix-toolbar">
4
4
  <div class="bg-gray-50 flex flex-row flex-wrap border group-[.errors]:border-t-red-600 gap-4 group-[.errors]:border-x-red-600 px-3 py-2 relative rounded-t-md shadow-sm w-full dark:bg-white/[.02] dark:border-gray-700 dark:group-[.errors]:border-t-red-500 dark:group-[.errors]:border-x-red-500">
5
- <div data-trix-button-group="text-tools" class="bg-white border border-md flex flex-row rounded-md shadow-sm shrink-0 dark:bg-gray-900 dark:border-gray-700 dark:text-gray-400">
5
+ <div data-trix-button-group="text-tools" class="bg-white border border-md flex flex-row rounded-md shadow-sm shrink-0 dark:bg-gray-900 dark:border-gray-700 dark:text-gray-300">
6
6
  {% spaceless %}
7
7
  <button type="button" data-trix-attribute="p" data-trix-key="p" title="{% trans "Paragraph" %}" tabindex="-1" class="border-r cursor-pointer flex items-center h-8 justify-center transition-colors w-8 hover:text-primary-600 dark:border-gray-700">
8
8
  <span class="material-symbols-outlined">format_paragraph</span>
@@ -30,7 +30,7 @@
30
30
  {% endspaceless %}
31
31
  </div>
32
32
 
33
- <div data-trix-button-group="block-headings" class="bg-white border border-md flex flex-row rounded-md shadow-sm dark:bg-gray-900 dark:border-gray-700 dark:text-gray-400">
33
+ <div data-trix-button-group="block-headings" class="bg-white border border-md flex flex-row rounded-md shadow-sm dark:bg-gray-900 dark:border-gray-700 dark:text-gray-300">
34
34
  {% spaceless %}
35
35
  <button type="button" data-trix-attribute="heading1" title="{% trans "Heading" %} 1" tabindex="-1" class="border-r cursor-pointer flex items-center h-8 justify-center transition-colors w-8 hover:text-primary-600 dark:border-gray-700">
36
36
  <span class="material-symbols-outlined">format_h1</span>
@@ -50,7 +50,7 @@
50
50
  {% endspaceless %}
51
51
  </div>
52
52
 
53
- <div data-trix-button-group="block-tools" class="bg-white border border-md flex flex-row rounded-md shadow-sm dark:bg-gray-900 dark:border-gray-700 dark:text-gray-400">
53
+ <div data-trix-button-group="block-tools" class="bg-white border border-md flex flex-row rounded-md shadow-sm dark:bg-gray-900 dark:border-gray-700 dark:text-gray-300">
54
54
  {% spaceless %}
55
55
  <button type="button" data-trix-attribute="quote" title="{% trans "Quote" %}" tabindex="-1" class="border-r cursor-pointer flex items-center h-8 justify-center transition-colors w-8 hover:text-primary-600 dark:border-gray-700">
56
56
  <span class="material-symbols-outlined">format_quote</span>
@@ -79,7 +79,7 @@
79
79
  </div>
80
80
 
81
81
  <div class="lg:ml-auto">
82
- <div data-trix-button-group="history-tools" class="bg-white border border-md flex flex-row rounded-md shadow-sm dark:bg-gray-900 dark:border-gray-700 dark:text-gray-400">
82
+ <div data-trix-button-group="history-tools" class="bg-white border border-md flex flex-row rounded-md shadow-sm dark:bg-gray-900 dark:border-gray-700 dark:text-gray-300">
83
83
  <button type="button" data-trix-action="undo" data-trix-key="z" title="{% trans "Undo" %}" tabindex="-1" class="border-r cursor-pointer flex items-center h-8 justify-center transition-colors w-8 hover:text-primary-600 dark:border-gray-700">
84
84
  <span class="material-symbols-outlined">undo</span>
85
85
  </button>
@@ -92,9 +92,9 @@
92
92
  <div data-trix-dialogs>
93
93
  <div class="absolute bg-white border-b -bottom-px left-0 px-4 py-2 right-0 shadow-sm translate-y-full dark:bg-gray-900 dark:border-gray-700" data-trix-dialog="href" data-trix-dialog-attribute="href">
94
94
  <div class="flex flex-row">
95
- <input type="url" name="href" class="border bg-white font-medium px-3 rounded-md shadow-sm text-gray-500 text-sm focus:ring focus:ring-primary-300 focus:border-primary-600 focus:outline-none group-[.errors]:border-red-600 group-[.errors]:focus:ring-red-200 dark:bg-gray-900 dark:border-gray-700 dark:text-gray-400 dark:focus:ring-primary-600/30 dark:group-[.errors]:border-red-500 dark:group-[.errors]:focus:ring-red-600/40" placeholder="{% trans "Enter an URL" %}" required data-trix-input>
95
+ <input type="url" name="href" class="border bg-white font-medium px-3 rounded-md shadow-sm text-gray-500 text-sm focus:ring focus:ring-primary-300 focus:border-primary-600 focus:outline-none group-[.errors]:border-red-600 group-[.errors]:focus:ring-red-200 dark:bg-gray-900 dark:border-gray-700 dark:text-gray-300 dark:focus:ring-primary-600/30 dark:group-[.errors]:border-red-500 dark:group-[.errors]:focus:ring-red-600/40" placeholder="{% trans "Enter an URL" %}" required data-trix-input>
96
96
 
97
- <div class="bg-white border border-md flex flex-row ml-4 rounded-md shadow-sm dark:bg-gray-900 dark:border-gray-700 dark:text-gray-400">
97
+ <div class="bg-white border border-md flex flex-row ml-4 rounded-md shadow-sm dark:bg-gray-900 dark:border-gray-700 dark:text-gray-300">
98
98
  <button type="button" data-trix-method="setAttribute" title="{% trans "Link" %}" class="border-r cursor-pointer flex items-center h-8 justify-center text-gray-400 transition-colors w-8 hover:text-primary-600 dark:border-gray-700">
99
99
  <span class="material-symbols-outlined">link</span>
100
100
  </button>
@@ -1,6 +1,6 @@
1
1
  {% include "unfold/forms/helpers/toolbar.html" %}
2
2
 
3
- <input type="hidden" name="{{ widget.name }}" id="wysiwyg-{{ widget.name }}"{% if widget.value != None %} value="{{ widget.value }}"{% endif %}>
3
+ <input type="hidden" name="{{ widget.name }}" id="wysiwyg-{{ widget.name }}"{% if widget.value != None %} value="{{ widget.value }}"{% endif %} {% include "django/forms/widgets/attrs.html" %}>
4
4
 
5
5
  <div class="max-w-4xl relative">
6
6
  <trix-editor input="wysiwyg-{{ widget.name }}" {% include "django/forms/widgets/attrs.html" %}></trix-editor>
@@ -4,7 +4,11 @@ from django.core.validators import EMPTY_VALUES
4
4
  from django.forms import MultiWidget, Widget
5
5
  from django.http import QueryDict
6
6
  from django.utils.datastructures import MultiValueDict
7
- from unfold.widgets import PROSE_CLASSES, UnfoldAdminTextInputWidget
7
+ from unfold.widgets import (
8
+ PROSE_CLASSES,
9
+ UnfoldAdminSelectWidget,
10
+ UnfoldAdminTextInputWidget,
11
+ )
8
12
 
9
13
  WYSIWYG_CLASSES = [
10
14
  *PROSE_CLASSES,
@@ -20,26 +24,33 @@ WYSIWYG_CLASSES = [
20
24
  "w-full",
21
25
  "focus:outline-none",
22
26
  "dark:border-gray-700",
23
- "dark:text-gray-400",
27
+ "dark:text-gray-300",
24
28
  "dark:group-[.errors]:border-red-500",
25
29
  ]
26
30
 
27
31
 
28
32
  class ArrayWidget(MultiWidget):
29
33
  template_name = "unfold/forms/array.html"
30
- widget_class = UnfoldAdminTextInputWidget
31
34
 
32
35
  def __init__(self, *args: Any, **kwargs: Any) -> None:
33
- widgets = [self.widget_class]
36
+ if "choices" in kwargs:
37
+ self.choices = kwargs["choices"]
38
+
39
+ widgets = [self.get_widget_instance()]
34
40
  super().__init__(widgets)
35
41
 
42
+ def get_widget_instance(self) -> Any:
43
+ if hasattr(self, "choices"):
44
+ return UnfoldAdminSelectWidget(choices=self.choices)
45
+
46
+ return UnfoldAdminTextInputWidget()
47
+
36
48
  def get_context(self, name: str, value: str, attrs: Dict) -> Dict:
37
49
  self._resolve_widgets(value)
38
50
  context = super().get_context(name, value, attrs)
39
- template_widget = UnfoldAdminTextInputWidget()
40
- template_widget.name = name
41
-
42
- context.update({"template": template_widget})
51
+ context.update(
52
+ {"template": self.get_widget_instance().get_context(name, "", {})["widget"]}
53
+ )
43
54
  return context
44
55
 
45
56
  def value_from_datadict(
@@ -71,12 +82,12 @@ class ArrayWidget(MultiWidget):
71
82
  value = []
72
83
 
73
84
  elif isinstance(value, List):
74
- self.widgets = [self.widget_class for item in value]
85
+ self.widgets = [self.get_widget_instance() for item in value]
75
86
  else:
76
- self.widgets = [self.widget_class for item in value.split(",")]
87
+ self.widgets = [self.get_widget_instance() for item in value.split(",")]
77
88
 
78
89
  self.widgets_names = ["" for i in range(len(self.widgets))]
79
- self.widgets = [w() if isinstance(w, type) else w for w in self.widgets]
90
+ self.widgets = [w if isinstance(w, type) else w for w in self.widgets]
80
91
 
81
92
 
82
93
  class WysiwygWidget(Widget):
@@ -8,7 +8,7 @@
8
8
  </h2>
9
9
 
10
10
  {% if groups_perms.items %}
11
- <table id="group-permissions" class="border-gray-200 border-spacing-none border-separate mb-6 text-gray-700 w-full dark:text-gray-400 lg:border lg:rounded-md lg:shadow-sm lg:dark:border-gray-800">
11
+ <table id="group-permissions" class="border-gray-200 border-spacing-none border-separate mb-6 text-gray-700 w-full dark:text-gray-300 lg:border lg:rounded-md lg:shadow-sm lg:dark:border-gray-800">
12
12
  <thead class="hidden lg:table-header-group">
13
13
  <tr>
14
14
  <th class="align-middle font-medium px-3 py-2 text-left text-gray-400 text-sm">
@@ -30,14 +30,14 @@
30
30
  <tbody>
31
31
  {% for group, group_perms in groups_perms.items %}
32
32
  <tr class="block border mb-3 rounded-md shadow-sm lg:table-row lg:border-none lg:mb-0 lg:shadow-none dark:border-gray-800">
33
- <th class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans "User" %}">
33
+ <th class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-300 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans "User" %}">
34
34
  <span class="text-gray-700 dark:text-gray-200">
35
35
  {{ group }}
36
36
  </span>
37
37
  </th>
38
38
 
39
39
  {% for perm in model_perms %}
40
- <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{{ perm.name }}">
40
+ <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-300 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{{ perm.name }}">
41
41
  {% if perm.codename in group_perms %}
42
42
  {% include "unfold/helpers/boolean.html" with value=False %}
43
43
  {% else %}
@@ -46,7 +46,7 @@
46
46
  </td>
47
47
  {% endfor %}
48
48
 
49
- <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-right text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans "Action" %}">
49
+ <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-right text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-300 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans "Action" %}">
50
50
  <a href="group-manage/{{ group.id|safe }}/" class="hover:text-gray-700 dark:hover:text-white">
51
51
  {% trans "Edit" %}
52
52
  </a>
@@ -8,7 +8,7 @@
8
8
  </h2>
9
9
 
10
10
  {% if users_perms.items %}
11
- <table id="user-permissions" class="border-gray-200 border-spacing-none border-separate mb-6 text-gray-700 w-full dark:text-gray-400 lg:border lg:rounded-md lg:shadow-sm lg:dark:border-gray-800">
11
+ <table id="user-permissions" class="border-gray-200 border-spacing-none border-separate mb-6 text-gray-700 w-full dark:text-gray-300 lg:border lg:rounded-md lg:shadow-sm lg:dark:border-gray-800">
12
12
  <thead class="hidden lg:table-header-group">
13
13
  <tr>
14
14
  <th class="align-middle font-medium px-3 py-2 text-left text-gray-400 text-sm">
@@ -30,14 +30,14 @@
30
30
  <tbody>
31
31
  {% for user, user_perms in users_perms.items %}
32
32
  <tr class="block border mb-3 rounded-md shadow-sm lg:table-row lg:border-none lg:mb-0 lg:shadow-none dark:border-gray-800">
33
- <th class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans "User" %}">
33
+ <th class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-300 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans "User" %}">
34
34
  <span class="text-gray-700 dark:text-gray-200">
35
35
  {{ user }}
36
36
  </span>
37
37
  </th>
38
38
 
39
39
  {% for perm in model_perms %}
40
- <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{{ perm.name }}">
40
+ <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-300 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{{ perm.name }}">
41
41
  {% if perm.codename in group_perms %}
42
42
  {% include "unfold/helpers/boolean.html" with value=False %}
43
43
  {% else %}
@@ -46,7 +46,7 @@
46
46
  </td>
47
47
  {% endfor %}
48
48
 
49
- <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-right text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans "Action" %}">
49
+ <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-right text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-300 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans "Action" %}">
50
50
  <a href="user-manage/{{ user.id|safe }}/" class="hover:text-gray-700 dark:hover:text-white">
51
51
  {% trans "Edit" %}
52
52
  </a>
@@ -5,6 +5,6 @@
5
5
  {{ block.super }}
6
6
 
7
7
  {% if show_change_form_export %}
8
- <input type="submit" value="{% translate 'Export' %}" name="_export-item" class="bg-white text-gray-500 border cursor-pointer flex font-medium items-center px-3 py-2 mr-3 rounded-md shadow-sm text-sm dark:bg-gray-900 dark:border dark:border-gray-700 dark:text-gray-400">
8
+ <input type="submit" value="{% translate 'Export' %}" name="_export-item" class="bg-white text-gray-500 border cursor-pointer flex font-medium items-center px-3 py-2 mr-3 rounded-md shadow-sm text-sm dark:bg-gray-900 dark:border dark:border-gray-700 dark:text-gray-300">
9
9
  {% endif %}
10
10
  {% endblock %}
@@ -26,7 +26,7 @@
26
26
  </div>
27
27
  </div>
28
28
 
29
- <div class="block border leading-relaxed rounded p-4 text-sm traceback dark:border-gray-800 dark:text-gray-400 " x-show="open">
29
+ <div class="block border leading-relaxed rounded p-4 text-sm traceback dark:border-gray-800 dark:text-gray-300 " x-show="open">
30
30
  {{ error.traceback|linebreaks }}
31
31
  </div>
32
32
  </li>
@@ -1,7 +1,7 @@
1
1
  {% load admin_urls i18n import_export_tags unfold %}
2
2
 
3
3
  {% block preview %}
4
- <table class="border-gray-200 border-spacing-none border-separate text-gray-700 w-full dark:text-gray-400 lg:border lg:rounded-md lg:shadow-sm lg:dark:border-gray-800">
4
+ <table class="border-gray-200 border-spacing-none border-separate text-gray-700 w-full dark:text-gray-300 lg:border lg:rounded-md lg:shadow-sm lg:dark:border-gray-800">
5
5
  <thead class="hidden lg:table-header-group">
6
6
  <tr>
7
7
  <th class="align-middle capitalize font-medium px-3 py-2 text-left text-gray-400 text-sm"></th>
@@ -17,7 +17,7 @@
17
17
  <tbody>
18
18
  {% for row in result.valid_rows %}
19
19
  <tr class="{{ row.import_type }} {% cycle '' 'bg-gray-50 dark:bg-white/[.02]' %} block border mb-3 rounded-md shadow-sm lg:table-row lg:border-none lg:mb-0 lg:shadow-none dark:border-gray-800">
20
- <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:block before:capitalize before:content-[attr(data-label)] before:mr-auto before:text-gray-500 dark:before:text-gray-400 lg:before:hidden lg:py-3 lg:table-cell dark:border-gray-800">
20
+ <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:block before:capitalize before:content-[attr(data-label)] before:mr-auto before:text-gray-500 dark:before:text-gray-300 lg:before:hidden lg:py-3 lg:table-cell dark:border-gray-800">
21
21
  {% if row.import_type == 'new' %}
22
22
  {% trans "New" %}
23
23
  {% elif row.import_type == 'skip' %}
@@ -30,7 +30,7 @@
30
30
  </td>
31
31
 
32
32
  {% for field in row.diff %}
33
- <td data-label="{{ result.diff_headers|index:forloop.counter0 }}" class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:block before:capitalize before:content-[attr(data-label)] before:mr-auto before:text-gray-500 dark:before:text-gray-400 lg:before:hidden lg:py-3 lg:table-cell dark:border-gray-800">
33
+ <td data-label="{{ result.diff_headers|index:forloop.counter0 }}" class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:block before:capitalize before:content-[attr(data-label)] before:mr-auto before:text-gray-500 dark:before:text-gray-300 lg:before:hidden lg:py-3 lg:table-cell dark:border-gray-800">
34
34
  {{ field }}
35
35
  </td>
36
36
  {% endfor %}
@@ -15,7 +15,7 @@
15
15
  </div>
16
16
  </div>
17
17
 
18
- <table class="border-gray-200 border-spacing-none border-separate text-gray-700 w-full dark:text-gray-400 lg:border lg:rounded-md lg:shadow-sm lg:dark:border-gray-800">
18
+ <table class="border-gray-200 border-spacing-none border-separate text-gray-700 w-full dark:text-gray-300 lg:border lg:rounded-md lg:shadow-sm lg:dark:border-gray-800">
19
19
  <thead class="hidden lg:table-header-group">
20
20
  <tr>
21
21
  <th class="align-middle capitalize font-medium px-3 py-2 text-left text-gray-400 text-sm">
@@ -37,11 +37,11 @@
37
37
  <tbody>
38
38
  {% for row in result.invalid_rows %}
39
39
  <tr class="{% cycle '' 'bg-gray-50 dark:bg-white/[.02]' %} block border mb-3 rounded-md shadow-sm lg:table-row lg:border-none lg:mb-0 lg:shadow-none dark:border-gray-800">
40
- <td data-label="{% trans "Row" %}" class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:block before:capitalize before:content-[attr(data-label)] before:mr-auto before:text-gray-500 dark:before:text-gray-400 lg:before:hidden lg:py-3 lg:table-cell dark:border-gray-800">
40
+ <td data-label="{% trans "Row" %}" class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:block before:capitalize before:content-[attr(data-label)] before:mr-auto before:text-gray-500 dark:before:text-gray-300 lg:before:hidden lg:py-3 lg:table-cell dark:border-gray-800">
41
41
  {{ row.number }}
42
42
  </td>
43
43
 
44
- <td data-label="{% trans "Errors" %}" class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:block before:capitalize before:content-[attr(data-label)] before:mr-auto before:text-gray-500 dark:before:text-gray-400 lg:before:hidden lg:py-3 lg:table-cell dark:border-gray-800">
44
+ <td data-label="{% trans "Errors" %}" class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:block before:capitalize before:content-[attr(data-label)] before:mr-auto before:text-gray-500 dark:before:text-gray-300 lg:before:hidden lg:py-3 lg:table-cell dark:border-gray-800">
45
45
  <div>
46
46
  <span class="bg-red-600 font-semibold ml-2 px-1 rounded-sm text-xs text-white">{{ row.error_count }}</span>
47
47
  </div>
@@ -77,7 +77,7 @@
77
77
  </td>
78
78
 
79
79
  {% for field in row.values %}
80
- <td data-label="{{ result.diff_headers|index:forloop.counter0 }}" class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:block before:capitalize before:content-[attr(data-label)] before:mr-auto before:text-gray-500 dark:before:text-gray-400 lg:before:hidden lg:py-3 lg:table-cell dark:border-gray-800">
80
+ <td data-label="{{ result.diff_headers|index:forloop.counter0 }}" class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:block before:capitalize before:content-[attr(data-label)] before:mr-auto before:text-gray-500 dark:before:text-gray-300 lg:before:hidden lg:py-3 lg:table-cell dark:border-gray-800">
81
81
  {{ field }}
82
82
  </td>
83
83
  {% endfor %}
@@ -12,9 +12,8 @@ class NonrelatedInlineModelFormSet(BaseModelFormSet):
12
12
  **kwargs: Any,
13
13
  ) -> None:
14
14
  self.instance = instance
15
- self.queryset = self.provided_queryset
16
-
17
15
  super().__init__(**kwargs)
16
+ self.queryset = self.provided_queryset
18
17
 
19
18
  @classmethod
20
19
  def get_default_prefix(cls: BaseModelFormSet) -> str:
@@ -3,7 +3,7 @@
3
3
  {% load admin_urls %}
4
4
  {% load getattribute from getattributes %}
5
5
 
6
- <table id="change-history" class="border-gray-200 border-spacing-none border-separate mb-6 text-gray-700 w-full dark:text-gray-400 lg:border lg:rounded-md lg:shadow-sm lg:dark:border-gray-800">
6
+ <table id="change-history" class="border-gray-200 border-spacing-none border-separate mb-6 text-gray-700 w-full dark:text-gray-300 lg:border lg:rounded-md lg:shadow-sm lg:dark:border-gray-800">
7
7
  <thead class="hidden lg:table-header-group">
8
8
  <tr>
9
9
  <th class="align-middle font-medium px-3 py-2 text-left text-gray-400 text-sm">
@@ -41,27 +41,27 @@
41
41
  <tbody>
42
42
  {% for record in historical_records %}
43
43
  <tr class="block border mb-3 rounded-md shadow-sm lg:table-row lg:border-none lg:mb-0 lg:shadow-none dark:border-gray-800">
44
- <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Object' %}">
44
+ <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-300 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Object' %}">
45
45
  <a href="{% url opts|admin_urlname:'simple_history' object.pk record.pk %}">
46
46
  {{ record.history_object }}
47
47
  </a>
48
48
  </td>
49
49
 
50
50
  {% for column in history_list_display %}
51
- <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans column %}">
51
+ <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-300 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans column %}">
52
52
  {{ record|getattribute:column }}
53
53
  </th>
54
54
  {% endfor %}
55
55
 
56
- <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Date/time' %}">
56
+ <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-300 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Date/time' %}">
57
57
  {{ record.history_date }}
58
58
  </td>
59
59
 
60
- <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Comment' %}">
60
+ <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-300 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Comment' %}">
61
61
  {{ record.get_history_type_display }}
62
62
  </td>
63
63
 
64
- <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Changed by' %}">
64
+ <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-300 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Changed by' %}">
65
65
  {% if record.history_user %}
66
66
  {% url admin_user_view record.history_user_id as admin_user_url %}
67
67
 
@@ -75,11 +75,11 @@
75
75
  {% endif %}
76
76
  </td>
77
77
 
78
- <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Change reason' %}">
78
+ <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-300 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Change reason' %}">
79
79
  {{ record.history_change_reason }}
80
80
  </td>
81
81
 
82
- <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Changes' %}">
82
+ <td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-300 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Changes' %}">
83
83
  {% block history_delta_changes %}
84
84
  {% if record.history_delta_changes %}
85
85
  <ul>
@@ -97,7 +97,7 @@
97
97
  {% endif %}
98
98
 
99
99
  {% if change.old and change.new %}
100
- <span class="align-text-top material-symbols-outlined md-18 text-gray-300 group-hover:text-gray-400 dark:text-gray-600">arrow_right_alt</span>
100
+ <span class="align-text-top material-symbols-outlined md-18 text-gray-300 group-hover:text-gray-300 dark:text-gray-600">arrow_right_alt</span>
101
101
  {% endif %}
102
102
 
103
103
  {% if change.new %}
@@ -16,7 +16,7 @@
16
16
  </button>
17
17
  {% endif %}
18
18
 
19
- <a href="{{ history_url }}" class="border font-medium mr-auto px-3 py-2 rounded-md text-sm text-gray-500 text-center transition-all w-full hover:bg-gray-50 lg:block lg:w-auto dark:border-gray-700 dark:text-gray-400 dark:hover:text-gray-200 dark:hover:bg-gray-900">
19
+ <a href="{{ history_url }}" class="border font-medium mr-auto px-3 py-2 rounded-md text-sm text-gray-500 text-center transition-all w-full hover:bg-gray-50 lg:block lg:w-auto dark:border-gray-700 dark:text-gray-300 dark:hover:text-gray-200 dark:hover:bg-gray-900">
20
20
  {% trans 'Close' %}
21
21
  </a>
22
22
  </div>
unfold/dataclasses.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass
2
- from typing import Dict, Optional
2
+ from typing import Callable, Dict, Optional, Union
3
3
 
4
4
  from .typing import ActionFunction
5
5
 
@@ -11,3 +11,12 @@ class UnfoldAction:
11
11
  description: str
12
12
  path: str
13
13
  attrs: Optional[Dict] = None
14
+ object_id: Optional[Union[int, str]] = None
15
+
16
+
17
+ @dataclass
18
+ class Favicon:
19
+ href: Union[str, Callable]
20
+ rel: Optional[str] = None
21
+ type: Optional[str] = None
22
+ sizes: Optional[str] = None
unfold/fields.py CHANGED
@@ -95,7 +95,7 @@ class UnfoldAdminReadonlyField(helpers.AdminReadonlyField):
95
95
  current_app=self.model_admin.admin_site.name,
96
96
  )
97
97
  return format_html(
98
- '<a href="{}" class="text-primary-600 underline whitespace-nowrap dark:text-primary-500">{}</a>',
98
+ '<a href="{}" class="text-primary-600 underline dark:text-primary-500">{}</a>',
99
99
  url,
100
100
  remote_obj,
101
101
  )
unfold/settings.py CHANGED
@@ -7,6 +7,7 @@ CONFIG_DEFAULTS = {
7
7
  "SITE_ICON": None,
8
8
  "SITE_SYMBOL": None,
9
9
  "SITE_LOGO": None,
10
+ "SITE_FAVICONS": [],
10
11
  "SHOW_HISTORY": True,
11
12
  "SHOW_VIEW_ON_SITE": True,
12
13
  "COLORS": {