django-unfold 0.25.0__py3-none-any.whl → 0.26.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.25.0.dist-info → django_unfold-0.26.0.dist-info}/METADATA +51 -6
- {django_unfold-0.25.0.dist-info → django_unfold-0.26.0.dist-info}/RECORD +36 -27
- unfold/admin.py +11 -3
- unfold/contrib/import_export/forms.py +17 -0
- unfold/contrib/import_export/templates/admin/import_export/change_form.html +10 -0
- unfold/contrib/import_export/templates/admin/import_export/export.html +38 -3
- unfold/contrib/import_export/templates/admin/import_export/import_form.html +8 -12
- unfold/contrib/import_export/templates/admin/import_export/resource_fields_list.html +1 -1
- unfold/contrib/inlines/__init__.py +0 -0
- unfold/contrib/inlines/admin.py +141 -0
- unfold/contrib/inlines/apps.py +6 -0
- unfold/contrib/inlines/checks.py +18 -0
- unfold/contrib/inlines/forms.py +43 -0
- unfold/forms.py +6 -0
- unfold/static/unfold/css/simplebar.css +230 -0
- unfold/static/unfold/css/styles.css +1 -1
- unfold/static/unfold/js/simplebar.js +10 -0
- unfold/styles.css +9 -1
- unfold/templates/admin/app_list.html +1 -1
- unfold/templates/admin/change_form.html +11 -9
- unfold/templates/admin/change_list_results.html +2 -2
- unfold/templates/admin/edit_inline/stacked.html +6 -6
- unfold/templates/admin/edit_inline/tabular.html +3 -3
- unfold/templates/admin/includes/fieldset.html +1 -1
- unfold/templates/unfold/helpers/app_list.html +1 -1
- unfold/templates/unfold/helpers/display_header.html +11 -8
- unfold/templates/unfold/helpers/field.html +20 -6
- unfold/templates/unfold/helpers/fieldsets_tabs.html +4 -4
- unfold/templates/unfold/helpers/form_label.html +1 -1
- unfold/templates/unfold/layouts/skeleton.html +2 -0
- unfold/templates/unfold/widgets/foreign_key_raw_id.html +21 -0
- unfold/templates/unfold/widgets/textarea.html +1 -7
- unfold/templates/unfold/widgets/textarea_expandable.html +7 -0
- unfold/widgets.py +36 -3
- unfold/contrib/import_export/admin.py +0 -37
- {django_unfold-0.25.0.dist-info → django_unfold-0.26.0.dist-info}/LICENSE.md +0 -0
- {django_unfold-0.25.0.dist-info → django_unfold-0.26.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
from typing import Any, Callable, Optional
|
2
|
+
|
3
|
+
from django.db.models import Model, QuerySet
|
4
|
+
from django.forms import BaseModelFormSet, ModelForm, modelformset_factory
|
5
|
+
|
6
|
+
|
7
|
+
class NonrelatedInlineModelFormSet(BaseModelFormSet):
|
8
|
+
def __init__(
|
9
|
+
self,
|
10
|
+
instance: Optional[Model] = None,
|
11
|
+
save_as_new: bool = False,
|
12
|
+
**kwargs: Any,
|
13
|
+
) -> None:
|
14
|
+
self.instance = instance
|
15
|
+
self.queryset = self.provided_queryset
|
16
|
+
|
17
|
+
super().__init__(**kwargs)
|
18
|
+
|
19
|
+
@classmethod
|
20
|
+
def get_default_prefix(cls: BaseModelFormSet) -> str:
|
21
|
+
return f"{cls.model._meta.app_label}-{cls.model._meta.model_name}"
|
22
|
+
|
23
|
+
def save_new(self, form: ModelForm, commit: bool = True):
|
24
|
+
obj = super().save_new(form, commit=False)
|
25
|
+
self.save_new_instance(self.instance, obj)
|
26
|
+
|
27
|
+
if commit:
|
28
|
+
obj.save()
|
29
|
+
|
30
|
+
return obj
|
31
|
+
|
32
|
+
|
33
|
+
def nonrelated_inline_formset_factory(
|
34
|
+
model: Model,
|
35
|
+
queryset: Optional[QuerySet] = None,
|
36
|
+
formset: BaseModelFormSet = NonrelatedInlineModelFormSet,
|
37
|
+
save_new_instance: Optional[Callable] = None,
|
38
|
+
**kwargs: Any,
|
39
|
+
) -> BaseModelFormSet:
|
40
|
+
inline_formset = modelformset_factory(model, formset=formset, **kwargs)
|
41
|
+
inline_formset.provided_queryset = queryset
|
42
|
+
inline_formset.save_new_instance = save_new_instance
|
43
|
+
return inline_formset
|
unfold/forms.py
CHANGED
@@ -10,6 +10,7 @@ from django.contrib.admin.forms import (
|
|
10
10
|
from django.contrib.auth.forms import (
|
11
11
|
AdminPasswordChangeForm as BaseAdminPasswordChangeForm,
|
12
12
|
)
|
13
|
+
from django.contrib.auth.forms import ReadOnlyPasswordHashWidget
|
13
14
|
from django.contrib.auth.forms import UserChangeForm as BaseUserChangeForm
|
14
15
|
from django.contrib.auth.forms import UserCreationForm as BaseUserCreationForm
|
15
16
|
from django.http import HttpRequest
|
@@ -19,6 +20,10 @@ from django.utils.translation import gettext_lazy as _
|
|
19
20
|
from .widgets import BASE_INPUT_CLASSES, INPUT_CLASSES, SELECT_CLASSES
|
20
21
|
|
21
22
|
|
23
|
+
class UnfoldReadOnlyPasswordHashWidget(ReadOnlyPasswordHashWidget):
|
24
|
+
pass
|
25
|
+
|
26
|
+
|
22
27
|
class ActionForm(forms.Form):
|
23
28
|
action = forms.ChoiceField(
|
24
29
|
label="",
|
@@ -72,6 +77,7 @@ class UserChangeForm(BaseUserChangeForm):
|
|
72
77
|
**kwargs,
|
73
78
|
) -> None:
|
74
79
|
super().__init__(request, *args, **kwargs)
|
80
|
+
self.fields["password"].widget = UnfoldReadOnlyPasswordHashWidget()
|
75
81
|
|
76
82
|
self.fields["password"].help_text = _(
|
77
83
|
"Raw passwords are not stored, so there is no way to see this "
|
@@ -0,0 +1,230 @@
|
|
1
|
+
[data-simplebar] {
|
2
|
+
position: relative;
|
3
|
+
flex-direction: column;
|
4
|
+
flex-wrap: wrap;
|
5
|
+
justify-content: flex-start;
|
6
|
+
align-content: flex-start;
|
7
|
+
align-items: flex-start;
|
8
|
+
}
|
9
|
+
|
10
|
+
.simplebar-wrapper {
|
11
|
+
overflow: hidden;
|
12
|
+
width: inherit;
|
13
|
+
height: inherit;
|
14
|
+
max-width: inherit;
|
15
|
+
max-height: inherit;
|
16
|
+
}
|
17
|
+
|
18
|
+
.simplebar-mask {
|
19
|
+
direction: inherit;
|
20
|
+
position: absolute;
|
21
|
+
overflow: hidden;
|
22
|
+
padding: 0;
|
23
|
+
margin: 0;
|
24
|
+
left: 0;
|
25
|
+
top: 0;
|
26
|
+
bottom: 0;
|
27
|
+
right: 0;
|
28
|
+
width: auto !important;
|
29
|
+
height: auto !important;
|
30
|
+
z-index: 0;
|
31
|
+
}
|
32
|
+
|
33
|
+
.simplebar-offset {
|
34
|
+
direction: inherit !important;
|
35
|
+
box-sizing: inherit !important;
|
36
|
+
resize: none !important;
|
37
|
+
position: absolute;
|
38
|
+
top: 0;
|
39
|
+
left: 0;
|
40
|
+
bottom: 0;
|
41
|
+
right: 0;
|
42
|
+
padding: 0;
|
43
|
+
margin: 0;
|
44
|
+
-webkit-overflow-scrolling: touch;
|
45
|
+
}
|
46
|
+
|
47
|
+
.simplebar-content-wrapper {
|
48
|
+
direction: inherit;
|
49
|
+
box-sizing: border-box !important;
|
50
|
+
position: relative;
|
51
|
+
display: block;
|
52
|
+
height: 100%; /* Required for horizontal native scrollbar to not appear if parent is taller than natural height */
|
53
|
+
width: auto;
|
54
|
+
max-width: 100%; /* Not required for horizontal scroll to trigger */
|
55
|
+
max-height: 100%; /* Needed for vertical scroll to trigger */
|
56
|
+
overflow: auto;
|
57
|
+
scrollbar-width: none;
|
58
|
+
-ms-overflow-style: none;
|
59
|
+
}
|
60
|
+
|
61
|
+
.simplebar-content-wrapper::-webkit-scrollbar,
|
62
|
+
.simplebar-hide-scrollbar::-webkit-scrollbar {
|
63
|
+
display: none;
|
64
|
+
width: 0;
|
65
|
+
height: 0;
|
66
|
+
}
|
67
|
+
|
68
|
+
.simplebar-content:before,
|
69
|
+
.simplebar-content:after {
|
70
|
+
content: ' ';
|
71
|
+
display: table;
|
72
|
+
}
|
73
|
+
|
74
|
+
.simplebar-placeholder {
|
75
|
+
max-height: 100%;
|
76
|
+
max-width: 100%;
|
77
|
+
width: 100%;
|
78
|
+
pointer-events: none;
|
79
|
+
}
|
80
|
+
|
81
|
+
.simplebar-height-auto-observer-wrapper {
|
82
|
+
box-sizing: inherit !important;
|
83
|
+
height: 100%;
|
84
|
+
width: 100%;
|
85
|
+
max-width: 1px;
|
86
|
+
position: relative;
|
87
|
+
float: left;
|
88
|
+
max-height: 1px;
|
89
|
+
overflow: hidden;
|
90
|
+
z-index: -1;
|
91
|
+
padding: 0;
|
92
|
+
margin: 0;
|
93
|
+
pointer-events: none;
|
94
|
+
flex-grow: inherit;
|
95
|
+
flex-shrink: 0;
|
96
|
+
flex-basis: 0;
|
97
|
+
}
|
98
|
+
|
99
|
+
.simplebar-height-auto-observer {
|
100
|
+
box-sizing: inherit;
|
101
|
+
display: block;
|
102
|
+
opacity: 0;
|
103
|
+
position: absolute;
|
104
|
+
top: 0;
|
105
|
+
left: 0;
|
106
|
+
height: 1000%;
|
107
|
+
width: 1000%;
|
108
|
+
min-height: 1px;
|
109
|
+
min-width: 1px;
|
110
|
+
overflow: hidden;
|
111
|
+
pointer-events: none;
|
112
|
+
z-index: -1;
|
113
|
+
}
|
114
|
+
|
115
|
+
.simplebar-track {
|
116
|
+
z-index: 1;
|
117
|
+
position: absolute;
|
118
|
+
right: 0;
|
119
|
+
bottom: 0;
|
120
|
+
pointer-events: none;
|
121
|
+
overflow: hidden;
|
122
|
+
}
|
123
|
+
|
124
|
+
[data-simplebar].simplebar-dragging {
|
125
|
+
pointer-events: none;
|
126
|
+
-webkit-touch-callout: none;
|
127
|
+
-webkit-user-select: none;
|
128
|
+
-khtml-user-select: none;
|
129
|
+
-moz-user-select: none;
|
130
|
+
-ms-user-select: none;
|
131
|
+
user-select: none;
|
132
|
+
}
|
133
|
+
|
134
|
+
[data-simplebar].simplebar-dragging .simplebar-content {
|
135
|
+
pointer-events: none;
|
136
|
+
-webkit-touch-callout: none;
|
137
|
+
-webkit-user-select: none;
|
138
|
+
-khtml-user-select: none;
|
139
|
+
-moz-user-select: none;
|
140
|
+
-ms-user-select: none;
|
141
|
+
user-select: none;
|
142
|
+
}
|
143
|
+
|
144
|
+
[data-simplebar].simplebar-dragging .simplebar-track {
|
145
|
+
pointer-events: all;
|
146
|
+
}
|
147
|
+
|
148
|
+
.simplebar-scrollbar {
|
149
|
+
position: absolute;
|
150
|
+
left: 0;
|
151
|
+
right: 0;
|
152
|
+
min-height: 10px;
|
153
|
+
}
|
154
|
+
|
155
|
+
.simplebar-scrollbar:before {
|
156
|
+
position: absolute;
|
157
|
+
content: '';
|
158
|
+
background: black;
|
159
|
+
border-radius: 7px;
|
160
|
+
left: 2px;
|
161
|
+
right: 2px;
|
162
|
+
opacity: 0;
|
163
|
+
transition: opacity 0.2s 0.5s linear;
|
164
|
+
}
|
165
|
+
|
166
|
+
.simplebar-scrollbar.simplebar-visible:before {
|
167
|
+
opacity: 0.5;
|
168
|
+
transition-delay: 0s;
|
169
|
+
transition-duration: 0s;
|
170
|
+
}
|
171
|
+
|
172
|
+
.simplebar-track.simplebar-vertical {
|
173
|
+
top: 0;
|
174
|
+
width: 11px;
|
175
|
+
}
|
176
|
+
|
177
|
+
.simplebar-scrollbar:before {
|
178
|
+
top: 2px;
|
179
|
+
bottom: 2px;
|
180
|
+
left: 2px;
|
181
|
+
right: 2px;
|
182
|
+
}
|
183
|
+
|
184
|
+
.simplebar-track.simplebar-horizontal {
|
185
|
+
left: 0;
|
186
|
+
height: 11px;
|
187
|
+
}
|
188
|
+
|
189
|
+
.simplebar-track.simplebar-horizontal .simplebar-scrollbar {
|
190
|
+
right: auto;
|
191
|
+
left: 0;
|
192
|
+
top: 0;
|
193
|
+
bottom: 0;
|
194
|
+
min-height: 0;
|
195
|
+
min-width: 10px;
|
196
|
+
width: auto;
|
197
|
+
}
|
198
|
+
|
199
|
+
/* Rtl support */
|
200
|
+
[data-simplebar-direction='rtl'] .simplebar-track.simplebar-vertical {
|
201
|
+
right: auto;
|
202
|
+
left: 0;
|
203
|
+
}
|
204
|
+
|
205
|
+
.simplebar-dummy-scrollbar-size {
|
206
|
+
direction: rtl;
|
207
|
+
position: fixed;
|
208
|
+
opacity: 0;
|
209
|
+
visibility: hidden;
|
210
|
+
height: 500px;
|
211
|
+
width: 500px;
|
212
|
+
overflow-y: hidden;
|
213
|
+
overflow-x: scroll;
|
214
|
+
-ms-overflow-style: scrollbar !important;
|
215
|
+
}
|
216
|
+
|
217
|
+
.simplebar-dummy-scrollbar-size > div {
|
218
|
+
width: 200%;
|
219
|
+
height: 200%;
|
220
|
+
margin: 10px 0;
|
221
|
+
}
|
222
|
+
|
223
|
+
.simplebar-hide-scrollbar {
|
224
|
+
position: fixed;
|
225
|
+
left: 0;
|
226
|
+
visibility: hidden;
|
227
|
+
overflow-y: scroll;
|
228
|
+
scrollbar-width: none;
|
229
|
+
-ms-overflow-style: none;
|
230
|
+
}
|