wagtail 6.0.1__py3-none-any.whl → 6.1rc1__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 (512) hide show
  1. wagtail/__init__.py +1 -1
  2. wagtail/admin/checks.py +51 -0
  3. wagtail/admin/compare.py +1 -1
  4. wagtail/admin/filters.py +70 -1
  5. wagtail/admin/forms/account.py +1 -1
  6. wagtail/admin/forms/collections.py +15 -0
  7. wagtail/admin/forms/pages.py +49 -0
  8. wagtail/admin/locale/ca/LC_MESSAGES/django.mo +0 -0
  9. wagtail/admin/locale/ca/LC_MESSAGES/django.po +122 -0
  10. wagtail/admin/locale/de/LC_MESSAGES/django.mo +0 -0
  11. wagtail/admin/locale/de/LC_MESSAGES/django.po +5 -5
  12. wagtail/admin/locale/en/LC_MESSAGES/django.po +474 -385
  13. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +3 -3
  14. wagtail/admin/locale/es/LC_MESSAGES/django.mo +0 -0
  15. wagtail/admin/locale/es/LC_MESSAGES/django.po +6 -6
  16. wagtail/admin/locale/fr/LC_MESSAGES/django.mo +0 -0
  17. wagtail/admin/locale/fr/LC_MESSAGES/django.po +70 -3
  18. wagtail/admin/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  19. wagtail/admin/locale/he_IL/LC_MESSAGES/django.po +2 -6
  20. wagtail/admin/locale/he_IL/LC_MESSAGES/djangojs.mo +0 -0
  21. wagtail/admin/locale/he_IL/LC_MESSAGES/djangojs.po +2 -2
  22. wagtail/admin/locale/hr_HR/LC_MESSAGES/django.mo +0 -0
  23. wagtail/admin/locale/hr_HR/LC_MESSAGES/django.po +4 -0
  24. wagtail/admin/locale/hu/LC_MESSAGES/django.mo +0 -0
  25. wagtail/admin/locale/hu/LC_MESSAGES/django.po +142 -2
  26. wagtail/admin/locale/it/LC_MESSAGES/django.mo +0 -0
  27. wagtail/admin/locale/it/LC_MESSAGES/django.po +80 -8
  28. wagtail/admin/locale/it/LC_MESSAGES/djangojs.mo +0 -0
  29. wagtail/admin/locale/it/LC_MESSAGES/djangojs.po +14 -2
  30. wagtail/admin/locale/lv/LC_MESSAGES/django.mo +0 -0
  31. wagtail/admin/locale/lv/LC_MESSAGES/django.po +154 -1
  32. wagtail/admin/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  33. wagtail/admin/locale/pt_PT/LC_MESSAGES/django.po +73 -2
  34. wagtail/admin/locale/ro/LC_MESSAGES/django.mo +0 -0
  35. wagtail/admin/locale/ro/LC_MESSAGES/django.po +3 -3
  36. wagtail/admin/locale/sl/LC_MESSAGES/django.mo +0 -0
  37. wagtail/admin/locale/sl/LC_MESSAGES/django.po +145 -2
  38. wagtail/admin/locale/sv/LC_MESSAGES/django.mo +0 -0
  39. wagtail/admin/locale/sv/LC_MESSAGES/django.po +77 -3
  40. wagtail/admin/locale/zh_Hant/LC_MESSAGES/django.mo +0 -0
  41. wagtail/admin/locale/zh_Hant/LC_MESSAGES/django.po +17 -1
  42. wagtail/admin/panels/comment_panel.py +1 -1
  43. wagtail/admin/panels/field_panel.py +1 -1
  44. wagtail/admin/rich_text/converters/editor_html.py +3 -1
  45. wagtail/admin/rich_text/editors/draftail/__init__.py +28 -2
  46. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  47. wagtail/admin/static/wagtailadmin/css/panels/draftail.css +1 -1
  48. wagtail/admin/static/wagtailadmin/images/favicon.ico +0 -0
  49. wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
  50. wagtail/admin/static/wagtailadmin/js/chooser-modal.js +1 -1
  51. wagtail/admin/static/wagtailadmin/js/chooser-widget-telepath.js +1 -1
  52. wagtail/admin/static/wagtailadmin/js/chooser-widget.js +1 -1
  53. wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
  54. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  55. wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +1 -1
  56. wagtail/admin/static/wagtailadmin/js/date-time-chooser.js +1 -1
  57. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  58. wagtail/admin/static/wagtailadmin/js/expanding-formset.js +1 -1
  59. wagtail/admin/static/wagtailadmin/js/filtered-select.js +1 -1
  60. wagtail/admin/static/wagtailadmin/js/modal-workflow.js +1 -1
  61. wagtail/admin/static/wagtailadmin/js/page-chooser-modal.js +1 -1
  62. wagtail/admin/static/wagtailadmin/js/page-chooser-telepath.js +1 -1
  63. wagtail/admin/static/wagtailadmin/js/page-chooser.js +1 -1
  64. wagtail/admin/static/wagtailadmin/js/preview-panel.js +1 -1
  65. wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
  66. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  67. wagtail/admin/static/wagtailadmin/js/task-chooser-modal.js +1 -1
  68. wagtail/admin/static/wagtailadmin/js/task-chooser.js +1 -1
  69. wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
  70. wagtail/admin/static/wagtailadmin/js/telepath/telepath.js +1 -1
  71. wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
  72. wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
  73. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  74. wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +4 -4
  75. wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
  76. wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
  77. wagtail/admin/staticfiles.py +1 -0
  78. wagtail/admin/templates/wagtailadmin/admin_base.html +1 -0
  79. wagtail/admin/templates/wagtailadmin/base.html +1 -0
  80. wagtail/admin/templates/wagtailadmin/collection_privacy/set_privacy.html +3 -1
  81. wagtail/admin/templates/wagtailadmin/collections/edit.html +0 -1
  82. wagtail/admin/templates/wagtailadmin/collections/index_results.html +10 -0
  83. wagtail/admin/templates/wagtailadmin/generic/base.html +1 -9
  84. wagtail/admin/templates/wagtailadmin/generic/form.html +4 -2
  85. wagtail/admin/templates/wagtailadmin/generic/history/action_cell.html +27 -0
  86. wagtail/admin/templates/wagtailadmin/generic/index_results.html +8 -0
  87. wagtail/admin/templates/wagtailadmin/home/workflow_objects_to_moderate.html +3 -4
  88. wagtail/admin/templates/wagtailadmin/icons/keyboard.svg +1 -0
  89. wagtail/admin/templates/wagtailadmin/page_privacy/set_privacy.html +3 -1
  90. wagtail/admin/templates/wagtailadmin/pages/_editor_js.html +0 -15
  91. wagtail/admin/templates/wagtailadmin/pages/action_menu/save_draft.html +3 -1
  92. wagtail/admin/templates/wagtailadmin/pages/choose_parent.html +17 -0
  93. wagtail/admin/templates/wagtailadmin/pages/explorable_index.html +8 -0
  94. wagtail/admin/templates/wagtailadmin/pages/history.html +1 -61
  95. wagtail/admin/templates/wagtailadmin/pages/index.html +1 -5
  96. wagtail/admin/templates/wagtailadmin/pages/listing/_locked_indicator.html +2 -2
  97. wagtail/admin/templates/wagtailadmin/pages/listing/_page_title_column_header.html +25 -27
  98. wagtail/admin/templates/wagtailadmin/pages/page_listing_header.html +2 -1
  99. wagtail/admin/templates/wagtailadmin/panels/multi_field_panel_child.html +1 -1
  100. wagtail/admin/templates/wagtailadmin/panels/publishing/schedule_publishing_panel.html +3 -1
  101. wagtail/admin/templates/wagtailadmin/panels/tabbed_interface.html +1 -1
  102. wagtail/admin/templates/wagtailadmin/shared/active_filters.html +2 -1
  103. wagtail/admin/templates/wagtailadmin/shared/breadcrumbs.html +8 -0
  104. wagtail/admin/templates/wagtailadmin/shared/forms/single_checkbox.html +1 -1
  105. wagtail/admin/templates/wagtailadmin/shared/headers/page_edit_header.html +1 -1
  106. wagtail/admin/templates/wagtailadmin/shared/headers/slim_header.html +21 -9
  107. wagtail/admin/templates/wagtailadmin/shared/human_readable_date.html +1 -1
  108. wagtail/admin/templates/wagtailadmin/shared/keyboard_shortcuts_dialog.html +29 -0
  109. wagtail/admin/templates/wagtailadmin/shared/side_panel_toggle.html +2 -1
  110. wagtail/admin/templates/wagtailadmin/skeleton.html +2 -1
  111. wagtail/admin/templates/wagtailadmin/tables/related_objects_cell.html +9 -0
  112. wagtail/admin/templates/wagtailadmin/tables/title_cell.html +9 -7
  113. wagtail/admin/templates/wagtailadmin/widgets/draftail_rich_text_area.html +1 -1
  114. wagtail/admin/templates/wagtailadmin/workflows/create.html +6 -23
  115. wagtail/admin/templates/wagtailadmin/workflows/create_task.html +6 -15
  116. wagtail/admin/templates/wagtailadmin/workflows/edit.html +6 -23
  117. wagtail/admin/templates/wagtailadmin/workflows/edit_task.html +6 -13
  118. wagtail/admin/templates/wagtailadmin/workflows/includes/task_usage_cell.html +4 -4
  119. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_tasks_cell.html +18 -0
  120. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_title_cell.html +7 -0
  121. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_used_by_cell.html +25 -0
  122. wagtail/admin/templates/wagtailadmin/workflows/index.html +0 -99
  123. wagtail/admin/templates/wagtailadmin/workflows/index_results.html +10 -0
  124. wagtail/admin/templates/wagtailadmin/workflows/task_index.html +0 -30
  125. wagtail/admin/templates/wagtailadmin/workflows/task_index_results.html +10 -0
  126. wagtail/admin/templates/wagtailadmin/workflows/usage.html +1 -1
  127. wagtail/admin/templatetags/wagtailadmin_tags.py +116 -39
  128. wagtail/admin/tests/api/test_pages.py +26 -10
  129. wagtail/admin/tests/pages/test_create_page.py +10 -4
  130. wagtail/admin/tests/pages/test_custom_listing.py +37 -0
  131. wagtail/admin/tests/pages/test_edit_page.py +6 -6
  132. wagtail/admin/tests/pages/test_explorer_view.py +19 -18
  133. wagtail/admin/tests/pages/test_move_page.py +1 -1
  134. wagtail/admin/tests/pages/test_page_usage.py +50 -2
  135. wagtail/admin/tests/pages/test_parent_page_chooser_view.py +119 -0
  136. wagtail/admin/tests/pages/test_preview.py +18 -4
  137. wagtail/admin/tests/test_account_management.py +20 -1
  138. wagtail/admin/tests/test_audit_log.py +172 -5
  139. wagtail/admin/tests/test_checks.py +92 -0
  140. wagtail/admin/tests/test_collections_views.py +19 -5
  141. wagtail/admin/tests/test_compare.py +6 -6
  142. wagtail/admin/tests/test_dashboard.py +404 -0
  143. wagtail/admin/tests/test_dbwhitelister.py +4 -5
  144. wagtail/admin/tests/test_edit_handlers.py +2 -2
  145. wagtail/admin/tests/test_keyboard_shortcuts.py +84 -0
  146. wagtail/admin/tests/test_page_chooser.py +31 -18
  147. wagtail/admin/tests/test_privacy.py +36 -2
  148. wagtail/admin/tests/test_rich_text.py +168 -23
  149. wagtail/admin/tests/test_templatetags.py +411 -43
  150. wagtail/admin/tests/test_views.py +4 -2
  151. wagtail/admin/tests/test_workflows.py +531 -9
  152. wagtail/admin/tests/tests.py +3 -1
  153. wagtail/admin/tests/ui/test_tables.py +48 -1
  154. wagtail/admin/tests/viewsets/test_model_viewset.py +130 -23
  155. wagtail/admin/ui/side_panels.py +3 -1
  156. wagtail/admin/ui/tables/__init__.py +13 -1
  157. wagtail/admin/ui/tables/pages.py +17 -6
  158. wagtail/admin/urls/__init__.py +8 -3
  159. wagtail/admin/urls/pages.py +5 -0
  160. wagtail/admin/urls/workflows.py +10 -0
  161. wagtail/admin/views/chooser.py +20 -24
  162. wagtail/admin/views/collections.py +17 -1
  163. wagtail/admin/views/generic/base.py +34 -4
  164. wagtail/admin/views/generic/history.py +220 -51
  165. wagtail/admin/views/generic/mixins.py +7 -4
  166. wagtail/admin/views/generic/models.py +54 -47
  167. wagtail/admin/views/generic/multiple_upload.py +17 -8
  168. wagtail/admin/views/generic/usage.py +17 -11
  169. wagtail/admin/views/home.py +15 -12
  170. wagtail/admin/views/mixins.py +30 -0
  171. wagtail/admin/views/pages/choose_parent.py +73 -0
  172. wagtail/admin/views/pages/history.py +54 -66
  173. wagtail/admin/views/pages/listing.py +187 -106
  174. wagtail/admin/views/pages/usage.py +6 -1
  175. wagtail/admin/views/pages/utils.py +70 -1
  176. wagtail/admin/views/workflows.py +150 -21
  177. wagtail/admin/viewsets/model.py +2 -2
  178. wagtail/admin/viewsets/pages.py +77 -0
  179. wagtail/admin/wagtail_hooks.py +40 -2
  180. wagtail/admin/widgets/button.py +10 -10
  181. wagtail/api/v2/filters.py +1 -1
  182. wagtail/api/v2/tests/test_pages.py +1 -1
  183. wagtail/blocks/base.py +18 -9
  184. wagtail/blocks/field_block.py +9 -7
  185. wagtail/blocks/list_block.py +16 -6
  186. wagtail/blocks/static_block.py +3 -0
  187. wagtail/blocks/stream_block.py +58 -23
  188. wagtail/blocks/struct_block.py +15 -9
  189. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +39 -47
  190. wagtail/contrib/forms/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  191. wagtail/contrib/forms/locale/he_IL/LC_MESSAGES/django.po +2 -2
  192. wagtail/contrib/forms/models.py +5 -5
  193. wagtail/contrib/forms/templates/wagtailforms/list_submissions.html +44 -33
  194. wagtail/contrib/forms/templates/wagtailforms/submissions_index.html +2 -63
  195. wagtail/contrib/forms/tests/test_models.py +26 -0
  196. wagtail/contrib/forms/urls.py +6 -0
  197. wagtail/contrib/forms/views.py +52 -49
  198. wagtail/contrib/redirects/locale/ca/LC_MESSAGES/django.mo +0 -0
  199. wagtail/contrib/redirects/locale/ca/LC_MESSAGES/django.po +3 -3
  200. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +34 -42
  201. wagtail/contrib/redirects/locale/fr/LC_MESSAGES/django.po +2 -2
  202. wagtail/contrib/redirects/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  203. wagtail/contrib/redirects/locale/he_IL/LC_MESSAGES/django.po +2 -2
  204. wagtail/contrib/redirects/signal_handlers.py +1 -1
  205. wagtail/contrib/redirects/templates/wagtailredirects/index.html +1 -36
  206. wagtail/contrib/redirects/templates/wagtailredirects/index_results.html +18 -0
  207. wagtail/contrib/redirects/templates/wagtailredirects/redirect_target_cell.html +8 -0
  208. wagtail/contrib/redirects/tests/test_import_command.py +1 -1
  209. wagtail/contrib/redirects/tests/test_redirects.py +79 -8
  210. wagtail/contrib/redirects/urls.py +2 -1
  211. wagtail/contrib/redirects/views.py +85 -55
  212. wagtail/contrib/search_promotions/admin_urls.py +2 -1
  213. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +41 -64
  214. wagtail/contrib/search_promotions/locale/fr/LC_MESSAGES/django.po +2 -2
  215. wagtail/contrib/search_promotions/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  216. wagtail/contrib/search_promotions/locale/he_IL/LC_MESSAGES/django.po +2 -2
  217. wagtail/contrib/search_promotions/locale/hr_HR/LC_MESSAGES/django.mo +0 -0
  218. wagtail/contrib/search_promotions/locale/hr_HR/LC_MESSAGES/django.po +41 -2
  219. wagtail/contrib/search_promotions/locale/it/LC_MESSAGES/django.mo +0 -0
  220. wagtail/contrib/search_promotions/locale/it/LC_MESSAGES/django.po +9 -3
  221. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/index.html +1 -16
  222. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/index_results.html +11 -0
  223. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/list.html +0 -51
  224. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/results.html +3 -16
  225. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/search_promotion_column.html +15 -0
  226. wagtail/contrib/search_promotions/tests.py +122 -9
  227. wagtail/contrib/search_promotions/views.py +66 -65
  228. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +3 -3
  229. wagtail/contrib/settings/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  230. wagtail/contrib/settings/locale/he_IL/LC_MESSAGES/django.po +2 -2
  231. wagtail/contrib/settings/locale/tr/LC_MESSAGES/django.mo +0 -0
  232. wagtail/contrib/settings/locale/tr/LC_MESSAGES/django.po +6 -2
  233. wagtail/contrib/settings/registry.py +10 -5
  234. wagtail/contrib/settings/tests/generic/test_admin.py +9 -0
  235. wagtail/contrib/settings/tests/site_specific/test_admin.py +10 -1
  236. wagtail/contrib/settings/tests/site_specific/test_model.py +3 -3
  237. wagtail/contrib/settings/tests/site_specific/test_templates.py +1 -1
  238. wagtail/contrib/settings/views.py +3 -1
  239. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
  240. wagtail/contrib/simple_translation/tests/test_wagtail_hooks.py +2 -2
  241. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +7 -7
  242. wagtail/contrib/styleguide/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  243. wagtail/contrib/styleguide/locale/he_IL/LC_MESSAGES/django.po +2 -2
  244. wagtail/contrib/table_block/blocks.py +2 -2
  245. wagtail/contrib/table_block/locale/ca/LC_MESSAGES/django.mo +0 -0
  246. wagtail/contrib/table_block/locale/ca/LC_MESSAGES/django.po +27 -2
  247. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
  248. wagtail/contrib/table_block/locale/hu/LC_MESSAGES/django.mo +0 -0
  249. wagtail/contrib/table_block/locale/hu/LC_MESSAGES/django.po +27 -2
  250. wagtail/contrib/table_block/locale/it/LC_MESSAGES/django.mo +0 -0
  251. wagtail/contrib/table_block/locale/it/LC_MESSAGES/django.po +27 -2
  252. wagtail/contrib/table_block/static/table_block/js/table.js +1 -1
  253. wagtail/contrib/table_block/tests.py +6 -0
  254. wagtail/contrib/typed_table_block/locale/ca/LC_MESSAGES/django.mo +0 -0
  255. wagtail/contrib/typed_table_block/locale/ca/LC_MESSAGES/django.po +12 -2
  256. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +1 -1
  257. wagtail/contrib/typed_table_block/locale/hu/LC_MESSAGES/django.mo +0 -0
  258. wagtail/contrib/typed_table_block/locale/hu/LC_MESSAGES/django.po +12 -2
  259. wagtail/contrib/typed_table_block/locale/it/LC_MESSAGES/django.mo +0 -0
  260. wagtail/contrib/typed_table_block/locale/it/LC_MESSAGES/django.po +12 -2
  261. wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
  262. wagtail/coreutils.py +3 -2
  263. wagtail/documents/admin_urls.py +2 -2
  264. wagtail/documents/locale/en/LC_MESSAGES/django.po +22 -22
  265. wagtail/documents/locale/fr/LC_MESSAGES/django.po +2 -2
  266. wagtail/documents/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  267. wagtail/documents/locale/he_IL/LC_MESSAGES/django.po +2 -2
  268. wagtail/documents/locale/hr_HR/LC_MESSAGES/django.mo +0 -0
  269. wagtail/documents/locale/hr_HR/LC_MESSAGES/django.po +19 -2
  270. wagtail/documents/locale/hu/LC_MESSAGES/django.mo +0 -0
  271. wagtail/documents/locale/hu/LC_MESSAGES/django.po +16 -2
  272. wagtail/documents/locale/it/LC_MESSAGES/django.mo +0 -0
  273. wagtail/documents/locale/it/LC_MESSAGES/django.po +19 -2
  274. wagtail/documents/migrations/0013_delete_uploadeddocument.py +16 -0
  275. wagtail/documents/models.py +1 -20
  276. wagtail/documents/rich_text/__init__.py +11 -7
  277. wagtail/documents/static/wagtaildocs/js/document-chooser-modal.js +1 -1
  278. wagtail/documents/static/wagtaildocs/js/document-chooser-telepath.js +1 -1
  279. wagtail/documents/static/wagtaildocs/js/document-chooser.js +1 -1
  280. wagtail/documents/templates/wagtaildocs/documents/index.html +0 -16
  281. wagtail/documents/tests/test_admin_views.py +155 -23
  282. wagtail/documents/tests/test_collection_privacy.py +55 -1
  283. wagtail/documents/tests/test_rich_text.py +14 -0
  284. wagtail/documents/views/documents.py +25 -22
  285. wagtail/documents/views/multiple.py +6 -7
  286. wagtail/documents/views/serve.py +16 -1
  287. wagtail/documents/wagtail_hooks.py +20 -15
  288. wagtail/embeds/blocks.py +5 -0
  289. wagtail/embeds/locale/en/LC_MESSAGES/django.po +2 -2
  290. wagtail/embeds/locale/fr/LC_MESSAGES/django.po +2 -2
  291. wagtail/embeds/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  292. wagtail/embeds/locale/he_IL/LC_MESSAGES/django.po +2 -2
  293. wagtail/embeds/rich_text/__init__.py +1 -1
  294. wagtail/embeds/tests/test_rich_text.py +14 -0
  295. wagtail/embeds/wagtail_hooks.py +4 -14
  296. wagtail/fields.py +3 -48
  297. wagtail/images/admin_urls.py +2 -2
  298. wagtail/images/check_files/wagtail.jpg +0 -0
  299. wagtail/images/check_files/wagtail.png +0 -0
  300. wagtail/images/fields.py +2 -0
  301. wagtail/images/image_operations.py +1 -1
  302. wagtail/images/locale/ca/LC_MESSAGES/django.mo +0 -0
  303. wagtail/images/locale/ca/LC_MESSAGES/django.po +12 -0
  304. wagtail/images/locale/en/LC_MESSAGES/django.po +33 -45
  305. wagtail/images/locale/fr/LC_MESSAGES/django.po +2 -2
  306. wagtail/images/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  307. wagtail/images/locale/he_IL/LC_MESSAGES/django.po +2 -2
  308. wagtail/images/locale/hu/LC_MESSAGES/django.mo +0 -0
  309. wagtail/images/locale/hu/LC_MESSAGES/django.po +28 -2
  310. wagtail/images/locale/it/LC_MESSAGES/django.mo +0 -0
  311. wagtail/images/locale/it/LC_MESSAGES/django.po +14 -2
  312. wagtail/images/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  313. wagtail/images/locale/pt_PT/LC_MESSAGES/django.po +4 -0
  314. wagtail/images/migrations/0026_delete_uploadedimage.py +16 -0
  315. wagtail/images/models.py +49 -43
  316. wagtail/images/rich_text/__init__.py +18 -8
  317. wagtail/images/static/wagtailimages/js/image-chooser-modal.js +1 -1
  318. wagtail/images/static/wagtailimages/js/image-chooser-telepath.js +1 -1
  319. wagtail/images/static/wagtailimages/js/image-chooser.js +1 -1
  320. wagtail/images/templates/wagtailimages/images/image_listing_header.html +6 -0
  321. wagtail/images/templates/wagtailimages/images/index.html +11 -51
  322. wagtail/images/tests/test_admin_views.py +119 -62
  323. wagtail/images/tests/test_image_operations.py +10 -0
  324. wagtail/images/tests/test_models.py +35 -33
  325. wagtail/images/tests/test_rich_text.py +14 -0
  326. wagtail/images/tests/utils.py +1 -1
  327. wagtail/images/views/images.py +35 -64
  328. wagtail/images/views/multiple.py +6 -7
  329. wagtail/images/wagtail_hooks.py +4 -14
  330. wagtail/locale/en/LC_MESSAGES/django.po +150 -136
  331. wagtail/locale/es/LC_MESSAGES/django.mo +0 -0
  332. wagtail/locale/es/LC_MESSAGES/django.po +3 -2
  333. wagtail/locale/fr/LC_MESSAGES/django.po +2 -2
  334. wagtail/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  335. wagtail/locale/he_IL/LC_MESSAGES/django.po +2 -2
  336. wagtail/locale/it/LC_MESSAGES/django.mo +0 -0
  337. wagtail/locale/it/LC_MESSAGES/django.po +5 -5
  338. wagtail/locale/sl/LC_MESSAGES/django.mo +0 -0
  339. wagtail/locale/sl/LC_MESSAGES/django.po +27 -2
  340. wagtail/locales/locale/ar/LC_MESSAGES/django.po +1 -1
  341. wagtail/locales/locale/be/LC_MESSAGES/django.po +1 -1
  342. wagtail/locales/locale/bg/LC_MESSAGES/django.po +1 -1
  343. wagtail/locales/locale/ca/LC_MESSAGES/django.po +1 -1
  344. wagtail/locales/locale/cs/LC_MESSAGES/django.po +1 -1
  345. wagtail/locales/locale/cy/LC_MESSAGES/django.po +1 -1
  346. wagtail/locales/locale/da/LC_MESSAGES/django.po +1 -1
  347. wagtail/locales/locale/de/LC_MESSAGES/django.po +1 -1
  348. wagtail/locales/locale/el/LC_MESSAGES/django.po +1 -1
  349. wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
  350. wagtail/locales/locale/es/LC_MESSAGES/django.po +1 -1
  351. wagtail/locales/locale/et/LC_MESSAGES/django.po +2 -2
  352. wagtail/locales/locale/fa/LC_MESSAGES/django.po +1 -1
  353. wagtail/locales/locale/fi/LC_MESSAGES/django.po +1 -1
  354. wagtail/locales/locale/fr/LC_MESSAGES/django.po +1 -1
  355. wagtail/locales/locale/gl/LC_MESSAGES/django.po +1 -1
  356. wagtail/locales/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  357. wagtail/locales/locale/he_IL/LC_MESSAGES/django.po +3 -3
  358. wagtail/locales/locale/hr_HR/LC_MESSAGES/django.po +1 -1
  359. wagtail/locales/locale/hu/LC_MESSAGES/django.po +1 -1
  360. wagtail/locales/locale/id_ID/LC_MESSAGES/django.po +1 -1
  361. wagtail/locales/locale/is_IS/LC_MESSAGES/django.po +1 -1
  362. wagtail/locales/locale/it/LC_MESSAGES/django.po +1 -1
  363. wagtail/locales/locale/ja/LC_MESSAGES/django.po +1 -1
  364. wagtail/locales/locale/ko/LC_MESSAGES/django.po +1 -1
  365. wagtail/locales/locale/lt/LC_MESSAGES/django.po +1 -1
  366. wagtail/locales/locale/lv/LC_MESSAGES/django.po +1 -1
  367. wagtail/locales/locale/mi/LC_MESSAGES/django.po +1 -1
  368. wagtail/locales/locale/mn/LC_MESSAGES/django.po +1 -1
  369. wagtail/locales/locale/my/LC_MESSAGES/django.po +1 -1
  370. wagtail/locales/locale/nb/LC_MESSAGES/django.po +1 -1
  371. wagtail/locales/locale/nl/LC_MESSAGES/django.po +1 -1
  372. wagtail/locales/locale/pl/LC_MESSAGES/django.po +1 -1
  373. wagtail/locales/locale/pt_BR/LC_MESSAGES/django.po +1 -1
  374. wagtail/locales/locale/pt_PT/LC_MESSAGES/django.po +1 -1
  375. wagtail/locales/locale/ro/LC_MESSAGES/django.po +1 -1
  376. wagtail/locales/locale/ru/LC_MESSAGES/django.po +1 -1
  377. wagtail/locales/locale/sk_SK/LC_MESSAGES/django.po +1 -1
  378. wagtail/locales/locale/sl/LC_MESSAGES/django.po +1 -1
  379. wagtail/locales/locale/sv/LC_MESSAGES/django.po +1 -1
  380. wagtail/locales/locale/tet/LC_MESSAGES/django.po +1 -1
  381. wagtail/locales/locale/th/LC_MESSAGES/django.po +1 -1
  382. wagtail/locales/locale/tr/LC_MESSAGES/django.po +1 -1
  383. wagtail/locales/locale/tr_TR/LC_MESSAGES/django.po +1 -1
  384. wagtail/locales/locale/uk/LC_MESSAGES/django.po +1 -1
  385. wagtail/locales/locale/vi/LC_MESSAGES/django.po +1 -1
  386. wagtail/locales/locale/zh/LC_MESSAGES/django.po +1 -1
  387. wagtail/locales/locale/zh_Hans/LC_MESSAGES/django.po +1 -1
  388. wagtail/locales/locale/zh_Hant/LC_MESSAGES/django.po +1 -1
  389. wagtail/locales/tests.py +18 -3
  390. wagtail/locales/views.py +0 -1
  391. wagtail/management/commands/rebuild_references_index.py +3 -1
  392. wagtail/migrations/0092_alter_collectionviewrestriction_password_and_more.py +33 -0
  393. wagtail/migrations/0093_uploadedfile.py +53 -0
  394. wagtail/models/__init__.py +147 -32
  395. wagtail/models/i18n.py +1 -1
  396. wagtail/models/{collections.py → media.py} +33 -2
  397. wagtail/models/reference_index.py +1 -1
  398. wagtail/models/view_restrictions.py +10 -3
  399. wagtail/project_template/project_name/settings/base.py +6 -0
  400. wagtail/project_template/requirements.txt +1 -1
  401. wagtail/rich_text/__init__.py +25 -8
  402. wagtail/rich_text/pages.py +19 -8
  403. wagtail/rich_text/rewriters.py +140 -68
  404. wagtail/search/backends/database/mysql/mysql.py +3 -3
  405. wagtail/search/backends/database/postgres/postgres.py +3 -3
  406. wagtail/search/backends/database/sqlite/sqlite.py +2 -2
  407. wagtail/search/backends/elasticsearch7.py +4 -0
  408. wagtail/search/locale/en/LC_MESSAGES/django.po +3 -3
  409. wagtail/search/tests/test_postgres_backend.py +50 -0
  410. wagtail/sites/locale/en/LC_MESSAGES/django.po +8 -8
  411. wagtail/sites/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  412. wagtail/sites/locale/he_IL/LC_MESSAGES/django.po +2 -2
  413. wagtail/sites/locale/ro/LC_MESSAGES/django.mo +0 -0
  414. wagtail/sites/locale/ro/LC_MESSAGES/django.po +3 -2
  415. wagtail/sites/tests.py +35 -9
  416. wagtail/sites/views.py +3 -1
  417. wagtail/snippets/locale/de/LC_MESSAGES/django.mo +0 -0
  418. wagtail/snippets/locale/de/LC_MESSAGES/django.po +7 -8
  419. wagtail/snippets/locale/en/LC_MESSAGES/django.po +16 -56
  420. wagtail/snippets/locale/fr/LC_MESSAGES/django.po +2 -2
  421. wagtail/snippets/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  422. wagtail/snippets/locale/he_IL/LC_MESSAGES/django.po +2 -2
  423. wagtail/snippets/locale/hr_HR/LC_MESSAGES/django.mo +0 -0
  424. wagtail/snippets/locale/hr_HR/LC_MESSAGES/django.po +6 -2
  425. wagtail/snippets/locale/lv/LC_MESSAGES/django.mo +0 -0
  426. wagtail/snippets/locale/lv/LC_MESSAGES/django.po +12 -0
  427. wagtail/snippets/locale/zh_Hant/LC_MESSAGES/django.mo +0 -0
  428. wagtail/snippets/locale/zh_Hant/LC_MESSAGES/django.po +4 -0
  429. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
  430. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
  431. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/publish.html +3 -1
  432. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/save.html +3 -1
  433. wagtail/snippets/templates/wagtailsnippets/snippets/create.html +2 -3
  434. wagtail/snippets/templates/wagtailsnippets/snippets/edit.html +2 -3
  435. wagtail/snippets/tests/test_preview.py +13 -2
  436. wagtail/snippets/tests/test_snippets.py +41 -16
  437. wagtail/snippets/tests/test_viewset.py +95 -18
  438. wagtail/snippets/tests/test_workflows.py +12 -0
  439. wagtail/snippets/views/snippets.py +1 -40
  440. wagtail/templatetags/wagtailcore_tags.py +1 -1
  441. wagtail/test/demosite/models.py +1 -1
  442. wagtail/test/middleware.py +14 -1
  443. wagtail/test/testapp/fixtures/test.json +20 -0
  444. wagtail/test/testapp/migrations/0001_squashed_0073_revisablechildmodel_secret_text.py +8 -8
  445. wagtail/test/testapp/migrations/0023_snippetchoosermodel_full_featured.py +1 -0
  446. wagtail/test/testapp/migrations/0034_custompermissionmodel.py +44 -0
  447. wagtail/test/testapp/migrations/0035_modelwithcustommanager.py +30 -0
  448. wagtail/test/testapp/migrations/0036_complexdefaultstreampage.py +28 -0
  449. wagtail/test/testapp/models.py +79 -2
  450. wagtail/test/testapp/templates/tests/custom_docs_password_required.html +10 -0
  451. wagtail/test/testapp/templates/tests/custom_page_password_required.html +10 -0
  452. wagtail/test/testapp/views.py +24 -2
  453. wagtail/test/testapp/wagtail_hooks.py +19 -0
  454. wagtail/test/utils/wagtail_tests.py +2 -2
  455. wagtail/tests/test_blocks.py +262 -1
  456. wagtail/tests/test_migrations.py +1 -1
  457. wagtail/tests/test_page_model.py +77 -0
  458. wagtail/tests/test_page_privacy.py +18 -1
  459. wagtail/tests/test_rich_text.py +95 -5
  460. wagtail/tests/test_streamfield.py +43 -0
  461. wagtail/tests/test_utils.py +8 -2
  462. wagtail/tests/test_views.py +52 -1
  463. wagtail/tests/test_whitelist.py +7 -7
  464. wagtail/users/forms.py +3 -1
  465. wagtail/users/locale/en/LC_MESSAGES/django.po +124 -96
  466. wagtail/users/locale/fr/LC_MESSAGES/django.po +2 -2
  467. wagtail/users/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  468. wagtail/users/locale/he_IL/LC_MESSAGES/django.po +2 -2
  469. wagtail/users/locale/hr_HR/LC_MESSAGES/django.mo +0 -0
  470. wagtail/users/locale/hr_HR/LC_MESSAGES/django.po +13 -2
  471. wagtail/users/migrations/0013_userprofile_density.py +23 -0
  472. wagtail/users/models.py +14 -3
  473. wagtail/users/templates/wagtailusers/groups/create.html +1 -7
  474. wagtail/users/templates/wagtailusers/groups/edit.html +1 -13
  475. wagtail/users/templates/wagtailusers/groups/includes/formatted_permissions.html +46 -2
  476. wagtail/users/templates/wagtailusers/groups/includes/group_form_js.html +0 -3
  477. wagtail/users/templates/wagtailusers/users/create.html +1 -14
  478. wagtail/users/templates/wagtailusers/users/edit.html +1 -14
  479. wagtail/users/templates/wagtailusers/users/index.html +2 -5
  480. wagtail/users/templates/wagtailusers/users/index_results.html +3 -13
  481. wagtail/users/templates/wagtailusers/users/user_cell.html +9 -0
  482. wagtail/users/templatetags/wagtailusers_tags.py +107 -20
  483. wagtail/users/tests/test_admin_views.py +669 -90
  484. wagtail/users/views/groups.py +58 -61
  485. wagtail/users/views/users.py +211 -92
  486. wagtail/users/wagtail_hooks.py +6 -38
  487. wagtail/users/widgets.py +3 -5
  488. wagtail/utils/text.py +1 -1
  489. wagtail/views.py +5 -9
  490. wagtail/whitelist.py +1 -1
  491. {wagtail-6.0.1.dist-info → wagtail-6.1rc1.dist-info}/METADATA +5 -6
  492. {wagtail-6.0.1.dist-info → wagtail-6.1rc1.dist-info}/RECORD +496 -477
  493. wagtail/admin/static/wagtailadmin/js/page-editor.js +0 -1
  494. wagtail/admin/static/wagtailadmin/js/vendor/mousetrap.min.js +0 -1
  495. wagtail/admin/static/wagtailadmin/js/vendor/urlify.js +0 -1
  496. wagtail/admin/static/wagtailadmin/js/vendor/xregexp.min.js +0 -1
  497. wagtail/admin/templates/wagtailadmin/collections/index.html +0 -34
  498. wagtail/admin/templates/wagtailadmin/pages/revisions/_actions.html +0 -22
  499. wagtail/admin/templates/wagtailadmin/shared/page_breadcrumbs.html +0 -55
  500. wagtail/admin/tests/pages/test_dashboard.py +0 -172
  501. wagtail/contrib/redirects/templates/wagtailredirects/results.html +0 -23
  502. wagtail/documents/templates/wagtaildocs/documents/list.html +0 -2
  503. wagtail/search/tests/test_postgres_stemming.py +0 -40
  504. wagtail/sites/templates/wagtailsites/create.html +0 -7
  505. wagtail/sites/templates/wagtailsites/edit.html +0 -7
  506. wagtail/snippets/templates/wagtailsnippets/snippets/revisions/_actions.html +0 -36
  507. wagtail/users/templates/wagtailusers/users/list.html +0 -62
  508. wagtail/users/urls/users.py +0 -12
  509. {wagtail-6.0.1.dist-info → wagtail-6.1rc1.dist-info}/LICENSE +0 -0
  510. {wagtail-6.0.1.dist-info → wagtail-6.1rc1.dist-info}/WHEEL +0 -0
  511. {wagtail-6.0.1.dist-info → wagtail-6.1rc1.dist-info}/entry_points.txt +0 -0
  512. {wagtail-6.0.1.dist-info → wagtail-6.1rc1.dist-info}/top_level.txt +0 -0
@@ -1095,7 +1095,7 @@ class TestCreateDraftStateSnippet(WagtailTestUtils, TestCase):
1095
1095
  # The publish button should have name="action-publish"
1096
1096
  self.assertContains(
1097
1097
  response,
1098
- '<button\n type="submit"\n name="action-publish"\n value="action-publish"\n class="button action-save button-longrunning"\n data-controller="w-progress"\n data-action="w-progress#activate"\n',
1098
+ '<button\n type="submit"\n name="action-publish"\n value="action-publish"\n class="button action-save button-longrunning"\n data-controller="w-progress w-kbd"\n data-action="w-progress#activate"\n data-w-kbd-key-value="mod+s"\n',
1099
1099
  )
1100
1100
  # The status side panel should be rendered so that the
1101
1101
  # publishing schedule can be configured
@@ -1598,13 +1598,13 @@ class TestSnippetEditView(BaseTestSnippetEditView):
1598
1598
  expected_url = "/admin/snippets/tests/advert/edit/%d/" % self.test_snippet.pk
1599
1599
  self.assertEqual(url_finder.get_edit_url(self.test_snippet), expected_url)
1600
1600
 
1601
- def test_non_existant_model(self):
1601
+ def test_non_existent_model(self):
1602
1602
  response = self.client.get(
1603
1603
  f"/admin/snippets/tests/foo/edit/{quote(self.test_snippet.pk)}/"
1604
1604
  )
1605
1605
  self.assertEqual(response.status_code, 404)
1606
1606
 
1607
- def test_nonexistant_id(self):
1607
+ def test_nonexistent_id(self):
1608
1608
  response = self.client.get(
1609
1609
  reverse("wagtailsnippets_tests_advert:edit", args=[999999])
1610
1610
  )
@@ -1906,7 +1906,7 @@ class TestEditDraftStateSnippet(BaseTestSnippetEditView):
1906
1906
  # The publish button should have name="action-publish"
1907
1907
  self.assertContains(
1908
1908
  response,
1909
- '<button\n type="submit"\n name="action-publish"\n value="action-publish"\n class="button action-save button-longrunning"\n data-controller="w-progress"\n data-action="w-progress#activate"\n',
1909
+ '<button\n type="submit"\n name="action-publish"\n value="action-publish"\n class="button action-save button-longrunning"\n data-controller="w-progress w-kbd"\n data-action="w-progress#activate"\n data-w-kbd-key-value="mod+s"\n',
1910
1910
  )
1911
1911
 
1912
1912
  # The status side panel should show "No publishing schedule set" info
@@ -2407,12 +2407,13 @@ class TestEditDraftStateSnippet(BaseTestSnippetEditView):
2407
2407
  )
2408
2408
  self.assertContains(response, "Unpublish")
2409
2409
 
2410
- # Should use the latest draft content for the title
2411
- self.assertContains(
2412
- response,
2413
- '<h2 class="w-header__title" id="header-title">Draft-enabled Bar, In Draft</h2>',
2414
- html=True,
2415
- )
2410
+ soup = self.get_soup(response.content)
2411
+ h2 = soup.select_one("#header-title")
2412
+ self.assertIsNotNone(h2)
2413
+ icon = h2.select_one("svg use")
2414
+ self.assertIsNotNone(icon)
2415
+ self.assertEqual(icon["href"], "#icon-snippet")
2416
+ self.assertEqual(h2.text.strip(), "Draft-enabled Bar, In Draft")
2416
2417
 
2417
2418
  # Should use the latest draft content for the form
2418
2419
  self.assertTagInHTML(
@@ -4157,7 +4158,7 @@ class TestSnippetHistory(WagtailTestUtils, TestCase):
4157
4158
  def test_simple(self):
4158
4159
  response = self.get(self.non_revisable_snippet)
4159
4160
  self.assertEqual(response.status_code, 200)
4160
- self.assertContains(response, '<td class="title">Created</td>', html=True)
4161
+ self.assertContains(response, "<td>Created</td>", html=True)
4161
4162
  self.assertContains(
4162
4163
  response,
4163
4164
  'data-w-tooltip-content-value="Sept. 30, 2021, 10:01 a.m."',
@@ -4189,7 +4190,7 @@ class TestSnippetHistory(WagtailTestUtils, TestCase):
4189
4190
  edit_url = self.get_url(self.non_revisable_snippet, "edit")
4190
4191
  self.assertNotContains(
4191
4192
  response,
4192
- f'<a href="{edit_url}" class="button button-small button-secondary">Edit</a>',
4193
+ f'<a href="{edit_url}">Edit</a>',
4193
4194
  )
4194
4195
 
4195
4196
  def test_should_show_actions_on_revisable_snippet(self):
@@ -4212,14 +4213,14 @@ class TestSnippetHistory(WagtailTestUtils, TestCase):
4212
4213
  # The latest revision should have an "Edit" action instead of "Review"
4213
4214
  self.assertContains(
4214
4215
  response,
4215
- f'<a href="{edit_url}" class="button button-small button-secondary">Edit</a>',
4216
+ f'<a href="{edit_url}">Edit</a>',
4216
4217
  count=1,
4217
4218
  )
4218
4219
 
4219
4220
  # Any other revision should have a "Review" action
4220
4221
  self.assertContains(
4221
4222
  response,
4222
- f'<a href="{revert_url}" class="button button-small button-secondary">Review this version</a>',
4223
+ f'<a href="{revert_url}">Review this version</a>',
4223
4224
  count=1,
4224
4225
  )
4225
4226
 
@@ -4261,6 +4262,24 @@ class TestSnippetHistory(WagtailTestUtils, TestCase):
4261
4262
  response = self.get(self.revisable_snippet)
4262
4263
  self.assertEqual(response.status_code, 200)
4263
4264
 
4265
+ def test_num_queries(self):
4266
+ snippet = self.revisable_snippet
4267
+
4268
+ # Warm up the cache
4269
+ self.get(snippet)
4270
+
4271
+ with self.assertNumQueries(14):
4272
+ self.get(snippet)
4273
+
4274
+ for i in range(20):
4275
+ revision = snippet.save_revision(user=self.user, log_action=True)
4276
+ if i % 5 == 0:
4277
+ revision.publish(user=self.user, log_action=True)
4278
+
4279
+ # Should have the same number of queries as before (no N+1 queries)
4280
+ with self.assertNumQueries(14):
4281
+ self.get(snippet)
4282
+
4264
4283
 
4265
4284
  class TestSnippetRevisions(WagtailTestUtils, TestCase):
4266
4285
  @property
@@ -4363,7 +4382,7 @@ class TestSnippetRevisions(WagtailTestUtils, TestCase):
4363
4382
  # The publish button should have name="action-publish"
4364
4383
  self.assertContains(
4365
4384
  response,
4366
- '<button\n type="submit"\n name="action-publish"\n value="action-publish"\n class="button action-save button-longrunning warning"\n data-controller="w-progress"\n data-action="w-progress#activate"\n',
4385
+ '<button\n type="submit"\n name="action-publish"\n value="action-publish"\n class="button action-save button-longrunning warning"\n data-controller="w-progress w-kbd"\n data-action="w-progress#activate"\n data-w-kbd-key-value="mod+s"\n',
4367
4386
  )
4368
4387
 
4369
4388
  # Should not show the Unpublish action menu item
@@ -4409,10 +4428,16 @@ class TestSnippetRevisions(WagtailTestUtils, TestCase):
4409
4428
 
4410
4429
  # Should show the preview panel
4411
4430
  preview_url = self.get_url("preview_on_edit")
4412
- self.assertContains(response, 'data-side-panel-toggle="preview"')
4413
4431
  self.assertContains(response, 'data-side-panel="preview"')
4414
4432
  self.assertContains(response, f'data-action="{preview_url}"')
4415
4433
 
4434
+ # Should have the preview side panel toggle button
4435
+ soup = self.get_soup(response.content)
4436
+ toggle_button = soup.find("button", {"data-side-panel-toggle": "preview"})
4437
+ self.assertIsNotNone(toggle_button)
4438
+ self.assertEqual("w-tooltip w-kbd", toggle_button["data-controller"])
4439
+ self.assertEqual("mod+p", toggle_button["data-w-kbd-key-value"])
4440
+
4416
4441
  def test_replace_revision(self):
4417
4442
  get_response = self.get()
4418
4443
  text_from_revision = get_response.context["form"].initial["text"]
@@ -42,6 +42,7 @@ from wagtail.test.testapp.models import (
42
42
  )
43
43
  from wagtail.test.utils import WagtailTestUtils
44
44
  from wagtail.test.utils.template_tests import AdminTemplateTestUtils
45
+ from wagtail.utils.timestamps import render_timestamp
45
46
 
46
47
 
47
48
  class TestIncorrectRegistration(SimpleTestCase):
@@ -69,8 +70,6 @@ class BaseSnippetViewSetTests(WagtailTestUtils, TestCase):
69
70
 
70
71
 
71
72
  class TestCustomIcon(BaseSnippetViewSetTests):
72
- # TODO: decide what to do with this test, since the new designs after
73
- # Universal Listings and unified breadcrumbs/header don't have icons
74
73
  model = FullFeaturedSnippet
75
74
 
76
75
  def setUp(self):
@@ -84,26 +83,28 @@ class TestCustomIcon(BaseSnippetViewSetTests):
84
83
  def test_get_views(self):
85
84
  pk = quote(self.object.pk)
86
85
  views = [
87
- # TODO: Some of these views have been migrated to use the slim_header
88
- # only, so there is no header_icon anymore.
89
- # ("list", []),
90
- # ("add", []),
91
- # ("edit", [pk]),
92
- # ("delete", [pk]),
93
- # ("usage", [pk]),
94
- ("unpublish", [pk]),
95
- ("workflow_history", [pk]),
96
- # ("revisions_revert", [pk, self.revision_1.id]),
97
- ("revisions_compare", [pk, self.revision_1.id, self.revision_2.id]),
98
- ("revisions_unschedule", [pk, self.revision_2.id]),
86
+ ("list", [], "headers/slim_header.html"),
87
+ ("add", [], "headers/slim_header.html"),
88
+ ("edit", [pk], "headers/slim_header.html"),
89
+ ("delete", [pk], "header.html"),
90
+ ("usage", [pk], "headers/slim_header.html"),
91
+ ("unpublish", [pk], "header.html"),
92
+ ("workflow_history", [pk], "header.html"),
93
+ ("revisions_revert", [pk, self.revision_1.id], "headers/slim_header.html"),
94
+ (
95
+ "revisions_compare",
96
+ [pk, self.revision_1.id, self.revision_2.id],
97
+ "header.html",
98
+ ),
99
+ ("revisions_unschedule", [pk, self.revision_2.id], "header.html"),
99
100
  ]
100
- for view_name, args in views:
101
+ for view_name, args, header in views:
101
102
  with self.subTest(view_name=view_name):
102
103
  response = self.client.get(self.get_url(view_name, args))
103
104
  self.assertEqual(response.status_code, 200)
104
105
  self.assertEqual(response.context["header_icon"], "cog")
105
106
  self.assertContains(response, "icon icon-cog", count=1)
106
- self.assertTemplateUsed(response, "wagtailadmin/shared/header.html")
107
+ self.assertTemplateUsed(response, f"wagtailadmin/shared/{header}")
107
108
 
108
109
  def test_get_history(self):
109
110
  response = self.client.get(self.get_url("history", [quote(self.object.pk)]))
@@ -112,6 +113,10 @@ class TestCustomIcon(BaseSnippetViewSetTests):
112
113
  response,
113
114
  "wagtailadmin/shared/headers/slim_header.html",
114
115
  )
116
+ # History view icon is not configurable for consistency with pages
117
+ self.assertEqual(response.context["header_icon"], "history")
118
+ self.assertContains(response, "icon icon-history")
119
+ self.assertNotContains(response, "icon icon-cog")
115
120
  self.assertTemplateNotUsed(response, "wagtailadmin/shared/header.html")
116
121
 
117
122
  def test_get_workflow_history_detail(self):
@@ -715,10 +720,12 @@ class TestListViewWithCustomColumns(BaseSnippetViewSetTests):
715
720
  # One from the country code column, another from the custom foo column
716
721
  self.assertContains(response, sort_country_code_url, count=2)
717
722
 
718
- html = response.content.decode()
723
+ soup = self.get_soup(response.content)
724
+
725
+ headings = soup.select("#listing-results table th")
719
726
 
720
727
  # The bulk actions column plus 6 columns defined in FullFeaturedSnippetViewSet
721
- self.assertTagInHTML("<th>", html, count=7, allow_extra_attrs=True)
728
+ self.assertEqual(len(headings), 7)
722
729
 
723
730
  def test_falsy_value(self):
724
731
  # https://github.com/wagtail/wagtail/issues/10765
@@ -769,6 +776,44 @@ class TestListViewWithCustomColumns(BaseSnippetViewSetTests):
769
776
  )
770
777
 
771
778
 
779
+ class TestRelatedFieldListDisplay(BaseSnippetViewSetTests):
780
+ model = SnippetChooserModel
781
+
782
+ def setUp(self):
783
+ super().setUp()
784
+ url = "https://example.com/free_examples"
785
+ self.advert = Advert.objects.create(url=url, text="Free Examples")
786
+ self.ffs = FullFeaturedSnippet.objects.create(text="royale with cheese")
787
+
788
+ def test_empty_foreignkey(self):
789
+ self.no_ffs_chooser = self.model.objects.create(advert=self.advert)
790
+ response = self.client.get(self.get_url("list"))
791
+ self.assertEqual(response.status_code, 200)
792
+ self.assertContains(response, "Chosen snippet text")
793
+ self.assertContains(response, "<td></td>", html=True)
794
+
795
+ def test_single_level_relation(self):
796
+ self.scm = self.model.objects.create(advert=self.advert, full_featured=self.ffs)
797
+ response = self.client.get(self.get_url("list"))
798
+ self.assertEqual(response.status_code, 200)
799
+ soup = self.get_soup(response.content)
800
+ headers = [
801
+ header.get_text(strip=True)
802
+ for header in soup.select("#listing-results table th")
803
+ ]
804
+ self.assertIn("Chosen snippet text", headers)
805
+ self.assertContains(response, "<td>royale with cheese</td>", html=True)
806
+
807
+ def test_multi_level_relation(self):
808
+ self.scm = self.model.objects.create(advert=self.advert, full_featured=self.ffs)
809
+ dummy_revision = self.ffs.save_revision()
810
+ timestamp = render_timestamp(dummy_revision.created_at)
811
+ response = self.client.get(self.get_url("list"))
812
+ self.assertEqual(response.status_code, 200)
813
+ self.assertContains(response, "Latest revision created at")
814
+ self.assertContains(response, f"<td>{timestamp}</td>", html=True)
815
+
816
+
772
817
  class TestListExport(BaseSnippetViewSetTests):
773
818
  model = FullFeaturedSnippet
774
819
 
@@ -1530,3 +1575,35 @@ class TestCustomMethods(BaseSnippetViewSetTests):
1530
1575
  soup = self.get_soup(response.content)
1531
1576
  links = soup.find_all("a", attrs={"href": add_url})
1532
1577
  self.assertEqual(len(links), 1)
1578
+
1579
+ def test_index_results_view_get_add_url_teleports_to_header(self):
1580
+ response = self.client.get(self.get_url("list_results"))
1581
+ add_url = self.get_url("add") + "?customised=param"
1582
+ soup = self.get_soup(response.content)
1583
+ template = soup.find(
1584
+ "template",
1585
+ {
1586
+ "data-controller": "w-teleport",
1587
+ "data-w-teleport-target-value": "#w-slim-header-buttons",
1588
+ },
1589
+ )
1590
+ self.assertIsNotNone(template)
1591
+ links = template.find_all("a", attrs={"href": add_url})
1592
+ self.assertEqual(len(links), 1)
1593
+
1594
+ @override_settings(WAGTAIL_I18N_ENABLED=True)
1595
+ def test_index_results_view_get_add_url_teleports_to_header_with_i18n(self):
1596
+ Locale.objects.create(language_code="fr")
1597
+ response = self.client.get(self.get_url("list_results") + "?locale=fr")
1598
+ add_url = self.get_url("add") + "?locale=fr&customised=param"
1599
+ soup = self.get_soup(response.content)
1600
+ template = soup.find(
1601
+ "template",
1602
+ {
1603
+ "data-controller": "w-teleport",
1604
+ "data-w-teleport-target-value": "#w-slim-header-buttons",
1605
+ },
1606
+ )
1607
+ self.assertIsNotNone(template)
1608
+ links = template.find_all("a", attrs={"href": add_url})
1609
+ self.assertEqual(len(links), 1)
@@ -268,6 +268,18 @@ class TestWorkflowHistory(BaseWorkflowsTestCase):
268
268
 
269
269
  self.assertRedirects(response, reverse("wagtailadmin_home"))
270
270
 
271
+ def test_get_history_renders_comment(self):
272
+ self.workflow_state.current_task_state.reject(comment="Can be better")
273
+ # Ensure the comment in the log entry is rendered in the History view.
274
+ # This is the main History view and not the Workflow History view, but
275
+ # we test it here so we can reuse the workflow setup.
276
+ response = self.client.get(self.get_url("history", (quote(self.object.pk),)))
277
+ self.assertContains(
278
+ response,
279
+ "<div>Comment: <em>Can be better</em></div>",
280
+ html=True,
281
+ )
282
+
271
283
 
272
284
  class TestConfirmWorkflowCancellation(BaseWorkflowsTestCase):
273
285
  def setUp(self):
@@ -20,10 +20,8 @@ from wagtail.admin.ui.side_panels import ChecksSidePanel, PreviewSidePanel
20
20
  from wagtail.admin.ui.tables import (
21
21
  BulkActionsCheckboxColumn,
22
22
  Column,
23
- DateColumn,
24
23
  LiveStatusTagColumn,
25
24
  TitleColumn,
26
- UserColumn,
27
25
  )
28
26
  from wagtail.admin.views import generic
29
27
  from wagtail.admin.views.generic import history, lock, workflow
@@ -90,7 +88,7 @@ class ModelIndexView(generic.BaseListingView):
90
88
  return [
91
89
  {
92
90
  "name": capfirst(model._meta.verbose_name_plural),
93
- "count": model.objects.all().count(),
91
+ "count": model._default_manager.all().count(),
94
92
  "model": model,
95
93
  }
96
94
  for model in get_snippet_models()
@@ -363,45 +361,8 @@ class UsageView(generic.UsageView):
363
361
  view_name = "usage"
364
362
 
365
363
 
366
- class ActionColumn(Column):
367
- cell_template_name = "wagtailsnippets/snippets/revisions/_actions.html"
368
-
369
- def __init__(self, *args, object=None, view=None, **kwargs):
370
- super().__init__(*args, **kwargs)
371
- self.object = object
372
- self.view = view
373
-
374
- def get_cell_context_data(self, instance, parent_context):
375
- context = super().get_cell_context_data(instance, parent_context)
376
- context["revision_enabled"] = isinstance(self.object, RevisionMixin)
377
- context["draftstate_enabled"] = isinstance(self.object, DraftStateMixin)
378
- context["preview_enabled"] = isinstance(self.object, PreviewableMixin)
379
- context["can_publish"] = self.view.user_has_permission("publish")
380
- context["object"] = self.object
381
- context["view"] = self.view
382
- return context
383
-
384
-
385
364
  class HistoryView(history.HistoryView):
386
365
  view_name = "history"
387
- revisions_view_url_name = None
388
- revisions_revert_url_name = None
389
- revisions_compare_url_name = None
390
- revisions_unschedule_url_name = None
391
-
392
- @cached_property
393
- def columns(self):
394
- return [
395
- ActionColumn(
396
- "message",
397
- object=self.object,
398
- view=self,
399
- classname="title",
400
- label=_("Action"),
401
- ),
402
- UserColumn("user", blank_display_name="system"),
403
- DateColumn("timestamp", label=_("Date")),
404
- ]
405
366
 
406
367
 
407
368
  class InspectView(generic.InspectView):
@@ -100,7 +100,7 @@ def wagtail_release_notes_path():
100
100
  def wagtail_feature_release_whats_new_link():
101
101
  major, minor, patch, release, num = VERSION
102
102
  if release == "final":
103
- return f"https://guide.wagtail.org/en-latest/releases/new-in-wagtail-{major}-{minor}/"
103
+ return f"https://guide.wagtail.org/en-{major}.{minor}.x/releases/new-in-wagtail-{major}-{minor}/"
104
104
  return "https://guide.wagtail.org/en-latest/releases/latest/"
105
105
 
106
106
 
@@ -471,7 +471,7 @@ class EventPage(Page):
471
471
 
472
472
  def get_event_index(self):
473
473
  # Find closest ancestor which is an event index
474
- return EventIndexPage.objects.ancester_of(self).last()
474
+ return EventIndexPage.objects.ancestor_of(self).last()
475
475
 
476
476
 
477
477
  class EventPageCarouselItem(Orderable, AbstractCarouselItem):
@@ -1,6 +1,9 @@
1
- from django.http import HttpResponseForbidden
1
+ from django.http import Http404, HttpResponse, HttpResponseForbidden
2
2
  from django.utils.deprecation import MiddlewareMixin
3
3
 
4
+ from wagtail.models import Page
5
+ from wagtail.views import serve
6
+
4
7
 
5
8
  class BlockDodgyUserAgentMiddleware(MiddlewareMixin):
6
9
  # Used to test that we're correctly handling responses returned from middleware during page
@@ -16,3 +19,13 @@ class BlockDodgyUserAgentMiddleware(MiddlewareMixin):
16
19
  and request.headers.get("user-agent") == "EvilHacker"
17
20
  ):
18
21
  return HttpResponseForbidden("Forbidden")
22
+
23
+
24
+ class SimplePageViewInterceptorMiddleware(MiddlewareMixin):
25
+ def process_view(self, request, view_func, view_args, view_kwargs):
26
+ if serve == view_func:
27
+ page = Page.find_for_request(request, *view_args, **view_kwargs)
28
+ if page is None:
29
+ raise Http404
30
+ elif page.content == "Intercept me":
31
+ return HttpResponse("Intercepted")
@@ -878,6 +878,15 @@
878
878
  "file": "documents/test.pdf"
879
879
  }
880
880
  },
881
+ {
882
+ "pk": 2,
883
+ "model": "wagtaildocs.Document",
884
+ "fields": {
885
+ "title": "another test document",
886
+ "created_at": "2020-01-01T12:00:00.000Z",
887
+ "file": "documents/another_test.pdf"
888
+ }
889
+ },
881
890
  {
882
891
  "pk": 1,
883
892
  "model": "wagtailcore.pageviewrestriction",
@@ -915,6 +924,17 @@
915
924
  "created_at": "2014-01-01T12:00:00.000Z"
916
925
  }
917
926
  },
927
+ {
928
+ "pk": 2,
929
+ "model": "wagtailimages.image",
930
+ "fields": {
931
+ "title": "Another image",
932
+ "file": "original_images/another.jpg",
933
+ "width": 1000,
934
+ "height": 1000,
935
+ "created_at": "2020-01-01T12:00:00.000Z"
936
+ }
937
+ },
918
938
  {
919
939
  "model": "wagtailcore.collectionviewrestriction",
920
940
  "pk": 1,
@@ -15,7 +15,7 @@ import wagtail.contrib.table_block.blocks
15
15
  import wagtail.fields
16
16
  import wagtail.images.blocks
17
17
  import wagtail.images.models
18
- import wagtail.models.collections
18
+ import wagtail.models.media
19
19
  import wagtail.search.index
20
20
  import wagtail.test.testapp.models
21
21
 
@@ -1043,7 +1043,7 @@ class Migration(migrations.Migration):
1043
1043
  (
1044
1044
  "collection",
1045
1045
  models.ForeignKey(
1046
- default=wagtail.models.collections.get_root_collection_id,
1046
+ default=wagtail.models.media.get_root_collection_id,
1047
1047
  on_delete=django.db.models.deletion.CASCADE,
1048
1048
  related_name="+",
1049
1049
  to="wagtailcore.collection",
@@ -2244,7 +2244,7 @@ class Migration(migrations.Migration):
2244
2244
  (
2245
2245
  "collection",
2246
2246
  models.ForeignKey(
2247
- default=wagtail.models.collections.get_root_collection_id,
2247
+ default=wagtail.models.media.get_root_collection_id,
2248
2248
  on_delete=django.db.models.deletion.CASCADE,
2249
2249
  related_name="+",
2250
2250
  to="wagtailcore.collection",
@@ -2341,7 +2341,7 @@ class Migration(migrations.Migration):
2341
2341
  (
2342
2342
  "collection",
2343
2343
  models.ForeignKey(
2344
- default=wagtail.models.collections.get_root_collection_id,
2344
+ default=wagtail.models.media.get_root_collection_id,
2345
2345
  on_delete=django.db.models.deletion.CASCADE,
2346
2346
  related_name="+",
2347
2347
  to="wagtailcore.collection",
@@ -2622,7 +2622,7 @@ class Migration(migrations.Migration):
2622
2622
  (
2623
2623
  "collection",
2624
2624
  models.ForeignKey(
2625
- default=wagtail.models.collections.get_root_collection_id,
2625
+ default=wagtail.models.media.get_root_collection_id,
2626
2626
  on_delete=django.db.models.deletion.CASCADE,
2627
2627
  related_name="+",
2628
2628
  to="wagtailcore.collection",
@@ -3891,7 +3891,7 @@ class Migration(migrations.Migration):
3891
3891
  (
3892
3892
  "collection",
3893
3893
  models.ForeignKey(
3894
- default=wagtail.models.collections.get_root_collection_id,
3894
+ default=wagtail.models.media.get_root_collection_id,
3895
3895
  on_delete=django.db.models.deletion.CASCADE,
3896
3896
  related_name="+",
3897
3897
  to="wagtailcore.collection",
@@ -3936,7 +3936,7 @@ class Migration(migrations.Migration):
3936
3936
  (
3937
3937
  "collection",
3938
3938
  models.ForeignKey(
3939
- default=wagtail.models.collections.get_root_collection_id,
3939
+ default=wagtail.models.media.get_root_collection_id,
3940
3940
  on_delete=django.db.models.deletion.CASCADE,
3941
3941
  related_name="+",
3942
3942
  to="wagtailcore.collection",
@@ -4055,7 +4055,7 @@ class Migration(migrations.Migration):
4055
4055
  (
4056
4056
  "collection",
4057
4057
  models.ForeignKey(
4058
- default=wagtail.models.collections.get_root_collection_id,
4058
+ default=wagtail.models.media.get_root_collection_id,
4059
4059
  on_delete=django.db.models.deletion.CASCADE,
4060
4060
  related_name="+",
4061
4061
  to="wagtailcore.collection",
@@ -19,6 +19,7 @@ class Migration(migrations.Migration):
19
19
  null=True,
20
20
  on_delete=django.db.models.deletion.CASCADE,
21
21
  to="tests.fullfeaturedsnippet",
22
+ verbose_name="Chosen snippet",
22
23
  ),
23
24
  ),
24
25
  ]
@@ -0,0 +1,44 @@
1
+ # Generated by Django 4.2.7 on 2024-02-22 09:21
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+ dependencies = [
8
+ ("tests", "0033_customcopyformpage"),
9
+ ]
10
+
11
+ operations = [
12
+ migrations.CreateModel(
13
+ name="CustomPermissionModel",
14
+ fields=[
15
+ (
16
+ "id",
17
+ models.AutoField(
18
+ auto_created=True,
19
+ primary_key=True,
20
+ serialize=False,
21
+ verbose_name="ID",
22
+ ),
23
+ ),
24
+ ("text", models.TextField(default="Tailwag")),
25
+ ],
26
+ options={
27
+ "verbose_name": "ADVANCED permission model",
28
+ "verbose_name_plural": "ADVANCED permission models",
29
+ "permissions": [
30
+ ("can_start_trouble", "Can start trouble"),
31
+ ("cause_chaos", "Cause chaos for advanced permission model"),
32
+ ("change_text", "Change text"),
33
+ ("control", "Manage custom permission model"),
34
+ ],
35
+ "default_permissions": (
36
+ "add",
37
+ "change",
38
+ "delete",
39
+ "view",
40
+ "bulk_update",
41
+ ),
42
+ },
43
+ ),
44
+ ]
@@ -0,0 +1,30 @@
1
+ # Generated by Django 5.0.1 on 2024-03-15 21:20
2
+
3
+ import django.db.models.manager
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+ dependencies = [
9
+ ("tests", "0034_custompermissionmodel"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.CreateModel(
14
+ name="ModelWithCustomManager",
15
+ fields=[
16
+ (
17
+ "id",
18
+ models.AutoField(
19
+ auto_created=True,
20
+ primary_key=True,
21
+ serialize=False,
22
+ verbose_name="ID",
23
+ ),
24
+ ),
25
+ ],
26
+ managers=[
27
+ ("instances", django.db.models.manager.Manager()),
28
+ ],
29
+ ),
30
+ ]
@@ -0,0 +1,28 @@
1
+ # Generated by Django 5.0.3 on 2024-04-15 22:12
2
+
3
+ import django.db.models.deletion
4
+ import wagtail.blocks
5
+ import wagtail.fields
6
+ from django.db import migrations, models
7
+
8
+
9
+ class Migration(migrations.Migration):
10
+
11
+ dependencies = [
12
+ ('tests', '0035_modelwithcustommanager'),
13
+ ('wagtailcore', '0093_uploadedfile'),
14
+ ]
15
+
16
+ operations = [
17
+ migrations.CreateModel(
18
+ name='ComplexDefaultStreamPage',
19
+ fields=[
20
+ ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
21
+ ('body', wagtail.fields.StreamField([('text', wagtail.blocks.CharBlock()), ('rich_text', wagtail.blocks.RichTextBlock()), ('books', wagtail.blocks.StreamBlock([('title', wagtail.blocks.CharBlock()), ('author', wagtail.blocks.CharBlock())]))], default=[('rich_text', '<p>My <i>lovely</i> books</p>'), ('books', [('title', 'The Great Gatsby'), ('author', 'F. Scott Fitzgerald')])])),
22
+ ],
23
+ options={
24
+ 'abstract': False,
25
+ },
26
+ bases=('wagtailcore.page',),
27
+ ),
28
+ ]