django-unfold 0.30.0__tar.gz → 0.31.0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (205) hide show
  1. {django_unfold-0.30.0 → django_unfold-0.31.0}/PKG-INFO +59 -18
  2. {django_unfold-0.30.0 → django_unfold-0.31.0}/README.md +58 -17
  3. {django_unfold-0.30.0 → django_unfold-0.31.0}/pyproject.toml +1 -1
  4. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/admin.py +30 -11
  5. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_numeric_slider.html +3 -3
  6. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/templates/unfold/forms/array.html +3 -1
  7. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/templates/unfold/forms/helpers/toolbar.html +6 -6
  8. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/templates/unfold/forms/wysiwyg.html +1 -1
  9. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/widgets.py +22 -11
  10. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/templates/unfold/guardian/group_form.html +4 -4
  11. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/templates/unfold/guardian/user_form.html +4 -4
  12. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/change_form.html +1 -1
  13. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_errors.html +1 -1
  14. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_preview.html +3 -3
  15. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_validation.html +4 -4
  16. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/inlines/forms.py +1 -2
  17. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/simple_history/templates/simple_history/object_history_list.html +9 -9
  18. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/simple_history/templates/simple_history/submit_line.html +1 -1
  19. django_unfold-0.31.0/src/unfold/dataclasses.py +22 -0
  20. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/fields.py +1 -1
  21. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/settings.py +1 -0
  22. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/sites.py +39 -15
  23. django_unfold-0.31.0/src/unfold/static/unfold/css/styles.css +1 -0
  24. django_unfold-0.31.0/src/unfold/static/unfold/js/alpine.anchor.js +1 -0
  25. django_unfold-0.31.0/src/unfold/static/unfold/js/alpine.js +5 -0
  26. django_unfold-0.31.0/src/unfold/static/unfold/js/alpine.persist.js +1 -0
  27. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/js/app.js +26 -3
  28. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/styles.css +10 -10
  29. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/actions.html +1 -1
  30. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/app_list.html +1 -1
  31. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/base.html +4 -4
  32. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/change_list.html +2 -2
  33. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/change_list_results.html +2 -2
  34. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/delete_confirmation.html +4 -4
  35. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/delete_selected_confirmation.html +4 -4
  36. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/edit_inline/stacked.html +2 -2
  37. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/edit_inline/tabular.html +3 -3
  38. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/filter.html +2 -2
  39. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/includes/fieldset.html +1 -1
  40. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/includes/object_delete_summary.html +1 -1
  41. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/login.html +8 -8
  42. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/object_history.html +4 -4
  43. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/search_form.html +1 -1
  44. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/submit_line.html +7 -5
  45. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/auth/widgets/read_only_password_hash.html +1 -1
  46. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/registration/logged_out.html +1 -1
  47. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/change_list_filter.html +9 -1
  48. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/account_links.html +2 -2
  49. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/actions_row.html +4 -4
  50. django_unfold-0.31.0/src/unfold/templates/unfold/helpers/app_list.html +99 -0
  51. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/app_list_default.html +4 -4
  52. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/breadcrumb_item.html +1 -1
  53. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/field_readonly_value.html +1 -1
  54. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/fieldset_row.html +6 -6
  55. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/fieldsets_tabs.html +2 -2
  56. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/header.html +1 -1
  57. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/help_text.html +1 -1
  58. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/history.html +1 -1
  59. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/label.html +1 -1
  60. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/search.html +7 -4
  61. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/search_results.html +2 -2
  62. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/tab_action.html +1 -1
  63. django_unfold-0.31.0/src/unfold/templates/unfold/helpers/tab_list.html +62 -0
  64. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/theme_switch.html +2 -2
  65. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/layouts/skeleton.html +6 -1
  66. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/clearable_file_input.html +14 -6
  67. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/clearable_file_input_small.html +4 -4
  68. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/split_datetime.html +2 -2
  69. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templatetags/unfold.py +33 -12
  70. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templatetags/unfold_list.py +16 -6
  71. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/widgets.py +2 -2
  72. django_unfold-0.30.0/src/unfold/dataclasses.py +0 -13
  73. django_unfold-0.30.0/src/unfold/static/unfold/css/styles.css +0 -1
  74. django_unfold-0.30.0/src/unfold/static/unfold/js/alpine.js +0 -5
  75. django_unfold-0.30.0/src/unfold/static/unfold/js/alpine.persist.js +0 -1
  76. django_unfold-0.30.0/src/unfold/templates/unfold/helpers/app_list.html +0 -89
  77. django_unfold-0.30.0/src/unfold/templates/unfold/helpers/tab_list.html +0 -40
  78. {django_unfold-0.30.0 → django_unfold-0.31.0}/LICENSE.md +0 -0
  79. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/__init__.py +0 -0
  80. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/apps.py +0 -0
  81. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/checks.py +0 -0
  82. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/__init__.py +0 -0
  83. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/__init__.py +0 -0
  84. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/admin.py +0 -0
  85. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/apps.py +0 -0
  86. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/forms.py +0 -0
  87. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/static/unfold/filters/css/nouislider.min.css +0 -0
  88. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/static/unfold/filters/js/DateTimeShortcuts.js +0 -0
  89. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/static/unfold/filters/js/admin-numeric-filter.js +0 -0
  90. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/static/unfold/filters/js/nouislider.min.js +0 -0
  91. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/static/unfold/filters/js/wNumb.min.js +0 -0
  92. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_date_range.html +0 -0
  93. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_datetime_range.html +0 -0
  94. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_field.html +0 -0
  95. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_numeric_range.html +0 -0
  96. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_numeric_single.html +0 -0
  97. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/__init__.py +0 -0
  98. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/apps.py +0 -0
  99. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/static/unfold/forms/css/trix.css +0 -0
  100. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/static/unfold/forms/js/trix.config.js +0 -0
  101. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/static/unfold/forms/js/trix.js +0 -0
  102. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/__init__.py +0 -0
  103. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/apps.py +0 -0
  104. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/change_form.html +0 -0
  105. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/field.html +0 -0
  106. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/obj_perms_manage.html +0 -0
  107. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/obj_perms_manage_group.html +0 -0
  108. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/obj_perms_manage_user.html +0 -0
  109. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/__init__.py +0 -0
  110. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/apps.py +0 -0
  111. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/forms.py +0 -0
  112. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/base.html +0 -0
  113. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/change_list_export.html +0 -0
  114. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/change_list_export_item.html +0 -0
  115. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/change_list_import_export.html +0 -0
  116. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/change_list_import_item.html +0 -0
  117. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/export.html +0 -0
  118. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/import.html +0 -0
  119. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_confirm.html +0 -0
  120. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_form.html +0 -0
  121. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/resource_fields_list.html +0 -0
  122. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/inlines/__init__.py +0 -0
  123. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/inlines/admin.py +0 -0
  124. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/inlines/apps.py +0 -0
  125. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/inlines/checks.py +0 -0
  126. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/simple_history/__init__.py +0 -0
  127. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/simple_history/apps.py +0 -0
  128. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/simple_history/templates/simple_history/object_history.html +0 -0
  129. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/simple_history/templates/simple_history/object_history_form.html +0 -0
  130. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/decorators.py +0 -0
  131. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/exceptions.py +0 -0
  132. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/forms.py +0 -0
  133. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/css/simplebar.css +0 -0
  134. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/fonts/inter/Inter-Bold.woff2 +0 -0
  135. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/fonts/inter/Inter-Medium.woff2 +0 -0
  136. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/fonts/inter/Inter-Regular.woff2 +0 -0
  137. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/fonts/inter/Inter-SemiBold.woff2 +0 -0
  138. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/fonts/inter/styles.css +0 -0
  139. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/fonts/material-symbols/Material-Symbols-Outlined.woff2 +0 -0
  140. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/fonts/material-symbols/styles.css +0 -0
  141. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/js/chart.js +0 -0
  142. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/js/htmx.js +0 -0
  143. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/js/simplebar.js +0 -0
  144. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/app_index.html +0 -0
  145. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/auth/user/add_form.html +0 -0
  146. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/auth/user/change_password.html +0 -0
  147. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/base_site.html +0 -0
  148. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/change_form.html +0 -0
  149. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/change_form_object_tools.html +0 -0
  150. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/change_list_object_tools.html +0 -0
  151. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/date_hierarchy.html +0 -0
  152. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/index.html +0 -0
  153. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/nav_sidebar.html +0 -0
  154. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/pagination.html +0 -0
  155. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/registration/password_change_done.html +0 -0
  156. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/registration/password_change_form.html +0 -0
  157. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/button.html +0 -0
  158. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/card.html +0 -0
  159. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/chart/bar.html +0 -0
  160. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/chart/line.html +0 -0
  161. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/container.html +0 -0
  162. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/flex.html +0 -0
  163. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/navigation.html +0 -0
  164. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/progress.html +0 -0
  165. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/separator.html +0 -0
  166. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/text.html +0 -0
  167. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/title.html +0 -0
  168. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/add_link.html +0 -0
  169. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/attrs.html +0 -0
  170. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/boolean.html +0 -0
  171. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/display_header.html +0 -0
  172. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/display_label.html +0 -0
  173. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/field.html +0 -0
  174. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/field_readonly.html +0 -0
  175. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/form_errors.html +0 -0
  176. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/form_label.html +0 -0
  177. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/messages/error.html +0 -0
  178. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/messages/errornote.html +0 -0
  179. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/messages/info.html +0 -0
  180. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/messages.html +0 -0
  181. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/navigation.html +0 -0
  182. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/pagination_current_item.html +0 -0
  183. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/pagination_ellipsis.html +0 -0
  184. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/site_icon.html +0 -0
  185. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/site_logo.html +0 -0
  186. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/submit.html +0 -0
  187. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/userlinks.html +0 -0
  188. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/welcomemsg.html +0 -0
  189. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/layouts/base.html +0 -0
  190. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/layouts/base_simple.html +0 -0
  191. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/date.html +0 -0
  192. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/foreign_key_raw_id.html +0 -0
  193. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/radio.html +0 -0
  194. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/radio_option.html +0 -0
  195. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/range.html +0 -0
  196. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/related_widget_wrapper.html +0 -0
  197. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/split_datetime_vertical.html +0 -0
  198. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/split_money.html +0 -0
  199. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/textarea.html +0 -0
  200. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/textarea_expandable.html +0 -0
  201. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/time.html +0 -0
  202. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templatetags/__init__.py +0 -0
  203. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/typing.py +0 -0
  204. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/utils.py +0 -0
  205. {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/views.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-unfold
3
- Version: 0.30.0
3
+ Version: 0.31.0
4
4
  Summary: Modern Django admin theme for seamless interface development
5
5
  Home-page: https://unfoldadmin.com
6
6
  License: MIT
@@ -33,7 +33,7 @@ Description-Content-Type: text/markdown
33
33
  ![Code Style - Ruff](https://img.shields.io/badge/code%20style-ruff-30173D.svg?style=for-the-badge)
34
34
  ![Pre Commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white&style=for-the-badge)
35
35
 
36
- Unfold is theme for Django admin incorporating most common practises for building full-fledged admin areas. It is designed to work at the top of default administration provided by Django.
36
+ Unfold is a theme for Django admin incorporating most common practices for building full-fledged admin areas. It is designed to work on top of default administration provided by Django.
37
37
 
38
38
  - **Unfold:** demo site is available at [unfoldadmin.com](https://unfoldadmin.com?utm_medium=github&utm_source=unfold)
39
39
  - **Formula:** repository with demo implementation at [github.com/unfoldadmin/formula](https://github.com/unfoldadmin/formula)
@@ -45,7 +45,7 @@ Did you decide to start using Unfold but you don't have time to make the switch
45
45
 
46
46
  ## Features <!-- omit from toc -->
47
47
 
48
- - **Visual**: provides new user interface based on Tailwind CSS framework
48
+ - **Visual**: provides a new user interface based on Tailwind CSS framework
49
49
  - **Sidebar:** simplifies definition of custom sidebar navigation with icons
50
50
  - **Dark mode:** supports both light and dark mode versions
51
51
  - **Configuration:** most of the basic options can be changed in settings.py
@@ -55,14 +55,16 @@ Did you decide to start using Unfold but you don't have time to make the switch
55
55
  - **Array widget:** built-in widget for `django.contrib.postgres.fields.ArrayField`
56
56
  - **Filters:** custom dropdown, numeric, datetime, and text fields
57
57
  - **Dashboard:** custom components for rapid dashboard development
58
+ - **Inline tabs:** group inlines into tab navigation in the change form
58
59
  - **Model tabs:** define custom tab navigations for models
59
- - **Fieldset tabs:** merge several fielsets into tabs in change form
60
- - **Colors:** possibility to override default color scheme
61
- - **Changeform modes:** display fields in changeform in compressed mode
60
+ - **Fieldset tabs:** merge several fieldsets into tabs in the change form
61
+ - **Colors:** possibility to override the default color scheme
62
+ - **Changeform modes:** display fields in the change form in compressed mode
62
63
  - **Third party packages:** default support for multiple popular applications
63
64
  - **Environment label**: distinguish between environments by displaying a label
64
65
  - **Nonrelated inlines**: displays nonrelated model as inline in changeform
65
66
  - **Parallel admin**: support for default admin in parallel with Unfold. [Admin migration guide](https://unfoldadmin.com/blog/migrating-django-admin-unfold/?utm_medium=github&utm_source=unfold)
67
+ - **Favicons**: built-in support for configuring various site favicons
66
68
  - **VS Code**: project configuration and development container is included
67
69
 
68
70
  ## Table of contents <!-- omit from toc -->
@@ -111,7 +113,7 @@ Did you decide to start using Unfold but you don't have time to make the switch
111
113
 
112
114
  ## Installation
113
115
 
114
- The installation process is minimal. Everything what is needed after installation is to put new application at the beginning of **INSTALLED_APPS**. Default admin configuration in urls.py can stay as it is and there are no changes required.
116
+ The installation process is minimal. Everything that is needed after installation is to put new application at the beginning of **INSTALLED_APPS**. The default admin configuration in urls.py can stay as it is, and no changes are required.
115
117
 
116
118
  ```python
117
119
  # settings.py
@@ -170,17 +172,24 @@ class CustomAdminClass(ModelAdmin):
170
172
 
171
173
  from django.contrib import admin
172
174
  from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
175
+ from django.contrib.auth.admin import GroupAdmin as BaseGroupAdmin
173
176
  from django.contrib.auth.models import User
174
177
 
175
178
  from unfold.admin import ModelAdmin
176
179
 
177
180
 
178
181
  admin.site.unregister(User)
182
+ admin.site.unregister(Group)
179
183
 
180
184
 
181
185
  @admin.register(User)
182
186
  class UserAdmin(BaseUserAdmin, ModelAdmin):
183
187
  pass
188
+
189
+
190
+ @admin.register(Group)
191
+ class GroupAdmin(BaseGroupAdmin, ModelAdmin):
192
+ pass
184
193
  ```
185
194
 
186
195
  ## Configuration
@@ -209,6 +218,14 @@ UNFOLD = {
209
218
  "dark": lambda request: static("logo-dark.svg"), # dark mode
210
219
  },
211
220
  "SITE_SYMBOL": "speed", # symbol from icon set
221
+ "SITE_FAVICONS": [
222
+ {
223
+ "rel": "icon",
224
+ "sizes": "32x32",
225
+ "type": "image/svg+xml",
226
+ "href": lambda request: static("favicon.svg"),
227
+ },
228
+ ],
212
229
  "SHOW_HISTORY": True, # show/hide "History" button, default: True
213
230
  "SHOW_VIEW_ON_SITE": True, # show/hide "View on site" button, default: True
214
231
  "ENVIRONMENT": "sample_app.environment_callback",
@@ -255,6 +272,7 @@ UNFOLD = {
255
272
  {
256
273
  "title": _("Navigation"),
257
274
  "separator": True, # Top border
275
+ "collapsible": True, # Collapsible group of links
258
276
  "items": [
259
277
  {
260
278
  "title": _("Dashboard"),
@@ -345,6 +363,9 @@ class CustomAdminClass(ModelAdmin):
345
363
  # Display submit button in filters
346
364
  list_filter_submit = False
347
365
 
366
+ # Display changelist in fullwidth
367
+ list_fullwidth = False
368
+
348
369
  # Position horizontal scrollbar in changelist at the top
349
370
  list_horizontal_scrollbar_top = False
350
371
 
@@ -441,7 +462,7 @@ class UserAdmin(ModelAdmin):
441
462
  actions_detail = ["change_detail_action_block"]
442
463
  actions_submit_line = ["submit_line_action_activate"]
443
464
 
444
- @action(description=_("Save & Activate"))
465
+ @action(description=_("Save & Activate"), permissions=["submit_line_action_activate"])
445
466
  def submit_line_action_activate(self, request: HttpRequest, obj: User):
446
467
  """
447
468
  If instance is modified in any way, it also needs to be saved,
@@ -453,6 +474,9 @@ class UserAdmin(ModelAdmin):
453
474
  obj.is_active = True
454
475
  obj.save()
455
476
 
477
+ def has_submit_line_action_activate_permission(self, request: HttpRequest, object_id: Union[str, int]):
478
+ pass
479
+
456
480
  @action(description=_("Import"), url_path="import")
457
481
  def changelist_global_action_import(self, request: HttpRequest):
458
482
  """
@@ -477,7 +501,7 @@ class UserAdmin(ModelAdmin):
477
501
  """
478
502
  return redirect(f"https://example.com/{object_id}")
479
503
 
480
- @action(description=_("Detail"), url_path="detail-action", attrs={"target": "_blank"})
504
+ @action(description=_("Detail"), url_path="detail-action", attrs={"target": "_blank"}, permissions=["change_detail_action_block"])
481
505
  def change_detail_action_block(self, request: HttpRequest, object_id: int):
482
506
  """
483
507
  Handler for detail action.
@@ -492,6 +516,10 @@ class UserAdmin(ModelAdmin):
492
516
  return redirect(
493
517
  reverse_lazy("admin:users_user_change", args=(object_id,))
494
518
  )
519
+
520
+
521
+ def has_change_detail_action_block_permission(self, request: HttpRequest, object_id: Union[str, int]):
522
+ pass
495
523
  ```
496
524
 
497
525
  ### Action with form example
@@ -563,7 +591,7 @@ Text input field which allows filtering by the free string submitted by the user
563
591
 
564
592
  `FieldTextFilter` requires just a model field name and the filter will make `__icontains` search on this field. There are no other things to configure so the integration in `list_filter` will be just one new row looking like `("model_field_name", FieldTextFilter)`.
565
593
 
566
- In the case of the `TextFilter`, it is needed the write a whole new class inheriting from `TextFilter` with a custom implementation of the `queryset` method and the `parameter_name` attribute. This attribute will be a representation of the search query parameter name in URI. The benefit of the `TextFilter` is the possibility of writing complex queries.
594
+ In the case of the `TextFilter`, it is needed to write a whole new class inheriting from `TextFilter` with a custom implementation of the `queryset` method and the `parameter_name` attribute. This attribute will be a representation of the search query parameter name in URI. The benefit of the `TextFilter` is the possibility of writing complex queries.
567
595
 
568
596
  ```python
569
597
  from django.contrib import admin
@@ -598,7 +626,7 @@ class MyAdmin(ModelAdmin):
598
626
 
599
627
  Dropdown filters will display a select field with a list of options. Unfold contains two types of dropdowns: `ChoicesDropdownFilter` and `RelatedDropdownFilter`.
600
628
 
601
- The difference between them is that `ChoicesDropdownFilter` will collect a list of options based on the `choices` attribute of the model field so most commonly it will be used in combination with `CharField` with specified `choices`. On the other side, `RelatedDropdownFilter` needs a one-to-many or many-to-many foreign key to display options.
629
+ The difference between them is that `ChoicesDropdownFilter` will collect a list of options based on the `choices` attribute of the model field so most commonly it will be used in combination with `CharField` with specified `choices`. On the other hand, `RelatedDropdownFilter` needs a one-to-many or many-to-many foreign key to display options.
602
630
 
603
631
  **Note:** At the moment Unfold does not implement a dropdown with an autocomplete functionality, so it is important not to use dropdowns displaying large datasets.
604
632
 
@@ -907,6 +935,19 @@ class MyModelAdmin(ModelAdmin):
907
935
  )
908
936
  ```
909
937
 
938
+ Inlines can be grouped into tab navigation by specifying `tab` attribute in the inline class.
939
+
940
+ ```python
941
+ # admin.py
942
+
943
+ from unfold.admin import TabularInline
944
+
945
+
946
+ class MyInline(TabularInline):
947
+ model = User
948
+ tab = True
949
+ ```
950
+
910
951
  ## Third party packages
911
952
 
912
953
  ### django-celery-beat
@@ -976,11 +1017,11 @@ class ClockedScheduleAdmin(BaseClockedScheduleAdmin, ModelAdmin):
976
1017
 
977
1018
  ### django-guardian
978
1019
 
979
- Adding support for django-guardian is quote straightforward in Unfold, just add `unfold.contrib.guardian` to `INSTALLED_APPS` at the beggining of the file. This action will override all templates coming from the django-guardian. Please note that **Object permissions** link is available in top right dropdown navigation.
1020
+ Adding support for django-guardian is quite straightforward in Unfold, just add `unfold.contrib.guardian` to `INSTALLED_APPS` at the beginning of the file. This action will override all templates coming from the django-guardian. Please note that **Object permissions** link is available in top right dropdown navigation.
980
1021
 
981
1022
  ### django-import-export
982
1023
 
983
- 1. Add `unfold.contrib.import_export` to `INSTALLED_APPS` at the beggining of the file. This action will override all templates coming from the application.
1024
+ 1. Add `unfold.contrib.import_export` to `INSTALLED_APPS` at the beginning of the file. This action will override all templates coming from the application.
984
1025
  2. Change `import_form_class` and `export_form_class` in ModelAdmin which is inheriting from `ImportExportModelAdmin`. This chunk of code is responsible for adding proper styling to form elements.
985
1026
 
986
1027
  ```python
@@ -1052,7 +1093,7 @@ This application is supported in Unfold by default. It is not needed to add any
1052
1093
 
1053
1094
  ### django-simple-history
1054
1095
 
1055
- To make this application work, add `unfold.contrib.simple_history` into `settings.py` in `INSTALLED_APPS` variable before right after `unfold`. This app should ensure that templates coming from django-simple-history are overriden by Unfold.
1096
+ To make this application work, add `unfold.contrib.simple_history` into `settings.py` in `INSTALLED_APPS` variable before right after `unfold`. This app should ensure that templates coming from django-simple-history are overridden by Unfold.
1056
1097
 
1057
1098
  ## User Admin Form
1058
1099
 
@@ -1133,7 +1174,7 @@ npx tailwindcss -o your_project/static/css/styles.css --watch --minify
1133
1174
 
1134
1175
  ### Overriding template
1135
1176
 
1136
- Create `templates/admin/index.html` in your project and paste the base template below into it. By default, all your custom styles here are not compiled because CSS classes are located in your specific project. Here it is needed to set up the Tailwind for your project and all requried instructions are located in [Project Level Tailwind Stylesheet](#project-level-tailwind-stylesheet) chapter.
1177
+ Create `templates/admin/index.html` in your project and paste the base template below into it. By default, all your custom styles here are not compiled because CSS classes are located in your specific project. Here it is needed to set up the Tailwind for your project and all required instructions are located in [Project Level Tailwind Stylesheet](#project-level-tailwind-stylesheet) chapter.
1137
1178
 
1138
1179
  ```html+django
1139
1180
  {% extends 'unfold/layouts/base_simple.html' %}
@@ -1255,7 +1296,7 @@ Below you can find a more complex example which is using multiple components and
1255
1296
 
1256
1297
  ### Pre-commit
1257
1298
 
1258
- Before adding any source code, it is recommended to have pre-commit installed on your local computer to check for all potential issues when comitting the code.
1299
+ Before adding any source code, it is recommended to have pre-commit installed on your local computer to check for all potential issues when committing the code.
1259
1300
 
1260
1301
  ```bash
1261
1302
  pip install pre-commit
@@ -1275,7 +1316,7 @@ To add a new feature or fix the easiest approach is to use django-unfold in comb
1275
1316
 
1276
1317
  ### Compiling Tailwind
1277
1318
 
1278
- At the moment project contains package.json with all dependencies required to compile new CSS file. Tailwind configuration file is set to check all html, js and py files for Tailwind's classeses occurrences.
1319
+ At the moment project contains package.json with all dependencies required to compile new CSS file. Tailwind configuration file is set to check all html, js and py files for Tailwind's classes occurrences.
1279
1320
 
1280
1321
  ```bash
1281
1322
  npm install
@@ -1285,7 +1326,7 @@ npm run tailwind:watch # run after each change in code
1285
1326
  npm run tailwind:build # run once
1286
1327
  ```
1287
1328
 
1288
- Some components like datepickers, calendars or selectors in admin was not possible to style by overriding html templates so their default styles are overriden in **styles.css**.
1329
+ Some components like datepickers, calendars or selectors in admin was not possible to style by overriding html templates so their default styles are overridden in **styles.css**.
1289
1330
 
1290
1331
  **Note:** most of the custom styles located in style.css are created via `@apply some-tailwind-class;` as is not possible to manually add CSS class to element which are for example created via jQuery.
1291
1332
 
@@ -9,7 +9,7 @@
9
9
  ![Code Style - Ruff](https://img.shields.io/badge/code%20style-ruff-30173D.svg?style=for-the-badge)
10
10
  ![Pre Commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white&style=for-the-badge)
11
11
 
12
- Unfold is theme for Django admin incorporating most common practises for building full-fledged admin areas. It is designed to work at the top of default administration provided by Django.
12
+ Unfold is a theme for Django admin incorporating most common practices for building full-fledged admin areas. It is designed to work on top of default administration provided by Django.
13
13
 
14
14
  - **Unfold:** demo site is available at [unfoldadmin.com](https://unfoldadmin.com?utm_medium=github&utm_source=unfold)
15
15
  - **Formula:** repository with demo implementation at [github.com/unfoldadmin/formula](https://github.com/unfoldadmin/formula)
@@ -21,7 +21,7 @@ Did you decide to start using Unfold but you don't have time to make the switch
21
21
 
22
22
  ## Features <!-- omit from toc -->
23
23
 
24
- - **Visual**: provides new user interface based on Tailwind CSS framework
24
+ - **Visual**: provides a new user interface based on Tailwind CSS framework
25
25
  - **Sidebar:** simplifies definition of custom sidebar navigation with icons
26
26
  - **Dark mode:** supports both light and dark mode versions
27
27
  - **Configuration:** most of the basic options can be changed in settings.py
@@ -31,14 +31,16 @@ Did you decide to start using Unfold but you don't have time to make the switch
31
31
  - **Array widget:** built-in widget for `django.contrib.postgres.fields.ArrayField`
32
32
  - **Filters:** custom dropdown, numeric, datetime, and text fields
33
33
  - **Dashboard:** custom components for rapid dashboard development
34
+ - **Inline tabs:** group inlines into tab navigation in the change form
34
35
  - **Model tabs:** define custom tab navigations for models
35
- - **Fieldset tabs:** merge several fielsets into tabs in change form
36
- - **Colors:** possibility to override default color scheme
37
- - **Changeform modes:** display fields in changeform in compressed mode
36
+ - **Fieldset tabs:** merge several fieldsets into tabs in the change form
37
+ - **Colors:** possibility to override the default color scheme
38
+ - **Changeform modes:** display fields in the change form in compressed mode
38
39
  - **Third party packages:** default support for multiple popular applications
39
40
  - **Environment label**: distinguish between environments by displaying a label
40
41
  - **Nonrelated inlines**: displays nonrelated model as inline in changeform
41
42
  - **Parallel admin**: support for default admin in parallel with Unfold. [Admin migration guide](https://unfoldadmin.com/blog/migrating-django-admin-unfold/?utm_medium=github&utm_source=unfold)
43
+ - **Favicons**: built-in support for configuring various site favicons
42
44
  - **VS Code**: project configuration and development container is included
43
45
 
44
46
  ## Table of contents <!-- omit from toc -->
@@ -87,7 +89,7 @@ Did you decide to start using Unfold but you don't have time to make the switch
87
89
 
88
90
  ## Installation
89
91
 
90
- The installation process is minimal. Everything what is needed after installation is to put new application at the beginning of **INSTALLED_APPS**. Default admin configuration in urls.py can stay as it is and there are no changes required.
92
+ The installation process is minimal. Everything that is needed after installation is to put new application at the beginning of **INSTALLED_APPS**. The default admin configuration in urls.py can stay as it is, and no changes are required.
91
93
 
92
94
  ```python
93
95
  # settings.py
@@ -146,17 +148,24 @@ class CustomAdminClass(ModelAdmin):
146
148
 
147
149
  from django.contrib import admin
148
150
  from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
151
+ from django.contrib.auth.admin import GroupAdmin as BaseGroupAdmin
149
152
  from django.contrib.auth.models import User
150
153
 
151
154
  from unfold.admin import ModelAdmin
152
155
 
153
156
 
154
157
  admin.site.unregister(User)
158
+ admin.site.unregister(Group)
155
159
 
156
160
 
157
161
  @admin.register(User)
158
162
  class UserAdmin(BaseUserAdmin, ModelAdmin):
159
163
  pass
164
+
165
+
166
+ @admin.register(Group)
167
+ class GroupAdmin(BaseGroupAdmin, ModelAdmin):
168
+ pass
160
169
  ```
161
170
 
162
171
  ## Configuration
@@ -185,6 +194,14 @@ UNFOLD = {
185
194
  "dark": lambda request: static("logo-dark.svg"), # dark mode
186
195
  },
187
196
  "SITE_SYMBOL": "speed", # symbol from icon set
197
+ "SITE_FAVICONS": [
198
+ {
199
+ "rel": "icon",
200
+ "sizes": "32x32",
201
+ "type": "image/svg+xml",
202
+ "href": lambda request: static("favicon.svg"),
203
+ },
204
+ ],
188
205
  "SHOW_HISTORY": True, # show/hide "History" button, default: True
189
206
  "SHOW_VIEW_ON_SITE": True, # show/hide "View on site" button, default: True
190
207
  "ENVIRONMENT": "sample_app.environment_callback",
@@ -231,6 +248,7 @@ UNFOLD = {
231
248
  {
232
249
  "title": _("Navigation"),
233
250
  "separator": True, # Top border
251
+ "collapsible": True, # Collapsible group of links
234
252
  "items": [
235
253
  {
236
254
  "title": _("Dashboard"),
@@ -321,6 +339,9 @@ class CustomAdminClass(ModelAdmin):
321
339
  # Display submit button in filters
322
340
  list_filter_submit = False
323
341
 
342
+ # Display changelist in fullwidth
343
+ list_fullwidth = False
344
+
324
345
  # Position horizontal scrollbar in changelist at the top
325
346
  list_horizontal_scrollbar_top = False
326
347
 
@@ -417,7 +438,7 @@ class UserAdmin(ModelAdmin):
417
438
  actions_detail = ["change_detail_action_block"]
418
439
  actions_submit_line = ["submit_line_action_activate"]
419
440
 
420
- @action(description=_("Save & Activate"))
441
+ @action(description=_("Save & Activate"), permissions=["submit_line_action_activate"])
421
442
  def submit_line_action_activate(self, request: HttpRequest, obj: User):
422
443
  """
423
444
  If instance is modified in any way, it also needs to be saved,
@@ -429,6 +450,9 @@ class UserAdmin(ModelAdmin):
429
450
  obj.is_active = True
430
451
  obj.save()
431
452
 
453
+ def has_submit_line_action_activate_permission(self, request: HttpRequest, object_id: Union[str, int]):
454
+ pass
455
+
432
456
  @action(description=_("Import"), url_path="import")
433
457
  def changelist_global_action_import(self, request: HttpRequest):
434
458
  """
@@ -453,7 +477,7 @@ class UserAdmin(ModelAdmin):
453
477
  """
454
478
  return redirect(f"https://example.com/{object_id}")
455
479
 
456
- @action(description=_("Detail"), url_path="detail-action", attrs={"target": "_blank"})
480
+ @action(description=_("Detail"), url_path="detail-action", attrs={"target": "_blank"}, permissions=["change_detail_action_block"])
457
481
  def change_detail_action_block(self, request: HttpRequest, object_id: int):
458
482
  """
459
483
  Handler for detail action.
@@ -468,6 +492,10 @@ class UserAdmin(ModelAdmin):
468
492
  return redirect(
469
493
  reverse_lazy("admin:users_user_change", args=(object_id,))
470
494
  )
495
+
496
+
497
+ def has_change_detail_action_block_permission(self, request: HttpRequest, object_id: Union[str, int]):
498
+ pass
471
499
  ```
472
500
 
473
501
  ### Action with form example
@@ -539,7 +567,7 @@ Text input field which allows filtering by the free string submitted by the user
539
567
 
540
568
  `FieldTextFilter` requires just a model field name and the filter will make `__icontains` search on this field. There are no other things to configure so the integration in `list_filter` will be just one new row looking like `("model_field_name", FieldTextFilter)`.
541
569
 
542
- In the case of the `TextFilter`, it is needed the write a whole new class inheriting from `TextFilter` with a custom implementation of the `queryset` method and the `parameter_name` attribute. This attribute will be a representation of the search query parameter name in URI. The benefit of the `TextFilter` is the possibility of writing complex queries.
570
+ In the case of the `TextFilter`, it is needed to write a whole new class inheriting from `TextFilter` with a custom implementation of the `queryset` method and the `parameter_name` attribute. This attribute will be a representation of the search query parameter name in URI. The benefit of the `TextFilter` is the possibility of writing complex queries.
543
571
 
544
572
  ```python
545
573
  from django.contrib import admin
@@ -574,7 +602,7 @@ class MyAdmin(ModelAdmin):
574
602
 
575
603
  Dropdown filters will display a select field with a list of options. Unfold contains two types of dropdowns: `ChoicesDropdownFilter` and `RelatedDropdownFilter`.
576
604
 
577
- The difference between them is that `ChoicesDropdownFilter` will collect a list of options based on the `choices` attribute of the model field so most commonly it will be used in combination with `CharField` with specified `choices`. On the other side, `RelatedDropdownFilter` needs a one-to-many or many-to-many foreign key to display options.
605
+ The difference between them is that `ChoicesDropdownFilter` will collect a list of options based on the `choices` attribute of the model field so most commonly it will be used in combination with `CharField` with specified `choices`. On the other hand, `RelatedDropdownFilter` needs a one-to-many or many-to-many foreign key to display options.
578
606
 
579
607
  **Note:** At the moment Unfold does not implement a dropdown with an autocomplete functionality, so it is important not to use dropdowns displaying large datasets.
580
608
 
@@ -883,6 +911,19 @@ class MyModelAdmin(ModelAdmin):
883
911
  )
884
912
  ```
885
913
 
914
+ Inlines can be grouped into tab navigation by specifying `tab` attribute in the inline class.
915
+
916
+ ```python
917
+ # admin.py
918
+
919
+ from unfold.admin import TabularInline
920
+
921
+
922
+ class MyInline(TabularInline):
923
+ model = User
924
+ tab = True
925
+ ```
926
+
886
927
  ## Third party packages
887
928
 
888
929
  ### django-celery-beat
@@ -952,11 +993,11 @@ class ClockedScheduleAdmin(BaseClockedScheduleAdmin, ModelAdmin):
952
993
 
953
994
  ### django-guardian
954
995
 
955
- Adding support for django-guardian is quote straightforward in Unfold, just add `unfold.contrib.guardian` to `INSTALLED_APPS` at the beggining of the file. This action will override all templates coming from the django-guardian. Please note that **Object permissions** link is available in top right dropdown navigation.
996
+ Adding support for django-guardian is quite straightforward in Unfold, just add `unfold.contrib.guardian` to `INSTALLED_APPS` at the beginning of the file. This action will override all templates coming from the django-guardian. Please note that **Object permissions** link is available in top right dropdown navigation.
956
997
 
957
998
  ### django-import-export
958
999
 
959
- 1. Add `unfold.contrib.import_export` to `INSTALLED_APPS` at the beggining of the file. This action will override all templates coming from the application.
1000
+ 1. Add `unfold.contrib.import_export` to `INSTALLED_APPS` at the beginning of the file. This action will override all templates coming from the application.
960
1001
  2. Change `import_form_class` and `export_form_class` in ModelAdmin which is inheriting from `ImportExportModelAdmin`. This chunk of code is responsible for adding proper styling to form elements.
961
1002
 
962
1003
  ```python
@@ -1028,7 +1069,7 @@ This application is supported in Unfold by default. It is not needed to add any
1028
1069
 
1029
1070
  ### django-simple-history
1030
1071
 
1031
- To make this application work, add `unfold.contrib.simple_history` into `settings.py` in `INSTALLED_APPS` variable before right after `unfold`. This app should ensure that templates coming from django-simple-history are overriden by Unfold.
1072
+ To make this application work, add `unfold.contrib.simple_history` into `settings.py` in `INSTALLED_APPS` variable before right after `unfold`. This app should ensure that templates coming from django-simple-history are overridden by Unfold.
1032
1073
 
1033
1074
  ## User Admin Form
1034
1075
 
@@ -1109,7 +1150,7 @@ npx tailwindcss -o your_project/static/css/styles.css --watch --minify
1109
1150
 
1110
1151
  ### Overriding template
1111
1152
 
1112
- Create `templates/admin/index.html` in your project and paste the base template below into it. By default, all your custom styles here are not compiled because CSS classes are located in your specific project. Here it is needed to set up the Tailwind for your project and all requried instructions are located in [Project Level Tailwind Stylesheet](#project-level-tailwind-stylesheet) chapter.
1153
+ Create `templates/admin/index.html` in your project and paste the base template below into it. By default, all your custom styles here are not compiled because CSS classes are located in your specific project. Here it is needed to set up the Tailwind for your project and all required instructions are located in [Project Level Tailwind Stylesheet](#project-level-tailwind-stylesheet) chapter.
1113
1154
 
1114
1155
  ```html+django
1115
1156
  {% extends 'unfold/layouts/base_simple.html' %}
@@ -1231,7 +1272,7 @@ Below you can find a more complex example which is using multiple components and
1231
1272
 
1232
1273
  ### Pre-commit
1233
1274
 
1234
- Before adding any source code, it is recommended to have pre-commit installed on your local computer to check for all potential issues when comitting the code.
1275
+ Before adding any source code, it is recommended to have pre-commit installed on your local computer to check for all potential issues when committing the code.
1235
1276
 
1236
1277
  ```bash
1237
1278
  pip install pre-commit
@@ -1251,7 +1292,7 @@ To add a new feature or fix the easiest approach is to use django-unfold in comb
1251
1292
 
1252
1293
  ### Compiling Tailwind
1253
1294
 
1254
- At the moment project contains package.json with all dependencies required to compile new CSS file. Tailwind configuration file is set to check all html, js and py files for Tailwind's classeses occurrences.
1295
+ At the moment project contains package.json with all dependencies required to compile new CSS file. Tailwind configuration file is set to check all html, js and py files for Tailwind's classes occurrences.
1255
1296
 
1256
1297
  ```bash
1257
1298
  npm install
@@ -1261,7 +1302,7 @@ npm run tailwind:watch # run after each change in code
1261
1302
  npm run tailwind:build # run once
1262
1303
  ```
1263
1304
 
1264
- Some components like datepickers, calendars or selectors in admin was not possible to style by overriding html templates so their default styles are overriden in **styles.css**.
1305
+ Some components like datepickers, calendars or selectors in admin was not possible to style by overriding html templates so their default styles are overridden in **styles.css**.
1265
1306
 
1266
1307
  **Note:** most of the custom styles located in style.css are created via `@apply some-tailwind-class;` as is not possible to manually add CSS class to element which are for example created via jQuery.
1267
1308
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "django-unfold"
3
- version = "0.30.0"
3
+ version = "0.31.0"
4
4
  description = "Modern Django admin theme for seamless interface development"
5
5
  license = "MIT"
6
6
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  import copy
2
2
  from functools import update_wrapper
3
- from typing import Any, Callable, Dict, List, Optional, Tuple
3
+ from typing import Any, Callable, Dict, List, Optional, Tuple, Union
4
4
 
5
5
  from django import forms
6
6
  from django.contrib.admin import ModelAdmin as BaseModelAdmin
@@ -148,6 +148,7 @@ class ModelAdminMixin:
148
148
  else:
149
149
  kwargs["widget"] = UnfoldAdminSelectWidget()
150
150
 
151
+ if "choices" not in kwargs:
151
152
  kwargs["choices"] = db_field.get_choices(
152
153
  include_blank=db_field.blank, blank_choice=[("", _("Select value"))]
153
154
  )
@@ -229,6 +230,7 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
229
230
  add_fieldsets = ()
230
231
  list_horizontal_scrollbar_top = False
231
232
  list_filter_submit = False
233
+ list_fullwidth = False
232
234
  compressed_fields = False
233
235
  readonly_preprocess_fields = {}
234
236
  checks_class = UnfoldModelAdminChecks
@@ -255,7 +257,10 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
255
257
  return super().get_fieldsets(request, obj)
256
258
 
257
259
  def _filter_unfold_actions_by_permissions(
258
- self, request: HttpRequest, actions: List[UnfoldAction]
260
+ self,
261
+ request: HttpRequest,
262
+ actions: List[UnfoldAction],
263
+ object_id: Optional[Union[int, str]] = None,
259
264
  ) -> List[UnfoldAction]:
260
265
  """Filter out any Unfold actions that the user doesn't have access to."""
261
266
  filtered_actions = []
@@ -263,12 +268,22 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
263
268
  if not hasattr(action.method, "allowed_permissions"):
264
269
  filtered_actions.append(action)
265
270
  continue
271
+
266
272
  permission_checks = (
267
273
  getattr(self, f"has_{permission}_permission")
268
274
  for permission in action.method.allowed_permissions
269
275
  )
270
- if any(has_permission(request) for has_permission in permission_checks):
271
- filtered_actions.append(action)
276
+
277
+ if object_id:
278
+ if any(
279
+ has_permission(request, object_id)
280
+ for has_permission in permission_checks
281
+ ):
282
+ filtered_actions.append(action)
283
+ else:
284
+ if any(has_permission(request) for has_permission in permission_checks):
285
+ filtered_actions.append(action)
286
+
272
287
  return filtered_actions
273
288
 
274
289
  def get_actions_list(self, request: HttpRequest) -> List[UnfoldAction]:
@@ -282,9 +297,11 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
282
297
  """
283
298
  return [self.get_unfold_action(action) for action in self.actions_list or []]
284
299
 
285
- def get_actions_detail(self, request: HttpRequest) -> List[UnfoldAction]:
300
+ def get_actions_detail(
301
+ self, request: HttpRequest, object_id: int
302
+ ) -> List[UnfoldAction]:
286
303
  return self._filter_unfold_actions_by_permissions(
287
- request, self._get_base_actions_detail()
304
+ request, self._get_base_actions_detail(), object_id
288
305
  )
289
306
 
290
307
  def _get_base_actions_detail(self) -> List[UnfoldAction]:
@@ -304,9 +321,11 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
304
321
  """
305
322
  return [self.get_unfold_action(action) for action in self.actions_row or []]
306
323
 
307
- def get_actions_submit_line(self, request: HttpRequest) -> List[UnfoldAction]:
324
+ def get_actions_submit_line(
325
+ self, request: HttpRequest, object_id: int
326
+ ) -> List[UnfoldAction]:
308
327
  return self._filter_unfold_actions_by_permissions(
309
- request, self._get_base_actions_submit_line()
328
+ request, self._get_base_actions_submit_line(), object_id
310
329
  )
311
330
 
312
331
  def _get_base_actions_submit_line(self) -> List[UnfoldAction]:
@@ -404,7 +423,7 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
404
423
 
405
424
  actions = []
406
425
  if object_id:
407
- for action in self.get_actions_detail(request):
426
+ for action in self.get_actions_detail(request, object_id):
408
427
  actions.append(
409
428
  {
410
429
  "title": action.description,
@@ -418,7 +437,7 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
418
437
 
419
438
  extra_context.update(
420
439
  {
421
- "actions_submit_line": self.get_actions_submit_line(request),
440
+ "actions_submit_line": self.get_actions_submit_line(request, object_id),
422
441
  "actions_detail": actions,
423
442
  }
424
443
  )
@@ -485,7 +504,7 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
485
504
  ) -> None:
486
505
  super().save_model(request, obj, form, change)
487
506
 
488
- for action in self.get_actions_submit_line(request):
507
+ for action in self.get_actions_submit_line(request, obj.pk):
489
508
  if action.action_name not in request.POST:
490
509
  continue
491
510
 
@@ -9,11 +9,11 @@
9
9
 
10
10
  {% if choice.min is not None and choice.max is not None and choice.step %}
11
11
  <div class="admin-numeric-filter-slider-tooltips">
12
- <span class="admin-numeric-filter-slider-tooltip-from border cursor-not-allowed flex flex-grow flex-row items-center mr-auto rounded-md shadow-sm px-3 py-2 w-full dark:bg-gray-900 dark:border-gray-700 dark:text-gray-400">
12
+ <span class="admin-numeric-filter-slider-tooltip-from border cursor-not-allowed flex flex-grow flex-row items-center mr-auto rounded-md shadow-sm px-3 py-2 w-full dark:bg-gray-900 dark:border-gray-700 dark:text-gray-300">
13
13
  {{ choice.value_from }}
14
14
  </span>
15
15
 
16
- <span class="admin-numeric-filter-slider-tooltip-to border cursor-not-allowed flex flex-grow flex-row items-center rounded-md shadow-sm px-3 py-2 w-full dark:bg-gray-900 dark:border-gray-700 dark:text-gray-400">
16
+ <span class="admin-numeric-filter-slider-tooltip-to border cursor-not-allowed flex flex-grow flex-row items-center rounded-md shadow-sm px-3 py-2 w-full dark:bg-gray-900 dark:border-gray-700 dark:text-gray-300">
17
17
  {{ choice.value_to }}
18
18
  </span>
19
19
  </div>
@@ -25,7 +25,7 @@
25
25
  {{ choice.form.as_p }}
26
26
  </div>
27
27
  {% else %}
28
- <div class="admin-numeric-filter-slider-error dark:text-gray-400">
28
+ <div class="admin-numeric-filter-slider-error dark:text-gray-300">
29
29
  <p>
30
30
  {% trans 'Not enough data.' %}
31
31
  </p>
@@ -15,7 +15,9 @@
15
15
 
16
16
  <template x-for="(item, index) in items" :key="item.key">
17
17
  <div class="flex flex-row">
18
- {% include template.template_name with widget=template %}
18
+ {% with widget=template %}
19
+ {% include template.template_name %}
20
+ {% endwith %}
19
21
 
20
22
  <a x-on:click="items.splice(index, 1)" class="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">
21
23
  <span class="material-symbols-outlined text-sm">delete</span>