wagtail 6.2.2__py3-none-any.whl → 6.3rc1__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 +8 -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.3rc1.dist-info}/METADATA +6 -6
  374. {wagtail-6.2.2.dist-info → wagtail-6.3rc1.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.3rc1.dist-info}/LICENSE +0 -0
  384. {wagtail-6.2.2.dist-info → wagtail-6.3rc1.dist-info}/WHEEL +0 -0
  385. {wagtail-6.2.2.dist-info → wagtail-6.3rc1.dist-info}/entry_points.txt +0 -0
  386. {wagtail-6.2.2.dist-info → wagtail-6.3rc1.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,5 @@
1
- from typing import Any, Mapping, Union
1
+ from collections.abc import Mapping
2
+ from typing import Any, Union
2
3
 
3
4
  from django.conf import settings
4
5
  from django.contrib.auth import get_user_model
@@ -7,10 +8,11 @@ from django.db.models import Exists, IntegerField, Max, OuterRef, Q
7
8
  from django.db.models.functions import Cast
8
9
  from django.forms import Media
9
10
  from django.http import Http404, HttpResponse
10
- from django.utils.translation import gettext_lazy
11
+ from django.utils.translation import gettext_lazy as _
11
12
  from django.views.generic.base import TemplateView
12
13
 
13
14
  from wagtail import hooks
15
+ from wagtail.admin.forms.search import SearchForm
14
16
  from wagtail.admin.icons import get_icons
15
17
  from wagtail.admin.navigation import get_site_for_user
16
18
  from wagtail.admin.site_summary import SiteSummaryPanel
@@ -33,9 +35,8 @@ User = get_user_model()
33
35
 
34
36
 
35
37
  class UpgradeNotificationPanel(Component):
36
- name = "upgrade_notification"
37
38
  template_name = "wagtailadmin/home/upgrade_notification.html"
38
- order = 100
39
+ dismissible_id = "last_upgrade_check"
39
40
 
40
41
  def get_upgrade_check_setting(self) -> Union[bool, str]:
41
42
  return getattr(settings, "WAGTAIL_ENABLE_UPDATE_CHECK", True)
@@ -46,8 +47,19 @@ class UpgradeNotificationPanel(Component):
46
47
  return True
47
48
  return False
48
49
 
50
+ def get_dismissible_value(self, user) -> str:
51
+ if profile := getattr(user, "wagtail_userprofile", None):
52
+ return profile.dismissibles.get(self.dismissible_id)
53
+ return None
54
+
49
55
  def get_context_data(self, parent_context: Mapping[str, Any]) -> Mapping[str, Any]:
50
- return {"lts_only": self.upgrade_check_lts_only()}
56
+ return {
57
+ "lts_only": self.upgrade_check_lts_only(),
58
+ "dismissible_id": self.dismissible_id,
59
+ "dismissible_value": self.get_dismissible_value(
60
+ parent_context["request"].user
61
+ ),
62
+ }
51
63
 
52
64
  def render_html(self, parent_context: Mapping[str, Any] = None) -> str:
53
65
  if (
@@ -282,15 +294,20 @@ class RecentEditsPanel(Component):
282
294
 
283
295
  class HomeView(WagtailAdminTemplateMixin, TemplateView):
284
296
  template_name = "wagtailadmin/home.html"
285
- page_title = gettext_lazy("Dashboard")
297
+ page_title = _("Dashboard")
298
+ permission_policy = page_permission_policy
286
299
 
287
300
  def get_context_data(self, **kwargs):
288
301
  context = super().get_context_data(**kwargs)
289
302
  panels = self.get_panels()
303
+ site_summary = SiteSummaryPanel(self.request)
290
304
  site_details = self.get_site_details()
291
305
 
292
- context["media"] = self.get_media(panels)
306
+ context["media"] = self.get_media([*panels, site_summary])
293
307
  context["panels"] = sorted(panels, key=lambda p: p.order)
308
+ context["site_summary"] = site_summary
309
+ context["upgrade_notification"] = UpgradeNotificationPanel()
310
+ context["search_form"] = SearchForm(placeholder=_("Search all pages…"))
294
311
  context["user"] = self.request.user
295
312
 
296
313
  return {**context, **site_details}
@@ -306,10 +323,8 @@ class HomeView(WagtailAdminTemplateMixin, TemplateView):
306
323
  def get_panels(self):
307
324
  request = self.request
308
325
  panels = [
309
- SiteSummaryPanel(request),
310
326
  # Disabled until a release warrants the banner.
311
327
  # WhatsNewInWagtailVersionPanel(),
312
- UpgradeNotificationPanel(),
313
328
  WorkflowObjectsToModeratePanel(),
314
329
  UserObjectsInWorkflowModerationPanel(),
315
330
  RecentEditsPanel(),
@@ -1,9 +1,14 @@
1
1
  from django.core.exceptions import PermissionDenied
2
2
  from django.shortcuts import get_object_or_404
3
+ from django.urls import reverse
4
+ from django.utils.html import format_html
5
+ from django.utils.safestring import mark_safe
6
+ from django.utils.translation import gettext_lazy as _
3
7
 
4
8
  from wagtail.admin.forms.pages import PageViewRestrictionForm
5
9
  from wagtail.admin.modal_workflow import render_modal_workflow
6
10
  from wagtail.models import Page, PageViewRestriction
11
+ from wagtail.models.view_restrictions import BaseViewRestriction
7
12
 
8
13
 
9
14
  def set_privacy(request, page_id):
@@ -12,14 +17,20 @@ def set_privacy(request, page_id):
12
17
  if not page_perms.can_set_view_restrictions():
13
18
  raise PermissionDenied
14
19
 
15
- # fetch restriction records in depth order so that ancestors appear first
16
- restrictions = page.get_view_restrictions().order_by("page__depth")
20
+ restrictions = page.get_view_restrictions().order_by("-page__depth")
17
21
  if restrictions:
18
- restriction = restrictions[0]
19
- restriction_exists_on_ancestor = restriction.page.id != page.id
22
+ if restrictions[0].page.id == page.id:
23
+ restriction = restrictions[0]
24
+ if len(restrictions) > 1:
25
+ restriction_on_ancestor = restrictions[1]
26
+ else:
27
+ restriction_on_ancestor = None
28
+ else:
29
+ restriction = None
30
+ restriction_on_ancestor = restrictions[0]
20
31
  else:
21
32
  restriction = None
22
- restriction_exists_on_ancestor = False
33
+ restriction_on_ancestor = None
23
34
 
24
35
  if request.method == "POST":
25
36
  form = PageViewRestrictionForm(
@@ -27,7 +38,7 @@ def set_privacy(request, page_id):
27
38
  instance=restriction,
28
39
  private_page_options=page.private_page_options,
29
40
  )
30
- if form.is_valid() and not restriction_exists_on_ancestor:
41
+ if form.is_valid():
31
42
  if form.cleaned_data["restriction_type"] == PageViewRestriction.NONE:
32
43
  # remove any existing restriction
33
44
  if restriction:
@@ -51,37 +62,50 @@ def set_privacy(request, page_id):
51
62
  )
52
63
 
53
64
  else: # request is a GET
54
- if not restriction_exists_on_ancestor:
55
- if restriction:
56
- form = PageViewRestrictionForm(
57
- instance=restriction, private_page_options=page.private_page_options
58
- )
59
- else:
60
- # no current view restrictions on this page
61
- form = PageViewRestrictionForm(
62
- initial={"restriction_type": "none"},
63
- private_page_options=page.private_page_options,
64
- )
65
+ if restriction:
66
+ form = PageViewRestrictionForm(
67
+ instance=restriction,
68
+ private_page_options=page.private_page_options,
69
+ )
65
70
 
66
- if restriction_exists_on_ancestor:
67
- # display a message indicating that there is a restriction at ancestor level -
68
- # do not provide the form for setting up new restrictions
69
- return render_modal_workflow(
70
- request,
71
- "wagtailadmin/page_privacy/ancestor_privacy.html",
72
- None,
73
- {
74
- "page_with_restriction": restriction.page,
75
- },
76
- )
77
- elif len(page.private_page_options) == 0:
71
+ else:
72
+ # no current view restrictions on this page
73
+ form = PageViewRestrictionForm(
74
+ initial={"restriction_type": "none"},
75
+ private_page_options=page.private_page_options,
76
+ )
77
+
78
+ if restriction_on_ancestor:
79
+ ancestor_page_link = format_html(
80
+ '<a href="{url}">{title}</a>',
81
+ url=reverse(
82
+ "wagtailadmin_pages:edit", args=[restriction_on_ancestor.page_id]
83
+ ),
84
+ title=restriction_on_ancestor.page.specific_deferred.get_admin_display_title(),
85
+ )
86
+ inherit_from_parent_choice = (
87
+ BaseViewRestriction.NONE,
88
+ format_html(
89
+ "<span>{}</span>",
90
+ mark_safe(
91
+ _(
92
+ "Privacy is inherited from the ancestor page - %(ancestor_page)s"
93
+ )
94
+ % {"ancestor_page": ancestor_page_link}
95
+ ),
96
+ ),
97
+ )
98
+ form.fields["restriction_type"].choices = [
99
+ inherit_from_parent_choice
100
+ ] + list(form.fields["restriction_type"].choices[1:])
101
+
102
+ if len(page.private_page_options) == 0:
78
103
  return render_modal_workflow(
79
104
  request,
80
105
  "wagtailadmin/page_privacy/no_privacy.html",
81
106
  None,
82
107
  )
83
108
  else:
84
- # no restriction set at ancestor level - can set restrictions here
85
109
  return render_modal_workflow(
86
110
  request,
87
111
  "wagtailadmin/page_privacy/set_privacy.html",
@@ -34,6 +34,7 @@ class PageHistoryFilterSet(history.HistoryFilterSet):
34
34
  class PageWorkflowHistoryViewMixin:
35
35
  model = Page
36
36
  pk_url_kwarg = "page_id"
37
+ edit_url_name = "wagtailadmin_pages:edit"
37
38
 
38
39
  def dispatch(self, request, *args, **kwargs):
39
40
  if not self.object.permissions_for_user(request.user).can_edit():
@@ -44,17 +45,23 @@ class PageWorkflowHistoryViewMixin:
44
45
  return super().get_context_data(**kwargs, page=self.object)
45
46
 
46
47
 
47
- class WorkflowHistoryView(PageWorkflowHistoryViewMixin, history.WorkflowHistoryView):
48
+ class WorkflowHistoryView(
49
+ PageWorkflowHistoryViewMixin,
50
+ GenericPageBreadcrumbsMixin,
51
+ history.WorkflowHistoryView,
52
+ ):
48
53
  header_icon = "doc-empty-inverse"
49
- workflow_history_url_name = "wagtailadmin_pages:workflow_history"
50
54
  workflow_history_detail_url_name = "wagtailadmin_pages:workflow_history_detail"
51
55
 
52
56
 
53
57
  class WorkflowHistoryDetailView(
54
- PageWorkflowHistoryViewMixin, history.WorkflowHistoryDetailView
58
+ PageWorkflowHistoryViewMixin,
59
+ GenericPageBreadcrumbsMixin,
60
+ history.WorkflowHistoryDetailView,
55
61
  ):
56
- object_icon = "doc-empty-inverse"
62
+ header_icon = "doc-empty-inverse"
57
63
  workflow_history_url_name = "wagtailadmin_pages:workflow_history"
64
+ breadcrumbs_items_to_take = 2
58
65
 
59
66
 
60
67
  class PageHistoryView(GenericPageBreadcrumbsMixin, history.HistoryView):
@@ -19,7 +19,6 @@ from wagtail.admin.filters import (
19
19
  MultipleUserFilter,
20
20
  WagtailFilterSet,
21
21
  )
22
- from wagtail.admin.forms.search import SearchForm
23
22
  from wagtail.admin.ui.components import MediaContainer
24
23
  from wagtail.admin.ui.side_panels import (
25
24
  PageStatusSidePanel,
@@ -32,6 +31,7 @@ from wagtail.admin.ui.tables.pages import (
32
31
  PageStatusColumn,
33
32
  PageTable,
34
33
  PageTitleColumn,
34
+ ParentPageColumn,
35
35
  )
36
36
  from wagtail.admin.views import generic
37
37
  from wagtail.models import Page, PageLogEntry, Site, get_page_content_types
@@ -115,7 +115,7 @@ class PageFilterSet(WagtailFilterSet):
115
115
  fields = [] # only needed for filters being generated automatically
116
116
 
117
117
 
118
- class ExplorablePageFilterSet(PageFilterSet):
118
+ class GenericPageFilterSet(PageFilterSet):
119
119
  content_type = MultipleContentTypeFilter(
120
120
  label=_("Page type"),
121
121
  queryset=lambda request: get_page_content_types(include_base_page_type=False),
@@ -123,29 +123,14 @@ class ExplorablePageFilterSet(PageFilterSet):
123
123
  )
124
124
 
125
125
 
126
- class IndexView(generic.IndexView):
127
- template_name = "wagtailadmin/pages/index.html"
128
- results_template_name = "wagtailadmin/pages/index_results.html"
129
- permission_policy = page_permission_policy
130
- any_permission_required = {
131
- "add",
132
- "change",
133
- "publish",
134
- "bulk_delete",
135
- "lock",
136
- "unlock",
137
- }
126
+ class PageListingMixin:
127
+ template_name = "wagtailadmin/pages/listing.html"
138
128
  context_object_name = "pages"
139
- page_kwarg = "p"
140
- paginate_by = 50
141
129
  table_class = PageTable
142
- table_classname = "listing full-width"
143
- filterset_class = PageFilterSet
144
- index_url_name = None
145
- index_results_url_name = None
130
+ filterset_class = GenericPageFilterSet
146
131
  default_ordering = "-latest_revision_created_at"
147
132
  model = Page
148
- _show_breadcrumbs = True
133
+ is_searchable = True
149
134
 
150
135
  columns = [
151
136
  BulkActionsColumn("bulk_actions"),
@@ -155,12 +140,20 @@ class IndexView(generic.IndexView):
155
140
  sort_key="title",
156
141
  classname="title",
157
142
  ),
143
+ ParentPageColumn("parent", label=_("Parent")),
158
144
  DateColumn(
159
145
  "latest_revision_created_at",
160
146
  label=_("Updated"),
161
147
  sort_key="latest_revision_created_at",
162
148
  width="12%",
163
149
  ),
150
+ Column(
151
+ "type",
152
+ label=_("Type"),
153
+ accessor="page_type_display_name",
154
+ sort_key="content_type",
155
+ width="12%",
156
+ ),
164
157
  PageStatusColumn(
165
158
  "status",
166
159
  label=_("Status"),
@@ -169,21 +162,13 @@ class IndexView(generic.IndexView):
169
162
  ),
170
163
  ]
171
164
 
172
- def get(self, request):
173
- # Search
174
- self.query_string = None
175
- self.is_searching = False
176
- if "q" in self.request.GET:
177
- self.search_form = SearchForm(self.request.GET)
178
- if self.search_form.is_valid():
179
- self.query_string = self.search_form.cleaned_data["q"]
180
- else:
181
- self.search_form = SearchForm()
182
-
183
- if self.query_string:
184
- self.is_searching = True
165
+ @cached_property
166
+ def i18n_enabled(self):
167
+ return getattr(settings, "WAGTAIL_I18N_ENABLED", False)
185
168
 
186
- return super().get(request)
169
+ @cached_property
170
+ def show_locale_labels(self):
171
+ return self.i18n_enabled
187
172
 
188
173
  def get_valid_orderings(self):
189
174
  valid_orderings = super().get_valid_orderings()
@@ -212,17 +197,8 @@ class IndexView(generic.IndexView):
212
197
 
213
198
  return ordering
214
199
 
215
- def get_base_queryset(self):
216
- pages = self.model.objects.filter(depth__gt=1)
217
- pages = self._annotate_queryset(pages)
218
- return pages
219
-
220
- def _annotate_queryset(self, pages):
221
- pages = pages.prefetch_related("content_type", "sites_rooted_here").filter(
222
- pk__in=self.permission_policy.explorable_instances(
223
- self.request.user
224
- ).values_list("pk", flat=True)
225
- )
200
+ def annotate_queryset(self, pages):
201
+ pages = pages.prefetch_related("content_type", "sites_rooted_here")
226
202
 
227
203
  # We want specific page instances, but do not need streamfield values here
228
204
  pages = pages.defer_streamfields().specific()
@@ -230,6 +206,8 @@ class IndexView(generic.IndexView):
230
206
  # Annotate queryset with various states to be used later for performance optimisations
231
207
  if getattr(settings, "WAGTAIL_WORKFLOW_ENABLED", True):
232
208
  pages = pages.prefetch_workflow_states()
209
+ if self.i18n_enabled:
210
+ pages = pages.prefetch_related("locale").annotate_has_untranslated_locale()
233
211
 
234
212
  pages = pages.annotate_site_root_state().annotate_approved_schedule()
235
213
 
@@ -268,38 +246,56 @@ class IndexView(generic.IndexView):
268
246
  def search_queryset(self, queryset):
269
247
  if self.is_searching:
270
248
  queryset = queryset.autocomplete(
271
- self.query_string, order_by_relevance=(not self.is_explicitly_ordered)
249
+ self.search_query, order_by_relevance=(not self.is_explicitly_ordered)
272
250
  )
273
251
 
274
252
  return queryset
275
253
 
276
- def get_index_url(self):
277
- return reverse(self.index_url_name)
278
-
279
- def get_index_results_url(self):
280
- return reverse(self.index_results_url_name)
281
-
282
- def get_breadcrumbs_items(self):
283
- return self.breadcrumbs_items + [{"url": "", "label": self.get_page_title()}]
284
-
285
254
  def get_table_kwargs(self):
286
255
  kwargs = super().get_table_kwargs()
287
256
  kwargs["actions_next_url"] = self.index_url
257
+ kwargs["show_locale_labels"] = self.show_locale_labels
288
258
  return kwargs
289
259
 
290
260
  def get_context_data(self, **kwargs):
291
261
  context = super().get_context_data(**kwargs)
292
262
 
293
- context.update(
294
- {
295
- "ordering": self.ordering,
296
- "search_form": self.search_form,
297
- "is_searching": self.is_searching,
298
- }
299
- )
263
+ if any(isinstance(column, ParentPageColumn) for column in self.columns):
264
+ Page.objects.annotate_parent_page(context["object_list"])
265
+
300
266
  return context
301
267
 
302
268
 
269
+ class IndexView(PageListingMixin, generic.IndexView):
270
+ permission_policy = page_permission_policy
271
+ any_permission_required = {
272
+ "add",
273
+ "change",
274
+ "publish",
275
+ "bulk_delete",
276
+ "lock",
277
+ "unlock",
278
+ }
279
+ template_name = "wagtailadmin/pages/index.html"
280
+ results_template_name = "wagtailadmin/pages/index_results.html"
281
+ paginate_by = 50
282
+ table_classname = "listing full-width"
283
+ filterset_class = PageFilterSet
284
+
285
+ @classproperty
286
+ def columns(cls):
287
+ return [col for col in PageListingMixin.columns if col.name != "type"]
288
+
289
+ def get_base_queryset(self):
290
+ pages = self.model.objects.filter(depth__gt=1).filter(
291
+ pk__in=page_permission_policy.explorable_instances(
292
+ self.request.user
293
+ ).values_list("pk", flat=True)
294
+ )
295
+ pages = self.annotate_queryset(pages)
296
+ return pages
297
+
298
+
303
299
  class ExplorableIndexView(IndexView):
304
300
  """
305
301
  A version of the page listing where the user is presented with a view of a specified parent page;
@@ -308,24 +304,15 @@ class ExplorableIndexView(IndexView):
308
304
  """
309
305
 
310
306
  template_name = "wagtailadmin/pages/explorable_index.html"
307
+ results_template_name = "wagtailadmin/pages/explorable_index_results.html"
311
308
  index_url_name = "wagtailadmin_explore"
312
309
  index_results_url_name = "wagtailadmin_explore_results"
313
310
  page_title = _("Exploring")
314
- filterset_class = ExplorablePageFilterSet
311
+ filterset_class = GenericPageFilterSet
315
312
 
316
313
  @classproperty
317
314
  def columns(cls):
318
- columns = super().columns.copy()
319
- columns.insert(
320
- 3,
321
- Column(
322
- "type",
323
- label=_("Type"),
324
- accessor="page_type_display_name",
325
- sort_key="content_type",
326
- width="12%",
327
- ),
328
- )
315
+ columns = [col for col in PageListingMixin.columns if col.name != "parent"]
329
316
  columns.append(NavigateToChildrenColumn("navigate", width="10%"))
330
317
  return columns
331
318
 
@@ -351,7 +338,6 @@ class ExplorableIndexView(IndexView):
351
338
  self.parent_page = self.parent_page.specific
352
339
  self.scheduled_page = self.parent_page.get_scheduled_revision_as_object()
353
340
 
354
- self.i18n_enabled = getattr(settings, "WAGTAIL_I18N_ENABLED", False)
355
341
  if self.i18n_enabled and not self.parent_page.is_root():
356
342
  self.locale = self.parent_page.locale
357
343
  self.translations = self.get_translations()
@@ -367,6 +353,10 @@ class ExplorableIndexView(IndexView):
367
353
  self.is_searching or self.is_filtering
368
354
  )
369
355
 
356
+ @cached_property
357
+ def show_locale_labels(self):
358
+ return self.i18n_enabled and self.parent_page.is_root()
359
+
370
360
  def get_base_queryset(self):
371
361
  if self.is_searching or self.is_filtering:
372
362
  if self.is_searching_whole_tree:
@@ -376,7 +366,12 @@ class ExplorableIndexView(IndexView):
376
366
  else:
377
367
  pages = self.parent_page.get_children()
378
368
 
379
- pages = self._annotate_queryset(pages)
369
+ pages = pages.filter(
370
+ pk__in=page_permission_policy.explorable_instances(
371
+ self.request.user
372
+ ).values_list("pk", flat=True)
373
+ )
374
+ pages = self.annotate_queryset(pages)
380
375
  return pages
381
376
 
382
377
  def search_queryset(self, queryset):
@@ -402,7 +397,6 @@ class ExplorableIndexView(IndexView):
402
397
  kwargs = super().get_table_kwargs()
403
398
  kwargs["use_row_ordering_attributes"] = self.show_ordering_column
404
399
  kwargs["parent_page"] = self.parent_page
405
- kwargs["show_locale_labels"] = self.i18n_enabled and self.parent_page.is_root()
406
400
 
407
401
  if self.show_ordering_column:
408
402
  kwargs["caption"] = _(
@@ -464,19 +458,12 @@ class ExplorableIndexView(IndexView):
464
458
  context = super().get_context_data(**kwargs)
465
459
 
466
460
  if self.is_searching:
467
- # postprocess this page of results to annotate each result with its parent page
468
- parent_page_paths = {
469
- page.path[: -page.steplen] for page in context["object_list"]
470
- }
471
- parent_pages_by_path = {
472
- page.path: page
473
- for page in Page.objects.filter(path__in=parent_page_paths).specific()
474
- }
461
+ Page.objects.annotate_parent_page(context["object_list"])
475
462
  for page in context["object_list"]:
476
- parent_page = parent_pages_by_path.get(page.path[: -page.steplen])
477
463
  # add annotation if parent page is found and is not the currently viewed parent
478
- if parent_page and parent_page != self.parent_page:
479
- page.annotated_parent_page = parent_page
464
+ # to be used by PageTitleColumn instead of a dedicated ParentPageColumn
465
+ if page._parent_page and page._parent_page != self.parent_page:
466
+ page.annotated_parent_page = page._parent_page
480
467
 
481
468
  context.update(
482
469
  {
@@ -14,7 +14,7 @@ def view_draft(request, page_id):
14
14
  raise PermissionDenied
15
15
 
16
16
  try:
17
- preview_mode = page.default_preview_mode
17
+ preview_mode = request.GET.get("mode", page.default_preview_mode)
18
18
  except IndexError:
19
19
  raise PermissionDenied
20
20