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
@@ -8,9 +8,13 @@ from wagtail.test.testapp.models import (
8
8
  SimplePage,
9
9
  )
10
10
  from wagtail.test.utils import WagtailTestUtils
11
+ from wagtail.test.utils.template_tests import AdminTemplateTestUtils
11
12
 
12
13
 
13
- class TestPageUsage(WagtailTestUtils, TestCase):
14
+ class TestPageUsage(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
15
+ # We don't show the "Home" breadcrumb item in page views
16
+ base_breadcrumb_items = []
17
+
14
18
  def setUp(self):
15
19
  self.user = self.login()
16
20
  self.root_page = Page.objects.get(id=2)
@@ -24,7 +28,7 @@ class TestPageUsage(WagtailTestUtils, TestCase):
24
28
  page.save_revision().publish()
25
29
  self.page = SimplePage.objects.get(id=page.id)
26
30
 
27
- def test_no_usage(self):
31
+ def test_simple(self):
28
32
  usage_url = reverse("wagtailadmin_pages:usage", args=(self.page.id,))
29
33
  response = self.client.get(usage_url)
30
34
 
@@ -33,6 +37,37 @@ class TestPageUsage(WagtailTestUtils, TestCase):
33
37
  self.assertContains(response, "Usage")
34
38
  self.assertContains(response, "Hello world!")
35
39
 
40
+ items = [
41
+ {
42
+ "url": reverse("wagtailadmin_explore_root"),
43
+ "label": "Root",
44
+ },
45
+ {
46
+ "url": reverse("wagtailadmin_explore", args=(self.root_page.id,)),
47
+ "label": "Welcome to your new Wagtail site!",
48
+ },
49
+ {
50
+ "url": reverse("wagtailadmin_explore", args=(self.page.id,)),
51
+ "label": "Hello world! (simple page)",
52
+ },
53
+ {
54
+ "url": "",
55
+ "label": "Usage",
56
+ "sublabel": "Hello world! (simple page)",
57
+ },
58
+ ]
59
+ self.assertBreadcrumbsItemsRendered(items, response.content)
60
+
61
+ # There should be exactly one edit link, rendered as a header button
62
+ edit_url = reverse("wagtailadmin_pages:edit", args=(self.page.id,))
63
+ soup = self.get_soup(response.content)
64
+ edit_links = soup.select(f"a[href='{edit_url}']")
65
+ self.assertEqual(len(edit_links), 1)
66
+ edit_link = edit_links[0]
67
+ classes = edit_link.attrs.get("class")
68
+ self.assertIn("w-header-button", classes)
69
+ self.assertIn("button", classes)
70
+
36
71
  def test_has_private_usage(self):
37
72
  PageChooserModel.objects.create(page=self.page)
38
73
  usage_url = reverse("wagtailadmin_pages:usage", args=(self.page.id,))
@@ -72,3 +107,16 @@ class TestPageUsage(WagtailTestUtils, TestCase):
72
107
  )
73
108
  self.assertContains(response, "Thank you redirect page")
74
109
  self.assertContains(response, "<td>Form page with redirect</td>", html=True)
110
+
111
+ def test_pagination(self):
112
+ for _ in range(50):
113
+ PageChooserModel.objects.create(page=self.page)
114
+
115
+ usage_url = reverse("wagtailadmin_pages:usage", args=(self.page.id,))
116
+ response = self.client.get(f"{usage_url}?p=2")
117
+
118
+ self.assertEqual(response.status_code, 200)
119
+ self.assertTemplateUsed(response, "wagtailadmin/generic/listing.html")
120
+ self.assertContains(response, "Page 2 of 3.")
121
+ self.assertContains(response, f"{usage_url}?p=1")
122
+ self.assertContains(response, f"{usage_url}?p=3")
@@ -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)