wagtail 7.1.1__py3-none-any.whl → 7.2rc1__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 (345) hide show
  1. wagtail/__init__.py +1 -1
  2. wagtail/actions/copy_page.py +1 -1
  3. wagtail/actions/create_alias.py +1 -1
  4. wagtail/actions/delete_page.py +1 -1
  5. wagtail/actions/publish_page_revision.py +1 -1
  6. wagtail/actions/publish_revision.py +1 -1
  7. wagtail/actions/revert_to_page_revision.py +1 -1
  8. wagtail/actions/unpublish.py +1 -1
  9. wagtail/actions/unpublish_page.py +1 -1
  10. wagtail/admin/auth.py +3 -1
  11. wagtail/admin/checks.py +2 -2
  12. wagtail/admin/filters.py +28 -1
  13. wagtail/admin/forms/collections.py +1 -1
  14. wagtail/admin/forms/comments.py +1 -1
  15. wagtail/admin/forms/models.py +1 -1
  16. wagtail/admin/forms/pages.py +1 -1
  17. wagtail/admin/forms/tags.py +1 -1
  18. wagtail/admin/locale/cs/LC_MESSAGES/django.mo +0 -0
  19. wagtail/admin/locale/cs/LC_MESSAGES/django.po +25 -1
  20. wagtail/admin/locale/en/LC_MESSAGES/django.po +278 -192
  21. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +29 -15
  22. wagtail/admin/locale/it/LC_MESSAGES/django.mo +0 -0
  23. wagtail/admin/locale/it/LC_MESSAGES/django.po +3 -2
  24. wagtail/admin/locale/nl/LC_MESSAGES/django.mo +0 -0
  25. wagtail/admin/locale/nl/LC_MESSAGES/django.po +57 -3
  26. wagtail/admin/locale/nl/LC_MESSAGES/djangojs.mo +0 -0
  27. wagtail/admin/locale/nl/LC_MESSAGES/djangojs.po +8 -2
  28. wagtail/admin/locale/ru/LC_MESSAGES/django.mo +0 -0
  29. wagtail/admin/locale/ru/LC_MESSAGES/django.po +58 -1
  30. wagtail/admin/locale/tr/LC_MESSAGES/django.mo +0 -0
  31. wagtail/admin/locale/tr/LC_MESSAGES/django.po +3 -2
  32. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  33. wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
  34. wagtail/admin/static/wagtailadmin/js/chooser-modal.js +1 -1
  35. wagtail/admin/static/wagtailadmin/js/chooser-widget-telepath.js +1 -1
  36. wagtail/admin/static/wagtailadmin/js/chooser-widget.js +1 -1
  37. wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
  38. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  39. wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +2 -2
  40. wagtail/admin/static/wagtailadmin/js/date-time-chooser.js +1 -1
  41. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  42. wagtail/admin/static/wagtailadmin/js/filtered-select.js +1 -1
  43. wagtail/admin/static/wagtailadmin/js/icons.js +1 -1
  44. wagtail/admin/static/wagtailadmin/js/modal-workflow.js +1 -1
  45. wagtail/admin/static/wagtailadmin/js/page-chooser-modal.js +1 -1
  46. wagtail/admin/static/wagtailadmin/js/page-chooser-telepath.js +1 -1
  47. wagtail/admin/static/wagtailadmin/js/page-chooser.js +1 -1
  48. wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
  49. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  50. wagtail/admin/static/wagtailadmin/js/task-chooser-modal.js +1 -1
  51. wagtail/admin/static/wagtailadmin/js/task-chooser.js +1 -1
  52. wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
  53. wagtail/admin/static/wagtailadmin/js/telepath/telepath.js +1 -1
  54. wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
  55. wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
  56. wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +2 -2
  57. wagtail/admin/static/wagtailadmin/js/vendor/bootstrap-modal.js +1 -1
  58. wagtail/admin/static/wagtailadmin/js/vendor/bootstrap-transition.js +1 -1
  59. wagtail/admin/static/wagtailadmin/js/vendor/jquery-3.6.0.min.js +1 -1
  60. wagtail/admin/static/wagtailadmin/js/vendor/jquery-ui-1.13.2.min.js +1 -1
  61. wagtail/admin/static/wagtailadmin/js/vendor/jquery.datetimepicker.js +1 -1
  62. wagtail/admin/static/wagtailadmin/js/vendor/jquery.fileupload-process.js +1 -1
  63. wagtail/admin/static/wagtailadmin/js/vendor/jquery.fileupload.js +1 -1
  64. wagtail/admin/static/wagtailadmin/js/vendor/jquery.iframe-transport.js +1 -1
  65. wagtail/admin/static/wagtailadmin/js/vendor/tag-it.js +1 -1
  66. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  67. wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +1 -1
  68. wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
  69. wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
  70. wagtail/admin/templates/wagtailadmin/account/account.html +2 -0
  71. wagtail/admin/templates/wagtailadmin/base.html +14 -0
  72. wagtail/admin/templates/wagtailadmin/generic/chooser/chooser.html +2 -1
  73. wagtail/admin/templates/wagtailadmin/generic/chooser/creation_form.html +2 -1
  74. wagtail/admin/templates/wagtailadmin/generic/form.html +3 -1
  75. wagtail/admin/templates/wagtailadmin/panels/multi_field_panel_child.html +1 -1
  76. wagtail/admin/templates/wagtailadmin/panels/object_list.html +1 -1
  77. wagtail/admin/templates/wagtailadmin/panels/tabbed_interface.html +3 -2
  78. wagtail/admin/templates/wagtailadmin/shared/formatted_field.html +1 -1
  79. wagtail/admin/templates/wagtailadmin/shared/forms/single_checkbox.html +1 -1
  80. wagtail/admin/templates/wagtailadmin/shared/keyboard_shortcuts_dialog.html +19 -0
  81. wagtail/admin/templates/wagtailadmin/shared/panel.html +1 -1
  82. wagtail/admin/templates/wagtailadmin/shared/set_privacy.html +15 -0
  83. wagtail/admin/templates/wagtailadmin/shared/side_panels/checks.html +28 -1
  84. wagtail/admin/templates/wagtailadmin/shared/workflow_history/detail.html +2 -2
  85. wagtail/admin/templates/wagtailadmin/{pages/listing/_ordering_header.html → tables/ordering_header.html} +2 -2
  86. wagtail/admin/templates/wagtailadmin/tables/title_cell.html +1 -1
  87. wagtail/admin/templates/wagtailadmin/userbar/base.html +6 -3
  88. wagtail/admin/templates/wagtailadmin/userbar/item_admin.html +2 -2
  89. wagtail/admin/templates/wagtailadmin/userbar/item_page_add.html +2 -2
  90. wagtail/admin/templates/wagtailadmin/userbar/item_page_edit.html +2 -2
  91. wagtail/admin/templates/wagtailadmin/userbar/item_page_explore.html +2 -2
  92. wagtail/admin/templates/wagtailadmin/widgets/{daterange_input.html → range_input.html} +1 -1
  93. wagtail/admin/templates/wagtailadmin/workflows/task_chooser/chooser.html +4 -2
  94. wagtail/admin/templatetags/wagtailadmin_tags.py +56 -22
  95. wagtail/admin/tests/api/test_pages.py +7 -7
  96. wagtail/admin/tests/api/test_renderer_classes.py +16 -0
  97. wagtail/admin/tests/pages/test_create_page.py +34 -2
  98. wagtail/admin/tests/pages/test_edit_page.py +128 -14
  99. wagtail/admin/tests/pages/test_explorer_view.py +34 -7
  100. wagtail/admin/tests/pages/test_reorder_page.py +11 -0
  101. wagtail/admin/tests/test_collections_views.py +12 -0
  102. wagtail/admin/tests/test_edit_handlers.py +3 -3
  103. wagtail/admin/tests/test_filters.py +2 -2
  104. wagtail/admin/tests/test_keyboard_shortcuts.py +52 -2
  105. wagtail/admin/tests/test_menu.py +0 -2
  106. wagtail/admin/tests/test_privacy.py +16 -16
  107. wagtail/admin/tests/test_templatetags.py +137 -0
  108. wagtail/admin/tests/test_userbar.py +75 -35
  109. wagtail/admin/tests/test_views_generic.py +34 -0
  110. wagtail/admin/tests/test_workflows.py +34 -0
  111. wagtail/admin/tests/viewsets/test_model_viewset.py +322 -0
  112. wagtail/admin/ui/tables/orderable.py +73 -0
  113. wagtail/admin/ui/tables/pages.py +3 -13
  114. wagtail/admin/userbar.py +6 -1
  115. wagtail/admin/views/collection_privacy.py +6 -2
  116. wagtail/admin/views/generic/__init__.py +1 -0
  117. wagtail/admin/views/generic/mixins.py +20 -2
  118. wagtail/admin/views/generic/models.py +67 -1
  119. wagtail/admin/views/generic/ordering.py +79 -0
  120. wagtail/admin/views/home.py +3 -3
  121. wagtail/admin/views/page_privacy.py +5 -2
  122. wagtail/admin/views/pages/create.py +1 -1
  123. wagtail/admin/views/pages/edit.py +2 -2
  124. wagtail/admin/views/pages/listing.py +7 -42
  125. wagtail/admin/views/pages/move.py +1 -1
  126. wagtail/admin/views/pages/ordering.py +1 -1
  127. wagtail/admin/viewsets/base.py +1 -1
  128. wagtail/admin/viewsets/model.py +49 -1
  129. wagtail/admin/wagtail_hooks.py +2 -1
  130. wagtail/admin/widgets/slug.py +10 -10
  131. wagtail/api/v2/serializers.py +1 -1
  132. wagtail/api/v2/tests/test_renderer_classes.py +32 -0
  133. wagtail/apps.py +2 -0
  134. wagtail/bin/wagtail.py +1 -1
  135. wagtail/blocks/struct_block.py +2 -1
  136. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +14 -14
  137. wagtail/contrib/forms/locale/nl/LC_MESSAGES/django.mo +0 -0
  138. wagtail/contrib/forms/locale/nl/LC_MESSAGES/django.po +19 -2
  139. wagtail/contrib/forms/locale/ru/LC_MESSAGES/django.mo +0 -0
  140. wagtail/contrib/forms/locale/ru/LC_MESSAGES/django.po +18 -1
  141. wagtail/contrib/frontend_cache/tests.py +4 -2
  142. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +4 -4
  143. wagtail/contrib/redirects/tests/test_tmp_storages.py +20 -0
  144. wagtail/contrib/redirects/tmp_storages.py +1 -1
  145. wagtail/contrib/redirects/views.py +3 -3
  146. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +3 -3
  147. wagtail/contrib/search_promotions/locale/tr/LC_MESSAGES/django.mo +0 -0
  148. wagtail/contrib/search_promotions/locale/tr/LC_MESSAGES/django.po +43 -3
  149. wagtail/contrib/search_promotions/static/wagtailsearchpromotions/js/query-chooser-modal.js +1 -1
  150. wagtail/contrib/search_promotions/views/settings.py +2 -2
  151. wagtail/contrib/settings/locale/cs/LC_MESSAGES/django.mo +0 -0
  152. wagtail/contrib/settings/locale/cs/LC_MESSAGES/django.po +6 -1
  153. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +1 -1
  154. wagtail/contrib/settings/locale/nl/LC_MESSAGES/django.mo +0 -0
  155. wagtail/contrib/settings/locale/nl/LC_MESSAGES/django.po +6 -2
  156. wagtail/contrib/settings/locale/ru/LC_MESSAGES/django.mo +0 -0
  157. wagtail/contrib/settings/locale/ru/LC_MESSAGES/django.po +6 -1
  158. wagtail/contrib/settings/tests/site_specific/test_admin.py +40 -6
  159. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
  160. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +1 -1
  161. wagtail/contrib/styleguide/templates/wagtailstyleguide/base.html +5 -5
  162. wagtail/contrib/table_block/blocks.py +1 -0
  163. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +5 -1
  164. wagtail/contrib/table_block/static/table_block/js/table.js +1 -1
  165. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +1 -1
  166. wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
  167. wagtail/coreutils.py +5 -5
  168. wagtail/documents/forms.py +18 -1
  169. wagtail/documents/locale/en/LC_MESSAGES/django.po +10 -10
  170. wagtail/documents/locale/nl/LC_MESSAGES/django.mo +0 -0
  171. wagtail/documents/locale/nl/LC_MESSAGES/django.po +9 -0
  172. wagtail/documents/locale/ru/LC_MESSAGES/django.mo +0 -0
  173. wagtail/documents/locale/ru/LC_MESSAGES/django.po +9 -0
  174. wagtail/documents/models.py +1 -1
  175. wagtail/documents/static/wagtaildocs/js/add-multiple.js +1 -1
  176. wagtail/documents/static/wagtaildocs/js/document-chooser-modal.js +1 -1
  177. wagtail/documents/static/wagtaildocs/js/document-chooser-telepath.js +1 -1
  178. wagtail/documents/static/wagtaildocs/js/document-chooser.js +1 -1
  179. wagtail/documents/templates/wagtaildocs/documents/add.html +0 -34
  180. wagtail/documents/tests/test_admin_views.py +132 -26
  181. wagtail/documents/tests/test_collection_privacy.py +18 -4
  182. wagtail/documents/tests/test_form_overrides.py +1 -1
  183. wagtail/documents/tests/test_search.py +21 -8
  184. wagtail/documents/views/documents.py +1 -1
  185. wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
  186. wagtail/embeds/static/wagtailembeds/js/embed-chooser-modal.js +1 -1
  187. wagtail/images/forms.py +16 -1
  188. wagtail/images/locale/cs/LC_MESSAGES/django.mo +0 -0
  189. wagtail/images/locale/cs/LC_MESSAGES/django.po +12 -1
  190. wagtail/images/locale/en/LC_MESSAGES/django.po +57 -46
  191. wagtail/images/locale/nl/LC_MESSAGES/django.mo +0 -0
  192. wagtail/images/locale/nl/LC_MESSAGES/django.po +37 -14
  193. wagtail/images/locale/ru/LC_MESSAGES/django.mo +0 -0
  194. wagtail/images/locale/ru/LC_MESSAGES/django.po +20 -1
  195. wagtail/images/models.py +1 -1
  196. wagtail/images/static/wagtailimages/js/add-multiple.js +1 -1
  197. wagtail/images/static/wagtailimages/js/focal-point-chooser.js +1 -1
  198. wagtail/images/static/wagtailimages/js/image-block.js +1 -1
  199. wagtail/images/static/wagtailimages/js/image-chooser-modal.js +1 -1
  200. wagtail/images/static/wagtailimages/js/image-chooser-telepath.js +1 -1
  201. wagtail/images/static/wagtailimages/js/image-chooser.js +1 -1
  202. wagtail/images/static/wagtailimages/js/image-url-generator.js +1 -1
  203. wagtail/images/static/wagtailimages/js/vendor/jquery.Jcrop.min.js +1 -1
  204. wagtail/images/static/wagtailimages/js/vendor/jquery.fileupload-image.js +1 -1
  205. wagtail/images/static/wagtailimages/js/vendor/jquery.fileupload-validate.js +1 -1
  206. wagtail/images/static/wagtailimages/js/vendor/load-image.min.js +1 -1
  207. wagtail/images/templates/wagtailimages/chooser/chooser.html +22 -13
  208. wagtail/images/templates/wagtailimages/chooser/image_preview_column_cell.html +10 -0
  209. wagtail/images/templates/wagtailimages/chooser/results.html +24 -20
  210. wagtail/images/templates/wagtailimages/chooser/title_column_cell.html +15 -0
  211. wagtail/images/templates/wagtailimages/images/add.html +0 -34
  212. wagtail/images/templates/wagtailimages/images/index.html +3 -3
  213. wagtail/images/templates/wagtailimages/images/index_results.html +1 -1
  214. wagtail/images/templates/wagtailimages/images/layout_toggle_button.html +8 -7
  215. wagtail/images/templatetags/wagtailimages_tags.py +2 -2
  216. wagtail/images/tests/test_admin_views.py +87 -0
  217. wagtail/images/tests/test_form_overrides.py +1 -1
  218. wagtail/images/tests/test_models.py +48 -9
  219. wagtail/images/views/chooser.py +66 -2
  220. wagtail/locale/en/LC_MESSAGES/django.po +55 -55
  221. wagtail/locale/is_IS/LC_MESSAGES/django.mo +0 -0
  222. wagtail/locale/is_IS/LC_MESSAGES/django.po +3 -3
  223. wagtail/locale/nl/LC_MESSAGES/django.mo +0 -0
  224. wagtail/locale/nl/LC_MESSAGES/django.po +11 -2
  225. wagtail/locale/ru/LC_MESSAGES/django.mo +0 -0
  226. wagtail/locale/ru/LC_MESSAGES/django.po +11 -1
  227. wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
  228. wagtail/locales/locale/nl/LC_MESSAGES/django.mo +0 -0
  229. wagtail/locales/locale/nl/LC_MESSAGES/django.po +12 -1
  230. wagtail/locales/locale/ru/LC_MESSAGES/django.mo +0 -0
  231. wagtail/locales/locale/ru/LC_MESSAGES/django.po +10 -1
  232. wagtail/locales/views.py +2 -2
  233. wagtail/models/orderable.py +10 -0
  234. wagtail/models/pages.py +9 -11
  235. wagtail/models/sites.py +1 -1
  236. wagtail/models/workflows.py +8 -5
  237. wagtail/project_template/home/tests.py +6 -7
  238. wagtail/project_template/project_name/settings/base.py +9 -9
  239. wagtail/project_template/requirements.txt +1 -1
  240. wagtail/query.py +7 -2
  241. wagtail/rich_text/rewriters.py +1 -1
  242. wagtail/search/apps.py +4 -49
  243. wagtail/search/backends/__init__.py +1 -113
  244. wagtail/search/backends/base.py +1 -547
  245. wagtail/search/backends/database/__init__.py +1 -50
  246. wagtail/search/backends/database/fallback.py +1 -253
  247. wagtail/search/backends/database/mysql/mysql.py +1 -700
  248. wagtail/search/backends/database/mysql/query.py +1 -258
  249. wagtail/search/backends/database/postgres/postgres.py +1 -749
  250. wagtail/search/backends/database/postgres/query.py +1 -83
  251. wagtail/search/backends/database/postgres/weights.py +1 -63
  252. wagtail/search/backends/database/sqlite/query.py +1 -294
  253. wagtail/search/backends/database/sqlite/sqlite.py +1 -719
  254. wagtail/search/backends/database/sqlite/utils.py +1 -35
  255. wagtail/search/backends/deprecation.py +45 -0
  256. wagtail/search/backends/elasticsearch7.py +18 -1260
  257. wagtail/search/backends/elasticsearch8.py +21 -96
  258. wagtail/search/backends/elasticsearch9.py +35 -0
  259. wagtail/search/backends/opensearch2.py +35 -0
  260. wagtail/search/backends/opensearch3.py +35 -0
  261. wagtail/search/index.py +1 -358
  262. wagtail/search/locale/en/LC_MESSAGES/django.po +2 -10
  263. wagtail/search/management/commands/update_index.py +1 -205
  264. wagtail/search/management/commands/wagtail_update_index.py +1 -4
  265. wagtail/search/models.py +32 -158
  266. wagtail/search/query.py +1 -114
  267. wagtail/search/queryset.py +1 -43
  268. wagtail/search/signal_handlers.py +1 -24
  269. wagtail/search/tasks.py +1 -10
  270. wagtail/search/tests/test_elasticsearch.py +22 -0
  271. wagtail/search/utils.py +1 -206
  272. wagtail/sites/locale/en/LC_MESSAGES/django.po +1 -1
  273. wagtail/snippets/locale/en/LC_MESSAGES/django.po +3 -3
  274. wagtail/snippets/locale/ru/LC_MESSAGES/django.mo +0 -0
  275. wagtail/snippets/locale/ru/LC_MESSAGES/django.po +8 -1
  276. wagtail/snippets/locale/tr/LC_MESSAGES/django.mo +0 -0
  277. wagtail/snippets/locale/tr/LC_MESSAGES/django.po +8 -1
  278. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
  279. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
  280. wagtail/snippets/tests/test_preview.py +5 -6
  281. wagtail/snippets/tests/test_reordering.py +319 -0
  282. wagtail/snippets/tests/test_snippets.py +65 -12
  283. wagtail/snippets/views/snippets.py +16 -0
  284. wagtail/test/numberformat.py +30 -0
  285. wagtail/test/settings.py +35 -12
  286. wagtail/test/testapp/fields.py +12 -0
  287. wagtail/test/testapp/migrations/0056_commentablejsonpage.py +50 -0
  288. wagtail/test/testapp/migrations/0057_featurecompletetoy_sort_order.py +23 -0
  289. wagtail/test/testapp/migrations/0058_customlocktask.py +31 -0
  290. wagtail/test/testapp/models.py +27 -0
  291. wagtail/test/testapp/urls.py +1 -0
  292. wagtail/test/testapp/views.py +18 -2
  293. wagtail/test/utils/page_tests.py +17 -17
  294. wagtail/test/utils/template_tests.py +4 -6
  295. wagtail/test/utils/wagtail_tests.py +1 -2
  296. wagtail/tests/test_blocks.py +15 -0
  297. wagtail/tests/test_page_model.py +15 -0
  298. wagtail/{search/tests → tests}/test_page_search.py +29 -2
  299. wagtail/tests/test_search_fields.py +69 -0
  300. wagtail/tests/test_tests.py +62 -6
  301. wagtail/tests/test_workflow.py +25 -1
  302. wagtail/users/locale/cs/LC_MESSAGES/django.mo +0 -0
  303. wagtail/users/locale/cs/LC_MESSAGES/django.po +3 -0
  304. wagtail/users/locale/en/LC_MESSAGES/django.po +2 -2
  305. wagtail/users/locale/nl/LC_MESSAGES/django.mo +0 -0
  306. wagtail/users/locale/nl/LC_MESSAGES/django.po +6 -3
  307. wagtail/users/locale/ru/LC_MESSAGES/django.mo +0 -0
  308. wagtail/users/locale/ru/LC_MESSAGES/django.po +5 -1
  309. wagtail/users/locale/tr/LC_MESSAGES/django.mo +0 -0
  310. wagtail/users/locale/tr/LC_MESSAGES/django.po +78 -4
  311. wagtail/users/templates/wagtailusers/users/create.html +2 -0
  312. wagtail/users/templates/wagtailusers/users/edit.html +2 -0
  313. wagtail/users/tests/test_admin_views.py +4 -0
  314. wagtail/users/views/users.py +1 -1
  315. {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/METADATA +7 -6
  316. {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/RECORD +322 -328
  317. wagtail/admin/templates/wagtailadmin/collection_privacy/set_privacy.html +0 -13
  318. wagtail/admin/templates/wagtailadmin/page_privacy/set_privacy.html +0 -13
  319. wagtail/search/tests/__init__.py +0 -0
  320. wagtail/search/tests/elasticsearch_common_tests.py +0 -251
  321. wagtail/search/tests/test_backends.py +0 -1215
  322. wagtail/search/tests/test_db_backend.py +0 -62
  323. wagtail/search/tests/test_elasticsearch7_backend.py +0 -1452
  324. wagtail/search/tests/test_elasticsearch8_backend.py +0 -15
  325. wagtail/search/tests/test_index_functions.py +0 -256
  326. wagtail/search/tests/test_indexed_class.py +0 -157
  327. wagtail/search/tests/test_mysql_backend.py +0 -192
  328. wagtail/search/tests/test_postgres_backend.py +0 -210
  329. wagtail/search/tests/test_queries.py +0 -332
  330. wagtail/search/tests/test_related_fields.py +0 -102
  331. wagtail/search/tests/test_sqlite_backend.py +0 -52
  332. wagtail/test/search/__init__.py +0 -0
  333. wagtail/test/search/apps.py +0 -9
  334. wagtail/test/search/fixtures/search.json +0 -545
  335. wagtail/test/search/migrations/0001_initial.py +0 -146
  336. wagtail/test/search/migrations/0002_bookunindexed.py +0 -43
  337. wagtail/test/search/migrations/0003_book_summary.py +0 -18
  338. wagtail/test/search/migrations/__init__.py +0 -0
  339. wagtail/test/search/models.py +0 -137
  340. /wagtail/admin/templates/wagtailadmin/{pages/listing/_ordering_cell.html → tables/ordering_cell.html} +0 -0
  341. /wagtail/{search/checks.py → checks.py} +0 -0
  342. {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/WHEEL +0 -0
  343. {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/entry_points.txt +0 -0
  344. {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/licenses/LICENSE +0 -0
  345. {wagtail-7.1.1.dist-info → wagtail-7.2rc1.dist-info}/top_level.txt +0 -0
@@ -1828,3 +1828,325 @@ class TestHeaderButtons(WagtailTestUtils, TestCase):
1828
1828
  [(a.text.strip(), a.get("href")) for a in header_buttons],
1829
1829
  expected_buttons,
1830
1830
  )
1831
+
1832
+
1833
+ class TestIndexViewReordering(WagtailTestUtils, TestCase):
1834
+ def setUp(self):
1835
+ self.user = self.login()
1836
+ self.obj1 = FeatureCompleteToy.objects.create(name="Toy 1", sort_order=0)
1837
+ self.obj2 = FeatureCompleteToy.objects.create(name="Toy 2", sort_order=1)
1838
+ self.obj3 = FeatureCompleteToy.objects.create(name="Toy 3", sort_order=2)
1839
+
1840
+ def test_header_button_rendered(self):
1841
+ index_url = reverse("feature_complete_toy:index")
1842
+ custom_ordering_url = index_url + "?ordering=sort_order"
1843
+ response = self.client.get(index_url)
1844
+ self.assertEqual(response.status_code, 200)
1845
+ soup = self.get_soup(response.content)
1846
+ button = soup.select_one(
1847
+ f".w-slim-header .w-dropdown a[href='{custom_ordering_url}']"
1848
+ )
1849
+ self.assertIsNotNone(button)
1850
+ self.assertEqual(button.text.strip(), "Sort item order")
1851
+
1852
+ # Reordering feature disabled when not sorting by sort_order
1853
+ table = soup.select_one("main table")
1854
+ self.assertIsNotNone(table)
1855
+ self.assertFalse(table.get("data-controller"))
1856
+ first_th = soup.select_one("main thead th:first-child")
1857
+ self.assertIsNotNone(first_th)
1858
+ self.assertEqual(first_th.text.strip(), "Name")
1859
+
1860
+ def test_show_ordering_column(self):
1861
+ index_url = reverse("feature_complete_toy:index")
1862
+ custom_ordering_url = index_url + "?ordering=sort_order"
1863
+ response = self.client.get(custom_ordering_url)
1864
+ self.assertEqual(response.status_code, 200)
1865
+ soup = self.get_soup(response.content)
1866
+
1867
+ # The table should have the w-orderable controller
1868
+ table = soup.select_one("main table")
1869
+ self.assertIsNotNone(table)
1870
+ self.assertEqual(table.get("data-controller"), "w-orderable")
1871
+ self.assertEqual(
1872
+ table.get("data-w-orderable-message-value"),
1873
+ "'__LABEL__' has been moved successfully.",
1874
+ )
1875
+ self.assertEqual(
1876
+ table.get("data-w-orderable-url-value"),
1877
+ reverse("feature_complete_toy:reorder", args=[999999]),
1878
+ )
1879
+
1880
+ # The ordering column added as the first column
1881
+ first_th = table.select_one("thead th:first-child")
1882
+ self.assertIsNotNone(first_th)
1883
+ self.assertEqual(first_th.text.strip(), "Sort")
1884
+
1885
+ # All rows have the corresponding attributes for reordering
1886
+ rows = table.select("tbody tr")
1887
+ self.assertEqual(len(rows), 3)
1888
+ expected = [
1889
+ {
1890
+ "id": f"item_{quote(toy.pk)}",
1891
+ "data-w-orderable-item-id": quote(toy.pk),
1892
+ "data-w-orderable-item-label": str(toy),
1893
+ "data-w-orderable-target": "item",
1894
+ }
1895
+ for toy in [self.obj1, self.obj2, self.obj3]
1896
+ ]
1897
+ for row, expected_attrs in zip(rows, expected):
1898
+ for attr, value in expected_attrs.items():
1899
+ self.assertEqual(row.get(attr), value)
1900
+ handle = row.select_one("td button[data-w-orderable-target='handle']")
1901
+ self.assertIsNotNone(handle)
1902
+
1903
+ def test_reordering_disabled_with_explicit_sort_order_field_none(self):
1904
+ # The model has a sort_order_field, but the viewset explicitly sets
1905
+ # sort_order_field = None
1906
+ index_url = reverse("fctoy-alt2:index")
1907
+ custom_ordering_url = index_url + "?ordering=sort_order"
1908
+ response = self.client.get(custom_ordering_url)
1909
+ self.assertEqual(response.status_code, 200)
1910
+ soup = self.get_soup(response.content)
1911
+
1912
+ # Header button for enabling reordering should not be rendered
1913
+ button = soup.select_one(
1914
+ f".w-slim-header .w-dropdown a[href='{custom_ordering_url}']"
1915
+ )
1916
+ self.assertIsNone(button)
1917
+
1918
+ # Reordering feature not enabled
1919
+ table = soup.select_one("main table")
1920
+ self.assertIsNotNone(table)
1921
+ self.assertFalse(table.get("data-controller"))
1922
+ first_th = soup.select_one("main thead th:first-child")
1923
+ self.assertIsNotNone(first_th)
1924
+ self.assertEqual(first_th.text.strip(), "Feature complete toy")
1925
+
1926
+ def test_reordering_disabled_with_no_sort_order_field(self):
1927
+ # This model has no sort_order_field defined on the model nor the viewset
1928
+ JSONStreamModel.objects.create()
1929
+ index_url = reverse("streammodel:index")
1930
+ custom_ordering_url = index_url + "?ordering="
1931
+ response = self.client.get(custom_ordering_url)
1932
+ self.assertEqual(response.status_code, 200)
1933
+ soup = self.get_soup(response.content)
1934
+
1935
+ # Header button for enabling reordering should not be rendered
1936
+ button = soup.select_one(
1937
+ f".w-slim-header .w-dropdown a[href^='{custom_ordering_url}']"
1938
+ )
1939
+ self.assertIsNone(button)
1940
+
1941
+ # Reordering feature not enabled
1942
+ table = soup.select_one("main table")
1943
+ self.assertIsNotNone(table)
1944
+ self.assertFalse(table.get("data-controller"))
1945
+ first_th = soup.select_one("main thead th:first-child")
1946
+ self.assertIsNotNone(first_th)
1947
+ self.assertEqual(first_th.text.strip(), "JSON stream model")
1948
+
1949
+ def test_reordering_disabled_with_insufficient_permission(self):
1950
+ self.user.is_superuser = False
1951
+ self.user.save()
1952
+ admin_permission = Permission.objects.get(
1953
+ content_type__app_label="wagtailadmin", codename="access_admin"
1954
+ )
1955
+ view_permission = Permission.objects.get(
1956
+ content_type__app_label=self.obj1._meta.app_label,
1957
+ codename=get_permission_codename("view", self.obj1._meta),
1958
+ )
1959
+ self.user.user_permissions.add(admin_permission, view_permission)
1960
+
1961
+ index_url = reverse("feature_complete_toy:index")
1962
+ custom_ordering_url = index_url + "?ordering=sort_order"
1963
+ response = self.client.get(custom_ordering_url)
1964
+ self.assertEqual(response.status_code, 200)
1965
+ soup = self.get_soup(response.content)
1966
+
1967
+ # Header button for enabling reordering should not be rendered
1968
+ button = soup.select_one(
1969
+ f".w-slim-header .w-dropdown a[href='{custom_ordering_url}']"
1970
+ )
1971
+ self.assertIsNone(button)
1972
+
1973
+ # Reordering feature not enabled
1974
+ table = soup.select_one("main table")
1975
+ self.assertIsNotNone(table)
1976
+ self.assertFalse(table.get("data-controller"))
1977
+ first_th = soup.select_one("main thead th:first-child")
1978
+ self.assertIsNotNone(first_th)
1979
+ self.assertEqual(first_th.text.strip(), "Name")
1980
+
1981
+ def test_minimal_permission(self):
1982
+ self.user.is_superuser = False
1983
+ self.user.save()
1984
+ admin_permission = Permission.objects.get(
1985
+ content_type__app_label="wagtailadmin", codename="access_admin"
1986
+ )
1987
+ change_permission = Permission.objects.get(
1988
+ content_type__app_label=self.obj1._meta.app_label,
1989
+ codename=get_permission_codename("change", self.obj1._meta),
1990
+ )
1991
+ self.user.user_permissions.add(admin_permission, change_permission)
1992
+
1993
+ self.test_header_button_rendered()
1994
+ self.test_show_ordering_column()
1995
+
1996
+
1997
+ class TestCreateViewReordering(WagtailTestUtils, TestCase):
1998
+ def setUp(self):
1999
+ self.user = self.login()
2000
+ FeatureCompleteToy.objects.bulk_create(
2001
+ [
2002
+ FeatureCompleteToy(name="Toy 1", sort_order=0),
2003
+ FeatureCompleteToy(name="Toy 2", sort_order=1),
2004
+ FeatureCompleteToy(name="Toy 3", sort_order=2),
2005
+ ]
2006
+ )
2007
+
2008
+ def test_create_sets_max_sort_order(self):
2009
+ response = self.client.post(
2010
+ reverse("feature_complete_toy:add"),
2011
+ data={"name": "New Toy", "release_date": "2025-08-17"},
2012
+ )
2013
+ self.assertRedirects(response, reverse("feature_complete_toy:index"))
2014
+ new_toy = FeatureCompleteToy.objects.get(name="New Toy")
2015
+ self.assertEqual(new_toy.sort_order, 3)
2016
+
2017
+ def test_create_does_not_set_max_sort_order_without_sort_order_field(self):
2018
+ response = self.client.post(
2019
+ reverse("fctoy-alt2:add"),
2020
+ data={"name": "New Toy", "release_date": "2025-08-17", "strid": "foo"},
2021
+ )
2022
+ self.assertRedirects(response, reverse("fctoy-alt2:index"))
2023
+ new_toy = FeatureCompleteToy.objects.get(name="New Toy")
2024
+ self.assertIsNone(new_toy.sort_order)
2025
+
2026
+
2027
+ class TestReorderView(WagtailTestUtils, TestCase):
2028
+ def setUp(self):
2029
+ self.user = self.login()
2030
+ # We don't do any normalization, so the sort_order values may not be
2031
+ # consecutive integers (e.g. after an item is deleted), and the update
2032
+ # logic may cause the sort_order values to be negative or larger than
2033
+ # the number of items in the queryset.
2034
+ self.obj1 = FeatureCompleteToy.objects.create(name="Toy 1", sort_order=-3)
2035
+ self.obj2 = FeatureCompleteToy.objects.create(name="Toy 2", sort_order=4)
2036
+ self.obj3 = FeatureCompleteToy.objects.create(name="Toy 3", sort_order=9)
2037
+
2038
+ def get_url(self, obj):
2039
+ return reverse("feature_complete_toy:reorder", args=(quote(obj.pk),))
2040
+
2041
+ def assertOrder(self, objs):
2042
+ self.assertSequenceEqual(
2043
+ [
2044
+ (obj, obj.sort_order)
2045
+ for obj in FeatureCompleteToy.objects.order_by("sort_order")
2046
+ ],
2047
+ objs,
2048
+ )
2049
+
2050
+ def test_reorder_view_disabled_without_sort_order_field(self):
2051
+ # The alt2 viewset explicitly sets sort_order_field to `None`,
2052
+ # so the reorder view should not be available
2053
+ with self.assertRaises(NoReverseMatch):
2054
+ reverse("fctoy-alt2:reorder", args=(quote(self.obj1.pk),))
2055
+
2056
+ # This model has no sort_order_field on the model nor the viewset
2057
+ obj = JSONStreamModel.objects.create()
2058
+ with self.assertRaises(NoReverseMatch):
2059
+ reverse("streammodel:reorder", args=(quote(obj.pk),))
2060
+
2061
+ def test_get_request_does_not_alter_order(self):
2062
+ response = self.client.get(self.get_url(self.obj1))
2063
+ self.assertEqual(response.status_code, 405)
2064
+
2065
+ # Ensure item order does not change
2066
+ self.assertOrder([(self.obj1, -3), (self.obj2, 4), (self.obj3, 9)])
2067
+
2068
+ def test_post_request_without_position_argument_moves_to_the_end(self):
2069
+ response = self.client.post(self.get_url(self.obj1))
2070
+ self.assertEqual(response.status_code, 200)
2071
+
2072
+ # The item will be moved to the last position by taking the sort_order
2073
+ # of the last item, and the sort_order of the other items updated by -1
2074
+ self.assertOrder([(self.obj2, 3), (self.obj3, 8), (self.obj1, 9)])
2075
+
2076
+ def test_post_request_with_non_integer_position_moves_to_the_end(self):
2077
+ response = self.client.post(self.get_url(self.obj1) + "?position=good")
2078
+ self.assertEqual(response.status_code, 200)
2079
+
2080
+ # The item will be moved to the last position by taking the sort_order
2081
+ # of the last item, and the sort_order of the other items updated by -1
2082
+ self.assertOrder([(self.obj2, 3), (self.obj3, 8), (self.obj1, 9)])
2083
+
2084
+ def test_move_position_up(self):
2085
+ # Move obj3 to the first position
2086
+ response = self.client.post(self.get_url(self.obj3) + "?position=0")
2087
+ self.assertEqual(response.status_code, 200)
2088
+
2089
+ # Check if obj3 is now the first item by taking obj1's sort_order and
2090
+ # incrementing sort_order of the other items after it by 1
2091
+ self.assertOrder([(self.obj3, -3), (self.obj1, -2), (self.obj2, 5)])
2092
+
2093
+ def test_move_position_down(self):
2094
+ # Move obj1 to the second position
2095
+ response = self.client.post(self.get_url(self.obj1) + "?position=1")
2096
+ self.assertEqual(response.status_code, 200)
2097
+
2098
+ # Check if obj1 is now the second item by taking obj2's sort_order
2099
+ # and decrementing sort_order of the other items before it by 1
2100
+ self.assertOrder([(self.obj2, 3), (self.obj1, 4), (self.obj3, 9)])
2101
+
2102
+ def test_move_position_to_same_position(self):
2103
+ # Move obj1 to position 0 (where it already is)
2104
+ response = self.client.post(self.get_url(self.obj1) + "?position=0")
2105
+ self.assertEqual(response.status_code, 200)
2106
+
2107
+ # Ensure item order does not change
2108
+ self.assertOrder([(self.obj1, -3), (self.obj2, 4), (self.obj3, 9)])
2109
+
2110
+ def test_move_position_with_invalid_target_position(self):
2111
+ response = self.client.post(self.get_url(self.obj1) + "?position=99")
2112
+ self.assertEqual(response.status_code, 200)
2113
+
2114
+ # The item will be moved to the last position by taking the sort_order
2115
+ # of the last item, and the sort_order of the other items updated by -1
2116
+ self.assertOrder([(self.obj2, 3), (self.obj3, 8), (self.obj1, 9)])
2117
+
2118
+ def test_insufficient_permission(self):
2119
+ self.user.is_superuser = False
2120
+ self.user.save()
2121
+ admin_permission = Permission.objects.get(
2122
+ content_type__app_label="wagtailadmin", codename="access_admin"
2123
+ )
2124
+ view_permission = Permission.objects.get(
2125
+ content_type__app_label=self.obj1._meta.app_label,
2126
+ codename=get_permission_codename("view", self.obj1._meta),
2127
+ )
2128
+ self.user.user_permissions.add(admin_permission, view_permission)
2129
+
2130
+ response = self.client.post(self.get_url(self.obj1) + "?position=1")
2131
+ self.assertEqual(response.status_code, 302)
2132
+ self.assertRedirects(response, reverse("wagtailadmin_home"))
2133
+ self.assertOrder([(self.obj1, -3), (self.obj2, 4), (self.obj3, 9)])
2134
+
2135
+ def test_minimal_permission(self):
2136
+ self.user.is_superuser = False
2137
+ self.user.save()
2138
+ admin_permission = Permission.objects.get(
2139
+ content_type__app_label="wagtailadmin", codename="access_admin"
2140
+ )
2141
+ change_permission = Permission.objects.get(
2142
+ content_type__app_label=self.obj1._meta.app_label,
2143
+ codename=get_permission_codename("change", self.obj1._meta),
2144
+ )
2145
+ self.user.user_permissions.add(admin_permission, change_permission)
2146
+
2147
+ response = self.client.post(self.get_url(self.obj1) + "?position=1")
2148
+ self.assertEqual(response.status_code, 200)
2149
+
2150
+ # Check if obj1 is now the second item by taking obj2's sort_order
2151
+ # and decrementing sort_order of the other items before it by 1
2152
+ self.assertOrder([(self.obj2, 3), (self.obj1, 4), (self.obj3, 9)])
@@ -0,0 +1,73 @@
1
+ from collections import OrderedDict
2
+
3
+ from django.contrib.admin.utils import quote
4
+ from django.utils.functional import cached_property
5
+ from django.utils.translation import gettext, gettext_lazy
6
+
7
+ from wagtail.admin.ui.tables import BaseColumn, BulkActionsCheckboxColumn
8
+
9
+
10
+ class OrderingColumn(BaseColumn):
11
+ header_template_name = "wagtailadmin/tables/ordering_header.html"
12
+ cell_template_name = "wagtailadmin/tables/ordering_cell.html"
13
+
14
+
15
+ class OrderableTableMixin:
16
+ success_message = gettext_lazy("'%(page_title)s' has been moved successfully.")
17
+
18
+ def __init__(self, *args, sort_order_field=None, reorder_url=None, **kwargs):
19
+ super().__init__(*args, **kwargs)
20
+ self.sort_order_field = sort_order_field
21
+ self.reorder_url = reorder_url
22
+ if self.reorder_url:
23
+ self._add_ordering_column()
24
+
25
+ @cached_property
26
+ def ordering_column(self):
27
+ return OrderingColumn("ordering", width="80px", sort_key=self.sort_order_field)
28
+
29
+ def _add_ordering_column(self):
30
+ self.columns = OrderedDict(
31
+ [(self.ordering_column.name, self.ordering_column)]
32
+ + [
33
+ (column_name, column)
34
+ for column_name, column in self.columns.items()
35
+ # Replace bulk actions column with the ordering column if it exists
36
+ if not isinstance(column, BulkActionsCheckboxColumn)
37
+ ]
38
+ )
39
+
40
+ @property
41
+ def attrs(self):
42
+ attrs = super().attrs
43
+ if self.reorder_url:
44
+ attrs = {
45
+ **attrs,
46
+ "data-controller": "w-orderable",
47
+ "data-w-orderable-active-class": "w-orderable--active",
48
+ "data-w-orderable-chosen-class": "w-orderable__item--active",
49
+ "data-w-orderable-container-value": "tbody",
50
+ "data-w-orderable-message-value": self.get_success_message(),
51
+ "data-w-orderable-url-value": self.reorder_url,
52
+ }
53
+ return attrs
54
+
55
+ def get_success_message(self):
56
+ return self.success_message % {"page_title": "__LABEL__"}
57
+
58
+ def get_row_attrs(self, instance):
59
+ attrs = super().get_row_attrs(instance)
60
+ if self.reorder_url:
61
+ attrs["id"] = "item_%s" % quote(instance.pk)
62
+ attrs["data-w-orderable-item-id"] = quote(instance.pk)
63
+ attrs["data-w-orderable-item-label"] = str(instance)
64
+ attrs["data-w-orderable-target"] = "item"
65
+ return attrs
66
+
67
+ def get_caption(self):
68
+ caption = super().get_caption()
69
+ if not caption and self.reorder_url:
70
+ return gettext(
71
+ "Focus on the drag button and press up or down arrows to move the item, then press enter to submit the change."
72
+ )
73
+ return caption
@@ -2,6 +2,7 @@ from django.utils.safestring import mark_safe
2
2
  from django.utils.translation import gettext
3
3
 
4
4
  from wagtail.admin.ui.tables import BaseColumn, BulkActionsCheckboxColumn, Column, Table
5
+ from wagtail.admin.ui.tables.orderable import OrderableTableMixin
5
6
 
6
7
 
7
8
  class PageTitleColumn(BaseColumn):
@@ -77,11 +78,6 @@ class BulkActionsColumn(BulkActionsCheckboxColumn):
77
78
  return context
78
79
 
79
80
 
80
- class OrderingColumn(BaseColumn):
81
- header_template_name = "wagtailadmin/pages/listing/_ordering_header.html"
82
- cell_template_name = "wagtailadmin/pages/listing/_ordering_cell.html"
83
-
84
-
85
81
  class PageTypeColumn(Column):
86
82
  def get_header_context_data(self, parent_context):
87
83
  context = super().get_header_context_data(parent_context)
@@ -109,11 +105,10 @@ class NavigateToChildrenColumn(BaseColumn):
109
105
  return mark_safe("<td></td>")
110
106
 
111
107
 
112
- class PageTable(Table):
108
+ class PageTable(OrderableTableMixin, Table):
113
109
  def __init__(
114
110
  self,
115
111
  *args,
116
- use_row_ordering_attributes=False,
117
112
  parent_page=None,
118
113
  show_locale_labels=False,
119
114
  actions_next_url=None,
@@ -121,9 +116,6 @@ class PageTable(Table):
121
116
  ):
122
117
  super().__init__(*args, **kwargs)
123
118
 
124
- # If true, attributes will be added on the <tr> element to support reordering
125
- self.use_row_ordering_attributes = use_row_ordering_attributes
126
-
127
119
  # The parent page of the pages being listed - used to add extra context to the title text
128
120
  # of the reordering links. Leave this undefined if the pages being listed do not share a
129
121
  # common parent.
@@ -163,11 +155,9 @@ class PageTable(Table):
163
155
 
164
156
  def get_row_attrs(self, instance):
165
157
  attrs = super().get_row_attrs(instance)
166
- if self.use_row_ordering_attributes:
158
+ if self.reorder_url:
167
159
  attrs["id"] = "page_%d" % instance.id
168
- attrs["data-w-orderable-item-id"] = instance.id
169
160
  attrs["data-w-orderable-item-label"] = instance.get_admin_display_title()
170
- attrs["data-w-orderable-target"] = "item"
171
161
  return attrs
172
162
 
173
163
  def get_context_data(self, parent_context):
wagtail/admin/userbar.py CHANGED
@@ -364,10 +364,15 @@ class Userbar(Component):
364
364
  # Remove any unrendered items
365
365
  rendered_items = [item for item in rendered_items if item]
366
366
 
367
+ if request:
368
+ origin = f"{request.scheme}://{request.get_host()}"
369
+ else:
370
+ origin = get_admin_base_url() or ""
371
+
367
372
  # Render the userbar items
368
373
  return {
369
374
  "request": request,
370
- "origin": get_admin_base_url(),
375
+ "origin": origin,
371
376
  "items": rendered_items,
372
377
  "position": self.position,
373
378
  "page": self.object,
@@ -1,5 +1,6 @@
1
1
  from django.core.exceptions import PermissionDenied
2
2
  from django.shortcuts import get_object_or_404
3
+ from django.urls import reverse
3
4
 
4
5
  from wagtail.admin.forms.collections import CollectionViewRestrictionForm
5
6
  from wagtail.admin.modal_workflow import render_modal_workflow
@@ -69,10 +70,13 @@ def set_privacy(request, collection_id):
69
70
  # no restriction set at ancestor level - can set restrictions here
70
71
  return render_modal_workflow(
71
72
  request,
72
- "wagtailadmin/collection_privacy/set_privacy.html",
73
+ "wagtailadmin/shared/set_privacy.html",
73
74
  None,
74
75
  {
75
- "collection": collection,
76
+ "action_url": reverse(
77
+ "wagtailadmin_collections:set_privacy", args=(collection.pk,)
78
+ ),
79
+ "object": collection,
76
80
  "form": form,
77
81
  },
78
82
  json_data={"step": "set_privacy"},
@@ -26,5 +26,6 @@ from .models import ( # noqa: F401
26
26
  RevisionsUnscheduleView,
27
27
  UnpublishView,
28
28
  )
29
+ from .ordering import ReorderView # noqa: F401
29
30
  from .permissions import PermissionCheckedMixin # noqa: F401
30
31
  from .usage import UsageView # noqa: F401
@@ -1,5 +1,4 @@
1
1
  import json
2
- from typing import Optional
3
2
 
4
3
  from django.conf import settings
5
4
  from django.contrib.admin.utils import quote
@@ -38,6 +37,7 @@ from wagtail.models import (
38
37
  WorkflowMixin,
39
38
  WorkflowState,
40
39
  )
40
+ from wagtail.models.orderable import set_max_order
41
41
  from wagtail.utils.timestamps import render_timestamp
42
42
 
43
43
 
@@ -123,7 +123,7 @@ class LocaleMixin:
123
123
  def translations(self):
124
124
  return self.get_translations() if self.locale else []
125
125
 
126
- def get_locale(self) -> Optional[Locale]:
126
+ def get_locale(self) -> Locale | None:
127
127
  if not getattr(self, "model", None):
128
128
  return None
129
129
 
@@ -240,6 +240,15 @@ class IndexViewOptionalFeaturesMixin:
240
240
  list_display.append(LiveStatusTagColumn())
241
241
  return list_display
242
242
 
243
+ def get_reorder_url(self):
244
+ if (
245
+ self.model
246
+ and issubclass(self.model, DraftStateMixin)
247
+ and not self.user_has_permission("publish")
248
+ ):
249
+ return None
250
+ return super().get_reorder_url()
251
+
243
252
 
244
253
  class CreateEditViewOptionalFeaturesMixin:
245
254
  """
@@ -524,6 +533,15 @@ class CreateEditViewOptionalFeaturesMixin:
524
533
  else:
525
534
  instance = self.form.save()
526
535
 
536
+ # Apply max order number if the model uses custom ordering and the
537
+ # sort_order_field is not set.
538
+ if (
539
+ self.view_name == "create"
540
+ and self.sort_order_field
541
+ and getattr(instance, self.sort_order_field) is None
542
+ ):
543
+ set_max_order(instance, self.sort_order_field)
544
+
527
545
  self.has_content_changes = self.view_name == "create" or self.form.has_changed()
528
546
 
529
547
  # Save revision if the model inherits from RevisionMixin