wagtail 6.3.1__py3-none-any.whl → 6.4rc1__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 (307) hide show
  1. wagtail/__init__.py +1 -1
  2. wagtail/actions/publish_revision.py +4 -5
  3. wagtail/admin/auth.py +0 -2
  4. wagtail/admin/checks.py +1 -1
  5. wagtail/admin/filters.py +3 -1
  6. wagtail/admin/forms/account.py +21 -11
  7. wagtail/admin/forms/collections.py +2 -9
  8. wagtail/admin/forms/formsets.py +32 -0
  9. wagtail/admin/forms/pages.py +5 -1
  10. wagtail/admin/forms/workflows.py +2 -13
  11. wagtail/admin/locale/ar/LC_MESSAGES/django.mo +0 -0
  12. wagtail/admin/locale/ar/LC_MESSAGES/django.po +68 -1
  13. wagtail/admin/locale/ar/LC_MESSAGES/djangojs.mo +0 -0
  14. wagtail/admin/locale/ar/LC_MESSAGES/djangojs.po +5 -1
  15. wagtail/admin/locale/en/LC_MESSAGES/django.po +312 -356
  16. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +21 -16
  17. wagtail/admin/locale/gl/LC_MESSAGES/djangojs.mo +0 -0
  18. wagtail/admin/locale/gl/LC_MESSAGES/djangojs.po +5 -5
  19. wagtail/admin/locale/pt_BR/LC_MESSAGES/django.mo +0 -0
  20. wagtail/admin/locale/pt_BR/LC_MESSAGES/django.po +29 -0
  21. wagtail/admin/menu.py +0 -13
  22. wagtail/admin/panels/base.py +2 -2
  23. wagtail/admin/panels/group.py +4 -1
  24. wagtail/admin/panels/inline_panel.py +5 -2
  25. wagtail/admin/panels/model_utils.py +36 -0
  26. wagtail/admin/panels/page_utils.py +2 -40
  27. wagtail/admin/panels/signal_handlers.py +0 -2
  28. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  29. wagtail/admin/static/wagtailadmin/css/panels/draftail.css +1 -1
  30. wagtail/admin/static/wagtailadmin/css/panels/streamfield.css +1 -1
  31. wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
  32. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  33. wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +1 -8
  34. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  35. wagtail/admin/static/wagtailadmin/js/modal-workflow.js +1 -1
  36. wagtail/admin/static/wagtailadmin/js/page-chooser-modal.js +1 -1
  37. wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
  38. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  39. wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
  40. wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
  41. wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +1 -1
  42. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  43. wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +7 -0
  44. wagtail/admin/templates/wagtailadmin/404.html +4 -0
  45. wagtail/admin/templates/wagtailadmin/chooser/browse.html +2 -1
  46. wagtail/admin/templates/wagtailadmin/chooser/tables/parent_page_cell.html +1 -1
  47. wagtail/admin/templates/wagtailadmin/collections/_privacy_switch.html +8 -1
  48. wagtail/admin/templates/wagtailadmin/generic/confirm_delete.html +15 -9
  49. wagtail/admin/templates/wagtailadmin/generic/confirm_unpublish.html +21 -25
  50. wagtail/admin/templates/wagtailadmin/generic/form.html +1 -1
  51. wagtail/admin/templates/wagtailadmin/generic/preview_error.html +3 -0
  52. wagtail/admin/templates/wagtailadmin/generic/revisions/compare.html +63 -76
  53. wagtail/admin/templates/wagtailadmin/pages/_editor_js.html +0 -2
  54. wagtail/admin/templates/wagtailadmin/pages/edit.html +1 -5
  55. wagtail/admin/templates/wagtailadmin/panels/inline_panel_child.html +1 -0
  56. wagtail/admin/templates/wagtailadmin/permissions/includes/collection_member_permissions_form.html +1 -1
  57. wagtail/admin/templates/wagtailadmin/permissions/includes/collection_member_permissions_formset.html +6 -22
  58. wagtail/admin/templates/wagtailadmin/shared/formatted_field.html +2 -2
  59. wagtail/admin/templates/wagtailadmin/shared/header.html +2 -2
  60. wagtail/admin/templates/wagtailadmin/shared/page_status_tag_new.html +32 -39
  61. wagtail/admin/templates/wagtailadmin/shared/revisions/confirm_unschedule.html +13 -17
  62. wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/privacy.html +15 -3
  63. wagtail/admin/templates/wagtailadmin/shared/side_panels/preview.html +1 -1
  64. wagtail/admin/templates/wagtailadmin/skeleton.html +4 -2
  65. wagtail/admin/templates/wagtailadmin/workflows/create.html +1 -1
  66. wagtail/admin/templates/wagtailadmin/workflows/edit.html +1 -1
  67. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_pages_form.html +1 -1
  68. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_pages_formset.html +6 -23
  69. wagtail/admin/templatetags/wagtailadmin_tags.py +12 -0
  70. wagtail/admin/templatetags/wagtailuserbar.py +2 -3
  71. wagtail/admin/tests/pages/test_create_page.py +110 -1
  72. wagtail/admin/tests/pages/test_edit_page.py +3 -2
  73. wagtail/admin/tests/pages/test_explorer_view.py +18 -0
  74. wagtail/admin/tests/pages/test_page_usage.py +24 -20
  75. wagtail/admin/tests/pages/test_preview.py +69 -1
  76. wagtail/admin/tests/pages/test_revisions.py +40 -6
  77. wagtail/admin/tests/test_account_management.py +39 -1
  78. wagtail/admin/tests/test_audit_log.py +4 -2
  79. wagtail/admin/tests/test_block_preview.py +224 -0
  80. wagtail/admin/tests/test_edit_handlers.py +23 -6
  81. wagtail/admin/tests/test_page_chooser.py +50 -3
  82. wagtail/admin/tests/test_privacy.py +49 -26
  83. wagtail/admin/tests/test_site_summary.py +15 -10
  84. wagtail/admin/tests/test_templatetags.py +19 -0
  85. wagtail/admin/tests/test_userbar.py +82 -1
  86. wagtail/admin/tests/test_views_generic.py +27 -12
  87. wagtail/admin/tests/test_workflows.py +69 -0
  88. wagtail/admin/tests/tests.py +23 -4
  89. wagtail/admin/tests/ui/test_sidebar.py +1 -1
  90. wagtail/admin/tests/viewsets/test_model_viewset.py +15 -13
  91. wagtail/admin/ui/side_panels.py +7 -4
  92. wagtail/admin/urls/__init__.py +6 -0
  93. wagtail/admin/urls/pages.py +1 -1
  94. wagtail/admin/userbar.py +21 -1
  95. wagtail/admin/views/account.py +5 -0
  96. wagtail/admin/views/chooser.py +5 -1
  97. wagtail/admin/views/collections.py +0 -2
  98. wagtail/admin/views/generic/base.py +20 -10
  99. wagtail/admin/views/generic/history.py +0 -1
  100. wagtail/admin/views/generic/models.py +79 -21
  101. wagtail/admin/views/generic/preview.py +50 -1
  102. wagtail/admin/views/mixins.py +4 -2
  103. wagtail/admin/views/pages/bulk_actions/delete.py +11 -23
  104. wagtail/admin/views/pages/bulk_actions/page_bulk_action.py +17 -0
  105. wagtail/admin/views/pages/bulk_actions/publish.py +11 -31
  106. wagtail/admin/views/pages/bulk_actions/unpublish.py +11 -31
  107. wagtail/admin/views/pages/create.py +1 -0
  108. wagtail/admin/views/pages/edit.py +38 -30
  109. wagtail/admin/views/pages/revisions.py +43 -114
  110. wagtail/admin/views/pages/utils.py +0 -1
  111. wagtail/admin/views/tags.py +6 -2
  112. wagtail/admin/views/workflows.py +8 -6
  113. wagtail/admin/viewsets/model.py +0 -4
  114. wagtail/admin/viewsets/pages.py +0 -1
  115. wagtail/admin/widgets/tags.py +1 -0
  116. wagtail/api/v2/tests/test_documents.py +4 -2
  117. wagtail/api/v2/tests/test_images.py +4 -2
  118. wagtail/api/v2/tests/test_pages.py +8 -4
  119. wagtail/blocks/base.py +59 -1
  120. wagtail/blocks/field_block.py +6 -0
  121. wagtail/blocks/list_block.py +4 -0
  122. wagtail/blocks/static_block.py +3 -0
  123. wagtail/blocks/stream_block.py +5 -1
  124. wagtail/blocks/struct_block.py +6 -0
  125. wagtail/compat.py +16 -0
  126. wagtail/contrib/forms/forms.py +27 -7
  127. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +2 -2
  128. wagtail/contrib/forms/locale/gl/LC_MESSAGES/django.mo +0 -0
  129. wagtail/contrib/forms/locale/gl/LC_MESSAGES/django.po +4 -4
  130. wagtail/contrib/forms/tests/test_models.py +7 -5
  131. wagtail/contrib/forms/tests/test_views.py +75 -0
  132. wagtail/contrib/frontend_cache/backends/cloudfront.py +1 -1
  133. wagtail/contrib/frontend_cache/tasks.py +83 -0
  134. wagtail/contrib/frontend_cache/tests.py +48 -33
  135. wagtail/contrib/frontend_cache/utils.py +2 -70
  136. wagtail/contrib/redirects/base_formats.py +2 -2
  137. wagtail/contrib/redirects/locale/ar/LC_MESSAGES/django.mo +0 -0
  138. wagtail/contrib/redirects/locale/ar/LC_MESSAGES/django.po +3 -0
  139. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +24 -37
  140. wagtail/contrib/redirects/templates/wagtailredirects/add.html +1 -24
  141. wagtail/contrib/redirects/templates/wagtailredirects/confirm_delete.html +3 -13
  142. wagtail/contrib/redirects/tests/test_redirects.py +122 -110
  143. wagtail/contrib/redirects/tests/test_signal_handlers.py +75 -69
  144. wagtail/contrib/redirects/urls.py +2 -2
  145. wagtail/contrib/redirects/views.py +35 -73
  146. wagtail/contrib/search_promotions/admin_urls.py +10 -3
  147. wagtail/contrib/search_promotions/forms.py +55 -26
  148. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +44 -54
  149. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/add.html +21 -31
  150. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/confirm_delete.html +3 -12
  151. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/edit.html +11 -34
  152. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/includes/searchpromotion_form.html +1 -0
  153. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/includes/searchpromotions_formset.js +2 -1
  154. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/index.html +0 -1
  155. wagtail/contrib/search_promotions/tests.py +814 -13
  156. wagtail/contrib/search_promotions/views/__init__.py +1 -0
  157. wagtail/contrib/search_promotions/views/reports.py +56 -0
  158. wagtail/contrib/search_promotions/views/settings.py +258 -0
  159. wagtail/contrib/search_promotions/wagtail_hooks.py +12 -1
  160. wagtail/contrib/settings/locale/ar/LC_MESSAGES/django.mo +0 -0
  161. wagtail/contrib/settings/locale/ar/LC_MESSAGES/django.po +6 -1
  162. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +3 -3
  163. wagtail/contrib/settings/templates/wagtailsettings/edit.html +1 -5
  164. wagtail/contrib/settings/tests/generic/test_admin.py +2 -5
  165. wagtail/contrib/settings/tests/generic/test_register.py +1 -1
  166. wagtail/contrib/settings/tests/site_specific/test_admin.py +2 -5
  167. wagtail/contrib/settings/tests/site_specific/test_register.py +1 -1
  168. wagtail/contrib/settings/views.py +9 -23
  169. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
  170. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +1 -1
  171. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
  172. wagtail/contrib/table_block/tests.py +4 -1
  173. wagtail/contrib/typed_table_block/blocks.py +3 -0
  174. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +10 -10
  175. wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
  176. wagtail/contrib/typed_table_block/tests.py +33 -0
  177. wagtail/documents/locale/en/LC_MESSAGES/django.po +26 -26
  178. wagtail/documents/migrations/0011_add_choose_permissions.py +1 -0
  179. wagtail/documents/models.py +1 -0
  180. wagtail/documents/signal_handlers.py +6 -2
  181. wagtail/documents/static/wagtaildocs/js/add-multiple.js +1 -1
  182. wagtail/documents/templates/wagtaildocs/documents/edit.html +1 -3
  183. wagtail/documents/templates/wagtaildocs/multiple/add.html +7 -1
  184. wagtail/documents/tests/test_admin_views.py +74 -33
  185. wagtail/documents/tests/test_views.py +21 -12
  186. wagtail/documents/views/chooser.py +1 -0
  187. wagtail/documents/views/documents.py +1 -2
  188. wagtail/documents/views/multiple.py +0 -1
  189. wagtail/documents/views/serve.py +9 -2
  190. wagtail/documents/wagtail_hooks.py +6 -1
  191. wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
  192. wagtail/embeds/oembed_providers.py +0 -64
  193. wagtail/fields.py +3 -0
  194. wagtail/images/apps.py +2 -1
  195. wagtail/images/blocks.py +14 -2
  196. wagtail/images/forms.py +40 -3
  197. wagtail/images/locale/ar/LC_MESSAGES/django.mo +0 -0
  198. wagtail/images/locale/ar/LC_MESSAGES/django.po +4 -0
  199. wagtail/images/locale/en/LC_MESSAGES/django.po +49 -49
  200. wagtail/images/migrations/0023_add_choose_permissions.py +1 -0
  201. wagtail/images/rich_text/contentstate.py +1 -0
  202. wagtail/images/rich_text/editor_html.py +1 -0
  203. wagtail/images/signal_handlers.py +17 -10
  204. wagtail/images/static/wagtailimages/js/add-multiple.js +1 -1
  205. wagtail/images/static/wagtailimages/js/image-block.js +1 -1
  206. wagtail/images/static/wagtailimages/js/image-chooser-telepath.js +1 -1
  207. wagtail/images/static/wagtailimages/js/image-chooser.js +1 -1
  208. wagtail/images/static/wagtailimages/js/image-url-generator.js +1 -1
  209. wagtail/images/static/wagtailimages/js/vendor/jquery.fileupload-image.js +1 -1
  210. wagtail/images/tasks.py +18 -0
  211. wagtail/images/templates/wagtailimages/images/edit.html +1 -3
  212. wagtail/images/templates/wagtailimages/images/url_generator.html +1 -1
  213. wagtail/images/templates/wagtailimages/multiple/add.html +7 -2
  214. wagtail/images/templates/wagtailimages/widgets/image_chooser.html +1 -1
  215. wagtail/images/tests/test_admin_views.py +53 -29
  216. wagtail/images/tests/test_blocks.py +34 -2
  217. wagtail/images/tests/test_models.py +12 -10
  218. wagtail/images/tests/tests.py +10 -0
  219. wagtail/images/views/chooser.py +1 -0
  220. wagtail/images/views/images.py +1 -3
  221. wagtail/images/views/multiple.py +0 -1
  222. wagtail/images/views/serve.py +18 -2
  223. wagtail/images/widgets.py +3 -0
  224. wagtail/locale/en/LC_MESSAGES/django.po +228 -216
  225. wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
  226. wagtail/management/commands/publish_scheduled.py +1 -1
  227. wagtail/migrations/0087_alter_grouppagepermission_unique_together_and_more.py +16 -8
  228. wagtail/models/__init__.py +300 -119
  229. wagtail/models/i18n.py +2 -2
  230. wagtail/models/panels.py +37 -0
  231. wagtail/models/sites.py +7 -6
  232. wagtail/permission_policies/pages.py +2 -2
  233. wagtail/project_template/project_name/settings/base.py +4 -0
  234. wagtail/project_template/requirements.txt +1 -1
  235. wagtail/query.py +145 -0
  236. wagtail/search/backends/database/mysql/mysql.py +25 -17
  237. wagtail/search/backends/database/postgres/postgres.py +44 -83
  238. wagtail/search/backends/database/sqlite/sqlite.py +25 -17
  239. wagtail/search/backends/elasticsearch7.py +4 -0
  240. wagtail/search/locale/en/LC_MESSAGES/django.po +1 -1
  241. wagtail/search/query.py +8 -2
  242. wagtail/search/signal_handlers.py +6 -9
  243. wagtail/search/tasks.py +10 -0
  244. wagtail/search/tests/test_elasticsearch7_backend.py +21 -0
  245. wagtail/search/tests/test_index_functions.py +10 -6
  246. wagtail/search/tests/test_postgres_backend.py +0 -14
  247. wagtail/signal_handlers.py +5 -20
  248. wagtail/sites/locale/en/LC_MESSAGES/django.po +1 -1
  249. wagtail/snippets/locale/en/LC_MESSAGES/django.po +3 -13
  250. wagtail/snippets/locale/sv/LC_MESSAGES/django.mo +0 -0
  251. wagtail/snippets/locale/sv/LC_MESSAGES/django.po +4 -3
  252. wagtail/snippets/tests/test_preview.py +5 -0
  253. wagtail/snippets/tests/test_snippets.py +100 -45
  254. wagtail/snippets/tests/test_usage.py +29 -24
  255. wagtail/snippets/tests/test_viewset.py +1 -1
  256. wagtail/snippets/views/snippets.py +0 -12
  257. wagtail/tasks.py +41 -0
  258. wagtail/templates/wagtailcore/shared/block_preview.html +29 -0
  259. wagtail/test/earlypage/__init__.py +0 -0
  260. wagtail/test/earlypage/migrations/0001_initial.py +37 -0
  261. wagtail/test/earlypage/migrations/__init__.py +0 -0
  262. wagtail/test/earlypage/models.py +14 -0
  263. wagtail/test/settings.py +3 -0
  264. wagtail/test/testapp/fixtures/test.json +7 -0
  265. wagtail/test/testapp/fixtures/test_specific.json +6 -3
  266. wagtail/test/testapp/models.py +58 -44
  267. wagtail/test/testapp/templates/tests/custom_block_preview.html +16 -0
  268. wagtail/test/testapp/templates/tests/static_block_preview.html +5 -0
  269. wagtail/test/testapp/wagtail_hooks.py +9 -0
  270. wagtail/tests/test_blocks.py +189 -2
  271. wagtail/tests/test_hooks.py +166 -1
  272. wagtail/tests/test_management_commands.py +54 -13
  273. wagtail/tests/test_page_allowed_http_methods.py +32 -0
  274. wagtail/tests/test_page_model.py +68 -0
  275. wagtail/tests/test_page_privacy.py +10 -0
  276. wagtail/tests/test_page_queryset.py +79 -0
  277. wagtail/tests/test_reference_index.py +84 -75
  278. wagtail/tests/test_streamfield.py +30 -0
  279. wagtail/tests/test_utils.py +61 -0
  280. wagtail/users/forms.py +2 -9
  281. wagtail/users/locale/en/LC_MESSAGES/django.po +17 -17
  282. wagtail/users/locale/nl/LC_MESSAGES/django.mo +0 -0
  283. wagtail/users/locale/nl/LC_MESSAGES/django.po +4 -3
  284. wagtail/users/templates/wagtailusers/groups/create.html +0 -5
  285. wagtail/users/templates/wagtailusers/groups/includes/page_permissions_form.html +1 -1
  286. wagtail/users/templates/wagtailusers/groups/includes/page_permissions_formset.html +6 -6
  287. wagtail/users/tests/test_admin_views.py +96 -4
  288. wagtail/users/tests/test_utils.py +76 -0
  289. wagtail/users/utils.py +43 -11
  290. wagtail/utils/setup.py +2 -2
  291. wagtail/utils/templates.py +26 -0
  292. wagtail/utils/widgets.py +1 -0
  293. wagtail/views.py +9 -1
  294. wagtail/wagtail_hooks.py +67 -29
  295. {wagtail-6.3.1.dist-info → wagtail-6.4rc1.dist-info}/METADATA +2 -2
  296. {wagtail-6.3.1.dist-info → wagtail-6.4rc1.dist-info}/RECORD +300 -287
  297. wagtail/admin/static/wagtailadmin/js/expanding-formset.js +0 -1
  298. wagtail/admin/static/wagtailadmin/js/vendor/rangy-core.js +0 -1
  299. wagtail/admin/static/wagtailadmin/js/vendor/uuidv4.min.js +0 -1
  300. wagtail/contrib/search_promotions/views.py +0 -323
  301. wagtail/images/static/wagtailimages/js/vendor/canvas-to-blob.min.js +0 -1
  302. wagtail/users/static/wagtailusers/js/group-form.js +0 -1
  303. wagtail/users/templates/wagtailusers/groups/includes/group_form_js.html +0 -3
  304. {wagtail-6.3.1.dist-info → wagtail-6.4rc1.dist-info}/LICENSE +0 -0
  305. {wagtail-6.3.1.dist-info → wagtail-6.4rc1.dist-info}/WHEEL +0 -0
  306. {wagtail-6.3.1.dist-info → wagtail-6.4rc1.dist-info}/entry_points.txt +0 -0
  307. {wagtail-6.3.1.dist-info → wagtail-6.4rc1.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,7 @@
5
5
  {{ edit_handler.render_form_content }}
6
6
 
7
7
  <div class="w-form-width">
8
- {% panel id="workflow-pages" icon="doc-empty-inverse" heading=_("Assign your workflow to pages") %}
8
+ {% panel id="workflow-pages" icon="doc-empty-inverse" heading=_("Assign your workflow to pages") attrs=pages_formset.attrs %}
9
9
  {% include "wagtailadmin/workflows/includes/workflow_pages_formset.html" with formset=pages_formset %}
10
10
  {% endpanel %}
11
11
 
@@ -5,7 +5,7 @@
5
5
  {{ edit_handler.render_form_content }}
6
6
 
7
7
  <div class="w-form-width">
8
- {% panel id="workflow-pages" icon="doc-empty-inverse" heading=_("Assign your workflow to pages") %}
8
+ {% panel id="workflow-pages" icon="doc-empty-inverse" heading=_("Assign your workflow to pages") attrs=pages_formset.attrs %}
9
9
  {% if workflow.active %}
10
10
  <p class="help-block help-info">
11
11
  {% icon name='help' %}
@@ -5,5 +5,5 @@
5
5
  </td>
6
6
 
7
7
  <td>
8
- <button class="button button-small no" type="button" id="{{ form.DELETE.id_for_label }}-button">{% trans "Delete" %}</button>
8
+ <button class="button button-small no" type="button" id="{{ form.DELETE.id_for_label }}-button" data-action="w-formset#delete">{% trans "Delete" %}</button>
9
9
  </td>
@@ -17,12 +17,12 @@
17
17
  <thead>
18
18
  <tr>
19
19
  <th>{% trans "Page" %}</th>
20
- <th></th>
20
+ <th aria-label="{% trans 'Action' %}"></th>
21
21
  </tr>
22
22
  </thead>
23
- <tbody id="id_{{ formset.prefix }}-FORMS">
23
+ <tbody id="id_{{ formset.prefix }}-FORMS" data-w-formset-target="forms">
24
24
  {% for form in formset.forms %}
25
- <tr id="inline_child_{{ form.prefix }}"{% if form.DELETE.value %} style="display: none;"{% endif %}>
25
+ <tr id="inline_child_{{ form.prefix }}"{% if form.DELETE.value %} hidden data-w-formset-target="deleted"{% else %} data-w-formset-target="child"{% endif %}>
26
26
  {% if form.non_field_errors %}
27
27
  <p class="error-message">
28
28
  {% for error in form.non_field_errors %}
@@ -36,29 +36,12 @@
36
36
  </tbody>
37
37
  </table>
38
38
 
39
- <template id="id_{{ formset.prefix }}-EMPTY_FORM_TEMPLATE">
40
- <tr id="inline_child_{{ formset.empty_form.prefix }}">
39
+ <template id="id_{{ formset.prefix }}-EMPTY_FORM_TEMPLATE" data-w-formset-target="template">
40
+ <tr id="inline_child_{{ formset.empty_form.prefix }}" data-w-formset-target="child">
41
41
  {% include "wagtailadmin/workflows/includes/workflow_pages_form.html" with form=formset.empty_form only %}
42
42
  </tr>
43
43
  </template>
44
44
 
45
45
  <p class="add">
46
- <button class="button bicolor button--icon" id="id_{{ formset.prefix }}-ADD" value="Add" type="button">{% icon name="plus" wrapped=1 %}{% trans "Assign to another page" %}</button>
46
+ <button class="button bicolor button--icon" id="id_{{ formset.prefix }}-ADD" value="Add" type="button" data-action="w-formset#add">{% icon name="plus" wrapped=1 %}{% trans "Assign to another page" %}</button>
47
47
  </p>
48
-
49
-
50
- <script>
51
- $(function() {
52
- buildExpandingFormset('id_{{ formset.prefix|escapejs }}', {
53
- onInit: function(index) {
54
- var deleteInputId = 'id_{{ formset.prefix|escapejs }}-' + index + '-DELETE';
55
- var childId = 'inline_child_{{ formset.prefix|escapejs }}-' + index;
56
- $('#' + deleteInputId + '-button').on('click', function() {
57
- /* set 'deleted' form field to true */
58
- $('#' + deleteInputId).val('1');
59
- $('#' + childId).fadeOut();
60
- });
61
- }
62
- });
63
- });
64
- </script>
@@ -654,8 +654,19 @@ def avatar_url(user, size=50, gravatar_only=False):
654
654
  """
655
655
  A template tag that receives a user and size and return
656
656
  the appropriate avatar url for that user.
657
+
658
+ If the 'get_avatar_url' hook is defined, then that will intercept this
659
+ logic and point to whatever resource that function returns. In this way,
660
+ users can swap out the Wagtail UserProfile avatar for some other image or
661
+ field of their own choosing without needing to alter anything on the
662
+ existing models.
663
+
657
664
  Example usage: {% avatar_url request.user 50 %}
665
+
658
666
  """
667
+ for hook_fn in hooks.get_hooks("get_avatar_url"):
668
+ if url := hook_fn(user, size):
669
+ return url
659
670
 
660
671
  if (
661
672
  not gravatar_only
@@ -972,6 +983,7 @@ def wagtail_config(context):
972
983
  "ADMIN_URLS": {
973
984
  "DISMISSIBLES": reverse("wagtailadmin_dismissibles"),
974
985
  "PAGES": reverse("wagtailadmin_explore_root"),
986
+ "BLOCK_PREVIEW": reverse("wagtailadmin_block_preview"),
975
987
  },
976
988
  "I18N_ENABLED": i18n_enabled(),
977
989
  "LOCALES": locales(serialize=False),
@@ -2,13 +2,13 @@ from django import template
2
2
  from django.template.loader import render_to_string
3
3
  from django.utils import translation
4
4
 
5
- from wagtail import hooks
6
5
  from wagtail.admin.userbar import (
7
6
  AccessibilityItem,
8
7
  AddPageItem,
9
8
  AdminItem,
10
9
  EditPageItem,
11
10
  ExplorePageItem,
11
+ apply_userbar_hooks,
12
12
  )
13
13
  from wagtail.models import PAGE_TEMPLATE_VAR, Page, Revision
14
14
  from wagtail.users.models import UserProfile
@@ -89,8 +89,7 @@ def wagtailuserbar(context, position="bottom-right"):
89
89
  AccessibilityItem(),
90
90
  ]
91
91
 
92
- for fn in hooks.get_hooks("construct_wagtail_userbar"):
93
- fn(request, items)
92
+ apply_userbar_hooks(request, items, page)
94
93
 
95
94
  # Render the items
96
95
  rendered_items = [item.render(request) for item in items]
@@ -9,7 +9,13 @@ from django.urls import reverse
9
9
  from django.utils import timezone
10
10
  from django.utils.translation import gettext_lazy as _
11
11
 
12
- from wagtail.models import GroupPagePermission, Locale, Page, Revision
12
+ from wagtail.models import (
13
+ GroupPagePermission,
14
+ Locale,
15
+ Page,
16
+ PageViewRestriction,
17
+ Revision,
18
+ )
13
19
  from wagtail.signals import page_published
14
20
  from wagtail.test.testapp.models import (
15
21
  BusinessChild,
@@ -421,6 +427,26 @@ class TestPageCreation(WagtailTestUtils, TestCase):
421
427
  )
422
428
  self.assertRedirects(response, "/admin/")
423
429
 
430
+ def test_create_page_defined_before_admin_load(self):
431
+ """
432
+ Test that a page model defined before wagtail.admin is loaded has all fields present
433
+ """
434
+ response = self.client.get(
435
+ reverse(
436
+ "wagtailadmin_pages:add",
437
+ args=("earlypage", "earlypage", self.root_page.id),
438
+ )
439
+ )
440
+ self.assertEqual(response.status_code, 200)
441
+ self.assertTemplateUsed(response, "wagtailadmin/pages/create.html")
442
+ # Title field should be present and have TitleFieldPanel behaviour
443
+ # including syncing with slug
444
+ self.assertContains(response, 'data-w-sync-target-value="#id_slug"')
445
+ # SEO title should be present in promote tab
446
+ self.assertContains(
447
+ response, "The name of the page displayed on search engine results"
448
+ )
449
+
424
450
  def test_create_simplepage_post(self):
425
451
  post_data = {
426
452
  "title": "New page!",
@@ -1975,3 +2001,86 @@ class TestCommenting(WagtailTestUtils, TestCase):
1975
2001
  self.assertEqual("page-edit-form", form["id"])
1976
2002
  self.assertIn("w-init", form["data-controller"])
1977
2003
  self.assertEqual("", form["data-w-init-event-value"])
2004
+
2005
+
2006
+ class TestCreateViewChildPagePrivacy(WagtailTestUtils, TestCase):
2007
+ def setUp(self):
2008
+ self.login()
2009
+
2010
+ self.homepage = Page.objects.get(id=2)
2011
+
2012
+ self.private_parent_page = self.homepage.add_child(
2013
+ instance=SimplePage(
2014
+ title="Private Parent page",
2015
+ content="hello",
2016
+ live=True,
2017
+ )
2018
+ )
2019
+
2020
+ PageViewRestriction.objects.create(
2021
+ page=self.private_parent_page,
2022
+ restriction_type="password",
2023
+ password="password123",
2024
+ )
2025
+
2026
+ self.private_child_page = self.private_parent_page.add_child(
2027
+ instance=SimplePage(
2028
+ title="child page",
2029
+ content="hello",
2030
+ live=True,
2031
+ )
2032
+ )
2033
+
2034
+ self.public_parent_page = self.homepage.add_child(
2035
+ instance=SimplePage(
2036
+ title="Public Parent page",
2037
+ content="hello",
2038
+ live=True,
2039
+ )
2040
+ )
2041
+
2042
+ self.public_child_page = self.public_parent_page.add_child(
2043
+ instance=SimplePage(
2044
+ title="public page",
2045
+ content="hello",
2046
+ live=True,
2047
+ )
2048
+ )
2049
+
2050
+ def test_sidebar_private(self):
2051
+ response = self.client.get(
2052
+ reverse(
2053
+ "wagtailadmin_pages:add",
2054
+ args=("tests", "simplepage", self.private_child_page.id),
2055
+ )
2056
+ )
2057
+
2058
+ self.assertEqual(response.status_code, 200)
2059
+
2060
+ soup = self.get_soup(response.content)
2061
+
2062
+ public_div = soup.select_one('[data-w-zone-switch-key-value="isPublic"]')
2063
+ private_div = soup.select_one('[data-w-zone-switch-key-value="!isPublic"]')
2064
+
2065
+ self.assertEqual(private_div["class"], ["!w-my-0"])
2066
+
2067
+ self.assertEqual(public_div["class"], ["w-hidden"])
2068
+
2069
+ def test_sidebar_public(self):
2070
+ response = self.client.get(
2071
+ reverse(
2072
+ "wagtailadmin_pages:add",
2073
+ args=("tests", "simplepage", self.public_child_page.id),
2074
+ )
2075
+ )
2076
+
2077
+ self.assertEqual(response.status_code, 200)
2078
+
2079
+ soup = self.get_soup(response.content)
2080
+
2081
+ public_div = soup.select_one('[data-w-zone-switch-key-value="isPublic"]')
2082
+ private_div = soup.select_one('[data-w-zone-switch-key-value="!isPublic"]')
2083
+
2084
+ self.assertEqual(public_div["class"], [])
2085
+
2086
+ self.assertEqual(private_div["class"], ["!w-my-0", "w-hidden"])
@@ -167,7 +167,7 @@ class TestPageEdit(WagtailTestUtils, TestCase):
167
167
  response,
168
168
  '<label class="w-field__label" for="id_speakers-__prefix__-last_name" id="id_speakers-__prefix__-last_name-label">',
169
169
  )
170
- self.assertContains(response, "Add speakers")
170
+ self.assertContains(response, "Add speaker")
171
171
  self.assertContains(response, "Put the keynote speaker first")
172
172
 
173
173
  # Test MultiFieldPanel help text
@@ -289,7 +289,8 @@ class TestPageEdit(WagtailTestUtils, TestCase):
289
289
  self.assertEqual(len(actions), 0)
290
290
 
291
291
  def test_usage_count_information_shown(self):
292
- PageChooserModel.objects.create(page=self.event_page)
292
+ with self.captureOnCommitCallbacks(execute=True):
293
+ PageChooserModel.objects.create(page=self.event_page)
293
294
 
294
295
  # Tests that the edit page loads
295
296
  response = self.client.get(
@@ -653,6 +653,24 @@ class TestPageExplorer(WagtailTestUtils, TestCase):
653
653
  self.assertIn("Simple page", page_type_labels)
654
654
  self.assertNotIn("Page", page_type_labels)
655
655
 
656
+ @override_settings(WAGTAIL_I18N_ENABLED=True)
657
+ def test_filter_by_locale_and_search(self):
658
+ fr_locale = Locale.objects.create(language_code="fr")
659
+ self.root_page.copy_for_translation(fr_locale, copy_parents=True)
660
+
661
+ response = self.client.get(
662
+ reverse("wagtailadmin_explore", args=(self.root_page.id,)),
663
+ {"locale": "en", "q": "hello"},
664
+ )
665
+ self.assertEqual(response.status_code, 200)
666
+ page_ids = {page.id for page in response.context["pages"]}
667
+ self.assertIn(self.child_page.id, page_ids)
668
+ self.assertContainsActiveFilter(
669
+ response,
670
+ "Locale: English",
671
+ "locale=en",
672
+ )
673
+
656
674
  def test_filter_by_date_updated(self):
657
675
  new_page_child = SimplePage(
658
676
  title="New page child",
@@ -19,13 +19,14 @@ class TestPageUsage(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
19
19
  self.user = self.login()
20
20
  self.root_page = Page.objects.get(id=2)
21
21
 
22
- page = SimplePage(
23
- title="Hello world!",
24
- slug="hello-world",
25
- content="hello",
26
- )
27
- self.root_page.add_child(instance=page)
28
- page.save_revision().publish()
22
+ with self.captureOnCommitCallbacks(execute=True):
23
+ page = SimplePage(
24
+ title="Hello world!",
25
+ slug="hello-world",
26
+ content="hello",
27
+ )
28
+ self.root_page.add_child(instance=page)
29
+ page.save_revision().publish()
29
30
  self.page = SimplePage.objects.get(id=page.id)
30
31
 
31
32
  def test_simple(self):
@@ -69,7 +70,8 @@ class TestPageUsage(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
69
70
  self.assertIn("button", classes)
70
71
 
71
72
  def test_has_private_usage(self):
72
- PageChooserModel.objects.create(page=self.page)
73
+ with self.captureOnCommitCallbacks(execute=True):
74
+ PageChooserModel.objects.create(page=self.page)
73
75
  usage_url = reverse("wagtailadmin_pages:usage", args=(self.page.id,))
74
76
  response = self.client.get(usage_url)
75
77
 
@@ -82,16 +84,17 @@ class TestPageUsage(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
82
84
  self.assertContains(response, "<td>Page chooser model</td>", html=True)
83
85
 
84
86
  def test_has_editable_usage(self):
85
- form_page = FormPageWithRedirect(
86
- title="Contact us",
87
- slug="contact-us",
88
- to_address="to@email.com",
89
- from_address="from@email.com",
90
- subject="The subject",
91
- thank_you_redirect_page=self.page,
92
- )
93
-
94
- form_page = self.root_page.add_child(instance=form_page)
87
+ with self.captureOnCommitCallbacks(execute=True):
88
+ form_page = FormPageWithRedirect(
89
+ title="Contact us",
90
+ slug="contact-us",
91
+ to_address="to@email.com",
92
+ from_address="from@email.com",
93
+ subject="The subject",
94
+ thank_you_redirect_page=self.page,
95
+ )
96
+
97
+ form_page = self.root_page.add_child(instance=form_page)
95
98
 
96
99
  usage_url = reverse("wagtailadmin_pages:usage", args=(self.page.id,))
97
100
  response = self.client.get(usage_url)
@@ -111,8 +114,9 @@ class TestPageUsage(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
111
114
  self.assertContains(response, "<td>Form page with redirect</td>", html=True)
112
115
 
113
116
  def test_pagination(self):
114
- for _ in range(50):
115
- PageChooserModel.objects.create(page=self.page)
117
+ with self.captureOnCommitCallbacks(execute=True):
118
+ for _ in range(50):
119
+ PageChooserModel.objects.create(page=self.page)
116
120
 
117
121
  usage_url = reverse("wagtailadmin_pages:usage", args=(self.page.id,))
118
122
  response = self.client.get(f"{usage_url}?p=2")
@@ -6,8 +6,9 @@ from django.urls import reverse
6
6
  from django.utils import timezone
7
7
  from freezegun import freeze_time
8
8
 
9
+ from wagtail.admin.staticfiles import versioned_static
9
10
  from wagtail.admin.views.pages.preview import PreviewOnEdit
10
- from wagtail.models import Page
11
+ from wagtail.models import Page, Site
11
12
  from wagtail.test.testapp.models import (
12
13
  CustomPreviewSizesPage,
13
14
  EventCategory,
@@ -159,6 +160,7 @@ class TestPreview(WagtailTestUtils, TestCase):
159
160
  '<h1 class="preview-error__title">Preview not available</h1>',
160
161
  html=True,
161
162
  )
163
+ self.assertNotContains(response, versioned_static("wagtailadmin/js/icons.js"))
162
164
 
163
165
  def test_preview_on_create_with_invalid_data(self):
164
166
  preview_url = reverse(
@@ -198,6 +200,7 @@ class TestPreview(WagtailTestUtils, TestCase):
198
200
  '<h1 class="preview-error__title">Preview not available</h1>',
199
201
  html=True,
200
202
  )
203
+ self.assertNotContains(response, versioned_static("wagtailadmin/js/icons.js"))
201
204
 
202
205
  def test_preview_on_create_with_m2m_field(self):
203
206
  preview_url = reverse(
@@ -228,6 +231,39 @@ class TestPreview(WagtailTestUtils, TestCase):
228
231
  self.assertContains(response, "<li>Parties</li>")
229
232
  self.assertContains(response, "<li>Holidays</li>")
230
233
 
234
+ def test_preview_on_create_with_incorrect_site_hostname(self):
235
+ # Failing to set a valid hostname in the Site record (as determined by ALLOWED_HOSTS)
236
+ # should not prevent the preview from being generated.
237
+ Site.objects.filter(is_default_site=True).update(hostname="bad.example.com")
238
+
239
+ preview_url = reverse(
240
+ "wagtailadmin_pages:preview_on_add",
241
+ args=("tests", "eventpage", self.home_page.id),
242
+ )
243
+ response = self.client.post(preview_url, self.post_data)
244
+
245
+ # Check the JSON response
246
+ self.assertEqual(response.status_code, 200)
247
+ self.assertJSONEqual(
248
+ response.content.decode(),
249
+ {"is_valid": True, "is_available": True},
250
+ )
251
+
252
+ # Check the user can refresh the preview
253
+ preview_session_key = "wagtail-preview-tests-eventpage-{}".format(
254
+ self.home_page.id
255
+ )
256
+ self.assertIn(preview_session_key, self.client.session)
257
+
258
+ response = self.client.get(preview_url)
259
+
260
+ # Check the HTML response
261
+ self.assertEqual(response.status_code, 200)
262
+ self.assertTemplateUsed(response, "tests/event_page.html")
263
+ self.assertContains(response, "Beach party")
264
+ self.assertContains(response, "<li>Parties</li>")
265
+ self.assertContains(response, "<li>Holidays</li>")
266
+
231
267
  def test_preview_on_edit_with_m2m_field(self):
232
268
  preview_url = reverse(
233
269
  "wagtailadmin_pages:preview_on_edit", args=(self.event_page.id,)
@@ -254,6 +290,36 @@ class TestPreview(WagtailTestUtils, TestCase):
254
290
  self.assertContains(response, "<li>Parties</li>")
255
291
  self.assertContains(response, "<li>Holidays</li>")
256
292
 
293
+ def test_preview_on_edit_with_incorrect_site_hostname(self):
294
+ # Failing to set a valid hostname in the Site record (as determined by ALLOWED_HOSTS)
295
+ # should not prevent the preview from being generated.
296
+ Site.objects.filter(is_default_site=True).update(hostname="bad.example.com")
297
+
298
+ preview_url = reverse(
299
+ "wagtailadmin_pages:preview_on_edit", args=(self.event_page.id,)
300
+ )
301
+ response = self.client.post(preview_url, self.post_data)
302
+
303
+ # Check the JSON response
304
+ self.assertEqual(response.status_code, 200)
305
+ self.assertJSONEqual(
306
+ response.content.decode(),
307
+ {"is_valid": True, "is_available": True},
308
+ )
309
+
310
+ # Check the user can refresh the preview
311
+ preview_session_key = f"wagtail-preview-{self.event_page.id}"
312
+ self.assertIn(preview_session_key, self.client.session)
313
+
314
+ response = self.client.get(preview_url)
315
+
316
+ # Check the HTML response
317
+ self.assertEqual(response.status_code, 200)
318
+ self.assertTemplateUsed(response, "tests/event_page.html")
319
+ self.assertContains(response, "Beach party")
320
+ self.assertContains(response, "<li>Parties</li>")
321
+ self.assertContains(response, "<li>Holidays</li>")
322
+
257
323
  def test_preview_on_edit_with_valid_then_invalid_data(self):
258
324
  preview_url = reverse(
259
325
  "wagtailadmin_pages:preview_on_edit", args=(self.event_page.id,)
@@ -355,6 +421,7 @@ class TestPreview(WagtailTestUtils, TestCase):
355
421
  '<h1 class="preview-error__title">Preview not available</h1>',
356
422
  html=True,
357
423
  )
424
+ self.assertNotContains(response, versioned_static("wagtailadmin/js/icons.js"))
358
425
 
359
426
  def test_preview_on_edit_clear_preview_data(self):
360
427
  preview_session_key = f"wagtail-preview-{self.event_page.id}"
@@ -390,6 +457,7 @@ class TestPreview(WagtailTestUtils, TestCase):
390
457
  '<h1 class="preview-error__title">Preview not available</h1>',
391
458
  html=True,
392
459
  )
460
+ self.assertNotContains(response, versioned_static("wagtailadmin/js/icons.js"))
393
461
 
394
462
  def test_preview_modes(self):
395
463
  preview_url = reverse(
@@ -14,6 +14,7 @@ from wagtail.test.testapp.models import (
14
14
  SecretPage,
15
15
  )
16
16
  from wagtail.test.utils import WagtailTestUtils
17
+ from wagtail.test.utils.template_tests import AdminTemplateTestUtils
17
18
  from wagtail.test.utils.timestamps import local_datetime
18
19
 
19
20
 
@@ -119,12 +120,17 @@ class TestRevisions(WagtailTestUtils, TestCase):
119
120
  # Form should show the content of the revision, not the current draft
120
121
  self.assertContains(response, "Last Christmas I gave you my heart")
121
122
 
122
- # Form should include a hidden 'revision' field
123
- revision_field = (
124
- """<input type="hidden" name="revision" value="%d" />"""
125
- % self.last_christmas_revision.id
123
+ # Form should use the revisions revert URL as the action
124
+ soup = self.get_soup(response.content)
125
+ form = soup.select_one("form[data-edit-form]")
126
+ self.assertIsNotNone(form)
127
+ self.assertEqual(
128
+ form.get("action"),
129
+ reverse(
130
+ "wagtailadmin_pages:revisions_revert",
131
+ args=(self.christmas_event.id, self.last_christmas_revision.id),
132
+ ),
126
133
  )
127
- self.assertContains(response, revision_field)
128
134
 
129
135
  # Buttons should be relabelled
130
136
  self.assertContains(response, "Replace current draft")
@@ -199,9 +205,10 @@ class TestStreamRevisions(WagtailTestUtils, TestCase):
199
205
  )
200
206
 
201
207
 
202
- class TestCompareRevisions(WagtailTestUtils, TestCase):
208
+ class TestCompareRevisions(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
203
209
  # Actual tests for the comparison classes can be found in test_compare.py
204
210
 
211
+ base_breadcrumb_items = []
205
212
  fixtures = ["test.json"]
206
213
 
207
214
  def setUp(self):
@@ -246,6 +253,33 @@ class TestCompareRevisions(WagtailTestUtils, TestCase):
246
253
  html=True,
247
254
  )
248
255
 
256
+ history_url = reverse(
257
+ "wagtailadmin_pages:history", args=(self.christmas_event.id,)
258
+ )
259
+
260
+ self.assertBreadcrumbsItemsRendered(
261
+ [
262
+ {
263
+ "url": reverse("wagtailadmin_explore_root")
264
+ if page.is_root()
265
+ else reverse("wagtailadmin_explore", args=(page.pk,)),
266
+ "label": page.get_admin_display_title(),
267
+ }
268
+ for page in self.christmas_event.get_ancestors(inclusive=True)
269
+ ]
270
+ + [
271
+ {"url": history_url, "label": "History"},
272
+ {"url": "", "label": "Compare", "sublabel": "This Christmas"},
273
+ ],
274
+ response.content,
275
+ )
276
+
277
+ soup = self.get_soup(response.content)
278
+ edit_url = reverse("wagtailadmin_pages:edit", args=(self.christmas_event.id,))
279
+ edit_button = soup.select_one(f"a.w-header-button[href='{edit_url}']")
280
+ self.assertIsNotNone(edit_button)
281
+ self.assertEqual(edit_button.text.strip(), "Edit")
282
+
249
283
  def test_compare_revisions_earliest(self):
250
284
  compare_url = reverse(
251
285
  "wagtailadmin_pages:revisions_compare",
@@ -19,6 +19,7 @@ from wagtail.admin.localization import (
19
19
  from wagtail.admin.views.account import AccountView, profile_tab
20
20
  from wagtail.images.tests.utils import get_test_image_file
21
21
  from wagtail.test.utils import WagtailTestUtils
22
+ from wagtail.test.utils.template_tests import AdminTemplateTestUtils
22
23
  from wagtail.users.models import UserProfile
23
24
 
24
25
 
@@ -238,7 +239,9 @@ class TestAccountSectionUtilsMixin:
238
239
  return self.client.post(reverse("wagtailadmin_account"), post_data)
239
240
 
240
241
 
241
- class TestAccountSection(WagtailTestUtils, TestCase, TestAccountSectionUtilsMixin):
242
+ class TestAccountSection(
243
+ AdminTemplateTestUtils, TestAccountSectionUtilsMixin, WagtailTestUtils, TestCase
244
+ ):
242
245
  """
243
246
  This tests that the accounts section is working
244
247
  """
@@ -282,6 +285,14 @@ class TestAccountSection(WagtailTestUtils, TestCase, TestAccountSectionUtilsMixi
282
285
  # Check if the default title exists
283
286
  self.assertContains(response, "Name and Email")
284
287
 
288
+ soup = self.get_soup(response.content)
289
+ self.assertBreadcrumbsItemsRendered(
290
+ [{"url": "", "label": "Account"}], response.content
291
+ )
292
+ heading = soup.select_one("main h2")
293
+ self.assertIsNotNone(heading)
294
+ self.assertEqual(heading.text.strip(), "Account")
295
+
285
296
  def test_change_name_post(self):
286
297
  response = self.post_form(
287
298
  {
@@ -521,6 +532,17 @@ class TestAccountSection(WagtailTestUtils, TestCase, TestAccountSectionUtilsMixi
521
532
  get_available_admin_languages(), WAGTAILADMIN_PROVIDED_LANGUAGES
522
533
  )
523
534
 
535
+ @override_settings(LANGUAGE_CODE="id")
536
+ def test_default_language_follows_server_setting(self):
537
+ response = self.client.get(reverse("wagtailadmin_account"))
538
+ self.assertEqual(response.status_code, 200)
539
+ soup = self.get_soup(response.content)
540
+ option = soup.select_one(
541
+ 'select[name="locale-preferred_language"] option[value=""]'
542
+ )
543
+ self.assertIsNotNone(option)
544
+ self.assertEqual(option.text.strip(), "Use server language: Bahasa Indonesia")
545
+
524
546
  @override_settings(WAGTAILADMIN_PERMITTED_LANGUAGES=[("en", "English")])
525
547
  def test_not_show_options_if_only_one_language_is_permitted(self):
526
548
  response = self.client.get(reverse("wagtailadmin_account"))
@@ -577,6 +599,22 @@ class TestAccountSection(WagtailTestUtils, TestCase, TestAccountSectionUtilsMixi
577
599
  sorted(zoneinfo.available_timezones()),
578
600
  )
579
601
 
602
+ response = self.client.get(reverse("wagtailadmin_account"))
603
+ self.assertEqual(response.status_code, 200)
604
+ soup = self.get_soup(response.content)
605
+
606
+ select = soup.select_one('select[name="locale-current_time_zone"]')
607
+ self.assertIsNotNone(select)
608
+ self.assertEqual(select.get("data-controller"), "w-init w-locale")
609
+ self.assertEqual(
610
+ select.get("data-action"),
611
+ "w-init:ready->w-locale#localizeTimeZoneOptions",
612
+ )
613
+ self.assertEqual(
614
+ select.get("data-w-locale-server-time-zone-param"),
615
+ settings.TIME_ZONE,
616
+ )
617
+
580
618
  @unittest.skipUnless(settings.USE_TZ, "Timezone support is disabled")
581
619
  @override_settings(WAGTAIL_USER_TIME_ZONES=["Europe/London"])
582
620
  def test_not_show_options_if_only_one_time_zone_is_permitted(self):
@@ -374,12 +374,14 @@ class TestAuditLogAdmin(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
374
374
 
375
375
  self.login(user=self.administrator)
376
376
  response = self.client.post(
377
- reverse("wagtailadmin_pages:edit", args=(self.hello_page.id,)),
377
+ reverse(
378
+ "wagtailadmin_pages:revisions_revert",
379
+ args=(self.hello_page.id, revision.id),
380
+ ),
378
381
  {
379
382
  "title": "Hello World!",
380
383
  "content": "another hello",
381
384
  "slug": "hello-world",
382
- "revision": revision.id,
383
385
  "action-publish": "action-publish",
384
386
  },
385
387
  follow=True,