wagtail 6.0.2__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 (355) 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/de/LC_MESSAGES/django.mo +0 -0
  9. wagtail/admin/locale/de/LC_MESSAGES/django.po +5 -5
  10. wagtail/admin/locale/en/LC_MESSAGES/django.po +474 -385
  11. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +3 -3
  12. wagtail/admin/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  13. wagtail/admin/locale/pt_PT/LC_MESSAGES/django.po +73 -2
  14. wagtail/admin/locale/ro/LC_MESSAGES/django.mo +0 -0
  15. wagtail/admin/locale/ro/LC_MESSAGES/django.po +3 -3
  16. wagtail/admin/panels/comment_panel.py +1 -1
  17. wagtail/admin/panels/field_panel.py +1 -1
  18. wagtail/admin/rich_text/converters/editor_html.py +3 -1
  19. wagtail/admin/rich_text/editors/draftail/__init__.py +28 -2
  20. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  21. wagtail/admin/static/wagtailadmin/css/panels/draftail.css +1 -1
  22. wagtail/admin/static/wagtailadmin/images/favicon.ico +0 -0
  23. wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
  24. wagtail/admin/static/wagtailadmin/js/chooser-modal.js +1 -1
  25. wagtail/admin/static/wagtailadmin/js/chooser-widget-telepath.js +1 -1
  26. wagtail/admin/static/wagtailadmin/js/chooser-widget.js +1 -1
  27. wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
  28. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  29. wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +1 -1
  30. wagtail/admin/static/wagtailadmin/js/date-time-chooser.js +1 -1
  31. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  32. wagtail/admin/static/wagtailadmin/js/expanding-formset.js +1 -1
  33. wagtail/admin/static/wagtailadmin/js/filtered-select.js +1 -1
  34. wagtail/admin/static/wagtailadmin/js/modal-workflow.js +1 -1
  35. wagtail/admin/static/wagtailadmin/js/page-chooser-modal.js +1 -1
  36. wagtail/admin/static/wagtailadmin/js/page-chooser-telepath.js +1 -1
  37. wagtail/admin/static/wagtailadmin/js/page-chooser.js +1 -1
  38. wagtail/admin/static/wagtailadmin/js/preview-panel.js +1 -1
  39. wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
  40. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  41. wagtail/admin/static/wagtailadmin/js/task-chooser-modal.js +1 -1
  42. wagtail/admin/static/wagtailadmin/js/task-chooser.js +1 -1
  43. wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
  44. wagtail/admin/static/wagtailadmin/js/telepath/telepath.js +1 -1
  45. wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
  46. wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
  47. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  48. wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +4 -4
  49. wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
  50. wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
  51. wagtail/admin/staticfiles.py +1 -0
  52. wagtail/admin/templates/wagtailadmin/base.html +1 -0
  53. wagtail/admin/templates/wagtailadmin/collection_privacy/set_privacy.html +3 -1
  54. wagtail/admin/templates/wagtailadmin/collections/index_results.html +10 -0
  55. wagtail/admin/templates/wagtailadmin/generic/base.html +1 -9
  56. wagtail/admin/templates/wagtailadmin/generic/form.html +3 -2
  57. wagtail/admin/templates/wagtailadmin/generic/history/action_cell.html +27 -0
  58. wagtail/admin/templates/wagtailadmin/home/workflow_objects_to_moderate.html +3 -3
  59. wagtail/admin/templates/wagtailadmin/icons/keyboard.svg +1 -0
  60. wagtail/admin/templates/wagtailadmin/page_privacy/set_privacy.html +3 -1
  61. wagtail/admin/templates/wagtailadmin/pages/_editor_js.html +0 -14
  62. wagtail/admin/templates/wagtailadmin/pages/action_menu/save_draft.html +3 -1
  63. wagtail/admin/templates/wagtailadmin/pages/choose_parent.html +17 -0
  64. wagtail/admin/templates/wagtailadmin/pages/explorable_index.html +8 -0
  65. wagtail/admin/templates/wagtailadmin/pages/history.html +1 -61
  66. wagtail/admin/templates/wagtailadmin/pages/index.html +1 -3
  67. wagtail/admin/templates/wagtailadmin/pages/listing/_locked_indicator.html +2 -2
  68. wagtail/admin/templates/wagtailadmin/pages/listing/_page_title_column_header.html +25 -27
  69. wagtail/admin/templates/wagtailadmin/pages/page_listing_header.html +2 -1
  70. wagtail/admin/templates/wagtailadmin/panels/multi_field_panel_child.html +1 -1
  71. wagtail/admin/templates/wagtailadmin/panels/publishing/schedule_publishing_panel.html +3 -1
  72. wagtail/admin/templates/wagtailadmin/panels/tabbed_interface.html +1 -1
  73. wagtail/admin/templates/wagtailadmin/shared/active_filters.html +2 -1
  74. wagtail/admin/templates/wagtailadmin/shared/breadcrumbs.html +8 -0
  75. wagtail/admin/templates/wagtailadmin/shared/forms/single_checkbox.html +1 -1
  76. wagtail/admin/templates/wagtailadmin/shared/headers/page_edit_header.html +1 -1
  77. wagtail/admin/templates/wagtailadmin/shared/headers/slim_header.html +21 -9
  78. wagtail/admin/templates/wagtailadmin/shared/human_readable_date.html +1 -1
  79. wagtail/admin/templates/wagtailadmin/shared/keyboard_shortcuts_dialog.html +29 -0
  80. wagtail/admin/templates/wagtailadmin/shared/side_panel_toggle.html +2 -1
  81. wagtail/admin/templates/wagtailadmin/skeleton.html +2 -1
  82. wagtail/admin/templates/wagtailadmin/tables/related_objects_cell.html +9 -0
  83. wagtail/admin/templates/wagtailadmin/tables/title_cell.html +9 -7
  84. wagtail/admin/templates/wagtailadmin/widgets/draftail_rich_text_area.html +1 -1
  85. wagtail/admin/templates/wagtailadmin/workflows/create.html +6 -23
  86. wagtail/admin/templates/wagtailadmin/workflows/create_task.html +6 -15
  87. wagtail/admin/templates/wagtailadmin/workflows/edit.html +6 -23
  88. wagtail/admin/templates/wagtailadmin/workflows/edit_task.html +6 -13
  89. wagtail/admin/templates/wagtailadmin/workflows/includes/task_usage_cell.html +4 -4
  90. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_tasks_cell.html +18 -0
  91. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_title_cell.html +7 -0
  92. wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_used_by_cell.html +25 -0
  93. wagtail/admin/templates/wagtailadmin/workflows/index.html +0 -99
  94. wagtail/admin/templates/wagtailadmin/workflows/index_results.html +10 -0
  95. wagtail/admin/templates/wagtailadmin/workflows/task_index.html +0 -30
  96. wagtail/admin/templates/wagtailadmin/workflows/task_index_results.html +10 -0
  97. wagtail/admin/templates/wagtailadmin/workflows/usage.html +1 -1
  98. wagtail/admin/templatetags/wagtailadmin_tags.py +116 -39
  99. wagtail/admin/tests/pages/test_create_page.py +10 -4
  100. wagtail/admin/tests/pages/test_custom_listing.py +37 -0
  101. wagtail/admin/tests/pages/test_edit_page.py +6 -6
  102. wagtail/admin/tests/pages/test_explorer_view.py +19 -18
  103. wagtail/admin/tests/pages/test_move_page.py +1 -1
  104. wagtail/admin/tests/pages/test_page_usage.py +50 -2
  105. wagtail/admin/tests/pages/test_parent_page_chooser_view.py +119 -0
  106. wagtail/admin/tests/pages/test_preview.py +18 -4
  107. wagtail/admin/tests/test_account_management.py +20 -1
  108. wagtail/admin/tests/test_audit_log.py +172 -5
  109. wagtail/admin/tests/test_checks.py +92 -0
  110. wagtail/admin/tests/test_collections_views.py +19 -5
  111. wagtail/admin/tests/test_compare.py +6 -6
  112. wagtail/admin/tests/test_dashboard.py +404 -0
  113. wagtail/admin/tests/test_dbwhitelister.py +4 -5
  114. wagtail/admin/tests/test_edit_handlers.py +2 -2
  115. wagtail/admin/tests/test_keyboard_shortcuts.py +84 -0
  116. wagtail/admin/tests/test_page_chooser.py +31 -18
  117. wagtail/admin/tests/test_privacy.py +36 -2
  118. wagtail/admin/tests/test_rich_text.py +168 -23
  119. wagtail/admin/tests/test_templatetags.py +411 -43
  120. wagtail/admin/tests/test_views.py +4 -2
  121. wagtail/admin/tests/test_workflows.py +531 -9
  122. wagtail/admin/tests/tests.py +3 -1
  123. wagtail/admin/tests/ui/test_tables.py +48 -1
  124. wagtail/admin/tests/viewsets/test_model_viewset.py +126 -29
  125. wagtail/admin/ui/side_panels.py +3 -1
  126. wagtail/admin/ui/tables/__init__.py +13 -1
  127. wagtail/admin/ui/tables/pages.py +17 -6
  128. wagtail/admin/urls/__init__.py +8 -3
  129. wagtail/admin/urls/pages.py +5 -0
  130. wagtail/admin/urls/workflows.py +10 -0
  131. wagtail/admin/views/chooser.py +20 -24
  132. wagtail/admin/views/collections.py +17 -1
  133. wagtail/admin/views/generic/base.py +31 -4
  134. wagtail/admin/views/generic/history.py +220 -51
  135. wagtail/admin/views/generic/mixins.py +7 -4
  136. wagtail/admin/views/generic/models.py +54 -38
  137. wagtail/admin/views/generic/multiple_upload.py +17 -8
  138. wagtail/admin/views/generic/usage.py +17 -11
  139. wagtail/admin/views/home.py +15 -12
  140. wagtail/admin/views/mixins.py +30 -0
  141. wagtail/admin/views/pages/choose_parent.py +73 -0
  142. wagtail/admin/views/pages/history.py +54 -66
  143. wagtail/admin/views/pages/listing.py +187 -106
  144. wagtail/admin/views/pages/usage.py +6 -1
  145. wagtail/admin/views/pages/utils.py +70 -1
  146. wagtail/admin/views/workflows.py +150 -21
  147. wagtail/admin/viewsets/model.py +2 -2
  148. wagtail/admin/viewsets/pages.py +77 -0
  149. wagtail/admin/wagtail_hooks.py +40 -2
  150. wagtail/admin/widgets/button.py +10 -9
  151. wagtail/api/v2/filters.py +1 -1
  152. wagtail/api/v2/tests/test_pages.py +1 -1
  153. wagtail/blocks/base.py +18 -9
  154. wagtail/blocks/field_block.py +9 -7
  155. wagtail/blocks/list_block.py +16 -6
  156. wagtail/blocks/static_block.py +3 -0
  157. wagtail/blocks/stream_block.py +58 -23
  158. wagtail/blocks/struct_block.py +15 -9
  159. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +39 -47
  160. wagtail/contrib/forms/models.py +5 -5
  161. wagtail/contrib/forms/templates/wagtailforms/list_submissions.html +44 -33
  162. wagtail/contrib/forms/templates/wagtailforms/submissions_index.html +2 -63
  163. wagtail/contrib/forms/tests/test_models.py +26 -0
  164. wagtail/contrib/forms/urls.py +6 -0
  165. wagtail/contrib/forms/views.py +52 -49
  166. wagtail/contrib/redirects/locale/ca/LC_MESSAGES/django.mo +0 -0
  167. wagtail/contrib/redirects/locale/ca/LC_MESSAGES/django.po +3 -3
  168. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +34 -42
  169. wagtail/contrib/redirects/signal_handlers.py +1 -1
  170. wagtail/contrib/redirects/templates/wagtailredirects/index.html +1 -36
  171. wagtail/contrib/redirects/templates/wagtailredirects/index_results.html +18 -0
  172. wagtail/contrib/redirects/templates/wagtailredirects/redirect_target_cell.html +8 -0
  173. wagtail/contrib/redirects/tests/test_import_command.py +1 -1
  174. wagtail/contrib/redirects/tests/test_redirects.py +79 -8
  175. wagtail/contrib/redirects/urls.py +2 -1
  176. wagtail/contrib/redirects/views.py +85 -55
  177. wagtail/contrib/search_promotions/admin_urls.py +2 -1
  178. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +41 -64
  179. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/index.html +1 -16
  180. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/index_results.html +11 -0
  181. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/list.html +0 -51
  182. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/results.html +3 -16
  183. wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/search_promotion_column.html +15 -0
  184. wagtail/contrib/search_promotions/tests.py +122 -9
  185. wagtail/contrib/search_promotions/views.py +66 -65
  186. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +3 -3
  187. wagtail/contrib/settings/registry.py +10 -5
  188. wagtail/contrib/settings/tests/generic/test_admin.py +9 -0
  189. wagtail/contrib/settings/tests/site_specific/test_admin.py +10 -1
  190. wagtail/contrib/settings/tests/site_specific/test_model.py +3 -3
  191. wagtail/contrib/settings/tests/site_specific/test_templates.py +1 -1
  192. wagtail/contrib/settings/views.py +3 -1
  193. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
  194. wagtail/contrib/simple_translation/tests/test_wagtail_hooks.py +2 -2
  195. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +7 -7
  196. wagtail/contrib/table_block/blocks.py +1 -1
  197. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
  198. wagtail/contrib/table_block/static/table_block/js/table.js +1 -1
  199. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +1 -1
  200. wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
  201. wagtail/coreutils.py +3 -2
  202. wagtail/documents/admin_urls.py +2 -2
  203. wagtail/documents/locale/en/LC_MESSAGES/django.po +22 -22
  204. wagtail/documents/migrations/0013_delete_uploadeddocument.py +16 -0
  205. wagtail/documents/models.py +1 -20
  206. wagtail/documents/rich_text/__init__.py +11 -7
  207. wagtail/documents/static/wagtaildocs/js/document-chooser-modal.js +1 -1
  208. wagtail/documents/static/wagtaildocs/js/document-chooser-telepath.js +1 -1
  209. wagtail/documents/static/wagtaildocs/js/document-chooser.js +1 -1
  210. wagtail/documents/templates/wagtaildocs/documents/index.html +0 -16
  211. wagtail/documents/tests/test_admin_views.py +155 -23
  212. wagtail/documents/tests/test_collection_privacy.py +55 -1
  213. wagtail/documents/tests/test_rich_text.py +14 -0
  214. wagtail/documents/views/documents.py +25 -22
  215. wagtail/documents/views/multiple.py +6 -7
  216. wagtail/documents/views/serve.py +16 -1
  217. wagtail/documents/wagtail_hooks.py +20 -15
  218. wagtail/embeds/blocks.py +5 -0
  219. wagtail/embeds/locale/en/LC_MESSAGES/django.po +2 -2
  220. wagtail/embeds/rich_text/__init__.py +1 -1
  221. wagtail/embeds/tests/test_rich_text.py +14 -0
  222. wagtail/embeds/wagtail_hooks.py +4 -14
  223. wagtail/fields.py +3 -48
  224. wagtail/images/admin_urls.py +2 -2
  225. wagtail/images/check_files/wagtail.jpg +0 -0
  226. wagtail/images/check_files/wagtail.png +0 -0
  227. wagtail/images/fields.py +2 -0
  228. wagtail/images/image_operations.py +1 -1
  229. wagtail/images/locale/en/LC_MESSAGES/django.po +33 -45
  230. wagtail/images/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  231. wagtail/images/locale/pt_PT/LC_MESSAGES/django.po +4 -0
  232. wagtail/images/migrations/0026_delete_uploadedimage.py +16 -0
  233. wagtail/images/models.py +49 -43
  234. wagtail/images/rich_text/__init__.py +18 -8
  235. wagtail/images/static/wagtailimages/js/image-chooser-modal.js +1 -1
  236. wagtail/images/static/wagtailimages/js/image-chooser-telepath.js +1 -1
  237. wagtail/images/static/wagtailimages/js/image-chooser.js +1 -1
  238. wagtail/images/templates/wagtailimages/images/image_listing_header.html +6 -0
  239. wagtail/images/templates/wagtailimages/images/index.html +11 -51
  240. wagtail/images/tests/test_admin_views.py +119 -62
  241. wagtail/images/tests/test_image_operations.py +10 -0
  242. wagtail/images/tests/test_models.py +35 -33
  243. wagtail/images/tests/test_rich_text.py +14 -0
  244. wagtail/images/tests/utils.py +1 -1
  245. wagtail/images/views/images.py +35 -64
  246. wagtail/images/views/multiple.py +6 -7
  247. wagtail/images/wagtail_hooks.py +4 -14
  248. wagtail/locale/en/LC_MESSAGES/django.po +150 -136
  249. wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
  250. wagtail/locales/tests.py +18 -3
  251. wagtail/locales/views.py +0 -1
  252. wagtail/management/commands/rebuild_references_index.py +3 -1
  253. wagtail/migrations/0092_alter_collectionviewrestriction_password_and_more.py +33 -0
  254. wagtail/migrations/0093_uploadedfile.py +53 -0
  255. wagtail/models/__init__.py +147 -32
  256. wagtail/models/i18n.py +1 -1
  257. wagtail/models/{collections.py → media.py} +33 -2
  258. wagtail/models/reference_index.py +1 -1
  259. wagtail/models/view_restrictions.py +10 -3
  260. wagtail/project_template/project_name/settings/base.py +6 -0
  261. wagtail/project_template/requirements.txt +1 -1
  262. wagtail/rich_text/__init__.py +25 -8
  263. wagtail/rich_text/pages.py +19 -8
  264. wagtail/rich_text/rewriters.py +140 -68
  265. wagtail/search/backends/database/mysql/mysql.py +3 -3
  266. wagtail/search/backends/database/postgres/postgres.py +3 -3
  267. wagtail/search/backends/database/sqlite/sqlite.py +2 -2
  268. wagtail/search/backends/elasticsearch7.py +4 -0
  269. wagtail/search/locale/en/LC_MESSAGES/django.po +3 -3
  270. wagtail/search/tests/test_postgres_backend.py +50 -0
  271. wagtail/sites/locale/en/LC_MESSAGES/django.po +8 -8
  272. wagtail/sites/tests.py +35 -9
  273. wagtail/sites/views.py +3 -1
  274. wagtail/snippets/locale/de/LC_MESSAGES/django.mo +0 -0
  275. wagtail/snippets/locale/de/LC_MESSAGES/django.po +5 -6
  276. wagtail/snippets/locale/en/LC_MESSAGES/django.po +16 -56
  277. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
  278. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
  279. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/publish.html +3 -1
  280. wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/save.html +3 -1
  281. wagtail/snippets/templates/wagtailsnippets/snippets/create.html +1 -1
  282. wagtail/snippets/templates/wagtailsnippets/snippets/edit.html +1 -1
  283. wagtail/snippets/tests/test_preview.py +13 -2
  284. wagtail/snippets/tests/test_snippets.py +41 -16
  285. wagtail/snippets/tests/test_viewset.py +63 -18
  286. wagtail/snippets/tests/test_workflows.py +12 -0
  287. wagtail/snippets/views/snippets.py +1 -40
  288. wagtail/templatetags/wagtailcore_tags.py +1 -1
  289. wagtail/test/demosite/models.py +1 -1
  290. wagtail/test/middleware.py +14 -1
  291. wagtail/test/testapp/fixtures/test.json +20 -0
  292. wagtail/test/testapp/migrations/0001_squashed_0073_revisablechildmodel_secret_text.py +8 -8
  293. wagtail/test/testapp/migrations/0023_snippetchoosermodel_full_featured.py +1 -0
  294. wagtail/test/testapp/migrations/0034_custompermissionmodel.py +44 -0
  295. wagtail/test/testapp/migrations/0035_modelwithcustommanager.py +30 -0
  296. wagtail/test/testapp/migrations/0036_complexdefaultstreampage.py +28 -0
  297. wagtail/test/testapp/models.py +79 -2
  298. wagtail/test/testapp/templates/tests/custom_docs_password_required.html +10 -0
  299. wagtail/test/testapp/templates/tests/custom_page_password_required.html +10 -0
  300. wagtail/test/testapp/views.py +24 -2
  301. wagtail/test/testapp/wagtail_hooks.py +19 -0
  302. wagtail/test/utils/wagtail_tests.py +2 -2
  303. wagtail/tests/test_blocks.py +262 -1
  304. wagtail/tests/test_migrations.py +1 -1
  305. wagtail/tests/test_page_model.py +77 -0
  306. wagtail/tests/test_page_privacy.py +18 -1
  307. wagtail/tests/test_rich_text.py +95 -5
  308. wagtail/tests/test_streamfield.py +43 -0
  309. wagtail/tests/test_utils.py +8 -2
  310. wagtail/tests/test_views.py +52 -1
  311. wagtail/tests/test_whitelist.py +7 -7
  312. wagtail/users/forms.py +3 -1
  313. wagtail/users/locale/en/LC_MESSAGES/django.po +124 -96
  314. wagtail/users/migrations/0013_userprofile_density.py +23 -0
  315. wagtail/users/models.py +14 -3
  316. wagtail/users/templates/wagtailusers/groups/create.html +1 -7
  317. wagtail/users/templates/wagtailusers/groups/edit.html +1 -13
  318. wagtail/users/templates/wagtailusers/groups/includes/formatted_permissions.html +46 -2
  319. wagtail/users/templates/wagtailusers/groups/includes/group_form_js.html +0 -2
  320. wagtail/users/templates/wagtailusers/users/create.html +1 -9
  321. wagtail/users/templates/wagtailusers/users/edit.html +1 -9
  322. wagtail/users/templates/wagtailusers/users/index.html +2 -5
  323. wagtail/users/templates/wagtailusers/users/index_results.html +3 -13
  324. wagtail/users/templates/wagtailusers/users/user_cell.html +9 -0
  325. wagtail/users/templatetags/wagtailusers_tags.py +107 -20
  326. wagtail/users/tests/test_admin_views.py +669 -90
  327. wagtail/users/views/groups.py +58 -61
  328. wagtail/users/views/users.py +211 -92
  329. wagtail/users/wagtail_hooks.py +6 -38
  330. wagtail/users/widgets.py +3 -5
  331. wagtail/utils/text.py +1 -1
  332. wagtail/views.py +5 -9
  333. wagtail/whitelist.py +1 -1
  334. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/METADATA +4 -5
  335. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/RECORD +339 -320
  336. wagtail/admin/static/wagtailadmin/js/page-editor.js +0 -1
  337. wagtail/admin/static/wagtailadmin/js/vendor/mousetrap.min.js +0 -1
  338. wagtail/admin/static/wagtailadmin/js/vendor/urlify.js +0 -1
  339. wagtail/admin/static/wagtailadmin/js/vendor/xregexp.min.js +0 -1
  340. wagtail/admin/templates/wagtailadmin/collections/index.html +0 -34
  341. wagtail/admin/templates/wagtailadmin/pages/revisions/_actions.html +0 -22
  342. wagtail/admin/templates/wagtailadmin/shared/page_breadcrumbs.html +0 -55
  343. wagtail/admin/tests/pages/test_dashboard.py +0 -172
  344. wagtail/contrib/redirects/templates/wagtailredirects/results.html +0 -23
  345. wagtail/documents/templates/wagtaildocs/documents/list.html +0 -2
  346. wagtail/search/tests/test_postgres_stemming.py +0 -40
  347. wagtail/sites/templates/wagtailsites/create.html +0 -6
  348. wagtail/sites/templates/wagtailsites/edit.html +0 -6
  349. wagtail/snippets/templates/wagtailsnippets/snippets/revisions/_actions.html +0 -36
  350. wagtail/users/templates/wagtailusers/users/list.html +0 -62
  351. wagtail/users/urls/users.py +0 -12
  352. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/LICENSE +0 -0
  353. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/WHEEL +0 -0
  354. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/entry_points.txt +0 -0
  355. {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,119 @@
1
+ from django.contrib.auth.models import Group, Permission
2
+ from django.test import TestCase
3
+ from django.urls import reverse
4
+
5
+ from wagtail.models import GroupPagePermission, Page
6
+ from wagtail.test.testapp.models import BusinessIndex
7
+ from wagtail.test.utils import WagtailTestUtils
8
+ from wagtail.test.utils.template_tests import AdminTemplateTestUtils
9
+
10
+
11
+ class TestParentPageChooserView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
12
+ fixtures = ["test.json"]
13
+
14
+ def setUp(self):
15
+ super().setUp()
16
+ self.user = self.login()
17
+ self.view_url = reverse("event_pages:choose_parent")
18
+
19
+ def test_get_page_parent_chooser(self):
20
+ response = self.client.get(self.view_url)
21
+ self.assertEqual(response.status_code, 200)
22
+ self.assertTemplateUsed(response, "wagtailadmin/pages/choose_parent.html")
23
+ self.assertBreadcrumbsItemsRendered(
24
+ [
25
+ {"url": reverse("event_pages:index"), "label": "Event pages"},
26
+ {"url": "", "label": "Choose parent", "sublabel": "Event page"},
27
+ ],
28
+ response.content,
29
+ )
30
+
31
+ def test_parent_chooser_redirect(self):
32
+ parent_page = Page.objects.first()
33
+ form_data = {
34
+ "parent_page": parent_page.pk,
35
+ }
36
+
37
+ response = self.client.post(self.view_url, form_data)
38
+ self.assertRedirects(
39
+ response,
40
+ reverse(
41
+ "wagtailadmin_pages:add", args=("tests", "eventpage", parent_page.pk)
42
+ ),
43
+ )
44
+
45
+ # Test another parent to make sure everything is working as intended
46
+ another_parent = parent_page.get_first_child()
47
+ form_data["parent_page"] = another_parent.pk
48
+
49
+ response = self.client.post(self.view_url, form_data)
50
+ self.assertRedirects(
51
+ response,
52
+ reverse(
53
+ "wagtailadmin_pages:add", args=("tests", "eventpage", another_parent.pk)
54
+ ),
55
+ )
56
+
57
+ def test_no_parent_selected(self):
58
+ error_html = """<p class="error-message">This field is required.</p>"""
59
+
60
+ response = self.client.post(self.view_url)
61
+ self.assertEqual(response.status_code, 200)
62
+ self.assertContains(response, error_html, html=True)
63
+
64
+ def test_user_no_add_subpage_permission(self):
65
+ parent_page = Page.objects.first()
66
+ test_group = Group.objects.create(name="test_group")
67
+ test_group.permissions.add(Permission.objects.get(codename="access_admin"))
68
+
69
+ page_with_add_permission = Page(title="Page not to be selected")
70
+ page_with_no_permission = Page(title="Page to be selected")
71
+ parent_page.add_child(instance=page_with_add_permission)
72
+ parent_page.add_child(instance=page_with_no_permission)
73
+
74
+ GroupPagePermission.objects.create(
75
+ group=test_group,
76
+ page=page_with_add_permission,
77
+ permission_type="add",
78
+ )
79
+ form_data = {
80
+ "parent_page": page_with_no_permission.pk,
81
+ }
82
+
83
+ self.user.is_superuser = False
84
+ self.user.groups.add(test_group)
85
+ self.user.save()
86
+
87
+ response = self.client.post(self.view_url, form_data)
88
+ self.assertEqual(response.status_code, 200)
89
+ self.assertContains(
90
+ response,
91
+ " You do not have permission to create a page under &quot;%s&quot;. "
92
+ % page_with_no_permission.get_admin_display_title(),
93
+ )
94
+
95
+ form_data["parent_page"] = page_with_add_permission.pk
96
+ response = self.client.post(self.view_url, form_data)
97
+ self.assertRedirects(
98
+ response,
99
+ reverse(
100
+ "wagtailadmin_pages:add",
101
+ args=("tests", "eventpage", page_with_add_permission.pk),
102
+ ),
103
+ )
104
+
105
+ def test_choosing_parent_with_unsupported_subpage_type(self):
106
+ parent_page = Page.objects.first()
107
+ page_with_limited_subtypes = BusinessIndex(title="EventPage unsupported")
108
+ parent_page.add_child(instance=page_with_limited_subtypes)
109
+ form_data = {
110
+ "parent_page": page_with_limited_subtypes.pk,
111
+ }
112
+
113
+ response = self.client.post(self.view_url, form_data)
114
+ self.assertEqual(response.status_code, 200)
115
+ self.assertContains(
116
+ response,
117
+ "You cannot create a page of type &quot;Event page&quot; under &quot;%s&quot;."
118
+ % page_with_limited_subtypes.get_admin_display_title(),
119
+ )
@@ -447,10 +447,16 @@ class TestEnablePreview(WagtailTestUtils, TestCase):
447
447
  self.assertEqual(response.status_code, 200)
448
448
 
449
449
  # Should show the preview panel
450
- self.assertContains(response, 'data-side-panel-toggle="preview"')
451
450
  self.assertContains(response, 'data-side-panel="preview"')
452
451
  self.assertContains(response, 'data-action="%s"' % preview_url)
453
452
 
453
+ # Should have the preview side panel toggle button
454
+ soup = self.get_soup(response.content)
455
+ toggle_button = soup.find("button", {"data-side-panel-toggle": "preview"})
456
+ self.assertIsNotNone(toggle_button)
457
+ self.assertEqual("w-tooltip w-kbd", toggle_button["data-controller"])
458
+ self.assertEqual("mod+p", toggle_button["data-w-kbd-key-value"])
459
+
454
460
  # Should show the iframe
455
461
  self.assertContains(
456
462
  response,
@@ -571,8 +577,11 @@ class TestEnablePreview(WagtailTestUtils, TestCase):
571
577
  )
572
578
 
573
579
  response = self.client.get(history_url)
574
- self.assertContains(response, "Preview")
575
- self.assertContains(response, preview_url)
580
+ soup = self.get_soup(response.content)
581
+
582
+ preview_link = soup.find("a", {"href": preview_url})
583
+ self.assertEqual(len(preview_link), 1)
584
+ self.assertEqual("Preview", preview_link.text)
576
585
 
577
586
 
578
587
  class TestDisablePreviewButton(WagtailTestUtils, TestCase):
@@ -635,5 +644,10 @@ class TestDisablePreviewButton(WagtailTestUtils, TestCase):
635
644
  "wagtailadmin_pages:revisions_view",
636
645
  args=(stream_page.id, latest_revision.id),
637
646
  )
638
- self.assertNotContains(response, "Preview")
647
+
639
648
  self.assertNotContains(response, preview_url)
649
+
650
+ soup = self.get_soup(response.content)
651
+
652
+ preview_link = soup.find("a", {"href": preview_url})
653
+ self.assertIsNone(preview_link)
@@ -231,6 +231,7 @@ class TestAccountSectionUtilsMixin:
231
231
  "locale-preferred_language": "es",
232
232
  "locale-current_time_zone": "Europe/London",
233
233
  "theme-theme": "dark",
234
+ "theme-density": "default",
234
235
  }
235
236
  post_data.update(extra_post_data)
236
237
  return self.client.post(reverse("wagtailadmin_account"), post_data)
@@ -476,7 +477,10 @@ class TestAccountSection(WagtailTestUtils, TestCase, TestAccountSectionUtilsMixi
476
477
 
477
478
  # check that the updated language preference is now indicated in HTML header
478
479
  response = self.client.get(reverse("wagtailadmin_home"))
479
- self.assertContains(response, '<html lang="es" dir="ltr" class="w-theme-dark">')
480
+ self.assertContains(
481
+ response,
482
+ '<html lang="es" dir="ltr" class="w-theme-dark w-density-default">',
483
+ )
480
484
 
481
485
  def test_unset_language_preferences(self):
482
486
  profile = UserProfile.get_for_user(self.user)
@@ -602,6 +606,21 @@ class TestAccountSection(WagtailTestUtils, TestCase, TestAccountSectionUtilsMixi
602
606
 
603
607
  self.assertEqual(profile.theme, "light")
604
608
 
609
+ def test_change_density_post(self):
610
+ response = self.post_form(
611
+ {
612
+ "theme-density": "snug",
613
+ }
614
+ )
615
+
616
+ # Check that the user was redirected to the account page
617
+ self.assertRedirects(response, reverse("wagtailadmin_account"))
618
+
619
+ profile = UserProfile.get_for_user(self.user)
620
+ profile.refresh_from_db()
621
+
622
+ self.assertEqual(profile.density, "snug")
623
+
605
624
  def test_sensitive_post_parameters(self):
606
625
  request = RequestFactory().post("wagtailadmin_account", data={})
607
626
  request.user = self.user
@@ -7,13 +7,17 @@ from django.urls import reverse
7
7
  from django.utils import timezone
8
8
  from freezegun import freeze_time
9
9
 
10
+ from wagtail.log_actions import log
10
11
  from wagtail.models import GroupPagePermission, Page, PageLogEntry, PageViewRestriction
11
12
  from wagtail.test.testapp.models import SimplePage
12
13
  from wagtail.test.utils import WagtailTestUtils
14
+ from wagtail.test.utils.template_tests import AdminTemplateTestUtils
13
15
  from wagtail.utils.timestamps import render_timestamp
14
16
 
15
17
 
16
- class TestAuditLogAdmin(WagtailTestUtils, TestCase):
18
+ class TestAuditLogAdmin(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
19
+ base_breadcrumb_items = []
20
+
17
21
  def setUp(self):
18
22
  self.root_page = Page.objects.get(id=2)
19
23
 
@@ -74,6 +78,39 @@ class TestAuditLogAdmin(WagtailTestUtils, TestCase):
74
78
  restriction.save(user=self.administrator)
75
79
  restriction.delete()
76
80
 
81
+ def test_simple(self):
82
+ history_url = reverse(
83
+ "wagtailadmin_pages:history", kwargs={"page_id": self.hello_page.id}
84
+ )
85
+
86
+ self.login(user=self.administrator)
87
+
88
+ response = self.client.get(history_url)
89
+ self.assertEqual(response.status_code, 200)
90
+ self.assertTemplateUsed(response, "wagtailadmin/pages/history.html")
91
+ self.assertTemplateUsed(response, "wagtailadmin/generic/listing.html")
92
+
93
+ items = [
94
+ {
95
+ "url": reverse("wagtailadmin_explore_root"),
96
+ "label": "Root",
97
+ },
98
+ {
99
+ "url": reverse("wagtailadmin_explore", args=(self.root_page.id,)),
100
+ "label": "Welcome to your new Wagtail site!",
101
+ },
102
+ {
103
+ "url": reverse("wagtailadmin_explore", args=(self.hello_page.id,)),
104
+ "label": "Hello world! (simple page)",
105
+ },
106
+ {
107
+ "url": "",
108
+ "label": "History",
109
+ "sublabel": "Hello world! (simple page)",
110
+ },
111
+ ]
112
+ self.assertBreadcrumbsItemsRendered(items, response.content)
113
+
77
114
  def test_page_history(self):
78
115
  self._update_page(self.hello_page)
79
116
 
@@ -95,15 +132,15 @@ class TestAuditLogAdmin(WagtailTestUtils, TestCase):
95
132
 
96
133
  self.assertContains(
97
134
  response,
98
- "Added the &#x27;Private, accessible to logged-in users&#x27; view restriction",
135
+ "Added the &#x27;Private, accessible to any logged-in users&#x27; view restriction",
99
136
  )
100
137
  self.assertContains(
101
138
  response,
102
- "Updated the view restriction to &#x27;Private, accessible with the following password&#x27;",
139
+ "Updated the view restriction to &#x27;Private, accessible with a shared password&#x27;",
103
140
  )
104
141
  self.assertContains(
105
142
  response,
106
- "Removed the &#x27;Private, accessible with the following password&#x27; view restriction",
143
+ "Removed the &#x27;Private, accessible with a shared password&#x27; view restriction",
107
144
  )
108
145
 
109
146
  self.assertContains(
@@ -123,14 +160,93 @@ class TestAuditLogAdmin(WagtailTestUtils, TestCase):
123
160
  history_url = reverse(
124
161
  "wagtailadmin_pages:history", kwargs={"page_id": self.hello_page.id}
125
162
  )
126
- response = self.client.get(history_url + "?action=wagtail.edit")
163
+
164
+ # Should allow filtering by multiple actions
165
+ response = self.client.get(
166
+ f"{history_url}?action=wagtail.edit&action=wagtail.lock"
167
+ )
168
+ self.assertEqual(response.status_code, 200)
169
+ self.assertContains(response, "Draft saved", count=2)
170
+ self.assertContains(response, "Locked")
171
+ self.assertNotContains(response, "Unlocked")
172
+ self.assertNotContains(response, "Page scheduled for publishing")
173
+ self.assertNotContains(response, "Published")
174
+
175
+ # Should render the active filter pills separately for each action
176
+ soup = self.get_soup(response.content)
177
+ active_filters = soup.select('[data-w-active-filter-id="id_action"]')
178
+ self.assertCountEqual(
179
+ [filter.get_text(separator=" ", strip=True) for filter in active_filters],
180
+ ["Action: Edit", "Action: Lock"],
181
+ )
182
+
183
+ def test_is_commenting_action_filters(self):
184
+ self.login(user=self.editor)
185
+ self._update_page(self.hello_page)
186
+
187
+ history_url = reverse(
188
+ "wagtailadmin_pages:history", kwargs={"page_id": self.hello_page.id}
189
+ )
190
+
191
+ log(
192
+ instance=self.hello_page,
193
+ action="wagtail.comments.create",
194
+ user=self.editor,
195
+ revision=self.hello_page.latest_revision,
196
+ data={
197
+ "comment": {
198
+ "id": 123,
199
+ "contentpath": "content",
200
+ "text": "A comment that was added",
201
+ }
202
+ },
203
+ )
204
+
205
+ log(
206
+ instance=self.hello_page,
207
+ action="wagtail.comments.edit",
208
+ user=self.editor,
209
+ revision=self.hello_page.latest_revision,
210
+ data={
211
+ "comment": {
212
+ "id": 123,
213
+ "contentpath": "content",
214
+ "text": "A comment that was edited",
215
+ }
216
+ },
217
+ )
218
+
219
+ # Without the filter applied
220
+ response = self.client.get(history_url)
127
221
  self.assertEqual(response.status_code, 200)
128
222
  self.assertContains(response, "Draft saved", count=2)
223
+ self.assertContains(response, "Locked")
224
+ self.assertContains(response, "Unlocked")
225
+ self.assertContains(response, "Page scheduled for publishing")
226
+ self.assertContains(response, "Published")
227
+
228
+ # Filter to only commenting actions
229
+ response = self.client.get(history_url + "?is_commenting_action=true")
230
+ self.assertEqual(response.status_code, 200)
231
+ self.assertContains(response, "A comment that was added")
232
+ self.assertContains(response, "A comment that was edited")
233
+ self.assertNotContains(response, "Draft saved")
129
234
  self.assertNotContains(response, "Locked")
130
235
  self.assertNotContains(response, "Unlocked")
131
236
  self.assertNotContains(response, "Page scheduled for publishing")
132
237
  self.assertNotContains(response, "Published")
133
238
 
239
+ # Filter to only non-commenting actions
240
+ response = self.client.get(history_url + "?is_commenting_action=false")
241
+ self.assertEqual(response.status_code, 200)
242
+ self.assertNotContains(response, "A comment that was added")
243
+ self.assertNotContains(response, "A comment that was edited")
244
+ self.assertContains(response, "Draft saved")
245
+ self.assertContains(response, "Locked")
246
+ self.assertContains(response, "Unlocked")
247
+ self.assertContains(response, "Page scheduled for publishing")
248
+ self.assertContains(response, "Published")
249
+
134
250
  def test_site_history(self):
135
251
  self._update_page(self.hello_page)
136
252
  self.about_page.save_revision(user=self.administrator, log_action=True)
@@ -328,3 +444,54 @@ class TestAuditLogAdmin(WagtailTestUtils, TestCase):
328
444
  response,
329
445
  f"Revision {revision.id} from {render_timestamp(revision.created_at)} unscheduled from publishing at {render_timestamp(go_live_at)}.",
330
446
  )
447
+
448
+ def test_num_queries(self):
449
+ self.login(user=self.editor)
450
+
451
+ history_url = reverse(
452
+ "wagtailadmin_pages:history", kwargs={"page_id": self.hello_page.id}
453
+ )
454
+
455
+ # Warm up the cache
456
+ self.client.get(history_url)
457
+
458
+ # Initial load, without any log entries
459
+ with self.assertNumQueries(17):
460
+ self.client.get(history_url)
461
+
462
+ # With some log entries
463
+ self._update_page(self.hello_page)
464
+ with self.assertNumQueries(19):
465
+ self.client.get(history_url)
466
+
467
+ # With even more log entries, should remain the same (no N+1 queries)
468
+ log(
469
+ instance=self.hello_page,
470
+ action="wagtail.comments.create",
471
+ user=self.editor,
472
+ revision=self.hello_page.latest_revision,
473
+ data={
474
+ "comment": {
475
+ "id": 123,
476
+ "contentpath": "content",
477
+ "text": "A comment that was added",
478
+ }
479
+ },
480
+ )
481
+
482
+ log(
483
+ instance=self.hello_page,
484
+ action="wagtail.comments.edit",
485
+ user=self.editor,
486
+ revision=self.hello_page.latest_revision,
487
+ data={
488
+ "comment": {
489
+ "id": 123,
490
+ "contentpath": "content",
491
+ "text": "A comment that was edited",
492
+ }
493
+ },
494
+ )
495
+ self._update_page(self.hello_page)
496
+ with self.assertNumQueries(19):
497
+ self.client.get(history_url)
@@ -0,0 +1,92 @@
1
+ from django.core.checks import Error
2
+ from django.test import TestCase, override_settings
3
+
4
+ from wagtail.admin.checks import datetime_format_check
5
+ from wagtail.test.utils import WagtailTestUtils
6
+
7
+
8
+ class TestDateTimeChecks(WagtailTestUtils, TestCase):
9
+ fixtures = ["test.json"]
10
+
11
+ def test_datetime_format(self):
12
+ with override_settings(
13
+ WAGTAIL_CONTENT_LANGUAGES=[
14
+ ("en", "English"),
15
+ ],
16
+ LANGUAGES=[
17
+ ("en", "English"),
18
+ ],
19
+ WAGTAIL_DATE_FORMAT="%m/%d/%Y",
20
+ WAGTAIL_TIME_FORMAT="%H:%M",
21
+ USE_L10N=True,
22
+ ):
23
+ errors = datetime_format_check(None)
24
+
25
+ self.assertEqual(errors, [])
26
+
27
+ def test_datetime_format_with_unsupported_date(self):
28
+ with override_settings(
29
+ WAGTAIL_CONTENT_LANGUAGES=[
30
+ ("en", "English"),
31
+ ],
32
+ LANGUAGES=[
33
+ ("en", "English"),
34
+ ],
35
+ WAGTAIL_DATE_FORMAT="%d.%m.%Y.",
36
+ WAGTAIL_TIME_FORMAT="%H:%M",
37
+ USE_L10N=True,
38
+ ):
39
+ errors = datetime_format_check(None)
40
+
41
+ expected_errors = [
42
+ Error(
43
+ "Configuration error",
44
+ hint="WAGTAIL_DATE_FORMAT %d.%m.%Y. must be in DATE_INPUT_FORMATS for language English (en).",
45
+ )
46
+ ]
47
+ self.assertEqual(errors, expected_errors)
48
+
49
+ def test_datetime_format_with_unsupported_date_not_using_l10n(self):
50
+ """
51
+ Test that the check doesn't raise an error when USE_L10N is False.
52
+ """
53
+
54
+ with override_settings(
55
+ WAGTAIL_CONTENT_LANGUAGES=[
56
+ ("en", "English"),
57
+ ],
58
+ LANGUAGES=[
59
+ ("en", "English"),
60
+ ],
61
+ WAGTAIL_DATE_FORMAT="%d.%m.%Y.",
62
+ WAGTAIL_TIME_FORMAT="%H:%M",
63
+ USE_L10N=False,
64
+ ):
65
+ errors = datetime_format_check(None)
66
+ self.assertEqual(errors, [])
67
+
68
+ def test_datetime_format_with_unsupported_datetime_and_time(self):
69
+ with override_settings(
70
+ WAGTAIL_CONTENT_LANGUAGES=[
71
+ ("en", "English"),
72
+ ],
73
+ LANGUAGES=[
74
+ ("en", "English"),
75
+ ],
76
+ WAGTAIL_DATETIME_FORMAT="%d.%m.%Y. %H:%M",
77
+ WAGTAIL_TIME_FORMAT="%I:%M %p",
78
+ USE_L10N=True,
79
+ ):
80
+ errors = datetime_format_check(None)
81
+
82
+ expected_errors = [
83
+ Error(
84
+ "Configuration error",
85
+ hint="WAGTAIL_DATETIME_FORMAT %d.%m.%Y. %H:%M must be in DATETIME_INPUT_FORMATS for language English (en).",
86
+ ),
87
+ Error(
88
+ "Configuration error",
89
+ hint="WAGTAIL_TIME_FORMAT %I:%M %p must be in TIME_INPUT_FORMATS for language English (en).",
90
+ ),
91
+ ]
92
+ self.assertEqual(errors, expected_errors)
@@ -55,7 +55,7 @@ class TestCollectionsIndexViewAsSuperuser(
55
55
  def test_simple(self):
56
56
  response = self.get()
57
57
  self.assertEqual(response.status_code, 200)
58
- self.assertTemplateUsed(response, "wagtailadmin/collections/index.html")
58
+ self.assertTemplateUsed(response, "wagtailadmin/generic/index.html")
59
59
 
60
60
  # Initially there should be no collections listed
61
61
  # (Root should not be shown)
@@ -67,10 +67,12 @@ class TestCollectionsIndexViewAsSuperuser(
67
67
  # Now the listing should contain our collection
68
68
  response = self.get()
69
69
  self.assertEqual(response.status_code, 200)
70
- self.assertTemplateUsed(response, "wagtailadmin/collections/index.html")
70
+ self.assertTemplateUsed(response, "wagtailadmin/generic/index.html")
71
71
  self.assertNotContains(response, "No collections have been created.")
72
72
  self.assertContains(response, "Holiday snaps")
73
- self.assertBreadcrumbsNotRendered(response.content)
73
+ self.assertBreadcrumbsItemsRendered(
74
+ [{"url": "", "label": "Collections"}], response.content
75
+ )
74
76
 
75
77
  def test_ordering(self):
76
78
  root_collection = Collection.get_first_root_node()
@@ -205,7 +207,13 @@ class TestAddCollectionAsSuperuser(AdminTemplateTestUtils, WagtailTestUtils, Tes
205
207
  response = self.get()
206
208
  self.assertEqual(response.status_code, 200)
207
209
  self.assertContains(response, self.root_collection.name)
208
- self.assertBreadcrumbsNotRendered(response.content)
210
+ self.assertBreadcrumbsItemsRendered(
211
+ [
212
+ {"label": "Collections", "url": "/admin/collections/"},
213
+ {"label": "New: Collection", "url": ""},
214
+ ],
215
+ response.content,
216
+ )
209
217
 
210
218
  def test_post(self):
211
219
  response = self.post(
@@ -324,7 +332,13 @@ class TestEditCollectionAsSuperuser(AdminTemplateTestUtils, WagtailTestUtils, Te
324
332
  response = self.get()
325
333
  self.assertEqual(response.status_code, 200)
326
334
  self.assertContains(response, "Delete collection")
327
- self.assertBreadcrumbsNotRendered(response.content)
335
+ self.assertBreadcrumbsItemsRendered(
336
+ [
337
+ {"url": "/admin/collections/", "label": "Collections"},
338
+ {"url": "", "label": str(self.collection)},
339
+ ],
340
+ response.content,
341
+ )
328
342
 
329
343
  def test_cannot_edit_root_collection(self):
330
344
  response = self.get(collection_id=self.root_collection.id)
@@ -153,13 +153,13 @@ class TestRichTextFieldComparison(TestFieldComparison):
153
153
  SimplePage._meta.get_field("content"),
154
154
  SimplePage(content="Original content"),
155
155
  SimplePage(
156
- content='<script type="text/javascript">doSomethingBad();</script>'
156
+ content='Do something good. <script type="text/javascript">doSomethingBad();</script>'
157
157
  ),
158
158
  )
159
159
 
160
160
  self.assertEqual(
161
161
  comparison.htmldiff(),
162
- '<span class="deletion">Original content</span><span class="addition">doSomethingBad();</span>',
162
+ '<span class="deletion">Original content</span><span class="addition">Do something good.</span>',
163
163
  )
164
164
  self.assertIsInstance(comparison.htmldiff(), SafeString)
165
165
 
@@ -491,7 +491,7 @@ class TestStreamFieldComparison(TestCase):
491
491
 
492
492
  self.assertEqual(
493
493
  comparison.htmldiff(),
494
- '<div class="comparison__child-object">I really like <span class="deletion">Wagtail &lt;3</span><span class="addition">evil code &gt;_&lt; doSomethingBad();</span></div>',
494
+ '<div class="comparison__child-object">I really like <span class="deletion">Wagtail &lt;3</span><span class="addition">evil code &gt;_&lt;</span></div>',
495
495
  )
496
496
  self.assertIsInstance(comparison.htmldiff(), SafeString)
497
497
 
@@ -525,7 +525,7 @@ class TestStreamFieldComparison(TestCase):
525
525
 
526
526
  self.assertEqual(
527
527
  comparison.htmldiff(),
528
- '<div class="comparison__child-object">Original and unchanged content</div>\n<div class="comparison__child-object addition">I really like evil code &gt;_&lt; doSomethingBad();</div>',
528
+ '<div class="comparison__child-object">Original and unchanged content</div>\n<div class="comparison__child-object addition">I really like evil code &gt;_&lt;</div>',
529
529
  )
530
530
  self.assertIsInstance(comparison.htmldiff(), SafeString)
531
531
 
@@ -559,7 +559,7 @@ class TestStreamFieldComparison(TestCase):
559
559
 
560
560
  self.assertEqual(
561
561
  comparison.htmldiff(),
562
- '<div class="comparison__child-object">Original and unchanged content</div>\n<div class="comparison__child-object deletion">I really like evil code &gt;_&lt; doSomethingBad();</div>',
562
+ '<div class="comparison__child-object">Original and unchanged content</div>\n<div class="comparison__child-object deletion">I really like evil code &gt;_&lt;</div>',
563
563
  )
564
564
  self.assertIsInstance(comparison.htmldiff(), SafeString)
565
565
 
@@ -1228,7 +1228,7 @@ class TestChildRelationComparison(TestCase):
1228
1228
  def test_has_changed(self):
1229
1229
  # Father Christmas renamed to Santa Claus. And Father Ted added.
1230
1230
  # Father Christmas should be mapped to Father Ted because they
1231
- # are most alike. Santa claus should be displayed as "new"
1231
+ # are most alike. Santa Claus should be displayed as "new"
1232
1232
  event_page = EventPage(title="Event page", slug="event")
1233
1233
  event_page.speakers.add(
1234
1234
  EventPageSpeaker(