django-unfold 0.57.0__py3-none-any.whl → 0.59.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.
Files changed (57) hide show
  1. {django_unfold-0.57.0.dist-info → django_unfold-0.59.0.dist-info}/METADATA +1 -1
  2. {django_unfold-0.57.0.dist-info → django_unfold-0.59.0.dist-info}/RECORD +57 -55
  3. unfold/checks.py +24 -2
  4. unfold/contrib/filters/templates/unfold/filters/filters_numeric_slider.html +2 -2
  5. unfold/contrib/import_export/templates/admin/import_export/base.html +1 -5
  6. unfold/contrib/import_export/templates/admin/import_export/import_form.html +1 -1
  7. unfold/contrib/simple_history/templates/simple_history/object_history_form.html +1 -1
  8. unfold/decorators.py +28 -15
  9. unfold/fields.py +1 -1
  10. unfold/forms.py +4 -2
  11. unfold/layout.py +16 -0
  12. unfold/mixins/action_model_admin.py +22 -14
  13. unfold/paginator.py +12 -1
  14. unfold/settings.py +8 -1
  15. unfold/sites.py +87 -40
  16. unfold/static/admin/js/admin/RelatedObjectLookups.js +9 -3
  17. unfold/static/unfold/css/styles.css +2 -2
  18. unfold/styles.css +59 -104
  19. unfold/templates/admin/auth/user/change_password.html +1 -1
  20. unfold/templates/admin/base.html +1 -1
  21. unfold/templates/admin/change_form.html +2 -1
  22. unfold/templates/admin/edit_inline/stacked.html +1 -1
  23. unfold/templates/admin/includes/fieldset.html +9 -3
  24. unfold/templates/admin/login.html +1 -1
  25. unfold/templates/admin/pagination.html +1 -1
  26. unfold/templates/admin/submit_line.html +7 -7
  27. unfold/templates/registration/password_change_done.html +1 -1
  28. unfold/templates/registration/password_change_form.html +1 -1
  29. unfold/templates/unfold/components/button.html +1 -1
  30. unfold/templates/unfold/components/card.html +23 -23
  31. unfold/templates/unfold/components/progress.html +9 -7
  32. unfold/templates/unfold/components/table.html +5 -5
  33. unfold/templates/unfold/helpers/account_links.html +14 -6
  34. unfold/templates/unfold/helpers/change_list_actions.html +2 -2
  35. unfold/templates/unfold/helpers/change_list_filter_actions.html +2 -2
  36. unfold/templates/unfold/helpers/edit_inline/tabular_heading.html +1 -1
  37. unfold/templates/unfold/helpers/empty_results.html +2 -2
  38. unfold/templates/unfold/helpers/field.html +2 -2
  39. unfold/templates/unfold/helpers/header.html +1 -1
  40. unfold/templates/unfold/helpers/language_form.html +10 -0
  41. unfold/templates/unfold/helpers/language_switch.html +17 -19
  42. unfold/templates/unfold/helpers/navigation.html +1 -1
  43. unfold/templates/unfold/helpers/pagination_infinite.html +3 -3
  44. unfold/templates/unfold/helpers/theme_switch.html +29 -27
  45. unfold/templates/unfold/helpers/userlinks.html +2 -6
  46. unfold/templates/unfold/helpers/welcomemsg.html +9 -7
  47. unfold/templates/unfold/widgets/select.html +1 -1
  48. unfold/templates/unfold_crispy/field.html +1 -1
  49. unfold/templates/unfold_crispy/layout/checkbox.html +2 -2
  50. unfold/templates/unfold_crispy/layout/fieldset.html +4 -2
  51. unfold/templates/unfold_crispy/layout/fieldset_subheader.html +3 -0
  52. unfold/templates/unfold_crispy/layout/table_inline_formset.html +18 -16
  53. unfold/templatetags/unfold.py +20 -1
  54. unfold/utils.py +2 -2
  55. unfold/widgets.py +10 -4
  56. {django_unfold-0.57.0.dist-info → django_unfold-0.59.0.dist-info}/LICENSE.md +0 -0
  57. {django_unfold-0.57.0.dist-info → django_unfold-0.59.0.dist-info}/WHEEL +0 -0
unfold/sites.py CHANGED
@@ -102,6 +102,13 @@ class UnfoldAdminSite(AdminSite):
102
102
  "environment_title_prefix": self._get_config(
103
103
  "ENVIRONMENT_TITLE_PREFIX", request
104
104
  ),
105
+ "languages_list": self._get_value(
106
+ self._get_config("LANGUAGES", request).get("navigation"), request
107
+ ),
108
+ "languages_action": self._get_value(
109
+ self._get_config("LANGUAGES", request).get("action"), request
110
+ ),
111
+ "account_links": self._get_account_links(request),
105
112
  "tab_list": self.get_tabs_list(request),
106
113
  "styles": self._get_list("STYLES", request),
107
114
  "scripts": self._get_list("SCRIPTS", request),
@@ -243,58 +250,75 @@ class UnfoldAdminSite(AdminSite):
243
250
  results = []
244
251
 
245
252
  for group in copy.deepcopy(navigation):
246
- allowed_items = []
253
+ group["items"] = self._get_navigation_items(request, group["items"], tabs)
254
+ results.append(group)
247
255
 
248
- for item in group["items"]:
249
- if "active" in item:
250
- item["active"] = self._get_value(item["active"], request)
251
- else:
252
- item["active"] = self._get_is_active(
253
- request, item.get("link_callback") or item["link"]
254
- )
256
+ return results
255
257
 
256
- # Checks if any tab item is active and then marks the sidebar link as active
257
- for tab in tabs:
258
- has_primary_link = False
259
- has_tab_link_active = False
258
+ def _get_navigation_items(
259
+ self, request: HttpRequest, items: list[dict], tabs: list[dict] = None
260
+ ) -> list:
261
+ allowed_items = []
260
262
 
261
- for tab_item in tab["items"]:
262
- if item["link"] == tab_item["link"]:
263
- has_primary_link = True
264
- continue
263
+ for item in items:
264
+ link = item.get("link")
265
265
 
266
- if self._get_is_active(
267
- request, tab_item.get("link_callback") or tab_item["link"]
268
- ):
269
- has_tab_link_active = True
270
- break
266
+ if "active" in item:
267
+ item["active"] = self._get_value(item["active"], request)
268
+ else:
269
+ item["active"] = self._get_is_active(
270
+ request, item.get("link_callback") or link
271
+ )
271
272
 
272
- if has_primary_link and has_tab_link_active:
273
- item["active"] = True
273
+ # Checks if any tab item is active and then marks the sidebar link as active
274
+ if (
275
+ tabs
276
+ and (is_active := self._get_is_tab_active(request, tabs, link))
277
+ and is_active
278
+ ):
279
+ item["active"] = True
274
280
 
275
- if isinstance(item["link"], Callable):
276
- item["link_callback"] = lazy(item["link"])(request)
281
+ # Link callback
282
+ if isinstance(link, Callable):
283
+ item["link_callback"] = lazy(link)(request)
277
284
 
278
- # Permission callback
279
- item["has_permission"] = self._call_permission_callback(
280
- item.get("permission"), request
281
- )
285
+ # Permission callback
286
+ item["has_permission"] = self._call_permission_callback(
287
+ item.get("permission"), request
288
+ )
282
289
 
283
- # Badge callbacks
284
- if "badge" in item and isinstance(item["badge"], str):
285
- try:
286
- callback = import_string(item["badge"])
287
- item["badge_callback"] = lazy(callback)(request)
288
- except ImportError:
289
- pass
290
+ # Badge callbacks
291
+ if "badge" in item and isinstance(item["badge"], str):
292
+ try:
293
+ callback = import_string(item["badge"])
294
+ item["badge_callback"] = lazy(callback)(request)
295
+ except ImportError:
296
+ pass
290
297
 
291
- allowed_items.append(item)
298
+ # Process nested items
299
+ if "items" in item:
300
+ item["items"] = self._get_navigation_items(request, item["items"])
292
301
 
293
- group["items"] = allowed_items
302
+ allowed_items.append(item)
294
303
 
295
- results.append(group)
304
+ return allowed_items
296
305
 
297
- return results
306
+ def _get_account_links(self, request: HttpRequest) -> list[dict[str, Any]]:
307
+ links = []
308
+
309
+ navigation = self._get_value(
310
+ get_config(self.settings_name)["ACCOUNT"].get("navigation"), request
311
+ )
312
+
313
+ for item in navigation:
314
+ links.append(
315
+ {
316
+ "title": self._get_value(item["title"], request),
317
+ "link": self._get_value(item["link"], request),
318
+ }
319
+ )
320
+
321
+ return links
298
322
 
299
323
  def get_tabs_list(self, request: HttpRequest) -> list[dict[str, Any]]:
300
324
  tabs = copy.deepcopy(self._get_config("TABS", request))
@@ -381,6 +405,29 @@ class UnfoldAdminSite(AdminSite):
381
405
 
382
406
  return False
383
407
 
408
+ def _get_is_tab_active(
409
+ self, request: HttpRequest, tabs: list[dict], link: str
410
+ ) -> bool:
411
+ for tab in tabs:
412
+ has_primary_link = False
413
+ has_tab_link_active = False
414
+
415
+ for tab_item in tab["items"]:
416
+ if link == tab_item["link"]:
417
+ has_primary_link = True
418
+ continue
419
+
420
+ if self._get_is_active(
421
+ request, tab_item.get("link_callback") or tab_item["link"]
422
+ ):
423
+ has_tab_link_active = True
424
+ break
425
+
426
+ if has_primary_link and has_tab_link_active:
427
+ return True
428
+
429
+ return False
430
+
384
431
  def _get_config(self, key: str, *args) -> Any:
385
432
  config = get_config(self.settings_name)
386
433
 
@@ -74,9 +74,15 @@
74
74
 
75
75
  function updateRelatedObjectLinks(triggeringLink) {
76
76
  const $this = $(triggeringLink);
77
- const siblings = $this.nextAll(
78
- ".view-related, .change-related, .delete-related"
79
- );
77
+ // !CHANGED from original
78
+ // const siblings = $this.nextAll(
79
+ // ".view-related, .change-related, .delete-related"
80
+ // );
81
+
82
+ const siblings = $this
83
+ .parent()
84
+ .nextAll(".view-related, .change-related, .delete-related");
85
+
80
86
  if (!siblings.length) {
81
87
  return;
82
88
  }