django-unfold 0.63.0__py3-none-any.whl → 0.64.1__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.63.0.dist-info → django_unfold-0.64.1.dist-info}/METADATA +1 -1
- {django_unfold-0.63.0.dist-info → django_unfold-0.64.1.dist-info}/RECORD +55 -51
- unfold/admin.py +1 -1
- unfold/contrib/constance/templates/admin/constance/change_list.html +0 -18
- unfold/contrib/filters/templates/unfold/filters/filters_numeric_slider.html +1 -1
- unfold/contrib/guardian/templates/admin/guardian/model/obj_perms_manage.html +0 -24
- unfold/contrib/guardian/templates/admin/guardian/model/obj_perms_manage_group.html +0 -26
- unfold/contrib/guardian/templates/admin/guardian/model/obj_perms_manage_user.html +0 -26
- unfold/contrib/import_export/templates/admin/import_export/export.html +0 -23
- unfold/contrib/import_export/templates/admin/import_export/import.html +0 -23
- unfold/contrib/simple_history/templates/simple_history/object_history_form.html +1 -33
- unfold/contrib/simple_history/templates/simple_history/object_history_list.html +0 -1
- unfold/dataclasses.py +8 -0
- unfold/settings.py +28 -22
- unfold/sites.py +120 -43
- unfold/static/unfold/css/styles.css +1 -1
- unfold/static/unfold/js/app.js +147 -9
- unfold/styles.css +32 -32
- unfold/templates/admin/app_index.html +0 -18
- unfold/templates/admin/auth/user/change_password.html +1 -26
- unfold/templates/admin/base.html +0 -16
- unfold/templates/admin/change_form.html +0 -33
- unfold/templates/admin/change_list.html +0 -19
- unfold/templates/admin/change_list_results.html +2 -2
- unfold/templates/admin/delete_confirmation.html +0 -21
- unfold/templates/admin/delete_selected_confirmation.html +0 -22
- unfold/templates/admin/index.html +0 -2
- unfold/templates/admin/object_history.html +0 -24
- unfold/templates/registration/password_change_done.html +0 -17
- unfold/templates/registration/password_change_form.html +0 -17
- unfold/templates/unfold/components/navigation.html +2 -2
- unfold/templates/unfold/components/table.html +55 -9
- unfold/templates/unfold/helpers/boolean.html +6 -6
- unfold/templates/unfold/helpers/command.html +53 -0
- unfold/templates/unfold/helpers/command_history.html +54 -0
- unfold/templates/unfold/helpers/command_results.html +50 -0
- unfold/templates/unfold/helpers/header_back_button.html +10 -2
- unfold/templates/unfold/helpers/header_title.html +11 -0
- unfold/templates/unfold/helpers/label.html +1 -1
- unfold/templates/unfold/helpers/navigation_header.html +2 -2
- unfold/templates/unfold/helpers/search.html +40 -22
- unfold/templates/unfold/helpers/search_results.html +2 -2
- unfold/templates/unfold/helpers/shortcut.html +1 -1
- unfold/templates/unfold/helpers/site_dropdown.html +1 -1
- unfold/templates/unfold/helpers/tab_items.html +15 -33
- unfold/templates/unfold/helpers/tab_list.html +1 -1
- unfold/templates/unfold/helpers/welcomemsg.html +6 -18
- unfold/templates/unfold/layouts/base_simple.html +0 -6
- unfold/templates/unfold/layouts/skeleton.html +4 -1
- unfold/templates/unfold/layouts/unauthenticated.html +0 -2
- unfold/templatetags/unfold.py +141 -0
- unfold/utils.py +29 -10
- unfold/views.py +4 -1
- {django_unfold-0.63.0.dist-info → django_unfold-0.64.1.dist-info}/LICENSE.md +0 -0
- {django_unfold-0.63.0.dist-info → django_unfold-0.64.1.dist-info}/WHEEL +0 -0
unfold/templatetags/unfold.py
CHANGED
@@ -14,7 +14,9 @@ from django.http import HttpRequest, QueryDict
|
|
14
14
|
from django.template import Context, Library, Node, RequestContext, TemplateSyntaxError
|
15
15
|
from django.template.base import NodeList, Parser, Token, token_kwargs
|
16
16
|
from django.template.loader import render_to_string
|
17
|
+
from django.urls import reverse_lazy
|
17
18
|
from django.utils.safestring import SafeText, mark_safe
|
19
|
+
from django.utils.translation import gettext_lazy as _
|
18
20
|
|
19
21
|
from unfold.components import ComponentRegistry
|
20
22
|
from unfold.dataclasses import UnfoldAction
|
@@ -603,3 +605,142 @@ def querystring_params(
|
|
603
605
|
result[query_key] = query_value
|
604
606
|
|
605
607
|
return result.urlencode()
|
608
|
+
|
609
|
+
|
610
|
+
@register.simple_tag(takes_context=True)
|
611
|
+
def header_title(context: RequestContext) -> str:
|
612
|
+
parts = []
|
613
|
+
opts = context.get("opts")
|
614
|
+
|
615
|
+
if opts:
|
616
|
+
parts.append(
|
617
|
+
{
|
618
|
+
"link": reverse_lazy("admin:app_list", args=[opts.app_label]),
|
619
|
+
"title": opts.app_config.verbose_name,
|
620
|
+
}
|
621
|
+
)
|
622
|
+
|
623
|
+
if (original := context.get("original")) and not isinstance(original, str):
|
624
|
+
parts.append(
|
625
|
+
{
|
626
|
+
"link": reverse_lazy(
|
627
|
+
f"admin:{original._meta.app_label}_{original._meta.model_name}_changelist"
|
628
|
+
),
|
629
|
+
"title": original._meta.verbose_name_plural,
|
630
|
+
}
|
631
|
+
)
|
632
|
+
|
633
|
+
parts.append(
|
634
|
+
{
|
635
|
+
"link": reverse_lazy(
|
636
|
+
f"admin:{original._meta.app_label}_{original._meta.model_name}_change",
|
637
|
+
args=[original.pk],
|
638
|
+
),
|
639
|
+
"title": original,
|
640
|
+
}
|
641
|
+
)
|
642
|
+
elif object := context.get("object"):
|
643
|
+
parts.append(
|
644
|
+
{
|
645
|
+
"link": reverse_lazy(
|
646
|
+
f"admin:{object._meta.app_label}_{object._meta.model_name}_changelist"
|
647
|
+
),
|
648
|
+
"title": object._meta.verbose_name_plural,
|
649
|
+
}
|
650
|
+
)
|
651
|
+
|
652
|
+
parts.append(
|
653
|
+
{
|
654
|
+
"link": reverse_lazy(
|
655
|
+
f"admin:{object._meta.app_label}_{object._meta.model_name}_change",
|
656
|
+
args=[object.pk],
|
657
|
+
),
|
658
|
+
"title": object,
|
659
|
+
}
|
660
|
+
)
|
661
|
+
else:
|
662
|
+
parts.append(
|
663
|
+
{
|
664
|
+
"link": reverse_lazy(
|
665
|
+
f"admin:{opts.app_label}_{opts.model_name}_changelist"
|
666
|
+
),
|
667
|
+
"title": opts.verbose_name_plural,
|
668
|
+
}
|
669
|
+
)
|
670
|
+
elif object := context.get("object"):
|
671
|
+
parts.append(
|
672
|
+
{
|
673
|
+
"link": reverse_lazy("admin:app_list", args=[object._meta.app_label]),
|
674
|
+
"title": object._meta.app_label,
|
675
|
+
}
|
676
|
+
)
|
677
|
+
|
678
|
+
parts.append(
|
679
|
+
{
|
680
|
+
"link": reverse_lazy(
|
681
|
+
f"admin:{object._meta.app_label}_{object._meta.model_name}_changelist",
|
682
|
+
),
|
683
|
+
"title": object._meta.verbose_name_plural,
|
684
|
+
}
|
685
|
+
)
|
686
|
+
|
687
|
+
parts.append(
|
688
|
+
{
|
689
|
+
"link": reverse_lazy(
|
690
|
+
f"admin:{object._meta.app_label}_{object._meta.model_name}_change",
|
691
|
+
args=[object.pk],
|
692
|
+
),
|
693
|
+
"title": object,
|
694
|
+
}
|
695
|
+
)
|
696
|
+
elif (model_admin := context.get("model_admin")) and hasattr(model_admin, "model"):
|
697
|
+
parts.append(
|
698
|
+
{
|
699
|
+
"link": reverse_lazy(
|
700
|
+
"admin:app_list", args=[model_admin.model._meta.app_label]
|
701
|
+
),
|
702
|
+
"title": model_admin.model._meta.app_label,
|
703
|
+
}
|
704
|
+
)
|
705
|
+
|
706
|
+
parts.append(
|
707
|
+
{
|
708
|
+
"link": reverse_lazy(
|
709
|
+
f"admin:{model_admin.model._meta.app_label}_{model_admin.model._meta.model_name}_changelist",
|
710
|
+
),
|
711
|
+
"title": model_admin.model._meta.verbose_name_plural,
|
712
|
+
}
|
713
|
+
)
|
714
|
+
|
715
|
+
if not opts and (content_title := context.get("content_title")):
|
716
|
+
parts.append(
|
717
|
+
{
|
718
|
+
"title": content_title,
|
719
|
+
}
|
720
|
+
)
|
721
|
+
|
722
|
+
if len(parts) == 0:
|
723
|
+
username = (
|
724
|
+
context.request.user.get_short_name() or context.request.user.get_username()
|
725
|
+
)
|
726
|
+
parts.append({"title": f"{_('Welcome')} {username}"})
|
727
|
+
|
728
|
+
return render_to_string(
|
729
|
+
"unfold/helpers/header_title.html",
|
730
|
+
request=context.request,
|
731
|
+
context={
|
732
|
+
"parts": parts,
|
733
|
+
},
|
734
|
+
)
|
735
|
+
|
736
|
+
|
737
|
+
@register.filter
|
738
|
+
def admin_object_app_url(object: Model, arg: str) -> str:
|
739
|
+
return f"admin:{object._meta.app_label}_{object._meta.model_name}_{arg}"
|
740
|
+
|
741
|
+
|
742
|
+
@register.filter
|
743
|
+
def has_nested_tables(table: dict) -> bool:
|
744
|
+
return any(
|
745
|
+
isinstance(row, dict) and "table" in row for row in table.get("rows", [])
|
746
|
+
)
|
unfold/utils.py
CHANGED
@@ -140,16 +140,6 @@ def display_for_field(value: Any, field: Any, empty_value_display: str) -> str:
|
|
140
140
|
return display_for_value(value, empty_value_display)
|
141
141
|
|
142
142
|
|
143
|
-
def hex_to_rgb(hex_color: str) -> list[int]:
|
144
|
-
hex_color = hex_color.lstrip("#")
|
145
|
-
|
146
|
-
r = int(hex_color[0:2], 16)
|
147
|
-
g = int(hex_color[2:4], 16)
|
148
|
-
b = int(hex_color[4:6], 16)
|
149
|
-
|
150
|
-
return (r, g, b)
|
151
|
-
|
152
|
-
|
153
143
|
def prettify_json(data: Any, encoder: Any) -> Optional[str]:
|
154
144
|
try:
|
155
145
|
from pygments import highlight
|
@@ -189,3 +179,32 @@ def parse_datetime_str(value: str) -> Optional[datetime.datetime]:
|
|
189
179
|
return datetime.datetime.strptime(value, format)
|
190
180
|
except (ValueError, TypeError):
|
191
181
|
continue
|
182
|
+
|
183
|
+
|
184
|
+
def hex_to_rgb(hex_color: str) -> list[int]:
|
185
|
+
hex_color = hex_color.lstrip("#")
|
186
|
+
|
187
|
+
r = int(hex_color[0:2], 16)
|
188
|
+
g = int(hex_color[2:4], 16)
|
189
|
+
b = int(hex_color[4:6], 16)
|
190
|
+
|
191
|
+
return (r, g, b)
|
192
|
+
|
193
|
+
|
194
|
+
def hex_to_values(value: str) -> str:
|
195
|
+
return ", ".join(str(item) for item in hex_to_rgb(value))
|
196
|
+
|
197
|
+
|
198
|
+
def convert_color(value: str) -> str:
|
199
|
+
if value[0] == "#":
|
200
|
+
return f"rgb({hex_to_values(value)})"
|
201
|
+
elif value.startswith("rgb") or value.startswith("oklch"):
|
202
|
+
return value
|
203
|
+
elif isinstance(value, str) and all(part.isdigit() for part in value.split()):
|
204
|
+
return f"rgb({', '.join(value.split(' '))})"
|
205
|
+
elif isinstance(value, str) and all(
|
206
|
+
part.strip().isdigit() for part in value.split(",")
|
207
|
+
):
|
208
|
+
return f"rgb({', '.join(part.strip() for part in value.split(','))})"
|
209
|
+
|
210
|
+
return value
|
unfold/views.py
CHANGED
@@ -43,5 +43,8 @@ class UnfoldModelAdminViewMixin(PermissionRequiredMixin):
|
|
43
43
|
return super().get_context_data(
|
44
44
|
**kwargs,
|
45
45
|
**self.model_admin.admin_site.each_context(self.request),
|
46
|
-
**{
|
46
|
+
**{
|
47
|
+
"title": self.title,
|
48
|
+
"model_admin": self.model_admin,
|
49
|
+
},
|
47
50
|
)
|
File without changes
|
File without changes
|