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,23 +1,17 @@
1
- from typing import Any, Dict
1
+ from typing import Any
2
2
 
3
- from django.conf import settings
4
3
  from django.contrib.contenttypes.models import ContentType
5
4
  from django.db.models.query import QuerySet
6
5
  from django.http import Http404
6
+ from django.utils.functional import classproperty
7
7
  from django.utils.translation import gettext_lazy as _
8
8
 
9
- from wagtail.admin.forms.search import SearchForm
10
- from wagtail.admin.ui.tables import Column, DateColumn
11
9
  from wagtail.admin.ui.tables.pages import (
12
- BulkActionsColumn,
13
10
  NavigateToChildrenColumn,
14
- PageStatusColumn,
15
- PageTable,
16
- PageTitleColumn,
17
- ParentPageColumn,
18
11
  )
19
12
  from wagtail.admin.views.generic.base import BaseListingView
20
13
  from wagtail.admin.views.generic.permissions import PermissionCheckedMixin
14
+ from wagtail.admin.views.pages.listing import PageListingMixin
21
15
  from wagtail.models import Page
22
16
  from wagtail.permissions import page_permission_policy
23
17
  from wagtail.search.query import MATCH_ALL
@@ -49,7 +43,7 @@ def page_filter_search(q, pages, all_pages=None, ordering=None):
49
43
  return pages, all_pages
50
44
 
51
45
 
52
- class BaseSearchView(PermissionCheckedMixin, BaseListingView):
46
+ class SearchView(PageListingMixin, PermissionCheckedMixin, BaseListingView):
53
47
  permission_policy = page_permission_policy
54
48
  any_permission_required = {
55
49
  "add",
@@ -60,43 +54,24 @@ class BaseSearchView(PermissionCheckedMixin, BaseListingView):
60
54
  "unlock",
61
55
  }
62
56
  paginate_by = 20
63
- page_kwarg = "p"
64
- context_object_name = "pages"
65
- table_class = PageTable
57
+ page_title = _("Search")
58
+ header_icon = "search"
66
59
  index_url_name = "wagtailadmin_pages:search"
60
+ index_results_url_name = "wagtailadmin_pages:search_results"
61
+ # We override get_queryset here that has a custom search implementation
62
+ is_searchable = True
63
+ # This view has its own filtering mechanism that doesn't use django-filter
64
+ filterset_class = None
65
+ template_name = "wagtailadmin/pages/search.html"
66
+ results_template_name = "wagtailadmin/pages/search_results.html"
67
67
 
68
- columns = [
69
- BulkActionsColumn("bulk_actions"),
70
- PageTitleColumn(
71
- "title",
72
- classname="title",
73
- label=_("Title"),
74
- sort_key="title",
75
- ),
76
- ParentPageColumn("parent", label=_("Parent")),
77
- DateColumn(
78
- "latest_revision_created_at",
79
- label=_("Updated"),
80
- sort_key="latest_revision_created_at",
81
- width="12%",
82
- ),
83
- Column(
84
- "type",
85
- label=_("Type"),
86
- accessor="page_type_display_name",
87
- width="12%",
88
- ),
89
- PageStatusColumn(
90
- "status",
91
- label=_("Status"),
92
- sort_key="live",
93
- width="12%",
94
- ),
95
- NavigateToChildrenColumn("navigate", width="10%"),
96
- ]
68
+ @classproperty
69
+ def columns(cls):
70
+ columns = PageListingMixin.columns.copy()
71
+ columns.append(NavigateToChildrenColumn("navigate", width="10%"))
72
+ return columns
97
73
 
98
74
  def get(self, request):
99
- self.show_locale_labels = getattr(settings, "WAGTAIL_I18N_ENABLED", False)
100
75
  self.content_types = []
101
76
  self.ordering = None
102
77
 
@@ -126,13 +101,13 @@ class BaseSearchView(PermissionCheckedMixin, BaseListingView):
126
101
  else:
127
102
  self.selected_content_type = None
128
103
 
129
- self.q = self.request.GET.get("q", "")
130
-
131
104
  return super().get(request)
132
105
 
133
106
  def get_queryset(self) -> QuerySet[Any]:
134
- pages = self.all_pages = (
135
- Page.objects.all().prefetch_related("content_type").specific()
107
+ pages = self.all_pages = Page.objects.all().filter(
108
+ pk__in=page_permission_policy.explorable_instances(
109
+ self.request.user
110
+ ).values_list("pk", flat=True)
136
111
  )
137
112
  if self.show_locale_labels:
138
113
  pages = pages.select_related("locale")
@@ -143,15 +118,17 @@ class BaseSearchView(PermissionCheckedMixin, BaseListingView):
143
118
  if self.selected_content_type:
144
119
  pages = pages.filter(content_type=self.selected_content_type)
145
120
 
121
+ pages = self.annotate_queryset(pages)
122
+
146
123
  # Parse query and filter
147
124
  pages, self.all_pages = page_filter_search(
148
- self.q, pages, self.all_pages, self.ordering
125
+ self.search_query, pages, self.all_pages, self.ordering
149
126
  )
150
127
 
151
128
  # Facets
152
129
  if pages.supports_facet:
153
130
  self.content_types = [
154
- (ContentType.objects.get(id=content_type_id), count)
131
+ (ContentType.objects.get_for_id(content_type_id), count)
155
132
  for content_type_id, count in self.all_pages.facet(
156
133
  "content_type_id"
157
134
  ).items()
@@ -159,34 +136,13 @@ class BaseSearchView(PermissionCheckedMixin, BaseListingView):
159
136
 
160
137
  return pages
161
138
 
162
- def get_table_kwargs(self):
163
- kwargs = super().get_table_kwargs()
164
- kwargs["show_locale_labels"] = self.show_locale_labels
165
- kwargs["actions_next_url"] = self.get_index_url()
166
- return kwargs
167
-
168
- def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
139
+ def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
169
140
  context = super().get_context_data(**kwargs)
170
141
  context.update(
171
142
  {
172
143
  "all_pages": self.all_pages,
173
- "query_string": self.q,
174
144
  "content_types": self.content_types,
175
145
  "selected_content_type": self.selected_content_type,
176
- "ordering": self.ordering,
177
146
  }
178
147
  )
179
148
  return context
180
-
181
-
182
- class SearchView(BaseSearchView):
183
- template_name = "wagtailadmin/pages/search.html"
184
-
185
- def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
186
- context = super().get_context_data(**kwargs)
187
- context["search_form"] = SearchForm(self.request.GET)
188
- return context
189
-
190
-
191
- class SearchResultsView(BaseSearchView):
192
- template_name = "wagtailadmin/pages/search_results.html"
@@ -1,41 +1,45 @@
1
- from typing import Any, Dict
1
+ from typing import Any
2
2
 
3
3
  from django.contrib.contenttypes.models import ContentType
4
4
  from django.core.exceptions import PermissionDenied
5
5
  from django.http import Http404
6
6
  from django.urls import reverse
7
+ from django.utils.functional import cached_property, classproperty
8
+ from django.utils.text import capfirst
9
+ from django.utils.translation import gettext
7
10
  from django.utils.translation import gettext_lazy as _
8
11
 
9
- from wagtail.admin.ui.tables import Column, DateColumn
10
- from wagtail.admin.ui.tables.pages import (
11
- PageStatusColumn,
12
- PageTable,
13
- PageTitleColumn,
14
- ParentPageColumn,
15
- )
16
12
  from wagtail.admin.views import generic
17
13
  from wagtail.admin.views.generic.base import BaseListingView
14
+ from wagtail.admin.views.generic.permissions import PermissionCheckedMixin
15
+ from wagtail.admin.views.pages.listing import PageFilterSet, PageListingMixin
18
16
  from wagtail.admin.views.pages.utils import (
19
17
  GenericPageBreadcrumbsMixin,
20
18
  )
21
19
  from wagtail.models import Page
20
+ from wagtail.permissions import page_permission_policy
22
21
 
23
22
 
24
- class ContentTypeUseView(BaseListingView):
25
- results_template_name = "wagtailadmin/pages/usage_results.html"
23
+ class ContentTypeUseView(PageListingMixin, PermissionCheckedMixin, BaseListingView):
24
+ permission_policy = page_permission_policy
25
+ any_permission_required = {
26
+ "add",
27
+ "change",
28
+ "publish",
29
+ "bulk_delete",
30
+ "lock",
31
+ "unlock",
32
+ }
33
+ index_url_name = "wagtailadmin_pages:type_use"
34
+ index_results_url_name = "wagtailadmin_pages:type_use_results"
26
35
  page_title = _("Pages using")
27
36
  header_icon = "doc-empty-inverse"
28
- page_kwarg = "p"
29
37
  paginate_by = 50
30
- columns = [
31
- PageTitleColumn("title", classname="title", label=_("Title")),
32
- ParentPageColumn("parent", label=_("Parent")),
33
- DateColumn("latest_revision_created_at", label=_("Updated"), width="12%"),
34
- Column("type", label=_("Type"), accessor="page_type_display_name", width="12%"),
35
- PageStatusColumn("status", label=_("Status"), width="12%"),
36
- ]
37
- table_class = PageTable
38
- table_classname = "listing"
38
+ filterset_class = PageFilterSet
39
+
40
+ @classproperty
41
+ def columns(cls):
42
+ return [col for col in PageListingMixin.columns if col.name != "type"]
39
43
 
40
44
  def get(self, request, *, content_type_app_name, content_type_model_name):
41
45
  try:
@@ -56,19 +60,54 @@ class ContentTypeUseView(BaseListingView):
56
60
  def get_page_subtitle(self):
57
61
  return self.page_class.get_verbose_name()
58
62
 
59
- def get_queryset(self):
60
- return self.page_class.objects.all().specific(defer=True)
63
+ @cached_property
64
+ def verbose_name_plural(self):
65
+ return self.page_class._meta.verbose_name_plural
66
+
67
+ def get_base_queryset(self):
68
+ queryset = self.page_class._default_manager.all().filter(
69
+ pk__in=self.permission_policy.explorable_instances(
70
+ self.request.user
71
+ ).values_list("pk", flat=True)
72
+ )
73
+ return self.annotate_queryset(queryset)
61
74
 
62
75
  def get_index_url(self):
63
76
  return reverse(
64
- "wagtailadmin_pages:type_use",
77
+ self.index_url_name,
78
+ args=[
79
+ self.kwargs["content_type_app_name"],
80
+ self.kwargs["content_type_model_name"],
81
+ ],
82
+ )
83
+
84
+ def get_index_results_url(self):
85
+ return reverse(
86
+ self.index_results_url_name,
65
87
  args=[
66
88
  self.kwargs["content_type_app_name"],
67
89
  self.kwargs["content_type_model_name"],
68
90
  ],
69
91
  )
70
92
 
71
- def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
93
+ def get_breadcrumbs_items(self):
94
+ return self.breadcrumbs_items + [
95
+ # Initially, this page was only accessible via the "choose page type"
96
+ # step of the page creation flow. However, that view might be skipped
97
+ # if there's only one valid page type. Since then, we've introduced
98
+ # the "page types usage" report, which always provides a link to this
99
+ # view for all page types. Use that as the parent link.
100
+ {
101
+ "url": reverse("wagtailadmin_reports:page_types_usage"),
102
+ "label": gettext("Page types usage"),
103
+ },
104
+ {
105
+ "url": self.get_index_url(),
106
+ "label": capfirst(self.page_class._meta.verbose_name_plural),
107
+ },
108
+ ]
109
+
110
+ def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
72
111
  context = super().get_context_data(**kwargs)
73
112
  context["page_class"] = self.page_class
74
113
  return context
@@ -66,6 +66,7 @@ class GenericPageBreadcrumbsMixin:
66
66
  # which in most cases is the final item that links to the current view.
67
67
  # However, this can be customised in the case of generic views that are
68
68
  # nested inside another generic view.
69
- return self.breadcrumbs_items + [
70
- super().get_breadcrumbs_items()[-self.breadcrumbs_items_to_take]
71
- ]
69
+ return (
70
+ self.breadcrumbs_items
71
+ + super().get_breadcrumbs_items()[-self.breadcrumbs_items_to_take :]
72
+ )
@@ -13,12 +13,6 @@ class ReportView(SpreadsheetExportMixin, PermissionCheckedMixin, BaseListingView
13
13
  results_template_name = "wagtailadmin/reports/base_report_results.html"
14
14
  title = ""
15
15
  paginate_by = 50
16
- _show_breadcrumbs = True
17
-
18
- def get_breadcrumbs_items(self):
19
- return super().get_breadcrumbs_items() + [
20
- {"url": "", "label": self.get_page_title()}
21
- ]
22
16
 
23
17
  def get_page_title(self):
24
18
  if self.page_title:
@@ -4,7 +4,7 @@ from django.contrib.contenttypes.models import ContentType
4
4
  from django.core.exceptions import PermissionDenied
5
5
  from django.core.paginator import Paginator
6
6
  from django.db import transaction
7
- from django.db.models import Count, OuterRef, Prefetch
7
+ from django.db.models import Count, Prefetch
8
8
  from django.db.models.functions import Lower
9
9
  from django.http import Http404, HttpResponseBadRequest
10
10
  from django.shortcuts import get_object_or_404, redirect, render
@@ -20,7 +20,10 @@ from django.views.generic import TemplateView
20
20
 
21
21
  from wagtail.admin import messages
22
22
  from wagtail.admin.auth import PermissionPolicyChecker
23
- from wagtail.admin.filters import MultipleContentTypeFilter, WagtailFilterSet
23
+ from wagtail.admin.filters import (
24
+ MultipleContentTypeFilter,
25
+ WagtailFilterSet,
26
+ )
24
27
  from wagtail.admin.forms.workflows import (
25
28
  TaskChooserSearchForm,
26
29
  WorkflowContentTypeForm,
@@ -31,13 +34,15 @@ from wagtail.admin.forms.workflows import (
31
34
  from wagtail.admin.modal_workflow import render_modal_workflow
32
35
  from wagtail.admin.ui.tables import BaseColumn, Column, TitleColumn
33
36
  from wagtail.admin.views.generic import CreateView, DeleteView, EditView, IndexView
37
+ from wagtail.admin.views.generic.base import BaseListingView
38
+ from wagtail.admin.views.generic.permissions import PermissionCheckedMixin
39
+ from wagtail.admin.views.pages.listing import PageListingMixin
34
40
  from wagtail.coreutils import resolve_model_string
35
41
  from wagtail.models import (
36
42
  Page,
37
43
  Task,
38
44
  TaskState,
39
45
  Workflow,
40
- WorkflowContentType,
41
46
  WorkflowState,
42
47
  WorkflowTask,
43
48
  )
@@ -138,7 +143,6 @@ class Index(IndexView):
138
143
  default_ordering = "name"
139
144
  search_fields = ["name"]
140
145
  filterset_class = WorkflowFilterSet
141
- _show_breadcrumbs = True
142
146
  paginate_by = 20
143
147
 
144
148
  def show_disabled(self):
@@ -146,10 +150,7 @@ class Index(IndexView):
146
150
 
147
151
  def get_base_queryset(self):
148
152
  queryset = super().get_base_queryset()
149
- content_types = WorkflowContentType.objects.filter(
150
- workflow=OuterRef("pk")
151
- ).values_list("pk", flat=True)
152
- queryset = queryset.annotate(content_types=Count(content_types))
153
+ queryset = queryset.annotate(content_types=Count("workflow_content_types"))
153
154
  return queryset.prefetch_related(
154
155
  "workflow_pages",
155
156
  "workflow_pages__page",
@@ -259,6 +260,7 @@ class Edit(EditView):
259
260
  enable_item_label = _("Enable")
260
261
  enable_url_name = "wagtailadmin_workflows:enable"
261
262
  header_icon = "tasks"
263
+ header_more_buttons = []
262
264
  edit_handler = None
263
265
  MAX_PAGES = 5
264
266
  _show_breadcrumbs = True
@@ -393,24 +395,64 @@ class Disable(DeleteView):
393
395
  self.object.deactivate(user=self.request.user)
394
396
 
395
397
 
396
- def usage(request, pk):
397
- workflow = get_object_or_404(Workflow, id=pk)
398
+ class WorkflowUsageView(PageListingMixin, PermissionCheckedMixin, BaseListingView):
399
+ permission_policy = workflow_permission_policy
400
+ any_permission_required = {"add", "change", "delete", "view"}
401
+ pk_url_kwarg = "pk"
402
+ index_url_name = "wagtailadmin_workflows:usage"
403
+ index_results_url_name = "wagtailadmin_workflows:usage_results"
404
+ paginate_by = 20
405
+ header_icon = "tasks"
406
+ page_title = _("Usage")
398
407
 
399
- editable_pages = page_permission_policy.instances_user_has_permission_for(
400
- request.user, "change"
401
- )
402
- pages = workflow.all_pages() & editable_pages
403
- paginator = Paginator(pages, per_page=10)
404
- pages = paginator.get_page(request.GET.get("p"))
408
+ def dispatch(self, request, *args, **kwargs):
409
+ self.object = self.get_object()
405
410
 
406
- return render(
407
- request,
408
- "wagtailadmin/workflows/usage.html",
409
- {
410
- "workflow": workflow,
411
- "used_by": pages,
412
- },
413
- )
411
+ # We set workflow_permission_policy as the main permission policy for this view
412
+ # for consistency with the other workflow views. However, since we are listing
413
+ # page objects in this view, we want to ensure the user has a page permission.
414
+ if not page_permission_policy.user_has_any_permission(
415
+ request.user,
416
+ {"add", "change", "publish", "bulk_delete", "lock", "unlock"},
417
+ ):
418
+ raise PermissionDenied
419
+
420
+ return super().dispatch(request, *args, **kwargs)
421
+
422
+ def get_page_subtitle(self):
423
+ return self.object.name
424
+
425
+ def get_breadcrumbs_items(self):
426
+ title = self.get_page_title()
427
+ subtitle = self.get_page_subtitle()
428
+ return self.breadcrumbs_items + [
429
+ {
430
+ "url": reverse("wagtailadmin_workflows:index"),
431
+ "label": capfirst(Workflow._meta.verbose_name_plural),
432
+ },
433
+ {
434
+ "url": reverse("wagtailadmin_workflows:edit", args=(self.object.pk,)),
435
+ "label": subtitle,
436
+ },
437
+ {"url": "", "label": title, "sublabel": subtitle},
438
+ ]
439
+
440
+ def get_index_url(self):
441
+ return reverse(self.index_url_name, args=(self.object.pk,))
442
+
443
+ def get_index_results_url(self):
444
+ return reverse(self.index_results_url_name, args=(self.object.pk,))
445
+
446
+ def get_object(self):
447
+ return get_object_or_404(Workflow, id=self.kwargs.get(self.pk_url_kwarg))
448
+
449
+ def get_base_queryset(self):
450
+ editable_pages = page_permission_policy.instances_user_has_permission_for(
451
+ self.request.user, "change"
452
+ ).filter(depth__gt=1)
453
+ pages = self.object.all_pages() & editable_pages
454
+ pages = self.annotate_queryset(pages)
455
+ return pages
414
456
 
415
457
 
416
458
  @require_POST
@@ -529,7 +571,6 @@ class TaskIndex(IndexView):
529
571
  default_ordering = "name"
530
572
  search_fields = ["name"]
531
573
  filterset_class = TaskFilterSet
532
- _show_breadcrumbs = True
533
574
  paginate_by = 50
534
575
 
535
576
  def show_disabled(self):
@@ -662,6 +703,7 @@ class EditTask(EditView):
662
703
  enable_item_label = _("Enable")
663
704
  enable_url_name = "wagtailadmin_workflows:enable_task"
664
705
  header_icon = "thumbtack"
706
+ header_more_buttons = []
665
707
  _show_breadcrumbs = True
666
708
 
667
709
  @cached_property
@@ -8,6 +8,7 @@ from django.forms.models import modelform_factory
8
8
  from django.shortcuts import redirect
9
9
  from django.urls import path
10
10
  from django.utils.functional import cached_property
11
+ from django.utils.text import capfirst
11
12
 
12
13
  from wagtail import hooks
13
14
  from wagtail.admin.admin_url_finder import (
@@ -468,7 +469,7 @@ class ModelViewSet(ViewSet):
468
469
  subclass of `django_filters.FilterSet <https://django-filter.readthedocs.io/en/stable/ref/filterset.html>`_.
469
470
  This will be passed to the ``filterset_class`` attribute of the index view.
470
471
  """
471
- return self.index_view_class.filterset_class
472
+ return self.UNDEFINED
472
473
 
473
474
  @cached_property
474
475
  def search_fields(self):
@@ -514,7 +515,7 @@ class ModelViewSet(ViewSet):
514
515
 
515
516
  @cached_property
516
517
  def menu_label(self):
517
- return self.model_opts.verbose_name_plural.title()
518
+ return capfirst(self.model_opts.verbose_name_plural)
518
519
 
519
520
  @cached_property
520
521
  def menu_item_class(self):
@@ -696,7 +697,7 @@ class ModelViewSetGroup(ViewSetGroup):
696
697
  def get_app_label_from_subitems(self):
697
698
  for instance in self.registerables:
698
699
  if app_label := getattr(instance, "app_label", ""):
699
- return app_label.title()
700
+ return capfirst(app_label)
700
701
  return ""
701
702
 
702
703
  @cached_property
@@ -7,6 +7,7 @@ from django.template.loader import render_to_string
7
7
  from django.urls import reverse
8
8
  from django.utils.functional import cached_property
9
9
  from django.utils.safestring import mark_safe
10
+ from django.utils.text import capfirst
10
11
  from django.utils.translation import gettext_lazy as _
11
12
 
12
13
  from wagtail.admin.admin_url_finder import AdminURLFinder
@@ -250,7 +251,7 @@ class AdminPageChooser(BaseChooser):
250
251
  cleaned_target_models = [Page]
251
252
 
252
253
  if len(cleaned_target_models) == 1 and cleaned_target_models[0] is not Page:
253
- model_name = cleaned_target_models[0]._meta.verbose_name.title()
254
+ model_name = capfirst(cleaned_target_models[0]._meta.verbose_name)
254
255
  self.choose_one_text += " (" + model_name + ")"
255
256
 
256
257
  self.user_perms = user_perms
@@ -1822,7 +1822,7 @@ class TestPageDetailWithStreamField(TestCase):
1822
1822
  self.assertEqual(content["body"][0]["value"], "foo")
1823
1823
  self.assertTrue(content["body"][0]["id"])
1824
1824
 
1825
- def test_image_block(self):
1825
+ def test_image_chooser_block(self):
1826
1826
  stream_page = self.make_stream_page('[{"type": "image", "value": 1}]')
1827
1827
 
1828
1828
  response_url = reverse("wagtailapi_v2:pages:detail", args=(stream_page.id,))
@@ -1833,7 +1833,7 @@ class TestPageDetailWithStreamField(TestCase):
1833
1833
  self.assertEqual(content["body"][0]["type"], "image")
1834
1834
  self.assertEqual(content["body"][0]["value"], 1)
1835
1835
 
1836
- def test_image_block_with_custom_get_api_representation(self):
1836
+ def test_image_chooser_block_with_custom_get_api_representation(self):
1837
1837
  stream_page = self.make_stream_page('[{"type": "image", "value": 1}]')
1838
1838
 
1839
1839
  response_url = "{}?extended=1".format(
@@ -1848,6 +1848,19 @@ class TestPageDetailWithStreamField(TestCase):
1848
1848
  content["body"][0]["value"], {"id": 1, "title": "A missing image"}
1849
1849
  )
1850
1850
 
1851
+ def test_image_block(self):
1852
+ stream_page = self.make_stream_page(
1853
+ '[{"type": "image_with_alt", "value": {"image": 1, "alt_text": "Some alt text", "decorative": false}}]'
1854
+ )
1855
+
1856
+ response_url = reverse("wagtailapi_v2:pages:detail", args=(stream_page.id,))
1857
+ response = self.client.get(response_url)
1858
+ content = json.loads(response.content.decode("utf-8"))
1859
+
1860
+ self.assertEqual(content["body"][0]["type"], "image_with_alt")
1861
+ self.assertEqual(content["body"][0]["value"]["image"], 1)
1862
+ self.assertEqual(content["body"][0]["value"]["alt_text"], "Some alt text")
1863
+
1851
1864
 
1852
1865
  @override_settings(
1853
1866
  WAGTAILFRONTENDCACHE={
@@ -1,3 +1,4 @@
1
+ import copy
1
2
  import datetime
2
3
  from decimal import Decimal
3
4
 
@@ -817,11 +818,22 @@ class ChooserBlock(FieldBlock):
817
818
  """Return the model instances for the given list of primary keys.
818
819
 
819
820
  The instances must be returned in the same order as the values and keep None values.
821
+ If the same ID appears multiple times, a distinct object instance is created for each one.
820
822
  """
821
823
  objects = self.model_class.objects.in_bulk(values)
822
- return [
823
- objects.get(id) for id in values
824
- ] # Keeps the ordering the same as in values.
824
+ seen_ids = set()
825
+ result = []
826
+
827
+ for id in values:
828
+ obj = objects.get(id)
829
+ if obj is not None and id in seen_ids:
830
+ # this object is already in the result list, so we need to make a copy
831
+ obj = copy.copy(obj)
832
+
833
+ result.append(obj)
834
+ seen_ids.add(id)
835
+
836
+ return result
825
837
 
826
838
  def get_prep_value(self, value):
827
839
  # the native value (a model instance or None) should serialise to a PK or None
@@ -33,6 +33,9 @@ class StaticBlock(Block):
33
33
  def normalize(self, value):
34
34
  return None
35
35
 
36
+ def render_basic(self, value, context=None):
37
+ return ""
38
+
36
39
  class Meta:
37
40
  admin_text = None
38
41
  default = None
@@ -6,13 +6,14 @@
6
6
  # Adam Hughes <adamhughes31@gmail.com>, 2017
7
7
  # Philip Crisp, 2022
8
8
  # Philip Crisp, 2022
9
+ # Philip Lindsay-Crisp, 2024
9
10
  msgid ""
10
11
  msgstr ""
11
12
  "Project-Id-Version: Wagtail\n"
12
13
  "Report-Msgid-Bugs-To: \n"
13
14
  "POT-Creation-Date: 2024-08-07 10:06+0100\n"
14
15
  "PO-Revision-Date: 2014-09-11 15:42+0000\n"
15
- "Last-Translator: Philip Crisp, 2022\n"
16
+ "Last-Translator: Philip Lindsay-Crisp, 2024\n"
16
17
  "Language-Team: Welsh (http://app.transifex.com/torchbox/wagtail/language/"
17
18
  "cy/)\n"
18
19
  "MIME-Version: 1.0\n"
@@ -106,9 +107,22 @@ msgstr "ofynnol"
106
107
  msgid "choices"
107
108
  msgstr "dewisiadau"
108
109
 
110
+ msgid ""
111
+ "Comma or new line separated list of choices. Only applicable in checkboxes, "
112
+ "radio and dropdown."
113
+ msgstr ""
114
+ "Coma neu restr o ddewisiadau wedi'u gwahanu â llinell newydd. Dim ond yn "
115
+ "berthnasol mewn blychau ticio, radio a'r gwymplen."
116
+
109
117
  msgid "default value"
110
118
  msgstr "gwerth rhagosodedig"
111
119
 
120
+ msgid ""
121
+ "Default value. Comma or new line separated values supported for checkboxes."
122
+ msgstr ""
123
+ "Gwerth diofyn. Cefnogir atalnod neu werthoedd gwahanu llinell newydd ar "
124
+ "gyfer blychau ticio."
125
+
112
126
  msgid "help text"
113
127
  msgstr "testun cymorth"
114
128
 
@@ -148,6 +162,17 @@ msgstr "Dileu data'r ffurflen%(title)s"
148
162
  msgid "Delete form data"
149
163
  msgstr "Dileu data'r ffurflen"
150
164
 
165
+ msgid "Are you sure you want to delete this form submission?"
166
+ msgid_plural "Are you sure you want to delete these form submissions?"
167
+ msgstr[0] ""
168
+ "Ydych chi'n siŵr eich fod chi am ddileu cyflwyniadau'r ffurflen hon?"
169
+ msgstr[1] ""
170
+ "Ydych chi'n siŵr eich fod chi am ddileu'r cyflwyniadau ffurflen hyn?"
171
+ msgstr[2] ""
172
+ "Ydych chi'n siŵr eich fod chi am ddileu'r cyflwyniadau ffurflen hyn?"
173
+ msgstr[3] ""
174
+ "Ydych chi'n siŵr eich fod chi am ddileu'r cyflwyniadau ffurflen hyn?"
175
+
151
176
  msgid "Delete"
152
177
  msgstr "Dileu"
153
178
 
@@ -187,3 +212,6 @@ msgstr[0] "Mae un cyflwyniad wedi'u dileu."
187
212
  msgstr[1] "Mae %(count)d cyflwyniad wedi'u dileu."
188
213
  msgstr[2] "Mae %(count)d cyflwyniad wedi'u dileu."
189
214
  msgstr[3] "Mae %(count)d cyflwyniad wedi'u dileu."
215
+
216
+ msgid "Form data"
217
+ msgstr "Data ffurflen"