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.
- {django_unfold-0.30.0.dist-info → django_unfold-0.32.0.dist-info}/METADATA +101 -31
- {django_unfold-0.30.0.dist-info → django_unfold-0.32.0.dist-info}/RECORD +76 -73
- unfold/admin.py +30 -11
- unfold/contrib/filters/templates/unfold/filters/filters_numeric_slider.html +3 -3
- unfold/contrib/forms/templates/unfold/forms/array.html +3 -1
- unfold/contrib/forms/templates/unfold/forms/helpers/toolbar.html +6 -6
- unfold/contrib/forms/templates/unfold/forms/wysiwyg.html +1 -1
- unfold/contrib/forms/widgets.py +22 -11
- unfold/contrib/guardian/templates/unfold/guardian/group_form.html +4 -4
- unfold/contrib/guardian/templates/unfold/guardian/user_form.html +4 -4
- unfold/contrib/import_export/templates/admin/import_export/change_form.html +1 -1
- unfold/contrib/import_export/templates/admin/import_export/import_errors.html +1 -1
- unfold/contrib/import_export/templates/admin/import_export/import_preview.html +3 -3
- unfold/contrib/import_export/templates/admin/import_export/import_validation.html +4 -4
- unfold/contrib/inlines/forms.py +1 -2
- unfold/contrib/simple_history/templates/simple_history/object_history_list.html +9 -9
- unfold/contrib/simple_history/templates/simple_history/submit_line.html +1 -1
- unfold/dataclasses.py +10 -1
- unfold/fields.py +1 -1
- unfold/settings.py +1 -0
- unfold/sites.py +39 -15
- unfold/static/unfold/css/styles.css +1 -1
- unfold/static/unfold/js/alpine.anchor.js +1 -0
- unfold/static/unfold/js/alpine.js +2 -2
- unfold/static/unfold/js/alpine.persist.js +1 -1
- unfold/static/unfold/js/app.js +26 -3
- unfold/styles.css +10 -10
- unfold/templates/admin/actions.html +1 -1
- unfold/templates/admin/app_list.html +1 -1
- unfold/templates/admin/base.html +4 -4
- unfold/templates/admin/change_list.html +2 -2
- unfold/templates/admin/change_list_results.html +2 -2
- unfold/templates/admin/delete_confirmation.html +4 -4
- unfold/templates/admin/delete_selected_confirmation.html +4 -4
- unfold/templates/admin/edit_inline/stacked.html +2 -2
- unfold/templates/admin/edit_inline/tabular.html +3 -3
- unfold/templates/admin/filter.html +2 -2
- unfold/templates/admin/includes/fieldset.html +1 -1
- unfold/templates/admin/includes/object_delete_summary.html +1 -1
- unfold/templates/admin/login.html +8 -8
- unfold/templates/admin/object_history.html +4 -4
- unfold/templates/admin/search_form.html +1 -1
- unfold/templates/admin/submit_line.html +7 -5
- unfold/templates/auth/widgets/read_only_password_hash.html +1 -1
- unfold/templates/registration/logged_out.html +1 -1
- unfold/templates/unfold/change_list_filter.html +9 -1
- unfold/templates/unfold/components/card.html +7 -3
- unfold/templates/unfold/components/icon.html +1 -0
- unfold/templates/unfold/components/separator.html +1 -1
- unfold/templates/unfold/components/table.html +31 -0
- unfold/templates/unfold/helpers/account_links.html +2 -2
- unfold/templates/unfold/helpers/actions_row.html +4 -4
- unfold/templates/unfold/helpers/app_list.html +48 -38
- unfold/templates/unfold/helpers/app_list_default.html +4 -4
- unfold/templates/unfold/helpers/breadcrumb_item.html +1 -1
- unfold/templates/unfold/helpers/field_readonly_value.html +1 -1
- unfold/templates/unfold/helpers/fieldset_row.html +6 -6
- unfold/templates/unfold/helpers/fieldsets_tabs.html +2 -2
- unfold/templates/unfold/helpers/header.html +1 -1
- unfold/templates/unfold/helpers/help_text.html +1 -1
- unfold/templates/unfold/helpers/history.html +1 -1
- unfold/templates/unfold/helpers/label.html +2 -3
- unfold/templates/unfold/helpers/search.html +7 -4
- unfold/templates/unfold/helpers/search_results.html +2 -2
- unfold/templates/unfold/helpers/tab_action.html +1 -1
- unfold/templates/unfold/helpers/tab_list.html +27 -5
- unfold/templates/unfold/helpers/theme_switch.html +2 -2
- unfold/templates/unfold/layouts/skeleton.html +6 -1
- unfold/templates/unfold/widgets/clearable_file_input.html +14 -6
- unfold/templates/unfold/widgets/clearable_file_input_small.html +4 -4
- unfold/templates/unfold/widgets/split_datetime.html +2 -2
- unfold/templatetags/unfold.py +33 -12
- unfold/templatetags/unfold_list.py +16 -6
- unfold/widgets.py +2 -2
- {django_unfold-0.30.0.dist-info → django_unfold-0.32.0.dist-info}/LICENSE.md +0 -0
- {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,
|
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
|
-
|
271
|
-
|
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(
|
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(
|
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-
|
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-
|
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-
|
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
|
-
{%
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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>
|
unfold/contrib/forms/widgets.py
CHANGED
@@ -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
|
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-
|
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
|
-
|
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
|
-
|
40
|
-
|
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.
|
85
|
+
self.widgets = [self.get_widget_instance() for item in value]
|
75
86
|
else:
|
76
|
-
self.widgets = [self.
|
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
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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 %}
|
unfold/contrib/inlines/forms.py
CHANGED
@@ -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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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-
|
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
|
98
|
+
'<a href="{}" class="text-primary-600 underline dark:text-primary-500">{}</a>',
|
99
99
|
url,
|
100
100
|
remote_obj,
|
101
101
|
)
|