django-unfold 0.62.0__py3-none-any.whl → 0.64.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.62.0.dist-info → django_unfold-0.64.0.dist-info}/METADATA +15 -2
- {django_unfold-0.62.0.dist-info → django_unfold-0.64.0.dist-info}/RECORD +71 -62
- unfold/admin.py +1 -1
- unfold/contrib/constance/__init__.py +0 -0
- unfold/contrib/constance/apps.py +6 -0
- unfold/contrib/constance/settings.py +32 -0
- unfold/contrib/constance/templates/admin/constance/change_list.html +52 -0
- unfold/contrib/constance/templates/admin/constance/includes/results_list.html +71 -0
- 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/fields.py +1 -1
- unfold/settings.py +28 -22
- unfold/sites.py +120 -43
- unfold/static/admin/js/inlines.js +42 -17
- unfold/static/unfold/css/styles.css +2 -2
- unfold/static/unfold/js/app.js +147 -9
- unfold/static/unfold/js/select2.init.js +4 -0
- unfold/styles.css +33 -33
- 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 +7 -34
- 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/includes/fieldset.html +1 -1
- unfold/templates/admin/index.html +0 -2
- unfold/templates/admin/login.html +1 -1
- unfold/templates/admin/object_history.html +0 -24
- unfold/templates/registration/logged_out.html +12 -7
- 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/pagination_inline.html +28 -20
- 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/submit.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/unauthenticated_header.html +2 -2
- unfold/templates/unfold/helpers/unauthenticated_title.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/templates/unfold/widgets/related_widget_wrapper.html +4 -4
- unfold/templatetags/unfold.py +141 -0
- unfold/utils.py +25 -10
- unfold/views.py +4 -1
- unfold/widgets.py +6 -1
- {django_unfold-0.62.0.dist-info → django_unfold-0.64.0.dist-info}/LICENSE.md +0 -0
- {django_unfold-0.62.0.dist-info → django_unfold-0.64.0.dist-info}/WHEEL +0 -0
@@ -6,32 +6,6 @@
|
|
6
6
|
{{ form.media }}
|
7
7
|
{% endblock %}
|
8
8
|
|
9
|
-
{% block breadcrumbs %}{% if not is_popup %}
|
10
|
-
<div class="px-4">
|
11
|
-
<div class="container mb-6 mx-auto -my-3 lg:mb-12">
|
12
|
-
<ul class="flex flex-wrap">
|
13
|
-
{% url 'admin:index' as link %}
|
14
|
-
{% trans 'Home' as name %}
|
15
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=name %}
|
16
|
-
|
17
|
-
{% url 'admin:app_list' app_label=opts.app_label as link %}
|
18
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=opts.app_config.verbose_name %}
|
19
|
-
|
20
|
-
{% url opts|admin_urlname:'changelist' as link %}
|
21
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=opts.verbose_name_plural|capfirst %}
|
22
|
-
|
23
|
-
{% url opts|admin_urlname:'change' object.pk|admin_urlquote as link %}
|
24
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=original|truncatewords:'18' %}
|
25
|
-
|
26
|
-
{% trans 'Object permissions' as name %}
|
27
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link="../../" name=name %}
|
28
|
-
|
29
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link='' name=user_obj|truncatewords:"18" %}
|
30
|
-
</ul>
|
31
|
-
</div>
|
32
|
-
</div>
|
33
|
-
{% endif %}{% endblock %}
|
34
|
-
|
35
9
|
{% block content %}
|
36
10
|
<div class="border border-base-200 overflow-hidden rounded-default p-3 shadow-xs dark:border-base-800">
|
37
11
|
<form method="post">
|
@@ -9,29 +9,6 @@
|
|
9
9
|
{{ form.media }}
|
10
10
|
{% endblock %}
|
11
11
|
|
12
|
-
{% block breadcrumbs %}
|
13
|
-
<div class="px-4">
|
14
|
-
<div class="container mb-6 mx-auto -my-3 lg:mb-12">
|
15
|
-
<ul class="flex flex-wrap">
|
16
|
-
{% url 'admin:index' as link %}
|
17
|
-
{% trans 'Home' as name %}
|
18
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=name %}
|
19
|
-
|
20
|
-
{% url 'admin:app_list' app_label=opts.app_label as link %}
|
21
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=opts.app_config.verbose_name %}
|
22
|
-
|
23
|
-
{% url opts|admin_urlname:'changelist' as link %}
|
24
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=opts.verbose_name_plural|capfirst %}
|
25
|
-
|
26
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link='' name=cl.opts.verbose_name_plural|capfirst %}
|
27
|
-
|
28
|
-
{% trans 'Export' as name %}
|
29
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link='' name=name %}
|
30
|
-
</ul>
|
31
|
-
</div>
|
32
|
-
</div>
|
33
|
-
{% endblock %}
|
34
|
-
|
35
12
|
{% block content %}
|
36
13
|
<form action="{{ export_url }}" method="POST">
|
37
14
|
{% csrf_token %}
|
@@ -20,29 +20,6 @@
|
|
20
20
|
{% endif %}
|
21
21
|
{% endblock %}
|
22
22
|
|
23
|
-
{% block breadcrumbs %}
|
24
|
-
<div class="px-4">
|
25
|
-
<div class="container mb-6 mx-auto -my-3 lg:mb-12">
|
26
|
-
<ul class="flex flex-wrap">
|
27
|
-
{% url 'admin:index' as link %}
|
28
|
-
{% trans 'Home' as name %}
|
29
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=name %}
|
30
|
-
|
31
|
-
{% url 'admin:app_list' app_label=opts.app_label as link %}
|
32
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=opts.app_config.verbose_name %}
|
33
|
-
|
34
|
-
{% url opts|admin_urlname:'changelist' as link %}
|
35
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=opts.verbose_name_plural|capfirst %}
|
36
|
-
|
37
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link='' name=cl.opts.verbose_name_plural|capfirst %}
|
38
|
-
|
39
|
-
{% trans 'Import' as name %}
|
40
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link='' name=name %}
|
41
|
-
</ul>
|
42
|
-
</div>
|
43
|
-
</div>
|
44
|
-
{% endblock %}
|
45
|
-
|
46
23
|
{% block content %}
|
47
24
|
{% if confirm_form %}
|
48
25
|
{% include "admin/import_export/import_confirm.html" %}
|
@@ -1,38 +1,6 @@
|
|
1
1
|
{% extends "admin/change_form.html" %}
|
2
2
|
|
3
|
-
{% load
|
4
|
-
{% load url from simple_history_compat %}
|
5
|
-
|
6
|
-
{% block breadcrumbs %}
|
7
|
-
<div class="px-4">
|
8
|
-
<div class="container mb-6 mx-auto -my-3 lg:mb-12">
|
9
|
-
<ul class="flex flex-wrap">
|
10
|
-
{% url 'admin:index' as link %}
|
11
|
-
{% trans 'Home' as name %}
|
12
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=name %}
|
13
|
-
|
14
|
-
{% url 'admin:app_list' app_label=opts.app_label as link %}
|
15
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=opts.app_config.verbose_name %}
|
16
|
-
|
17
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link=changelist_url name=opts.verbose_name_plural|capfirst %}
|
18
|
-
|
19
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link=change_url name=original|truncatewords:'18' %}
|
20
|
-
|
21
|
-
{% url opts|admin_urlname:'change' object.pk|admin_urlquote as link %}
|
22
|
-
{% trans 'History' as name %}
|
23
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link="../" name=name %}
|
24
|
-
|
25
|
-
{% if revert_disabled %}
|
26
|
-
{% trans "View" as name %}
|
27
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link="" name=name %}
|
28
|
-
{% else %}
|
29
|
-
{% trans "Revert" as name %}
|
30
|
-
{% include 'unfold/helpers/breadcrumb_item.html' with link="" name=name %}
|
31
|
-
{% endif %}
|
32
|
-
</ul>
|
33
|
-
</div>
|
34
|
-
</div>
|
35
|
-
{% endblock %}
|
3
|
+
{% load i18n %}
|
36
4
|
|
37
5
|
{% block submit_buttons_top %}
|
38
6
|
{% include "simple_history/submit_line.html" %}
|
unfold/dataclasses.py
CHANGED
@@ -18,6 +18,14 @@ class UnfoldAction:
|
|
18
18
|
variant: Optional[ActionVariant] = ActionVariant.DEFAULT
|
19
19
|
|
20
20
|
|
21
|
+
@dataclass
|
22
|
+
class SearchResult:
|
23
|
+
title: str
|
24
|
+
description: str
|
25
|
+
link: str
|
26
|
+
icon: Optional[str]
|
27
|
+
|
28
|
+
|
21
29
|
@dataclass
|
22
30
|
class Favicon:
|
23
31
|
href: Union[str, Callable]
|
unfold/fields.py
CHANGED
@@ -139,7 +139,7 @@ class UnfoldAdminReadonlyField(helpers.AdminReadonlyField):
|
|
139
139
|
result_repr = display_for_field(value, f, self.empty_value_display)
|
140
140
|
return conditional_escape(result_repr)
|
141
141
|
elif isinstance(f, models.URLField):
|
142
|
-
return format_html(
|
142
|
+
return value and format_html(
|
143
143
|
'<a href="{}" class="text-primary-600 dark:text-primary-500">{}</a>',
|
144
144
|
value,
|
145
145
|
value,
|
unfold/settings.py
CHANGED
@@ -18,30 +18,30 @@ CONFIG_DEFAULTS = {
|
|
18
18
|
"SHOW_BACK_BUTTON": False,
|
19
19
|
"COLORS": {
|
20
20
|
"base": {
|
21
|
-
"50": "
|
22
|
-
"100": "
|
23
|
-
"200": "
|
24
|
-
"300": "
|
25
|
-
"400": "
|
26
|
-
"500": "
|
27
|
-
"600": "
|
28
|
-
"700": "
|
29
|
-
"800": "
|
30
|
-
"900": "
|
31
|
-
"950": "
|
21
|
+
"50": "oklch(98.5% .002 247.839)",
|
22
|
+
"100": "oklch(96.7% .003 264.542)",
|
23
|
+
"200": "oklch(92.8% .006 264.531)",
|
24
|
+
"300": "oklch(87.2% .01 258.338)",
|
25
|
+
"400": "oklch(70.7% .022 261.325)",
|
26
|
+
"500": "oklch(55.1% .027 264.364)",
|
27
|
+
"600": "oklch(44.6% .03 256.802)",
|
28
|
+
"700": "oklch(37.3% .034 259.733)",
|
29
|
+
"800": "oklch(27.8% .033 256.848)",
|
30
|
+
"900": "oklch(21% .034 264.665)",
|
31
|
+
"950": "oklch(13% .028 261.692)",
|
32
32
|
},
|
33
33
|
"primary": {
|
34
|
-
"50": "
|
35
|
-
"100": "
|
36
|
-
"200": "
|
37
|
-
"300": "
|
38
|
-
"400": "
|
39
|
-
"500": "
|
40
|
-
"600": "
|
41
|
-
"700": "
|
42
|
-
"800": "
|
43
|
-
"900": "
|
44
|
-
"950": "
|
34
|
+
"50": "oklch(97.7% .014 308.299)",
|
35
|
+
"100": "oklch(94.6% .033 307.174)",
|
36
|
+
"200": "oklch(90.2% .063 306.703)",
|
37
|
+
"300": "oklch(82.7% .119 306.383)",
|
38
|
+
"400": "oklch(71.4% .203 305.504)",
|
39
|
+
"500": "oklch(62.7% .265 303.9)",
|
40
|
+
"600": "oklch(55.8% .288 302.321)",
|
41
|
+
"700": "oklch(49.6% .265 301.924)",
|
42
|
+
"800": "oklch(43.8% .218 303.724)",
|
43
|
+
"900": "oklch(38.1% .176 304.987)",
|
44
|
+
"950": "oklch(29.1% .149 302.717)",
|
45
45
|
},
|
46
46
|
"font": {
|
47
47
|
"subtle-light": "var(--color-base-500)", # text-base-500
|
@@ -64,8 +64,14 @@ CONFIG_DEFAULTS = {
|
|
64
64
|
"action": None,
|
65
65
|
"navigation": [],
|
66
66
|
},
|
67
|
+
"COMMAND": {
|
68
|
+
"search_models": False, # Enable search in the models
|
69
|
+
"show_history": False, # Enable history in the command search
|
70
|
+
"search_callback": None, # Inject a custom callback to the search form
|
71
|
+
},
|
67
72
|
"SIDEBAR": {
|
68
73
|
"show_search": False,
|
74
|
+
"command_search": False,
|
69
75
|
"show_all_applications": False,
|
70
76
|
"navigation": [],
|
71
77
|
},
|
unfold/sites.py
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
import copy
|
2
|
+
import time
|
2
3
|
from http import HTTPStatus
|
3
4
|
from typing import Any, Callable, Optional, Union
|
4
5
|
from urllib.parse import parse_qs, urlparse
|
5
6
|
|
6
7
|
from django.contrib.admin import AdminSite
|
8
|
+
from django.core.cache import cache
|
7
9
|
from django.core.validators import EMPTY_VALUES
|
8
10
|
from django.http import HttpRequest, HttpResponse
|
9
11
|
from django.template.response import TemplateResponse
|
10
12
|
from django.urls import URLPattern, path, reverse, reverse_lazy
|
11
13
|
from django.utils.functional import lazy
|
12
14
|
from django.utils.module_loading import import_string
|
15
|
+
from django.utils.text import slugify
|
13
16
|
|
14
|
-
from unfold.dataclasses import DropdownItem, Favicon
|
17
|
+
from unfold.dataclasses import DropdownItem, Favicon, SearchResult
|
15
18
|
|
16
19
|
try:
|
17
20
|
from django.contrib.auth.decorators import login_not_required
|
@@ -22,7 +25,7 @@ except ImportError:
|
|
22
25
|
|
23
26
|
|
24
27
|
from unfold.settings import get_config
|
25
|
-
from unfold.utils import
|
28
|
+
from unfold.utils import convert_color
|
26
29
|
from unfold.widgets import (
|
27
30
|
BUTTON_CLASSES,
|
28
31
|
CHECKBOX_CLASSES,
|
@@ -112,6 +115,12 @@ class UnfoldAdminSite(AdminSite):
|
|
112
115
|
"tab_list": self.get_tabs_list(request),
|
113
116
|
"styles": self._get_list("STYLES", request),
|
114
117
|
"scripts": self._get_list("SCRIPTS", request),
|
118
|
+
"command_show_history": self._get_config("COMMAND", request).get(
|
119
|
+
"show_history"
|
120
|
+
),
|
121
|
+
"sidebar_command_search": self._get_config("SIDEBAR", request).get(
|
122
|
+
"command_search"
|
123
|
+
),
|
115
124
|
"sidebar_show_all_applications": self._get_value(
|
116
125
|
sidebar_config.get("show_all_applications"), request
|
117
126
|
),
|
@@ -165,26 +174,21 @@ class UnfoldAdminSite(AdminSite):
|
|
165
174
|
|
166
175
|
return HttpResponse(status=HTTPStatus.OK)
|
167
176
|
|
168
|
-
def
|
169
|
-
self,
|
170
|
-
) ->
|
171
|
-
query = request.GET.get("s").lower()
|
172
|
-
app_list = super().get_app_list(request)
|
173
|
-
apps = []
|
177
|
+
def _search_apps(
|
178
|
+
self, app_list: list[dict[str, Any]], search_term: str
|
179
|
+
) -> list[SearchResult]:
|
174
180
|
results = []
|
175
|
-
|
176
|
-
if query in EMPTY_VALUES:
|
177
|
-
return HttpResponse()
|
181
|
+
apps = []
|
178
182
|
|
179
183
|
for app in app_list:
|
180
|
-
if
|
184
|
+
if search_term in app["name"].lower():
|
181
185
|
apps.append(app)
|
182
186
|
continue
|
183
187
|
|
184
188
|
models = []
|
185
189
|
|
186
190
|
for model in app["models"]:
|
187
|
-
if
|
191
|
+
if search_term in model["name"].lower():
|
188
192
|
models.append(model)
|
189
193
|
|
190
194
|
if len(models) > 0:
|
@@ -194,17 +198,111 @@ class UnfoldAdminSite(AdminSite):
|
|
194
198
|
for app in apps:
|
195
199
|
for model in app["models"]:
|
196
200
|
results.append(
|
197
|
-
|
198
|
-
"
|
199
|
-
"
|
200
|
-
|
201
|
+
SearchResult(
|
202
|
+
title=str(model["name"]),
|
203
|
+
description=app["name"],
|
204
|
+
link=model["admin_url"],
|
205
|
+
icon="tag",
|
206
|
+
)
|
207
|
+
)
|
208
|
+
|
209
|
+
return results
|
210
|
+
|
211
|
+
def _search_models(
|
212
|
+
self, request: HttpRequest, app_list: list[dict[str, Any]], search_term: str
|
213
|
+
) -> list[SearchResult]:
|
214
|
+
results = []
|
215
|
+
|
216
|
+
for app in app_list:
|
217
|
+
for model in app["models"]:
|
218
|
+
admin_instance = self._registry.get(model["model"])
|
219
|
+
search_fields = admin_instance.get_search_fields(request)
|
220
|
+
|
221
|
+
if not search_fields:
|
222
|
+
continue
|
223
|
+
|
224
|
+
pks = []
|
225
|
+
|
226
|
+
qs = admin_instance.get_queryset(request)
|
227
|
+
search_results, _has_duplicates = admin_instance.get_search_results(
|
228
|
+
request, qs, search_term
|
201
229
|
)
|
202
230
|
|
231
|
+
for item in search_results:
|
232
|
+
if item.pk in pks:
|
233
|
+
continue
|
234
|
+
|
235
|
+
pks.append(item.pk)
|
236
|
+
|
237
|
+
link = reverse_lazy(
|
238
|
+
f"{self.name}:{admin_instance.model._meta.app_label}_{admin_instance.model._meta.model_name}_change",
|
239
|
+
args=(item.pk,),
|
240
|
+
)
|
241
|
+
|
242
|
+
results.append(
|
243
|
+
SearchResult(
|
244
|
+
title=str(item),
|
245
|
+
description=f"{item._meta.app_label.capitalize()} - {item._meta.verbose_name.capitalize()}",
|
246
|
+
link=link,
|
247
|
+
icon="data_object",
|
248
|
+
)
|
249
|
+
)
|
250
|
+
|
251
|
+
return results
|
252
|
+
|
253
|
+
def search(
|
254
|
+
self, request: HttpRequest, extra_context: Optional[dict[str, Any]] = None
|
255
|
+
) -> TemplateResponse:
|
256
|
+
start_time = time.time()
|
257
|
+
|
258
|
+
CACHE_TIMEOUT = 10
|
259
|
+
|
260
|
+
search_term = request.GET.get("s")
|
261
|
+
extended_search = "extended" in request.GET
|
262
|
+
app_list = super().get_app_list(request)
|
263
|
+
template_name = "unfold/helpers/search_results.html"
|
264
|
+
|
265
|
+
if search_term in EMPTY_VALUES:
|
266
|
+
return HttpResponse()
|
267
|
+
|
268
|
+
search_term = search_term.lower()
|
269
|
+
cache_key = f"unfold_search_{request.user.pk}_{slugify(search_term)}"
|
270
|
+
cache_results = cache.get(cache_key)
|
271
|
+
|
272
|
+
if extended_search:
|
273
|
+
template_name = "unfold/helpers/command_results.html"
|
274
|
+
|
275
|
+
if cache_results:
|
276
|
+
results = cache_results
|
277
|
+
else:
|
278
|
+
results = self._search_apps(app_list, search_term)
|
279
|
+
search_models = self._get_config("COMMAND", request).get("search_models")
|
280
|
+
search_callback = self._get_config("COMMAND", request).get(
|
281
|
+
"search_callback"
|
282
|
+
)
|
283
|
+
|
284
|
+
if extended_search:
|
285
|
+
if search_callback:
|
286
|
+
results.extend(
|
287
|
+
self._get_value(search_callback, request, search_term)
|
288
|
+
)
|
289
|
+
|
290
|
+
if search_models is True:
|
291
|
+
results.extend(self._search_models(request, app_list, search_term))
|
292
|
+
|
293
|
+
cache.set(cache_key, results, timeout=CACHE_TIMEOUT)
|
294
|
+
|
295
|
+
execution_time = time.time() - start_time
|
296
|
+
|
203
297
|
return TemplateResponse(
|
204
298
|
request,
|
205
|
-
template=
|
299
|
+
template=template_name,
|
206
300
|
context={
|
207
301
|
"results": results,
|
302
|
+
"execution_time": execution_time,
|
303
|
+
"command_show_history": self._get_config("COMMAND", request).get(
|
304
|
+
"show_history"
|
305
|
+
),
|
208
306
|
},
|
209
307
|
headers={
|
210
308
|
"HX-Trigger": "search",
|
@@ -260,8 +358,8 @@ class UnfoldAdminSite(AdminSite):
|
|
260
358
|
# Checks if any tab item is active and then marks the sidebar link as active
|
261
359
|
if (
|
262
360
|
tabs
|
263
|
-
and
|
264
|
-
and
|
361
|
+
and self._get_is_tab_active(request, tabs, link)
|
362
|
+
and "active" not in item
|
265
363
|
):
|
266
364
|
item["active"] = True
|
267
365
|
|
@@ -408,7 +506,7 @@ class UnfoldAdminSite(AdminSite):
|
|
408
506
|
request, tab_item.get("link_callback") or tab_item["link"]
|
409
507
|
):
|
410
508
|
has_tab_link_active = True
|
411
|
-
|
509
|
+
continue
|
412
510
|
|
413
511
|
if has_primary_link and has_tab_link_active:
|
414
512
|
return True
|
@@ -440,33 +538,12 @@ class UnfoldAdminSite(AdminSite):
|
|
440
538
|
def _get_colors(self, key: str, *args) -> dict[str, dict[str, str]]:
|
441
539
|
colors = self._get_config(key, *args)
|
442
540
|
|
443
|
-
def rgb_to_values(value: str) -> str:
|
444
|
-
return ", ".join(
|
445
|
-
list(
|
446
|
-
map(
|
447
|
-
str.strip,
|
448
|
-
value.removeprefix("rgb(").removesuffix(")").split(","),
|
449
|
-
)
|
450
|
-
)
|
451
|
-
)
|
452
|
-
|
453
|
-
def hex_to_values(value: str) -> str:
|
454
|
-
return ", ".join(str(item) for item in hex_to_rgb(value))
|
455
|
-
|
456
541
|
for name, weights in colors.items():
|
457
542
|
weights = self._get_value(weights, *args)
|
458
543
|
colors[name] = weights
|
459
544
|
|
460
545
|
for weight, value in weights.items():
|
461
|
-
|
462
|
-
colors[name][weight] = hex_to_values(value)
|
463
|
-
elif value.startswith("rgb"):
|
464
|
-
colors[name][weight] = rgb_to_values(value)
|
465
|
-
elif isinstance(value, str) and all(
|
466
|
-
part.isdigit() for part in value.split()
|
467
|
-
):
|
468
|
-
colors[name][weight] = ", ".join(value.split(" "))
|
469
|
-
pass
|
546
|
+
colors[name][weight] = convert_color(value)
|
470
547
|
|
471
548
|
return colors
|
472
549
|
|
@@ -310,7 +310,7 @@
|
|
310
310
|
};
|
311
311
|
|
312
312
|
// Tabular inlines ---------------------------------------------------------
|
313
|
-
$.fn.tabularFormset = function (selector, options) {
|
313
|
+
$.fn.tabularFormset = function (selector, options, callback = null) {
|
314
314
|
const $rows = $(this);
|
315
315
|
|
316
316
|
const reinitDateTimeShortCuts = function () {
|
@@ -370,11 +370,15 @@
|
|
370
370
|
addButton: options.addButton,
|
371
371
|
});
|
372
372
|
|
373
|
+
if (typeof callback === "function") {
|
374
|
+
callback();
|
375
|
+
}
|
376
|
+
|
373
377
|
return $rows;
|
374
378
|
};
|
375
379
|
|
376
380
|
// Stacked inlines ---------------------------------------------------------
|
377
|
-
$.fn.stackedFormset = function (selector, options) {
|
381
|
+
$.fn.stackedFormset = function (selector, options, callback = null) {
|
378
382
|
const $rows = $(this);
|
379
383
|
const updateInlineLabel = function (row) {
|
380
384
|
$(selector)
|
@@ -449,26 +453,47 @@
|
|
449
453
|
addButton: options.addButton,
|
450
454
|
});
|
451
455
|
|
456
|
+
if (typeof callback === "function") {
|
457
|
+
callback();
|
458
|
+
}
|
459
|
+
|
452
460
|
return $rows;
|
453
461
|
};
|
454
462
|
|
463
|
+
$(window).on("htmx:afterSettle", function (event) {
|
464
|
+
if (event.target.classList.contains("js-inline-admin-formset")) {
|
465
|
+
initInlines($(event.target), function () {
|
466
|
+
if (typeof DateTimeShortcuts !== "undefined") {
|
467
|
+
$(".datetimeshortcuts").remove();
|
468
|
+
DateTimeShortcuts.init();
|
469
|
+
}
|
470
|
+
|
471
|
+
$(event.target).find(".admin-autocomplete").djangoAdminSelect2();
|
472
|
+
});
|
473
|
+
}
|
474
|
+
});
|
475
|
+
|
455
476
|
$(document).ready(function () {
|
456
477
|
$(".js-inline-admin-formset").each(function () {
|
457
|
-
|
458
|
-
inlineOptions = data.inlineFormset;
|
459
|
-
let selector;
|
460
|
-
switch (data.inlineType) {
|
461
|
-
case "stacked":
|
462
|
-
selector = inlineOptions.name + "-group .inline-related";
|
463
|
-
$(selector).stackedFormset(selector, inlineOptions.options);
|
464
|
-
break;
|
465
|
-
case "tabular":
|
466
|
-
selector =
|
467
|
-
inlineOptions.name +
|
468
|
-
"-group .tabular.inline-related tbody:last > tr.form-row";
|
469
|
-
$(selector).tabularFormset(selector, inlineOptions.options);
|
470
|
-
break;
|
471
|
-
}
|
478
|
+
initInlines(this);
|
472
479
|
});
|
473
480
|
});
|
481
|
+
|
482
|
+
function initInlines(el, callback = null) {
|
483
|
+
const data = $(el).data(),
|
484
|
+
inlineOptions = data.inlineFormset;
|
485
|
+
let selector;
|
486
|
+
switch (data.inlineType) {
|
487
|
+
case "stacked":
|
488
|
+
selector = inlineOptions.name + "-group .inline-related";
|
489
|
+
$(selector).stackedFormset(selector, inlineOptions.options, callback);
|
490
|
+
break;
|
491
|
+
case "tabular":
|
492
|
+
selector =
|
493
|
+
inlineOptions.name +
|
494
|
+
"-group .tabular.inline-related tbody:last > tr.form-row";
|
495
|
+
$(selector).tabularFormset(selector, inlineOptions.options, callback);
|
496
|
+
break;
|
497
|
+
}
|
498
|
+
}
|
474
499
|
}
|