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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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": {