wagtail 6.2.2__py3-none-any.whl → 6.3rc2__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 (386) hide show
  1. wagtail/__init__.py +1 -1
  2. wagtail/actions/copy_for_translation.py +6 -0
  3. wagtail/actions/publish_revision.py +3 -3
  4. wagtail/admin/action_menu.py +5 -3
  5. wagtail/admin/forms/account.py +1 -1
  6. wagtail/admin/icons.py +2 -6
  7. wagtail/admin/locale/cy/LC_MESSAGES/django.mo +0 -0
  8. wagtail/admin/locale/cy/LC_MESSAGES/django.po +32 -0
  9. wagtail/admin/locale/dv/LC_MESSAGES/django.mo +0 -0
  10. wagtail/admin/locale/dv/LC_MESSAGES/django.po +28 -0
  11. wagtail/admin/locale/en/LC_MESSAGES/django.po +451 -485
  12. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +7 -7
  13. wagtail/admin/locale/sl/LC_MESSAGES/django.mo +0 -0
  14. wagtail/admin/locale/sl/LC_MESSAGES/django.po +150 -0
  15. wagtail/admin/locale/sl/LC_MESSAGES/djangojs.mo +0 -0
  16. wagtail/admin/locale/sl/LC_MESSAGES/djangojs.po +9 -2
  17. wagtail/admin/locale/ug/LC_MESSAGES/django.mo +0 -0
  18. wagtail/admin/locale/ug/LC_MESSAGES/django.po +3250 -196
  19. wagtail/admin/localization.py +12 -2
  20. wagtail/admin/panels/model_utils.py +1 -1
  21. wagtail/admin/site_summary.py +0 -2
  22. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  23. wagtail/admin/static/wagtailadmin/css/panels/draftail.css +1 -1
  24. wagtail/admin/static/wagtailadmin/images/email-header.jpg +0 -0
  25. wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
  26. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  27. wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +12 -0
  28. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  29. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  30. wagtail/admin/static/wagtailadmin/js/telepath/telepath.js +1 -1
  31. wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
  32. wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
  33. wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +1 -1
  34. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  35. wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
  36. wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
  37. wagtail/admin/staticfiles.py +6 -4
  38. wagtail/admin/templates/wagtailadmin/account/account.html +42 -59
  39. wagtail/admin/templates/wagtailadmin/admin_base.html +0 -28
  40. wagtail/admin/templates/wagtailadmin/bulk_actions/footer.html +1 -1
  41. wagtail/admin/templates/wagtailadmin/chooser/_search_results.html +7 -5
  42. wagtail/admin/templates/wagtailadmin/chooser/tables/page_navigate_to_children_cell.html +1 -1
  43. wagtail/admin/templates/wagtailadmin/generic/chooser/results.html +7 -5
  44. wagtail/admin/templates/wagtailadmin/generic/edit.html +0 -8
  45. wagtail/admin/templates/wagtailadmin/generic/form.html +60 -17
  46. wagtail/admin/templates/wagtailadmin/generic/index.html +17 -0
  47. wagtail/admin/templates/wagtailadmin/generic/index_results.html +9 -35
  48. wagtail/admin/templates/wagtailadmin/generic/inspect.html +2 -21
  49. wagtail/admin/templates/wagtailadmin/generic/listing.html +11 -17
  50. wagtail/admin/templates/wagtailadmin/generic/listing_results.html +19 -1
  51. wagtail/admin/templates/wagtailadmin/home/account_summary.html +26 -0
  52. wagtail/admin/templates/wagtailadmin/home/locked_pages.html +28 -18
  53. wagtail/admin/templates/wagtailadmin/home/recent_edits.html +28 -17
  54. wagtail/admin/templates/wagtailadmin/home/site_summary_pages.html +2 -2
  55. wagtail/admin/templates/wagtailadmin/home/upgrade_notification.html +35 -13
  56. wagtail/admin/templates/wagtailadmin/home/user_objects_in_workflow_moderation.html +28 -18
  57. wagtail/admin/templates/wagtailadmin/home/workflow_objects_to_moderate.html +43 -32
  58. wagtail/admin/templates/wagtailadmin/home.html +22 -5
  59. wagtail/admin/templates/wagtailadmin/pages/_editor_js.html +0 -1
  60. wagtail/admin/templates/wagtailadmin/pages/action_menu/menu.html +1 -11
  61. wagtail/admin/templates/wagtailadmin/pages/action_menu/menu_item.html +1 -6
  62. wagtail/admin/templates/wagtailadmin/pages/action_menu/page_locked.html +1 -1
  63. wagtail/admin/templates/wagtailadmin/pages/action_menu/publish.html +1 -1
  64. wagtail/admin/templates/wagtailadmin/pages/action_menu/save_draft.html +1 -1
  65. wagtail/admin/templates/wagtailadmin/pages/bulk_actions/confirm_bulk_delete.html +12 -6
  66. wagtail/admin/templates/wagtailadmin/pages/bulk_actions/confirm_bulk_move.html +12 -7
  67. wagtail/admin/templates/wagtailadmin/pages/bulk_actions/confirm_bulk_publish.html +17 -11
  68. wagtail/admin/templates/wagtailadmin/pages/bulk_actions/confirm_bulk_unpublish.html +15 -9
  69. wagtail/admin/templates/wagtailadmin/pages/confirm_delete.html +9 -9
  70. wagtail/admin/templates/wagtailadmin/pages/confirm_move.html +2 -2
  71. wagtail/admin/templates/wagtailadmin/pages/confirm_unpublish.html +4 -4
  72. wagtail/admin/templates/wagtailadmin/pages/create.html +15 -34
  73. wagtail/admin/templates/wagtailadmin/pages/edit.html +15 -30
  74. wagtail/admin/templates/wagtailadmin/pages/explorable_index.html +6 -0
  75. wagtail/admin/templates/wagtailadmin/pages/explorable_index_results.html +60 -0
  76. wagtail/admin/templates/wagtailadmin/pages/index.html +1 -36
  77. wagtail/admin/templates/wagtailadmin/pages/index_results.html +2 -50
  78. wagtail/admin/templates/wagtailadmin/pages/listing/_locked_indicator.html +1 -1
  79. wagtail/admin/templates/wagtailadmin/pages/listing/_ordering_cell.html +1 -1
  80. wagtail/admin/templates/wagtailadmin/pages/listing/_page_header_buttons.html +1 -1
  81. wagtail/admin/templates/wagtailadmin/pages/listing/_page_title_column_header.html +3 -3
  82. wagtail/admin/templates/wagtailadmin/pages/listing/_pagination.html +1 -1
  83. wagtail/admin/templates/wagtailadmin/pages/listing.html +24 -0
  84. wagtail/admin/templates/wagtailadmin/pages/search.html +1 -20
  85. wagtail/admin/templates/wagtailadmin/pages/search_results.html +27 -25
  86. wagtail/admin/templates/wagtailadmin/permissions/includes/collection_member_permissions_formset.html +0 -1
  87. wagtail/admin/templates/wagtailadmin/reports/listing/_list_page_report.html +2 -2
  88. wagtail/admin/templates/wagtailadmin/reports/listing/_list_page_types_usage.html +6 -6
  89. wagtail/admin/templates/wagtailadmin/reports/workflow_tasks_results.html +1 -1
  90. wagtail/admin/templates/wagtailadmin/shared/action_menu/menu.html +14 -0
  91. wagtail/admin/templates/wagtailadmin/shared/action_menu/menu_item.html +6 -0
  92. wagtail/admin/templates/wagtailadmin/shared/avatar.html +13 -3
  93. wagtail/admin/templates/wagtailadmin/shared/header.html +0 -5
  94. wagtail/admin/templates/wagtailadmin/shared/headers/slim_header.html +1 -1
  95. wagtail/admin/templates/wagtailadmin/shared/page_status_tag_new.html +4 -1
  96. wagtail/admin/templates/wagtailadmin/shared/pagination_nav.html +1 -1
  97. wagtail/admin/templates/wagtailadmin/shared/side_panel_toggle.html +1 -1
  98. wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/locale.html +1 -1
  99. wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/usage.html +2 -2
  100. wagtail/admin/templates/wagtailadmin/shared/side_panels/preview.html +94 -52
  101. wagtail/admin/templates/wagtailadmin/{pages/_unsaved_changes_warning.html → shared/unsaved_changes_warning.html} +4 -4
  102. wagtail/admin/templates/wagtailadmin/shared/usage_summary.html +2 -2
  103. wagtail/admin/templates/wagtailadmin/shared/workflow_history/detail.html +1 -7
  104. wagtail/admin/templates/wagtailadmin/shared/workflow_history/listing.html +1 -0
  105. wagtail/admin/templates/wagtailadmin/shared/workflow_history/{list.html → listing_results.html} +33 -35
  106. wagtail/admin/templates/wagtailadmin/tables/references_cell.html +1 -1
  107. wagtail/admin/templates/wagtailadmin/workflows/create.html +11 -36
  108. wagtail/admin/templates/wagtailadmin/workflows/create_task.html +0 -38
  109. wagtail/admin/templates/wagtailadmin/workflows/edit.html +44 -74
  110. wagtail/admin/templates/wagtailadmin/workflows/edit_task.html +27 -66
  111. wagtail/admin/templates/wagtailadmin/workflows/includes/task_usage_cell.html +4 -2
  112. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_tasks_cell.html +4 -4
  113. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_used_by_cell.html +15 -11
  114. wagtail/admin/templates/wagtailadmin/workflows/task_chooser/includes/results.html +7 -5
  115. wagtail/admin/templatetags/wagtailadmin_tags.py +51 -22
  116. wagtail/admin/tests/pages/test_content_type_use_view.py +82 -2
  117. wagtail/admin/tests/pages/test_edit_page.py +70 -0
  118. wagtail/admin/tests/pages/test_explorer_view.py +65 -4
  119. wagtail/admin/tests/pages/test_page_search.py +8 -7
  120. wagtail/admin/tests/pages/test_page_usage.py +3 -1
  121. wagtail/admin/tests/pages/test_preview.py +208 -63
  122. wagtail/admin/tests/pages/test_reorder_page.py +91 -1
  123. wagtail/admin/tests/pages/test_view_draft.py +32 -1
  124. wagtail/admin/tests/pages/test_workflow_history.py +288 -7
  125. wagtail/admin/tests/test_account_management.py +23 -3
  126. wagtail/admin/tests/test_audit_log.py +24 -2
  127. wagtail/admin/tests/test_collections_views.py +17 -5
  128. wagtail/admin/tests/test_dashboard.py +1 -1
  129. wagtail/admin/tests/test_edit_handlers.py +3 -2
  130. wagtail/admin/tests/test_icon_sprite.py +4 -0
  131. wagtail/admin/tests/test_privacy.py +5 -19
  132. wagtail/admin/tests/test_reports_views.py +1 -1
  133. wagtail/admin/tests/test_site_summary.py +3 -3
  134. wagtail/admin/tests/test_templatetags.py +27 -3
  135. wagtail/admin/tests/test_upgrade_notification.py +71 -18
  136. wagtail/admin/tests/test_views.py +2 -2
  137. wagtail/admin/tests/test_views_generic.py +13 -0
  138. wagtail/admin/tests/test_widgets.py +3 -3
  139. wagtail/admin/tests/test_workflows.py +172 -27
  140. wagtail/admin/tests/tests.py +1 -1
  141. wagtail/admin/tests/viewsets/test_model_viewset.py +55 -3
  142. wagtail/admin/ui/side_panels.py +19 -0
  143. wagtail/admin/ui/sidebar.py +4 -3
  144. wagtail/admin/ui/tables/__init__.py +14 -1
  145. wagtail/admin/ui/tables/pages.py +6 -1
  146. wagtail/admin/urls/pages.py +10 -1
  147. wagtail/admin/urls/workflows.py +6 -1
  148. wagtail/admin/views/account.py +5 -1
  149. wagtail/admin/views/collections.py +0 -2
  150. wagtail/admin/views/generic/base.py +118 -1
  151. wagtail/admin/views/generic/history.py +158 -26
  152. wagtail/admin/views/generic/models.py +113 -99
  153. wagtail/admin/views/home.py +24 -9
  154. wagtail/admin/views/page_privacy.py +54 -30
  155. wagtail/admin/views/pages/history.py +11 -4
  156. wagtail/admin/views/pages/listing.py +76 -89
  157. wagtail/admin/views/pages/preview.py +1 -1
  158. wagtail/admin/views/pages/search.py +27 -71
  159. wagtail/admin/views/pages/usage.py +63 -24
  160. wagtail/admin/views/pages/utils.py +4 -3
  161. wagtail/admin/views/reports/base.py +0 -6
  162. wagtail/admin/views/workflows.py +67 -25
  163. wagtail/admin/viewsets/model.py +4 -3
  164. wagtail/admin/widgets/chooser.py +2 -1
  165. wagtail/api/v2/tests/test_pages.py +15 -2
  166. wagtail/blocks/field_block.py +15 -3
  167. wagtail/blocks/static_block.py +3 -0
  168. wagtail/contrib/forms/locale/cy/LC_MESSAGES/django.mo +0 -0
  169. wagtail/contrib/forms/locale/cy/LC_MESSAGES/django.po +29 -1
  170. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +15 -11
  171. wagtail/contrib/forms/templates/wagtailforms/confirm_delete.html +1 -0
  172. wagtail/contrib/forms/templates/wagtailforms/index.html +1 -1
  173. wagtail/contrib/forms/templates/wagtailforms/index_results.html +1 -1
  174. wagtail/contrib/forms/templates/wagtailforms/list_submissions.html +2 -1
  175. wagtail/contrib/forms/templates/wagtailforms/panels/form_responses_panel.html +2 -2
  176. wagtail/contrib/forms/tests/test_views.py +234 -35
  177. wagtail/contrib/forms/utils.py +8 -14
  178. wagtail/contrib/forms/views.py +72 -27
  179. wagtail/contrib/frontend_cache/backends/azure.py +1 -1
  180. wagtail/contrib/frontend_cache/backends/cloudfront.py +2 -2
  181. wagtail/contrib/frontend_cache/backends/dummy.py +11 -0
  182. wagtail/contrib/frontend_cache/tests.py +31 -37
  183. wagtail/contrib/frontend_cache/utils.py +12 -5
  184. wagtail/contrib/redirects/locale/cy/LC_MESSAGES/django.mo +0 -0
  185. wagtail/contrib/redirects/locale/cy/LC_MESSAGES/django.po +16 -1
  186. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +20 -24
  187. wagtail/contrib/redirects/models.py +16 -1
  188. wagtail/contrib/redirects/signal_handlers.py +18 -3
  189. wagtail/contrib/redirects/templates/wagtailredirects/add.html +5 -16
  190. wagtail/contrib/redirects/templates/wagtailredirects/import_summary.html +1 -1
  191. wagtail/contrib/redirects/tests/test_redirects.py +49 -6
  192. wagtail/contrib/redirects/tests/test_signal_handlers.py +42 -1
  193. wagtail/contrib/redirects/views.py +27 -3
  194. wagtail/contrib/search_promotions/locale/cy/LC_MESSAGES/django.mo +0 -0
  195. wagtail/contrib/search_promotions/locale/cy/LC_MESSAGES/django.po +60 -1
  196. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +12 -18
  197. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/add.html +5 -8
  198. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/edit.html +15 -10
  199. wagtail/contrib/search_promotions/tests.py +13 -2
  200. wagtail/contrib/search_promotions/views.py +15 -3
  201. wagtail/contrib/settings/locale/cy/LC_MESSAGES/django.mo +0 -0
  202. wagtail/contrib/settings/locale/cy/LC_MESSAGES/django.po +6 -1
  203. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +2 -10
  204. wagtail/contrib/settings/templates/wagtailsettings/edit.html +12 -45
  205. wagtail/contrib/simple_translation/locale/cy/LC_MESSAGES/django.mo +0 -0
  206. wagtail/contrib/simple_translation/locale/cy/LC_MESSAGES/django.po +13 -1
  207. wagtail/contrib/simple_translation/locale/dv/LC_MESSAGES/django.mo +0 -0
  208. wagtail/contrib/simple_translation/locale/dv/LC_MESSAGES/django.po +3 -0
  209. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +4 -4
  210. wagtail/contrib/simple_translation/locale/sl/LC_MESSAGES/django.mo +0 -0
  211. wagtail/contrib/simple_translation/locale/sl/LC_MESSAGES/django.po +5 -2
  212. wagtail/contrib/simple_translation/tests/test_views.py +51 -0
  213. wagtail/contrib/simple_translation/wagtail_hooks.py +16 -11
  214. wagtail/contrib/styleguide/locale/cy/LC_MESSAGES/django.mo +0 -0
  215. wagtail/contrib/styleguide/locale/cy/LC_MESSAGES/django.po +5 -1
  216. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +1 -1
  217. wagtail/contrib/table_block/locale/cy/LC_MESSAGES/django.mo +0 -0
  218. wagtail/contrib/table_block/locale/cy/LC_MESSAGES/django.po +27 -1
  219. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
  220. wagtail/contrib/typed_table_block/blocks.py +25 -0
  221. wagtail/contrib/typed_table_block/locale/cy/LC_MESSAGES/django.mo +0 -0
  222. wagtail/contrib/typed_table_block/locale/cy/LC_MESSAGES/django.po +12 -1
  223. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +10 -10
  224. wagtail/contrib/typed_table_block/tests.py +24 -1
  225. wagtail/coreutils.py +5 -11
  226. wagtail/documents/admin_urls.py +2 -2
  227. wagtail/documents/locale/cy/LC_MESSAGES/django.mo +0 -0
  228. wagtail/documents/locale/cy/LC_MESSAGES/django.po +10 -0
  229. wagtail/documents/locale/en/LC_MESSAGES/django.po +61 -76
  230. wagtail/documents/migrations/0014_alter_document_file_size.py +18 -0
  231. wagtail/documents/models.py +1 -1
  232. wagtail/documents/rich_text/__init__.py +1 -3
  233. wagtail/documents/static/wagtaildocs/js/add-multiple.js +1 -1
  234. wagtail/documents/templates/wagtaildocs/bulk_actions/confirm_bulk_add_tags.html +5 -1
  235. wagtail/documents/templates/wagtaildocs/bulk_actions/confirm_bulk_add_to_collection.html +5 -1
  236. wagtail/documents/templates/wagtaildocs/bulk_actions/confirm_bulk_delete.html +11 -5
  237. wagtail/documents/templates/wagtaildocs/documents/add.html +13 -41
  238. wagtail/documents/templates/wagtaildocs/documents/edit.html +28 -56
  239. wagtail/documents/templates/wagtaildocs/documents/index.html +1 -4
  240. wagtail/documents/templates/wagtaildocs/homepage/site_summary_documents.html +2 -2
  241. wagtail/documents/templates/wagtaildocs/multiple/add.html +36 -41
  242. wagtail/documents/tests/test_admin_views.py +64 -6
  243. wagtail/documents/tests/test_site_summary.py +3 -3
  244. wagtail/documents/views/documents.py +103 -113
  245. wagtail/documents/views/multiple.py +19 -1
  246. wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
  247. wagtail/embeds/oembed_providers.py +9 -19
  248. wagtail/fields.py +43 -27
  249. wagtail/images/admin_urls.py +2 -2
  250. wagtail/images/blocks.py +230 -2
  251. wagtail/images/fields.py +17 -29
  252. wagtail/images/image_operations.py +1 -1
  253. wagtail/images/locale/cy/LC_MESSAGES/django.mo +0 -0
  254. wagtail/images/locale/cy/LC_MESSAGES/django.po +128 -1
  255. wagtail/images/locale/en/LC_MESSAGES/django.po +119 -129
  256. wagtail/images/migrations/0025_alter_image_file_alter_rendition_file.py +36 -43
  257. wagtail/images/migrations/0027_image_description.py +20 -0
  258. wagtail/images/models.py +120 -45
  259. wagtail/images/rich_text/__init__.py +1 -3
  260. wagtail/images/static/wagtailimages/js/add-multiple.js +1 -1
  261. wagtail/images/static/wagtailimages/js/image-block.js +1 -0
  262. wagtail/images/templates/wagtailimages/bulk_actions/confirm_bulk_add_tags.html +5 -1
  263. wagtail/images/templates/wagtailimages/bulk_actions/confirm_bulk_add_to_collection.html +5 -1
  264. wagtail/images/templates/wagtailimages/bulk_actions/confirm_bulk_delete.html +11 -5
  265. wagtail/images/templates/wagtailimages/chooser/results.html +2 -2
  266. wagtail/images/templates/wagtailimages/homepage/site_summary_images.html +2 -2
  267. wagtail/images/templates/wagtailimages/images/_file_field.html +2 -2
  268. wagtail/images/templates/wagtailimages/images/add.html +13 -31
  269. wagtail/images/templates/wagtailimages/images/edit.html +53 -82
  270. wagtail/images/templates/wagtailimages/images/index.html +1 -4
  271. wagtail/images/templates/wagtailimages/images/url_generator.html +1 -1
  272. wagtail/images/templates/wagtailimages/multiple/add.html +40 -47
  273. wagtail/images/templates/wagtailimages/widgets/image.html +5 -0
  274. wagtail/images/templates/wagtailimages/widgets/image_chooser.html +1 -1
  275. wagtail/images/tests/test_admin_views.py +70 -10
  276. wagtail/images/tests/test_blocks.py +367 -1
  277. wagtail/images/tests/test_image_operations.py +23 -0
  278. wagtail/images/tests/test_models.py +20 -0
  279. wagtail/images/tests/test_signal_handlers.py +99 -95
  280. wagtail/images/tests/test_site_summary.py +3 -3
  281. wagtail/images/tests/test_templatetags.py +11 -7
  282. wagtail/images/tests/tests.py +4 -0
  283. wagtail/images/views/images.py +103 -104
  284. wagtail/images/views/multiple.py +17 -1
  285. wagtail/locale/cy/LC_MESSAGES/django.mo +0 -0
  286. wagtail/locale/cy/LC_MESSAGES/django.po +3 -0
  287. wagtail/locale/en/LC_MESSAGES/django.po +137 -125
  288. wagtail/locale/sl/LC_MESSAGES/django.mo +0 -0
  289. wagtail/locale/sl/LC_MESSAGES/django.po +3 -0
  290. wagtail/locales/locale/en/LC_MESSAGES/django.po +8 -8
  291. wagtail/locales/views.py +4 -1
  292. wagtail/migrations/0089_log_entry_data_json_null_to_object.py +1 -7
  293. wagtail/models/__init__.py +122 -14
  294. wagtail/models/audit_log.py +1 -3
  295. wagtail/models/i18n.py +1 -2
  296. wagtail/project_template/Dockerfile +3 -3
  297. wagtail/project_template/requirements.txt +2 -2
  298. wagtail/query.py +17 -4
  299. wagtail/rich_text/__init__.py +2 -3
  300. wagtail/rich_text/pages.py +2 -4
  301. wagtail/rich_text/rewriters.py +2 -2
  302. wagtail/search/backends/database/mysql/query.py +3 -3
  303. wagtail/search/backends/database/sqlite/query.py +6 -6
  304. wagtail/search/locale/en/LC_MESSAGES/django.po +1 -1
  305. wagtail/sites/locale/en/LC_MESSAGES/django.po +6 -6
  306. wagtail/sites/views.py +0 -1
  307. wagtail/snippets/action_menu.py +14 -4
  308. wagtail/snippets/locale/cy/LC_MESSAGES/django.mo +0 -0
  309. wagtail/snippets/locale/cy/LC_MESSAGES/django.po +73 -1
  310. wagtail/snippets/locale/en/LC_MESSAGES/django.po +27 -33
  311. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
  312. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
  313. wagtail/snippets/templates/wagtailsnippets/bulk_actions/confirm_bulk_delete.html +5 -3
  314. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/locked.html +1 -1
  315. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/menu.html +1 -11
  316. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/menu_item.html +1 -6
  317. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/publish.html +1 -1
  318. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/save.html +1 -1
  319. wagtail/snippets/templates/wagtailsnippets/snippets/create.html +1 -18
  320. wagtail/snippets/templates/wagtailsnippets/snippets/edit.html +1 -14
  321. wagtail/snippets/templates/wagtailsnippets/snippets/index.html +2 -5
  322. wagtail/snippets/tests/test_preview.py +193 -61
  323. wagtail/snippets/tests/test_snippets.py +247 -38
  324. wagtail/snippets/tests/test_usage.py +5 -0
  325. wagtail/snippets/tests/test_viewset.py +25 -9
  326. wagtail/snippets/tests/test_workflows.py +232 -19
  327. wagtail/snippets/views/snippets.py +1 -10
  328. wagtail/test/numberformat.py +104 -0
  329. wagtail/test/settings.py +10 -0
  330. wagtail/test/settings_ui.py +2 -0
  331. wagtail/test/testapp/migrations/0010_alter_customimage_file_and_more.py +71 -78
  332. wagtail/test/testapp/migrations/0040_nocreatablesubpagetypespage_nosubpagetypespage.py +54 -0
  333. wagtail/test/testapp/migrations/0041_alter_jsonstreammodel_options.py +17 -0
  334. wagtail/test/testapp/migrations/0042_alter_customdocument_file_size_and_more.py +28 -0
  335. wagtail/test/testapp/migrations/0043_customimage_description.py +41 -0
  336. wagtail/test/testapp/migrations/0044_custompreviewsizesmodel_custompreviewsizespage.py +52 -0
  337. wagtail/test/testapp/migrations/0045_alter_streampage_body.py +52 -0
  338. wagtail/test/testapp/models.py +62 -4
  339. wagtail/test/testapp/rich_text.py +2 -2
  340. wagtail/test/testapp/templates/tests/form_page_landing.html +2 -1
  341. wagtail/test/testapp/urls.py +5 -0
  342. wagtail/test/testapp/views.py +5 -0
  343. wagtail/test/utils/page_tests.py +5 -5
  344. wagtail/test/utils/template_tests.py +2 -2
  345. wagtail/tests/test_blocks.py +15 -0
  346. wagtail/tests/test_page_permissions.py +109 -0
  347. wagtail/tests/test_revision_model.py +27 -0
  348. wagtail/tests/test_signals.py +21 -2
  349. wagtail/tests/test_tests.py +30 -0
  350. wagtail/users/locale/cy/LC_MESSAGES/django.mo +0 -0
  351. wagtail/users/locale/cy/LC_MESSAGES/django.po +118 -1
  352. wagtail/users/locale/dv/LC_MESSAGES/django.mo +0 -0
  353. wagtail/users/locale/dv/LC_MESSAGES/django.po +3 -0
  354. wagtail/users/locale/en/LC_MESSAGES/django.po +89 -113
  355. wagtail/users/locale/sl/LC_MESSAGES/django.mo +0 -0
  356. wagtail/users/locale/sl/LC_MESSAGES/django.po +3 -0
  357. wagtail/users/migrations/0014_userprofile_contrast.py +23 -0
  358. wagtail/users/models.py +11 -0
  359. wagtail/users/templates/wagtailusers/bulk_actions/confirm_bulk_assign_role.html +5 -1
  360. wagtail/users/templates/wagtailusers/bulk_actions/confirm_bulk_delete.html +5 -1
  361. wagtail/users/templates/wagtailusers/bulk_actions/confirm_bulk_set_active_state.html +5 -1
  362. wagtail/users/templates/wagtailusers/groups/create.html +19 -17
  363. wagtail/users/templates/wagtailusers/groups/edit.html +2 -40
  364. wagtail/users/templates/wagtailusers/groups/includes/formatted_permissions.html +1 -62
  365. wagtail/users/templates/wagtailusers/groups/includes/page_permissions_formset.html +0 -1
  366. wagtail/users/templates/wagtailusers/users/create.html +46 -50
  367. wagtail/users/templates/wagtailusers/users/edit.html +45 -62
  368. wagtail/users/templates/wagtailusers/users/index.html +1 -4
  369. wagtail/users/templatetags/wagtailusers_tags.py +1 -5
  370. wagtail/users/tests/test_admin_views.py +85 -66
  371. wagtail/users/views/groups.py +4 -1
  372. wagtail/users/views/users.py +2 -0
  373. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/METADATA +6 -6
  374. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/RECORD +378 -367
  375. wagtail/admin/static/wagtailadmin/js/preview-panel.js +0 -2
  376. wagtail/admin/static/wagtailadmin/js/preview-panel.js.LICENSE.txt +0 -11
  377. wagtail/admin/templates/wagtailadmin/generic/history_results.html +0 -1
  378. wagtail/admin/templates/wagtailadmin/page_privacy/ancestor_privacy.html +0 -3
  379. wagtail/admin/templates/wagtailadmin/pages/usage_results.html +0 -6
  380. wagtail/admin/templates/wagtailadmin/shared/workflow_history/index.html +0 -17
  381. wagtail/admin/templates/wagtailadmin/shared/workflow_history/results.html +0 -17
  382. wagtail/admin/templates/wagtailadmin/workflows/usage.html +0 -44
  383. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/LICENSE +0 -0
  384. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/WHEEL +0 -0
  385. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/entry_points.txt +0 -0
  386. {wagtail-6.2.2.dist-info → wagtail-6.3rc2.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  import datetime
2
2
  from functools import wraps
3
3
 
4
- from django.test import TestCase
4
+ from django.test import TestCase, override_settings
5
5
  from django.urls import reverse
6
6
  from django.utils import timezone
7
7
  from freezegun import freeze_time
@@ -9,12 +9,14 @@ from freezegun import freeze_time
9
9
  from wagtail.admin.views.pages.preview import PreviewOnEdit
10
10
  from wagtail.models import Page
11
11
  from wagtail.test.testapp.models import (
12
+ CustomPreviewSizesPage,
12
13
  EventCategory,
13
14
  MultiPreviewModesPage,
14
15
  SimplePage,
15
16
  StreamPage,
16
17
  )
17
18
  from wagtail.test.utils import WagtailTestUtils
19
+ from wagtail.utils.deprecation import RemovedInWagtail70Warning
18
20
 
19
21
 
20
22
  class TestIssue2599(WagtailTestUtils, TestCase):
@@ -414,6 +416,26 @@ class TestPreview(WagtailTestUtils, TestCase):
414
416
  self.assertEqual(response.status_code, 200)
415
417
  self.assertTemplateUsed(response, template)
416
418
 
419
+ def test_preview_sizes(self):
420
+ page = CustomPreviewSizesPage(title="Custom preview size")
421
+ self.home_page.add_child(instance=page)
422
+ edit_url = reverse("wagtailadmin_pages:edit", args=(page.id,))
423
+
424
+ response = self.client.get(edit_url)
425
+ self.assertEqual(response.status_code, 200)
426
+ soup = self.get_soup(response.content)
427
+
428
+ radios = soup.select('input[type="radio"][name="preview-size"]')
429
+ self.assertEqual(len(radios), 2)
430
+
431
+ self.assertEqual("412", radios[0]["data-device-width"])
432
+ self.assertEqual("Custom mobile preview", radios[0]["aria-label"])
433
+ self.assertFalse(radios[0].has_attr("checked"))
434
+
435
+ self.assertEqual("1280", radios[1]["data-device-width"])
436
+ self.assertEqual("Original desktop", radios[1]["aria-label"])
437
+ self.assertTrue(radios[1].has_attr("checked"))
438
+
417
439
 
418
440
  class TestEnablePreview(WagtailTestUtils, TestCase):
419
441
  def setUp(self):
@@ -446,31 +468,33 @@ class TestEnablePreview(WagtailTestUtils, TestCase):
446
468
 
447
469
  self.assertEqual(response.status_code, 200)
448
470
 
449
- # Should show the preview panel
450
- self.assertContains(response, 'data-side-panel="preview"')
451
- self.assertContains(response, 'data-action="%s"' % preview_url)
452
-
453
471
  # Should have the preview side panel toggle button
454
472
  soup = self.get_soup(response.content)
473
+ self.assertIsNotNone(soup.select_one('[data-side-panel="preview"]'))
455
474
  toggle_button = soup.find("button", {"data-side-panel-toggle": "preview"})
456
475
  self.assertIsNotNone(toggle_button)
457
476
  self.assertEqual("w-tooltip w-kbd", toggle_button["data-controller"])
458
477
  self.assertEqual("mod+p", toggle_button["data-w-kbd-key-value"])
459
478
 
479
+ # Should set the preview URL value on the controller
480
+ controller = soup.select_one('[data-controller="w-preview"]')
481
+ self.assertIsNotNone(controller)
482
+ self.assertEqual(controller.get("data-w-preview-url-value"), preview_url)
483
+
460
484
  # Should show the iframe
461
- self.assertContains(
462
- response,
463
- '<iframe id="preview-iframe" loading="lazy" title="Preview" class="preview-panel__iframe" data-preview-iframe aria-describedby="preview-panel-error-banner">',
464
- )
485
+ iframe = controller.select_one("#w-preview-iframe")
486
+ self.assertIsNotNone(iframe)
487
+ self.assertEqual(iframe.get("data-w-preview-target"), "iframe")
465
488
 
466
489
  # Should show the new tab button with the default mode set
467
- self.assertContains(response, f'href="{new_tab_url}" target="_blank"')
490
+ new_tab_button = controller.select_one('a[data-w-preview-target="newTab"]')
491
+ self.assertIsNotNone(new_tab_button)
492
+ self.assertEqual(new_tab_button["href"], new_tab_url)
493
+ self.assertEqual(new_tab_button["target"], "_blank")
468
494
 
469
495
  # Should not show the preview mode selection
470
- self.assertNotContains(
471
- response,
472
- '<select id="id_preview_mode" name="preview_mode" class="preview-panel__mode-select" data-preview-mode-select>',
473
- )
496
+ mode_select = controller.select_one('[data-w-preview-target="mode"]')
497
+ self.assertIsNone(mode_select)
474
498
 
475
499
  def test_show_preview_panel_on_create_with_multiple_modes(self):
476
500
  create_url = self.get_url_on_add("add", self.multiple)
@@ -483,28 +507,34 @@ class TestEnablePreview(WagtailTestUtils, TestCase):
483
507
  # Should show the preview panel
484
508
  self.assertContains(response, 'data-side-panel-toggle="preview"')
485
509
  self.assertContains(response, 'data-side-panel="preview"')
486
- self.assertContains(response, 'data-action="%s"' % preview_url)
510
+
511
+ # Should set the preview URL value on the controller
512
+ soup = self.get_soup(response.content)
513
+ controller = soup.select_one('[data-controller="w-preview"]')
514
+ self.assertIsNotNone(controller)
515
+ self.assertEqual(controller.get("data-w-preview-url-value"), preview_url)
487
516
 
488
517
  # Should show the iframe
489
- self.assertContains(
490
- response,
491
- '<iframe id="preview-iframe" loading="lazy" title="Preview" class="preview-panel__iframe" data-preview-iframe aria-describedby="preview-panel-error-banner">',
492
- )
518
+ iframe = controller.select_one("#w-preview-iframe")
519
+ self.assertIsNotNone(iframe)
520
+ self.assertEqual(iframe.get("data-w-preview-target"), "iframe")
493
521
 
494
522
  # Should show the new tab button with the default mode set and correctly quoted
495
- self.assertContains(response, f'href="{new_tab_url}" target="_blank"')
496
-
497
- # should show the preview mode selection
498
- self.assertContains(
499
- response,
500
- '<select id="id_preview_mode" name="preview_mode" class="preview-panel__mode-select" data-preview-mode-select>',
501
- )
502
- self.assertContains(response, '<option value="original">Original</option>')
503
-
504
- # Should respect the default_preview_mode
505
- self.assertContains(
506
- response, '<option value="alt#1" selected>Alternate</option>'
507
- )
523
+ new_tab_button = controller.select_one('a[data-w-preview-target="newTab"]')
524
+ self.assertIsNotNone(new_tab_button)
525
+ self.assertEqual(new_tab_button["href"], new_tab_url)
526
+ self.assertEqual(new_tab_button["target"], "_blank")
527
+
528
+ # should show the preview mode selection with the default mode selected
529
+ mode_select = controller.select_one('[data-w-preview-target="mode"]')
530
+ self.assertIsNotNone(mode_select)
531
+ self.assertEqual(mode_select["id"], "id_preview_mode")
532
+ default_option = mode_select.select_one('option[value="alt#1"]')
533
+ self.assertIsNotNone(default_option)
534
+ self.assertIsNotNone(default_option.get("selected"))
535
+ other_option = mode_select.select_one('option[value="original"]')
536
+ self.assertIsNotNone(other_option)
537
+ self.assertIsNone(other_option.get("selected"))
508
538
 
509
539
  def test_show_preview_panel_on_edit_with_single_mode(self):
510
540
  edit_url = self.get_url_on_edit("edit", self.single)
@@ -514,25 +544,45 @@ class TestEnablePreview(WagtailTestUtils, TestCase):
514
544
 
515
545
  self.assertEqual(response.status_code, 200)
516
546
 
517
- # Should show the preview panel
518
- self.assertContains(response, 'data-side-panel-toggle="preview"')
519
- self.assertContains(response, 'data-side-panel="preview"')
520
- self.assertContains(response, 'data-action="%s"' % preview_url)
547
+ # Should have the preview side panel toggle button
548
+ soup = self.get_soup(response.content)
549
+ self.assertIsNotNone(soup.select_one('[data-side-panel="preview"]'))
550
+ toggle_button = soup.find("button", {"data-side-panel-toggle": "preview"})
551
+ self.assertIsNotNone(toggle_button)
552
+ self.assertEqual("w-tooltip w-kbd", toggle_button["data-controller"])
553
+ self.assertEqual("mod+p", toggle_button["data-w-kbd-key-value"])
554
+
555
+ # Should set the preview URL value on the controller
556
+ controller = soup.select_one('[data-controller="w-preview"]')
557
+ self.assertIsNotNone(controller)
558
+ self.assertEqual(controller.get("data-w-preview-url-value"), preview_url)
559
+
560
+ # Should have a default interval of 500ms and should render the hidden spinner
561
+ interval_value = controller.get("data-w-preview-auto-update-interval-value")
562
+ self.assertEqual(interval_value, "500")
563
+ spinner = controller.select_one('[data-w-preview-target="spinner"]')
564
+ self.assertIsNotNone(spinner)
565
+ self.assertIsNotNone(spinner.get("hidden"))
566
+ self.assertIsNotNone(spinner.select_one("svg.icon-spinner"))
567
+
568
+ # Should not render any buttons (the refresh button in particular)
569
+ refresh_button = controller.select_one("button")
570
+ self.assertIsNone(refresh_button)
521
571
 
522
572
  # Should show the iframe
523
- self.assertContains(
524
- response,
525
- '<iframe id="preview-iframe" loading="lazy" title="Preview" class="preview-panel__iframe" data-preview-iframe aria-describedby="preview-panel-error-banner">',
526
- )
573
+ iframe = controller.select_one("#w-preview-iframe")
574
+ self.assertIsNotNone(iframe)
575
+ self.assertEqual(iframe.get("data-w-preview-target"), "iframe")
527
576
 
528
577
  # Should show the new tab button with the default mode set
529
- self.assertContains(response, f'href="{new_tab_url}" target="_blank"')
578
+ new_tab_button = controller.select_one('a[data-w-preview-target="newTab"]')
579
+ self.assertIsNotNone(new_tab_button)
580
+ self.assertEqual(new_tab_button["href"], new_tab_url)
581
+ self.assertEqual(new_tab_button["target"], "_blank")
530
582
 
531
583
  # Should not show the preview mode selection
532
- self.assertNotContains(
533
- response,
534
- '<select id="id_preview_mode" name="preview_mode" class="preview-panel__mode-select" data-preview-mode-select>',
535
- )
584
+ mode_select = controller.select_one('[data-w-preview-target="mode"]')
585
+ self.assertIsNone(mode_select)
536
586
 
537
587
  def test_show_preview_panel_on_edit_with_multiple_modes(self):
538
588
  edit_url = self.get_url_on_edit("edit", self.multiple)
@@ -545,28 +595,121 @@ class TestEnablePreview(WagtailTestUtils, TestCase):
545
595
  # Should show the preview panel
546
596
  self.assertContains(response, 'data-side-panel-toggle="preview"')
547
597
  self.assertContains(response, 'data-side-panel="preview"')
548
- self.assertContains(response, 'data-action="%s"' % preview_url)
598
+
599
+ # Should set the preview URL value on the controller
600
+ soup = self.get_soup(response.content)
601
+ controller = soup.select_one('[data-controller="w-preview"]')
602
+ self.assertIsNotNone(controller)
603
+ self.assertEqual(controller.get("data-w-preview-url-value"), preview_url)
549
604
 
550
605
  # Should show the iframe
551
- self.assertContains(
552
- response,
553
- '<iframe id="preview-iframe" loading="lazy" title="Preview" class="preview-panel__iframe" data-preview-iframe aria-describedby="preview-panel-error-banner">',
554
- )
606
+ iframe = controller.select_one("#w-preview-iframe")
607
+ self.assertIsNotNone(iframe)
608
+ self.assertEqual(iframe.get("data-w-preview-target"), "iframe")
555
609
 
556
610
  # Should show the new tab button with the default mode set and correctly quoted
557
- self.assertContains(response, f'href="{new_tab_url}" target="_blank"')
611
+ new_tab_button = controller.select_one('a[data-w-preview-target="newTab"]')
612
+ self.assertIsNotNone(new_tab_button)
613
+ self.assertEqual(new_tab_button["href"], new_tab_url)
614
+ self.assertEqual(new_tab_button["target"], "_blank")
615
+
616
+ # should show the preview mode selection with the default mode selected
617
+ mode_select = controller.select_one('[data-w-preview-target="mode"]')
618
+ self.assertIsNotNone(mode_select)
619
+ self.assertEqual(mode_select["id"], "id_preview_mode")
620
+ default_option = mode_select.select_one('option[value="alt#1"]')
621
+ self.assertIsNotNone(default_option)
622
+ self.assertIsNotNone(default_option.get("selected"))
623
+ other_option = mode_select.select_one('option[value="original"]')
624
+ self.assertIsNotNone(other_option)
625
+ self.assertIsNone(other_option.get("selected"))
626
+
627
+ @override_settings(WAGTAIL_AUTO_UPDATE_PREVIEW_INTERVAL=12345)
628
+ def test_custom_auto_update_interval(self):
629
+ edit_url = self.get_url_on_edit("edit", self.single)
630
+ preview_url = self.get_url_on_edit("preview_on_edit", self.single)
631
+ response = self.client.get(edit_url)
558
632
 
559
- # should show the preview mode selection
560
- self.assertContains(
561
- response,
562
- '<select id="id_preview_mode" name="preview_mode" class="preview-panel__mode-select" data-preview-mode-select>',
563
- )
564
- self.assertContains(response, '<option value="original">Original</option>')
633
+ self.assertEqual(response.status_code, 200)
565
634
 
566
- # Should respect the default_preview_mode
567
- self.assertContains(
568
- response, '<option value="alt#1" selected>Alternate</option>'
569
- )
635
+ soup = self.get_soup(response.content)
636
+
637
+ # Should set the custom interval value on the controller
638
+ controller = soup.select_one('[data-controller="w-preview"]')
639
+ self.assertIsNotNone(controller)
640
+ self.assertEqual(controller.get("data-w-preview-url-value"), preview_url)
641
+ interval_value = controller.get("data-w-preview-auto-update-interval-value")
642
+ self.assertEqual(interval_value, "12345")
643
+
644
+ # Should render the spinner
645
+ spinner = controller.select_one('[data-w-preview-target="spinner"]')
646
+ self.assertIsNotNone(spinner)
647
+ self.assertIsNotNone(spinner.get("hidden"))
648
+ self.assertIsNotNone(spinner.select_one("svg.icon-spinner"))
649
+
650
+ # Should not render any buttons (the refresh button in particular)
651
+ refresh_button = controller.select_one("button")
652
+ self.assertIsNone(refresh_button)
653
+
654
+ @override_settings(WAGTAIL_AUTO_UPDATE_PREVIEW_INTERVAL=0)
655
+ def test_disable_auto_update_using_zero_interval(self):
656
+ edit_url = self.get_url_on_edit("edit", self.single)
657
+ preview_url = self.get_url_on_edit("preview_on_edit", self.single)
658
+ response = self.client.get(edit_url)
659
+
660
+ self.assertEqual(response.status_code, 200)
661
+
662
+ soup = self.get_soup(response.content)
663
+
664
+ # Should set the interval value on the controller
665
+ controller = soup.select_one('[data-controller="w-preview"]')
666
+ self.assertIsNotNone(controller)
667
+ self.assertEqual(controller.get("data-w-preview-url-value"), preview_url)
668
+ interval_value = controller.get("data-w-preview-auto-update-interval-value")
669
+ self.assertEqual(interval_value, "0")
670
+
671
+ # Should not render the spinner
672
+ spinner = controller.select_one('[data-w-preview-target="spinner"]')
673
+ self.assertIsNone(spinner)
674
+
675
+ # Should render the refresh button with the w-progress controller
676
+ refresh_button = controller.select_one("button")
677
+ self.assertIsNotNone(refresh_button)
678
+ self.assertEqual(refresh_button.get("data-controller"), "w-progress")
679
+ self.assertEqual(refresh_button.text.strip(), "Refresh")
680
+
681
+ @override_settings(WAGTAIL_AUTO_UPDATE_PREVIEW=False)
682
+ def test_disable_auto_update_using_deprecated_setting(self):
683
+ edit_url = self.get_url_on_edit("edit", self.single)
684
+ preview_url = self.get_url_on_edit("preview_on_edit", self.single)
685
+ with self.assertWarnsMessage(
686
+ RemovedInWagtail70Warning,
687
+ "`WAGTAIL_AUTO_UPDATE_PREVIEW` is deprecated. "
688
+ "Set `WAGTAIL_AUTO_UPDATE_PREVIEW_INTERVAL = 0` to disable auto-update "
689
+ "for previews.",
690
+ ):
691
+ response = self.client.get(edit_url)
692
+
693
+ self.assertEqual(response.status_code, 200)
694
+
695
+ soup = self.get_soup(response.content)
696
+
697
+ # Should set the interval value on the controller
698
+ controller = soup.select_one('[data-controller="w-preview"]')
699
+ self.assertIsNotNone(controller)
700
+ self.assertEqual(controller.get("data-w-preview-url-value"), preview_url)
701
+ interval_value = controller.get("data-w-preview-auto-update-interval-value")
702
+ self.assertEqual(interval_value, "0")
703
+
704
+ # Should not render the spinner
705
+ spinner = controller.select_one('[data-w-preview-target="spinner"]')
706
+ self.assertIsNone(spinner)
707
+
708
+ # Should render the refresh button with the w-progress controller
709
+ refresh_button = controller.select_one("button")
710
+ self.assertIsNotNone(refresh_button)
711
+ self.assertEqual(refresh_button.get("data-controller"), "w-progress")
712
+ self.assertEqual(refresh_button.text.strip(), "Refresh")
570
713
 
571
714
  def test_show_preview_on_revisions_list(self):
572
715
  latest_revision = self.single.save_revision(log_action=True)
@@ -612,7 +755,8 @@ class TestDisablePreviewButton(WagtailTestUtils, TestCase):
612
755
  )
613
756
  self.assertNotContains(response, 'data-side-panel-toggle="preview"')
614
757
  self.assertNotContains(response, 'data-side-panel="preview"')
615
- self.assertNotContains(response, 'data-action="%s"' % preview_url)
758
+ self.assertNotContains(response, 'data-controller="w-preview"')
759
+ self.assertNotContains(response, preview_url)
616
760
 
617
761
  def test_disable_preview_on_edit(self):
618
762
  stream_page = StreamPage(title="stream page", body=[("text", "hello")])
@@ -629,7 +773,8 @@ class TestDisablePreviewButton(WagtailTestUtils, TestCase):
629
773
  )
630
774
  self.assertNotContains(response, 'data-side-panel-toggle="preview"')
631
775
  self.assertNotContains(response, 'data-side-panel="preview"')
632
- self.assertNotContains(response, 'data-action="%s"' % preview_url)
776
+ self.assertNotContains(response, 'data-controller="w-preview"')
777
+ self.assertNotContains(response, preview_url)
633
778
 
634
779
  def test_disable_preview_on_revisions_list(self):
635
780
  stream_page = StreamPage(title="stream page", body=[("text", "hello")])
@@ -2,7 +2,13 @@ from django.test import TestCase
2
2
  from django.urls import reverse
3
3
 
4
4
  from wagtail.models import Page
5
- from wagtail.test.testapp.models import BusinessChild, BusinessIndex, SimplePage
5
+ from wagtail.test.testapp.models import (
6
+ BusinessChild,
7
+ BusinessIndex,
8
+ NoCreatableSubpageTypesPage,
9
+ NoSubpageTypesPage,
10
+ SimplePage,
11
+ )
6
12
  from wagtail.test.utils import WagtailTestUtils
7
13
 
8
14
 
@@ -140,3 +146,87 @@ class TestPageReorderWithParentPageRestrictions(TestPageReorder):
140
146
 
141
147
  # Login
142
148
  self.user = self.login()
149
+
150
+
151
+ class TestPageReorderWithNoCreatableSubPageTypes(TestPageReorder):
152
+ """
153
+ This TestCase is the same as the TestPageReorder class above, but uses a
154
+ NoCreatableSubpageTypesPage instance as the parent page instead of SimplePage.
155
+
156
+ This ensures that a parent page having no 'creatable' page types in
157
+ its `subpage_types` list does not prevent the reorder pre-existing or
158
+ automatically generated pages beneath it.
159
+ """
160
+
161
+ def setUp(self):
162
+ child_content = "<p>This is content</p>"
163
+
164
+ # Find root page
165
+ self.root_page = Page.objects.get(id=2)
166
+
167
+ # root
168
+ # |- parent_page (NoCreatableSubpageTypesPage)
169
+ # | |- child_1 (SimplePage)
170
+ # | |- child_2 (SimplePage)
171
+ # | |- child_3 (SimplePage)
172
+
173
+ self.index_page = NoCreatableSubpageTypesPage(title="Index", slug="index")
174
+ self.root_page.add_child(instance=self.index_page)
175
+
176
+ self.child_1 = SimplePage(
177
+ title="Child 1", slug="child-1", content=child_content
178
+ )
179
+ self.index_page.add_child(instance=self.child_1)
180
+ self.child_2 = SimplePage(
181
+ title="Child 2", slug="child-2", content=child_content
182
+ )
183
+ self.index_page.add_child(instance=self.child_2)
184
+ self.child_3 = SimplePage(
185
+ title="Child 3", slug="child-3", content=child_content
186
+ )
187
+ self.index_page.add_child(instance=self.child_3)
188
+
189
+ # Login
190
+ self.user = self.login()
191
+
192
+
193
+ class TestPageReorderWithNoSubPageTypes(TestPageReorder):
194
+ """
195
+ This TestCase is the same as the TestPageReorder class above, but uses a
196
+ NoSubpageTypesPage instance as the parent page instead of SimplePage.
197
+
198
+ This ensures that a parent page having an empty `subpage_types` list does
199
+ not prevent the reorder pre-existing or automatically generated pages
200
+ beneath it.
201
+ """
202
+
203
+ def setUp(self):
204
+ child_content = "<p>This is content</p>"
205
+
206
+ # Find root page
207
+ self.root_page = Page.objects.get(id=2)
208
+
209
+ # root
210
+ # |- parent_page (NoSubpageTypesPage)
211
+ # | |- child_1 (SimplePage)
212
+ # | |- child_2 (SimplePage)
213
+ # | |- child_3 (SimplePage)
214
+
215
+ self.index_page = NoSubpageTypesPage(title="Index", slug="index")
216
+ self.root_page.add_child(instance=self.index_page)
217
+
218
+ self.child_1 = SimplePage(
219
+ title="Child 1", slug="child-1", content=child_content
220
+ )
221
+ self.index_page.add_child(instance=self.child_1)
222
+ self.child_2 = SimplePage(
223
+ title="Child 2", slug="child-2", content=child_content
224
+ )
225
+ self.index_page.add_child(instance=self.child_2)
226
+ self.child_3 = SimplePage(
227
+ title="Child 3", slug="child-3", content=child_content
228
+ )
229
+ self.index_page.add_child(instance=self.child_3)
230
+
231
+ # Login
232
+ self.user = self.login()
@@ -4,7 +4,7 @@ from django.test import TestCase
4
4
  from django.urls import reverse
5
5
 
6
6
  from wagtail.models import Page
7
- from wagtail.test.testapp.models import SimplePage, StreamPage
7
+ from wagtail.test.testapp.models import MultiPreviewModesPage, SimplePage, StreamPage
8
8
  from wagtail.test.utils import WagtailTestUtils
9
9
 
10
10
 
@@ -112,3 +112,34 @@ class TestDraftAccess(WagtailTestUtils, TestCase):
112
112
  self.assertContains(
113
113
  response, reverse("wagtailadmin_pages:edit", args=(self.child_page.id,))
114
114
  )
115
+
116
+ def test_preview_modes(self):
117
+ """
118
+ Test that the preview_modes are respected when viewing a draft.
119
+ """
120
+ # Create a page with multiple preview modes
121
+ page = MultiPreviewModesPage(title="multi preview modes page")
122
+ self.root_page.add_child(instance=page)
123
+
124
+ # Login as admin
125
+ self.user = self.login()
126
+
127
+ # Test using explicit preview mode parameter
128
+ for mode, label in page.preview_modes:
129
+ with self.subTest(mode=mode, label=label):
130
+ response = self.client.get(
131
+ reverse("wagtailadmin_pages:view_draft", args=(page.id,)),
132
+ {"mode": mode},
133
+ )
134
+ # Ensure the correct template is used
135
+ self.assertEqual(response.status_code, 200)
136
+ preview_template = page.preview_templates[mode]
137
+ self.assertTemplateUsed(response, preview_template)
138
+
139
+ # Test default preview mode with no parameter
140
+ response = self.client.get(
141
+ reverse("wagtailadmin_pages:view_draft", args=(page.id,)),
142
+ )
143
+ self.assertEqual(response.status_code, 200)
144
+ preview_template = page.preview_templates[page.default_preview_mode]
145
+ self.assertTemplateUsed(response, preview_template)