django-unfold 0.21.1__py3-none-any.whl → 0.23.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- {django_unfold-0.21.1.dist-info → django_unfold-0.23.0.dist-info}/LICENSE.md +1 -1
- {django_unfold-0.21.1.dist-info → django_unfold-0.23.0.dist-info}/METADATA +26 -2
- {django_unfold-0.21.1.dist-info → django_unfold-0.23.0.dist-info}/RECORD +38 -38
- unfold/admin.py +29 -22
- unfold/apps.py +5 -0
- unfold/checks.py +1 -1
- unfold/contrib/filters/apps.py +1 -0
- unfold/contrib/forms/apps.py +1 -0
- unfold/contrib/guardian/apps.py +1 -1
- unfold/contrib/import_export/apps.py +1 -1
- unfold/forms.py +6 -1
- unfold/sites.py +4 -4
- unfold/static/unfold/css/styles.css +1 -1
- unfold/styles.css +15 -4
- unfold/templates/admin/actions.html +9 -9
- unfold/templates/admin/app_list.html +6 -14
- unfold/templates/admin/base.html +2 -4
- unfold/templates/admin/change_form.html +1 -2
- unfold/templates/admin/change_list.html +3 -3
- unfold/templates/admin/change_list_results.html +17 -5
- unfold/templates/admin/edit_inline/tabular.html +3 -3
- unfold/templates/admin/login.html +9 -5
- unfold/templates/admin/search_form.html +10 -12
- unfold/templates/unfold/helpers/account_links.html +2 -2
- unfold/templates/unfold/helpers/app_list.html +5 -1
- unfold/templates/unfold/helpers/display_label.html +2 -0
- unfold/templates/unfold/helpers/tab_list.html +1 -1
- unfold/templates/unfold/layouts/base_simple.html +1 -1
- unfold/templates/unfold/widgets/date.html +1 -1
- unfold/templates/{admin → unfold}/widgets/related_widget_wrapper.html +4 -4
- unfold/templates/unfold/widgets/time.html +1 -1
- unfold/templatetags/unfold_list.py +63 -48
- unfold/widgets.py +16 -3
- {django_unfold-0.21.1.dist-info → django_unfold-0.23.0.dist-info}/WHEEL +0 -0
- /unfold/templates/{admin → unfold}/widgets/clearable_file_input.html +0 -0
- /unfold/templates/{admin → unfold}/widgets/radio.html +0 -0
- /unfold/templates/{admin → unfold}/widgets/radio_option.html +0 -0
- /unfold/templates/{admin → unfold}/widgets/split_datetime.html +0 -0
@@ -65,7 +65,7 @@
|
|
65
65
|
{% csrf_token %}
|
66
66
|
|
67
67
|
{% if actions_detail %}
|
68
|
-
<div class="bg-gray-50 flex justify-end
|
68
|
+
<div class="bg-gray-50 flex justify-end mb-4 p-3 rounded-md dark:bg-gray-800">
|
69
69
|
{% for action in actions_detail %}
|
70
70
|
<a href="{{ action.path }}" 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"
|
71
71
|
{% for attr_name, attr_value in action.attrs.items %}
|
@@ -89,7 +89,6 @@
|
|
89
89
|
<input type="hidden" name="{{ to_field_var }}" value="{{ to_field }}">
|
90
90
|
{% endif %}
|
91
91
|
|
92
|
-
|
93
92
|
{% include "unfold/helpers/messages/errornote.html" with errors=errors %}
|
94
93
|
{% include "unfold/helpers/messages/error.html" with errors=adminform.form.non_field_errors %}
|
95
94
|
|
@@ -67,7 +67,7 @@
|
|
67
67
|
{% endif %}
|
68
68
|
|
69
69
|
<div class="flex -mx-4 module{% if cl.has_filters %} filtered{% endif %}" id="changelist">
|
70
|
-
<div class="changelist-form-container flex-grow px-4" x-data="{ filterOpen: false }">
|
70
|
+
<div class="changelist-form-container flex-grow min-w-0 px-4" x-data="{ filterOpen: false }">
|
71
71
|
{% block date_hierarchy %}
|
72
72
|
{% if cl.date_hierarchy %}
|
73
73
|
{% date_hierarchy cl %}
|
@@ -84,7 +84,7 @@
|
|
84
84
|
{% block result_list %}
|
85
85
|
{% if actions_on_top %}
|
86
86
|
{% if cl.search_fields or action_form or cl.has_filters %}
|
87
|
-
<div class="bg-gray-50 flex flex-col gap-3 mb-4 p-3 rounded-md
|
87
|
+
<div class="bg-gray-50 flex flex-col gap-3 mb-4 p-3 rounded-md lg:flex-row dark:bg-gray-800">
|
88
88
|
{% block search %}
|
89
89
|
{% search_form cl %}
|
90
90
|
{% endblock %}
|
@@ -95,7 +95,7 @@
|
|
95
95
|
|
96
96
|
{% block filters %}
|
97
97
|
{% if cl.has_filters %}
|
98
|
-
<a class="{% if cl.has_active_filters %}bg-primary-600 border-primary-600 text-white{% else %}bg-white text-gray-500 hover:text-gray-700 dark:bg-gray-900 dark:border-gray-700 dark:hover:text-gray-200 dark:text-gray-400{% endif %} border cursor-pointer flex font-medium group items-center px-3 py-2 rounded-md shadow-sm text-sm
|
98
|
+
<a class="{% if cl.has_active_filters %}bg-primary-600 border-primary-600 text-white{% else %}bg-white text-gray-500 hover:text-gray-700 dark:bg-gray-900 dark:border-gray-700 dark:hover:text-gray-200 dark:text-gray-400{% endif %} border cursor-pointer flex font-medium group items-center px-3 py-2 rounded-md shadow-sm text-sm lg:ml-auto md:mt-0" x-on:click="filterOpen = true" x-on:keydown.escape.window="filterOpen = false">
|
99
99
|
{% trans "Filters" %}
|
100
100
|
|
101
101
|
<span class="material-symbols-outlined md-18 ml-auto -mr-1 pl-4 {% if cl.has_active_filters %}text-white{% else %}text-gray-400 group-hover:text-gray-700 dark:group-hover:text-gray-200 dark:text-gray-500{% endif %}">filter_list</span>
|
@@ -7,11 +7,11 @@
|
|
7
7
|
{% endif %}
|
8
8
|
|
9
9
|
{% if results %}
|
10
|
-
<table id="result_list" 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">
|
11
|
-
<thead
|
10
|
+
<table id="result_list" class="block 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:table lg:dark:border-gray-800">
|
11
|
+
<thead>
|
12
12
|
<tr>
|
13
13
|
{% for header in result_headers %}
|
14
|
-
<th class="align-middle font-medium
|
14
|
+
<th class="align-middle font-medium py-2 text-left text-gray-400 text-sm {{ header.class_attrib }} {% if "action-toggle" in header.text and forloop.counter == 1 %}lg:px-3 lg:w-10{% else %}hidden px-3 lg:table-cell{% endif %}" scope="col">
|
15
15
|
<div class="flex items-center">
|
16
16
|
<div class="text">
|
17
17
|
{% if header.sortable %}
|
@@ -19,7 +19,19 @@
|
|
19
19
|
{{ header.text|capfirst }}
|
20
20
|
</a>
|
21
21
|
{% else %}
|
22
|
-
|
22
|
+
{% if "action-toggle" in header.text and forloop.counter == 1 %}
|
23
|
+
<label class="flex flex-row items-center gap-2">
|
24
|
+
{{ header.text|capfirst }}
|
25
|
+
|
26
|
+
<span class="block font-normal text-gray-500 dark:text-gray-400 lg:hidden">
|
27
|
+
{% trans "Select all rows"%}
|
28
|
+
</span>
|
29
|
+
</label>
|
30
|
+
{% else %}
|
31
|
+
<span>
|
32
|
+
{{ header.text|capfirst }}
|
33
|
+
</span>
|
34
|
+
{% endif %}
|
23
35
|
{% endif %}
|
24
36
|
</div>
|
25
37
|
|
@@ -52,7 +64,7 @@
|
|
52
64
|
</tr>
|
53
65
|
</thead>
|
54
66
|
|
55
|
-
<tbody>
|
67
|
+
<tbody class="block lg:table-row-group">
|
56
68
|
{% for result in results %}
|
57
69
|
{% if result.form and result.form.non_field_errors %}
|
58
70
|
<tr>
|
@@ -109,11 +109,11 @@
|
|
109
109
|
{% with is_last_col=forloop.last %}
|
110
110
|
{% for field in line %}
|
111
111
|
{% if field.is_readonly or not field.field.is_hidden %}
|
112
|
-
<td{% if field.field.name %} class="field-{{ field.field.name }}{% if field.field.errors|length > 0 %} errors{% endif %}{% if inline_admin_form.original %} p-3 lg:py-3{% else %} py-3{% endif %}{% if field.is_checkbox %} align-middle{% else %} align-top{% endif %} {% if is_last_row and not inline_admin_formset.has_add_permission %}{% if is_last_col %}border-0 {% else %}border-b lg:border-0{% endif %}{% else %}border-b{% endif %} border-gray-200 flex items-center before:capitalize before:content-[attr(data-label)] before:mr-auto before:text-gray-500 before:w-72 lg:before:hidden font-normal px-3 text-left text-sm lg:table-cell dark:border-gray-800"{% endif %} data-label="{{ field.field.label }}">
|
112
|
+
<td{% if field.field.name %} class="field-{{ field.field.name }}{% if field.field.errors|length > 0 %} errors{% endif %}{% if inline_admin_form.original %} p-3 lg:py-3{% else %} py-3{% endif %}{% if field.is_checkbox %} align-middle{% else %} align-top{% endif %} {% if is_last_row and not inline_admin_formset.has_add_permission %}{% if is_last_col %}border-0 {% else %}border-b lg:border-0{% endif %}{% else %}border-b{% endif %} border-gray-200 flex items-center before:capitalize before:content-[attr(data-label)] before:mr-auto before:text-gray-500 before:w-72 lg:before:hidden font-normal px-3 text-left text-sm lg:table-cell dark:border-gray-800 {% if field.field.is_hidden %} !hidden{% endif %}"{% endif %} data-label="{{ field.field.label }}">
|
113
113
|
{% if field.is_readonly %}
|
114
|
-
<
|
114
|
+
<div class="bg-gray-50 border font-medium max-w-lg px-3 py-2 rounded-md shadow-sm text-gray-500 text-sm truncate whitespace-nowrap dark:border-gray-700 dark:text-gray-400 dark:bg-gray-800">
|
115
115
|
{{ field.contents }}
|
116
|
-
</
|
116
|
+
</div>
|
117
117
|
{% else %}
|
118
118
|
{{ field.field }}
|
119
119
|
|
@@ -25,7 +25,7 @@
|
|
25
25
|
|
26
26
|
{% block base %}
|
27
27
|
<div class="flex min-h-screen">
|
28
|
-
<div class="flex flex-grow items-center justify-center mx-auto px-4">
|
28
|
+
<div class="flex flex-grow items-center justify-center mx-auto px-4 relative">
|
29
29
|
<div class="w-full sm:w-96">
|
30
30
|
<h1 class="font-semibold mb-10">
|
31
31
|
<span class="block text-gray-700 dark:text-gray-200">{% trans 'Welcome back to' %}</span>
|
@@ -72,13 +72,17 @@
|
|
72
72
|
</form>
|
73
73
|
</div>
|
74
74
|
|
75
|
-
|
76
|
-
|
75
|
+
<div class="absolute flex flex-row items-center justify-between left-0 m-4 right-0 top-0">
|
76
|
+
{% if site_url %}
|
77
77
|
<a href="{{ site_url }}" class="flex font-medium items-center text-sm text-primary-600">
|
78
78
|
<span class="material-symbols-outlined mr-2">arrow_back</span> {% trans 'Return to site' %}
|
79
79
|
</a>
|
80
|
-
|
81
|
-
|
80
|
+
{% endif %}
|
81
|
+
|
82
|
+
{% if not theme %}
|
83
|
+
{% include "unfold/helpers/theme_switch.html" %}
|
84
|
+
{% endif %}
|
85
|
+
</div>
|
82
86
|
</div>
|
83
87
|
|
84
88
|
{% if image %}
|
@@ -1,19 +1,17 @@
|
|
1
1
|
{% load i18n static %}
|
2
2
|
|
3
3
|
{% if cl.search_fields %}
|
4
|
-
<div id="toolbar"
|
5
|
-
<div>
|
6
|
-
<
|
7
|
-
<input class="font-medium h-9 px-3 text-gray-500 text-sm w-40 lg:w-60 focus:outline-none dark:bg-gray-900 dark:text-gray-400" type="text" name="{{ search_var }}" value="{{ cl.query }}" id="searchbar" placeholder="{% trans 'Type to search' %}" />
|
4
|
+
<div id="toolbar">
|
5
|
+
<div class="bg-white border flex rounded-md overflow-hidden shadow-sm lg:w-64 focus-within:ring focus-within:ring-primary-300 focus-within:border-primary-600 dark:bg-gray-900 dark:border-gray-700 dark:focus-within:border-primary-600 dark:focus-within:ring-primary-700 dark:focus-within:ring-opacity-50">
|
6
|
+
<input class="font-medium grow min-w-0 h-9 px-3 text-gray-500 text-sm focus:outline-none dark:bg-gray-900 dark:text-gray-400" type="text" name="{{ search_var }}" value="{{ cl.query }}" id="searchbar" placeholder="{% trans 'Type to search' %}" />
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
</div>
|
13
|
-
|
14
|
-
{% for pair in cl.params.items %}
|
15
|
-
{% if pair.0 != search_var %}<input type="hidden" name="{{ pair.0 }}" value="{{ pair.1 }}">{% endif %}
|
16
|
-
{% endfor %}
|
8
|
+
<button type="submit" class="flex items-center px-2 focus:outline-none" id="searchbar-submit">
|
9
|
+
<span class="material-symbols-outlined md-18 text-gray-400 dark:text-gray-500">search</span>
|
10
|
+
</button>
|
17
11
|
</div>
|
12
|
+
|
13
|
+
{% for pair in cl.params.items %}
|
14
|
+
{% if pair.0 != search_var %}<input type="hidden" name="{{ pair.0 }}" value="{{ pair.1 }}">{% endif %}
|
15
|
+
{% endfor %}
|
18
16
|
</div>
|
19
17
|
{% endif %}
|
@@ -25,10 +25,10 @@
|
|
25
25
|
{% endif %}
|
26
26
|
|
27
27
|
<div class="border-t mt-1 pt-1 dark:border-gray-700">
|
28
|
-
<form id="logout-form" method="post" action="{% url 'admin:logout' %}" class="
|
28
|
+
<form id="logout-form" method="post" action="{% url 'admin:logout' %}" class="mx-1">
|
29
29
|
{% csrf_token %}
|
30
30
|
|
31
|
-
<button type="submit">
|
31
|
+
<button type="submit" class="bg-none block px-3 py-2 text-left text-red-500 rounded w-full hover:bg-red-100 dark:hover:bg-red-500/20 dark:hover:text-red-500">
|
32
32
|
{% translate 'Log out' %}
|
33
33
|
</button>
|
34
34
|
</form>
|
@@ -31,7 +31,11 @@
|
|
31
31
|
|
32
32
|
{% if item.badge %}
|
33
33
|
<span class="bg-red-600 font-semibold ml-2 px-1 rounded-sm text-xs text-white">
|
34
|
-
{
|
34
|
+
{% if item.badge_callback %}
|
35
|
+
{{ item.badge_callback }}
|
36
|
+
{% else %}
|
37
|
+
{{ item.badge }}
|
38
|
+
{% endif %}
|
35
39
|
</span>
|
36
40
|
{% endif %}
|
37
41
|
</a>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
{% if not is_popup %}
|
2
2
|
{% if tab_list or actions_list or actions_items or nav_global %}
|
3
|
-
<div class="flex items-start flex-col mb-
|
3
|
+
<div class="flex items-start flex-col mb-4 text-gray-500 text-sm w-full md:border-b dark:md:border-gray-800 md:border-l-0 md:flex-row md:items-center md:justify-end dark:text-gray-400">
|
4
4
|
{% if tab_list %}
|
5
5
|
<ul class="border rounded-md flex flex-col w-full md:flex-row md:border-b-0 md:border-t-0 md:border-l-0 md:border-r-0 dark:border-gray-800">
|
6
6
|
{% for item in tab_list %}
|
@@ -9,7 +9,7 @@
|
|
9
9
|
{% if not is_hidden %}
|
10
10
|
{% if can_add_related or can_change_related or can_delete_related or can_view_related%}
|
11
11
|
{% if can_change_related %}
|
12
|
-
<a class="related-widget-wrapper-link change-related border cursor-pointer flex items-center h-9.5 justify-center ml-2 rounded shadow-sm shrink-0 text-gray-400 text-sm
|
12
|
+
<a class="related-widget-wrapper-link change-related bg-white border cursor-pointer flex items-center h-9.5 justify-center ml-2 rounded shadow-sm shrink-0 text-gray-400 text-sm w-9.5 hover:text-gray-700 dark:bg-gray-900 dark:border-gray-700 dark:text-gray-500 dark:hover:text-gray-200"
|
13
13
|
id="change_id_{{ name }}"
|
14
14
|
data-popup="yes"
|
15
15
|
data-href-template="{{ change_related_template_url }}?{{ url_params }}"
|
@@ -19,7 +19,7 @@
|
|
19
19
|
{% endif %}
|
20
20
|
|
21
21
|
{% if can_add_related %}
|
22
|
-
<a class="related-widget-wrapper-link add-related border cursor-pointer flex items-center h-9.5 justify-center ml-2 rounded shadow-sm shrink-0 text-gray-400 text-sm
|
22
|
+
<a class="related-widget-wrapper-link add-related bg-white border cursor-pointer flex items-center h-9.5 justify-center ml-2 rounded shadow-sm shrink-0 text-gray-400 text-sm w-9.5 hover:text-gray-700 dark:bg-gray-900 dark:border-gray-700 dark:text-gray-500 dark:hover:text-gray-200"
|
23
23
|
data-popup="yes"
|
24
24
|
id="add_id_{{ name }}"
|
25
25
|
href="{{ add_related_url }}?{{ url_params }}"
|
@@ -29,7 +29,7 @@
|
|
29
29
|
{% endif %}
|
30
30
|
|
31
31
|
{% if can_view_related %}
|
32
|
-
<a class="related-widget-wrapper-link view-related border cursor-pointer flex items-center h-9.5 justify-center ml-2 rounded shadow-sm shrink-0 text-gray-400 text-sm
|
32
|
+
<a class="related-widget-wrapper-link view-related bg-white border cursor-pointer flex items-center h-9.5 justify-center ml-2 rounded shadow-sm shrink-0 text-gray-400 text-sm w-9.5 hover:text-gray-700 dark:bg-gray-900 dark:border-gray-700 dark:text-gray-500 dark:hover:text-gray-200"
|
33
33
|
id="view_id_{{ name }}"
|
34
34
|
data-href-template="{{ change_related_template_url }}?{{ view_related_url_params }}"
|
35
35
|
title="{% blocktranslate %}View selected {{ model }}{% endblocktranslate %}">
|
@@ -38,7 +38,7 @@
|
|
38
38
|
{% endif %}
|
39
39
|
|
40
40
|
{% if can_delete_related %}
|
41
|
-
<a class="related-widget-wrapper-link delete-related border cursor-pointer flex items-center h-9.5 justify-center ml-2 rounded shadow-sm shrink-0 text-red-600 text-sm
|
41
|
+
<a class="related-widget-wrapper-link delete-related 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"
|
42
42
|
id="delete_id_{{ name }}"
|
43
43
|
data-href-template="{{ delete_related_template_url }}?{{ url_params }}"
|
44
44
|
data-popup="yes"
|
@@ -36,7 +36,63 @@ from ..widgets import UnfoldBooleanWidget
|
|
36
36
|
|
37
37
|
register = Library()
|
38
38
|
|
39
|
-
LINK_CLASSES = [
|
39
|
+
LINK_CLASSES = [
|
40
|
+
"text-gray-600",
|
41
|
+
"truncate",
|
42
|
+
"dark:text-gray-300",
|
43
|
+
]
|
44
|
+
|
45
|
+
ROW_CLASSES = [
|
46
|
+
"align-middle",
|
47
|
+
"flex",
|
48
|
+
"border-t",
|
49
|
+
"border-gray-200",
|
50
|
+
"font-normal",
|
51
|
+
"gap-4",
|
52
|
+
"min-w-0",
|
53
|
+
"overflow-hidden",
|
54
|
+
"px-3",
|
55
|
+
"py-2",
|
56
|
+
"text-left",
|
57
|
+
"text-gray-500",
|
58
|
+
"text-sm",
|
59
|
+
"before:flex",
|
60
|
+
"before:capitalize",
|
61
|
+
"before:content-[attr(data-label)]",
|
62
|
+
"before:items-center",
|
63
|
+
"before:mr-auto",
|
64
|
+
"before:text-gray-500",
|
65
|
+
"first:border-t-0",
|
66
|
+
"dark:before:text-gray-400",
|
67
|
+
"dark:text-gray-400",
|
68
|
+
"lg:before:hidden",
|
69
|
+
"lg:first:border-t",
|
70
|
+
"lg:py-3",
|
71
|
+
"lg:table-cell",
|
72
|
+
"dark:border-gray-800",
|
73
|
+
]
|
74
|
+
|
75
|
+
CHECKBOX_CLASSES = [
|
76
|
+
"action-checkbox",
|
77
|
+
"align-middle",
|
78
|
+
"flex",
|
79
|
+
"items-center",
|
80
|
+
"px-3",
|
81
|
+
"py-2",
|
82
|
+
"text-left",
|
83
|
+
"text-sm",
|
84
|
+
"before:block",
|
85
|
+
"before:capitalize",
|
86
|
+
"before:content-[attr(data-label)]",
|
87
|
+
"before:mr-auto",
|
88
|
+
"before:text-gray-500",
|
89
|
+
"lg:before:hidden",
|
90
|
+
"lg:border-t",
|
91
|
+
"lg:border-gray-200",
|
92
|
+
"lg:table-cell",
|
93
|
+
"dark:before:text-gray-400",
|
94
|
+
"dark:lg:border-gray-800",
|
95
|
+
]
|
40
96
|
|
41
97
|
|
42
98
|
def result_headers(cl):
|
@@ -95,7 +151,7 @@ def result_headers(cl):
|
|
95
151
|
if is_sorted:
|
96
152
|
order_type = ordering_field_columns.get(i).lower()
|
97
153
|
sort_priority = list(ordering_field_columns).index(i) + 1
|
98
|
-
th_classes.append("sorted
|
154
|
+
th_classes.append(f"sorted {order_type}ending")
|
99
155
|
new_order_type = {"asc": "desc", "desc": "asc"}[order_type]
|
100
156
|
|
101
157
|
# build new ordering param
|
@@ -132,7 +188,7 @@ def result_headers(cl):
|
|
132
188
|
"url_primary": cl.get_query_string({ORDER_VAR: ".".join(o_list_primary)}),
|
133
189
|
"url_remove": cl.get_query_string({ORDER_VAR: ".".join(o_list_remove)}),
|
134
190
|
"url_toggle": cl.get_query_string({ORDER_VAR: ".".join(o_list_toggle)}),
|
135
|
-
"class_attrib": format_html(
|
191
|
+
"class_attrib": format_html("{}", " ".join(th_classes))
|
136
192
|
if th_classes
|
137
193
|
else "",
|
138
194
|
}
|
@@ -157,29 +213,8 @@ def items_for_result(cl: ChangeList, result: HttpRequest, form) -> SafeText:
|
|
157
213
|
for field_index, field_name in enumerate(cl.list_display):
|
158
214
|
empty_value_display = cl.model_admin.get_empty_value_display()
|
159
215
|
row_classes = [
|
160
|
-
"field
|
161
|
-
|
162
|
-
"flex",
|
163
|
-
"border-t",
|
164
|
-
"border-gray-200",
|
165
|
-
"font-normal",
|
166
|
-
"px-3",
|
167
|
-
"py-2",
|
168
|
-
"text-left",
|
169
|
-
"text-sm",
|
170
|
-
"before:flex",
|
171
|
-
"before:capitalize",
|
172
|
-
"before:content-[attr(data-label)]",
|
173
|
-
"before:items-center",
|
174
|
-
"before:mr-auto",
|
175
|
-
"before:text-gray-500",
|
176
|
-
"first:border-t-0",
|
177
|
-
"dark:before:text-gray-400",
|
178
|
-
"lg:before:hidden",
|
179
|
-
"lg:first:border-t",
|
180
|
-
"lg:py-3",
|
181
|
-
"lg:table-cell",
|
182
|
-
"dark:border-gray-800",
|
216
|
+
f"field-{_coerce_field_name(field_name, field_index)}",
|
217
|
+
*ROW_CLASSES,
|
183
218
|
]
|
184
219
|
|
185
220
|
try:
|
@@ -192,27 +227,7 @@ def items_for_result(cl: ChangeList, result: HttpRequest, form) -> SafeText:
|
|
192
227
|
)
|
193
228
|
if f is None or f.auto_created:
|
194
229
|
if field_name == "action_checkbox":
|
195
|
-
row_classes =
|
196
|
-
"action-checkbox",
|
197
|
-
"align-middle",
|
198
|
-
"flex",
|
199
|
-
"items-center",
|
200
|
-
"px-3",
|
201
|
-
"py-2",
|
202
|
-
"text-left",
|
203
|
-
"text-sm",
|
204
|
-
"before:block",
|
205
|
-
"before:capitalize",
|
206
|
-
"before:content-[attr(data-label)]",
|
207
|
-
"before:mr-auto",
|
208
|
-
"before:text-gray-500",
|
209
|
-
"lg:before:hidden",
|
210
|
-
"lg:border-t",
|
211
|
-
"lg:border-gray-200",
|
212
|
-
"lg:table-cell",
|
213
|
-
"dark:before:text-gray-400",
|
214
|
-
"dark:lg:border-gray-800",
|
215
|
-
]
|
230
|
+
row_classes = CHECKBOX_CLASSES
|
216
231
|
boolean = getattr(attr, "boolean", False)
|
217
232
|
label = getattr(attr, "label", False)
|
218
233
|
header = getattr(attr, "header", False)
|
@@ -239,7 +254,7 @@ def items_for_result(cl: ChangeList, result: HttpRequest, form) -> SafeText:
|
|
239
254
|
f, (models.DateField, models.TimeField, models.ForeignKey)
|
240
255
|
):
|
241
256
|
row_classes.append("nowrap")
|
242
|
-
row_class = mark_safe(' class="
|
257
|
+
row_class = mark_safe(f' class="{" ".join(row_classes)}"')
|
243
258
|
# If list_display_links not defined, add the link tag to the first field
|
244
259
|
|
245
260
|
if link_in_col(first, field_name, cl):
|
unfold/widgets.py
CHANGED
@@ -13,6 +13,7 @@ from django.contrib.admin.widgets import (
|
|
13
13
|
AdminTextInputWidget,
|
14
14
|
AdminTimeWidget,
|
15
15
|
AdminUUIDInputWidget,
|
16
|
+
RelatedFieldWidgetWrapper,
|
16
17
|
)
|
17
18
|
from django.forms import (
|
18
19
|
CheckboxInput,
|
@@ -291,7 +292,7 @@ class FileFieldMixin:
|
|
291
292
|
|
292
293
|
|
293
294
|
class UnfoldAdminImageFieldWidget(FileFieldMixin, AdminFileWidget):
|
294
|
-
|
295
|
+
template_name = "unfold/widgets/clearable_file_input.html"
|
295
296
|
|
296
297
|
|
297
298
|
class UnfoldAdminFileFieldWidget(FileFieldMixin, AdminFileWidget):
|
@@ -374,6 +375,8 @@ class UnfoldAdminTextareaWidget(AdminTextareaWidget):
|
|
374
375
|
|
375
376
|
|
376
377
|
class UnfoldAdminSplitDateTimeWidget(AdminSplitDateTime):
|
378
|
+
template_name = "unfold/widgets/split_datetime.html"
|
379
|
+
|
377
380
|
def __init__(self, attrs: Optional[Dict[str, Any]] = None) -> None:
|
378
381
|
widgets = [UnfoldAdminDateWidget, UnfoldAdminTimeWidget]
|
379
382
|
MultiWidget.__init__(self, widgets, attrs)
|
@@ -433,7 +436,12 @@ class UnfoldAdminBigIntegerFieldWidget(AdminBigIntegerFieldWidget):
|
|
433
436
|
|
434
437
|
|
435
438
|
class UnfoldAdminNullBooleanSelectWidget(NullBooleanSelect):
|
436
|
-
|
439
|
+
def __init__(self, attrs=None):
|
440
|
+
if attrs is None:
|
441
|
+
attrs = {}
|
442
|
+
|
443
|
+
attrs["class"] = " ".join(SELECT_CLASSES)
|
444
|
+
super().__init__(attrs)
|
437
445
|
|
438
446
|
|
439
447
|
class UnfoldAdminSelect(Select):
|
@@ -446,7 +454,8 @@ class UnfoldAdminSelect(Select):
|
|
446
454
|
|
447
455
|
|
448
456
|
class UnfoldAdminRadioSelectWidget(AdminRadioSelect):
|
449
|
-
|
457
|
+
template_name = "unfold/widgets/radio.html"
|
458
|
+
option_template_name = "unfold/widgets/radio_option.html"
|
450
459
|
|
451
460
|
def __init__(self, radio_style: Optional[int] = None, *args, **kwargs):
|
452
461
|
super().__init__(*args, **kwargs)
|
@@ -506,3 +515,7 @@ class UnfoldBooleanSwitchWidget(CheckboxInput):
|
|
506
515
|
return super().__init__(
|
507
516
|
attrs={"class": " ".join(SWITCH_CLASSES), **(attrs or {})}, check_test=None
|
508
517
|
)
|
518
|
+
|
519
|
+
|
520
|
+
class UnfoldRelatedFieldWidgetWrapper(RelatedFieldWidgetWrapper):
|
521
|
+
template_name = "unfold/widgets/related_widget_wrapper.html"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|