We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Move "delete" from save draft drop up
We want to remove the delete action from the publishing menu and instead have it in the three dots "more" menu up by the breadcrumbs.

---

Note from @kaedroho: the Delete button should remain available even when the page is locked.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `wagtail/admin/action_menu.py`
Content:
```
1 """Handles rendering of the list of actions in the footer of the page create/edit views."""
2 from django.conf import settings
3 from django.forms import Media
4 from django.template.loader import render_to_string
5 from django.urls import reverse
6 from django.utils.functional import cached_property
7 from django.utils.translation import gettext_lazy as _
8 
9 from wagtail import hooks
10 from wagtail.admin.ui.components import Component
11 from wagtail.models import UserPagePermissionsProxy
12 
13 
14 class ActionMenuItem(Component):
15     """Defines an item in the actions drop-up on the page creation/edit view"""
16 
17     order = 100  # default order index if one is not specified on init
18     template_name = "wagtailadmin/pages/action_menu/menu_item.html"
19 
20     label = ""
21     name = None
22     classname = ""
23     icon_name = ""
24 
25     def __init__(self, order=None):
26         if order is not None:
27             self.order = order
28 
29     def get_user_page_permissions_tester(self, context):
30         if "user_page_permissions_tester" in context:
31             return context["user_page_permissions_tester"]
32         return context["user_page_permissions"].for_page(context["page"])
33 
34     def is_shown(self, context):
35         """
36         Whether this action should be shown on this request; permission checks etc should go here.
37         By default, actions are shown for unlocked pages, hidden for locked pages
38 
39         context = dictionary containing at least:
40             'request' = the current request object
41             'view' = 'create', 'edit' or 'revisions_revert'
42             'page' (if view = 'edit' or 'revisions_revert') = the page being edited
43             'parent_page' (if view = 'create') = the parent page of the page being created
44             'user_page_permissions' = a UserPagePermissionsProxy for the current user, to test permissions against
45             may also contain:
46             'user_page_permissions_tester' = a PagePermissionTester for the current user and page
47         """
48         return (
49             context["view"] == "create"
50             or not self.get_user_page_permissions_tester(context).page_locked()
51         )
52 
53     def get_context_data(self, parent_context):
54         """Defines context for the template, overridable to use more data"""
55         context = parent_context.copy()
56         url = self.get_url(parent_context)
57 
58         context.update(
59             {
60                 "label": self.label,
61                 "url": url,
62                 "name": self.name,
63                 "classname": self.classname,
64                 "icon_name": self.icon_name,
65                 "request": parent_context["request"],
66             }
67         )
68         return context
69 
70     def get_url(self, parent_context):
71         return None
72 
73 
74 class PublishMenuItem(ActionMenuItem):
75     label = _("Publish")
76     name = "action-publish"
77     template_name = "wagtailadmin/pages/action_menu/publish.html"
78     icon_name = "upload"
79 
80     def is_shown(self, context):
81         if context["view"] == "create":
82             return (
83                 context["user_page_permissions"]
84                 .for_page(context["parent_page"])
85                 .can_publish_subpage()
86             )
87         else:  # view == 'edit' or 'revisions_revert'
88             perms_tester = self.get_user_page_permissions_tester(context)
89             return not perms_tester.page_locked() and perms_tester.can_publish()
90 
91     def get_context_data(self, parent_context):
92         context = super().get_context_data(parent_context)
93         context["is_revision"] = context["view"] == "revisions_revert"
94         return context
95 
96 
97 class SubmitForModerationMenuItem(ActionMenuItem):
98     label = _("Submit for moderation")
99     name = "action-submit"
100     icon_name = "resubmit"
101 
102     def is_shown(self, context):
103         if not getattr(settings, "WAGTAIL_MODERATION_ENABLED", True):
104             return False
105 
106         if context["view"] == "create":
107             return context["parent_page"].has_workflow
108 
109         if context["view"] == "edit":
110             perms_tester = self.get_user_page_permissions_tester(context)
111             return (
112                 perms_tester.can_submit_for_moderation()
113                 and not perms_tester.page_locked()
114             )
115         # context == revisions_revert
116         return False
117 
118     def get_context_data(self, parent_context):
119         context = super().get_context_data(parent_context)
120         page = context.get("page")
121         workflow_state = page.current_workflow_state if page else None
122         if (
123             workflow_state
124             and workflow_state.status == workflow_state.STATUS_NEEDS_CHANGES
125         ):
126             context["label"] = _("Resubmit to {}").format(
127                 workflow_state.current_task_state.task.name
128             )
129         elif page:
130             workflow = page.get_workflow()
131             if workflow:
132                 context["label"] = _("Submit to {}").format(workflow.name)
133         return context
134 
135 
136 class WorkflowMenuItem(ActionMenuItem):
137     template_name = "wagtailadmin/pages/action_menu/workflow_menu_item.html"
138 
139     def __init__(self, name, label, launch_modal, *args, **kwargs):
140         self.name = name
141         self.label = label
142         self.launch_modal = launch_modal
143 
144         if kwargs.get("icon_name"):
145             self.icon_name = kwargs.pop("icon_name")
146 
147         super().__init__(*args, **kwargs)
148 
149     def get_context_data(self, parent_context):
150         context = super().get_context_data(parent_context)
151         context["launch_modal"] = self.launch_modal
152         context["current_task_state"] = context["page"].current_workflow_task_state
153         return context
154 
155     def is_shown(self, context):
156         if context["view"] == "edit":
157             perms_tester = self.get_user_page_permissions_tester(context)
158             return not perms_tester.page_locked()
159 
160 
161 class RestartWorkflowMenuItem(ActionMenuItem):
162     label = _("Restart workflow ")
163     name = "action-restart-workflow"
164     classname = "button--icon-flipped"
165     icon_name = "login"
166 
167     def is_shown(self, context):
168         if not getattr(settings, "WAGTAIL_MODERATION_ENABLED", True):
169             return False
170         elif context["view"] == "edit":
171             workflow_state = context["page"].current_workflow_state
172             perms_tester = self.get_user_page_permissions_tester(context)
173             return (
174                 perms_tester.can_submit_for_moderation()
175                 and not perms_tester.page_locked()
176                 and workflow_state
177                 and workflow_state.user_can_cancel(context["request"].user)
178             )
179         else:
180             return False
181 
182 
183 class CancelWorkflowMenuItem(ActionMenuItem):
184     label = _("Cancel workflow ")
185     name = "action-cancel-workflow"
186     icon_name = "error"
187 
188     def is_shown(self, context):
189         if context["view"] == "edit":
190             workflow_state = context["page"].current_workflow_state
191             return workflow_state and workflow_state.user_can_cancel(
192                 context["request"].user
193             )
194         return False
195 
196 
197 class UnpublishMenuItem(ActionMenuItem):
198     label = _("Unpublish")
199     name = "action-unpublish"
200     icon_name = "download-alt"
201     classname = "action-secondary"
202 
203     def is_shown(self, context):
204         if context["view"] == "edit":
205             perms_tester = self.get_user_page_permissions_tester(context)
206             return not perms_tester.page_locked() and perms_tester.can_unpublish()
207 
208     def get_url(self, context):
209         return reverse("wagtailadmin_pages:unpublish", args=(context["page"].id,))
210 
211 
212 class DeleteMenuItem(ActionMenuItem):
213     name = "action-delete"
214     label = _("Delete")
215     icon_name = "bin"
216     classname = "action-secondary"
217 
218     def is_shown(self, context):
219         if context["view"] == "edit":
220             perms_tester = self.get_user_page_permissions_tester(context)
221             return not perms_tester.page_locked() and perms_tester.can_delete()
222 
223     def get_url(self, context):
224         return reverse("wagtailadmin_pages:delete", args=(context["page"].id,))
225 
226 
227 class SaveDraftMenuItem(ActionMenuItem):
228     name = "action-save-draft"
229     label = _("Save Draft")
230     template_name = "wagtailadmin/pages/action_menu/save_draft.html"
231 
232     def get_context_data(self, parent_context):
233         context = super().get_context_data(parent_context)
234         context["is_revision"] = context["view"] == "revisions_revert"
235         return context
236 
237 
238 class PageLockedMenuItem(ActionMenuItem):
239     name = "action-page-locked"
240     label = _("Page locked")
241     template_name = "wagtailadmin/pages/action_menu/page_locked.html"
242 
243     def is_shown(self, context):
244         return (
245             "page" in context
246             and self.get_user_page_permissions_tester(context).page_locked()
247         )
248 
249     def get_context_data(self, parent_context):
250         context = super().get_context_data(parent_context)
251         context["is_revision"] = context["view"] == "revisions_revert"
252         return context
253 
254 
255 BASE_PAGE_ACTION_MENU_ITEMS = None
256 
257 
258 def _get_base_page_action_menu_items():
259     """
260     Retrieve the global list of menu items for the page action menu,
261     which may then be customised on a per-request basis
262     """
263     global BASE_PAGE_ACTION_MENU_ITEMS
264 
265     if BASE_PAGE_ACTION_MENU_ITEMS is None:
266         BASE_PAGE_ACTION_MENU_ITEMS = [
267             SaveDraftMenuItem(order=0),
268             DeleteMenuItem(order=10),
269             UnpublishMenuItem(order=20),
270             PublishMenuItem(order=30),
271             CancelWorkflowMenuItem(order=40),
272             RestartWorkflowMenuItem(order=50),
273             SubmitForModerationMenuItem(order=60),
274             PageLockedMenuItem(order=10000),
275         ]
276         for hook in hooks.get_hooks("register_page_action_menu_item"):
277             action_menu_item = hook()
278             if action_menu_item:
279                 BASE_PAGE_ACTION_MENU_ITEMS.append(action_menu_item)
280 
281     return BASE_PAGE_ACTION_MENU_ITEMS
282 
283 
284 class PageActionMenu:
285     template = "wagtailadmin/pages/action_menu/menu.html"
286 
287     def __init__(self, request, **kwargs):
288         self.request = request
289         self.context = kwargs
290         self.context["request"] = request
291         page = self.context.get("page")
292         user_page_permissions = UserPagePermissionsProxy(self.request.user)
293         self.context["user_page_permissions"] = user_page_permissions
294         if page:
295             self.context[
296                 "user_page_permissions_tester"
297             ] = user_page_permissions.for_page(page)
298 
299         self.menu_items = []
300 
301         if page:
302             task = page.current_workflow_task
303             current_workflow_state = page.current_workflow_state
304             is_final_task = (
305                 current_workflow_state and current_workflow_state.is_at_final_task
306             )
307             if task:
308                 actions = task.get_actions(page, request.user)
309                 workflow_menu_items = []
310                 for name, label, launch_modal in actions:
311                     icon_name = "edit"
312                     if name == "approve":
313                         if is_final_task and not getattr(
314                             settings,
315                             "WAGTAIL_WORKFLOW_REQUIRE_REAPPROVAL_ON_EDIT",
316                             False,
317                         ):
318                             label = _("%(label)s and Publish") % {"label": label}
319                         icon_name = "success"
320 
321                     item = WorkflowMenuItem(
322                         name, label, launch_modal, icon_name=icon_name
323                     )
324 
325                     if item.is_shown(self.context):
326                         workflow_menu_items.append(item)
327                 self.menu_items.extend(workflow_menu_items)
328 
329         for menu_item in _get_base_page_action_menu_items():
330             if menu_item.is_shown(self.context):
331                 self.menu_items.append(menu_item)
332 
333         self.menu_items.sort(key=lambda item: item.order)
334 
335         for hook in hooks.get_hooks("construct_page_action_menu"):
336             hook(self.menu_items, self.request, self.context)
337 
338         try:
339             self.default_item = self.menu_items.pop(0)
340         except IndexError:
341             self.default_item = None
342 
343     def render_html(self):
344         rendered_menu_items = [
345             menu_item.render_html(self.context) for menu_item in self.menu_items
346         ]
347 
348         rendered_default_item = self.default_item.render_html(self.context)
349 
350         return render_to_string(
351             self.template,
352             {
353                 "default_menu_item": rendered_default_item,
354                 "show_menu": bool(self.menu_items),
355                 "rendered_menu_items": rendered_menu_items,
356             },
357             request=self.request,
358         )
359 
360     @cached_property
361     def media(self):
362         media = Media()
363         for item in self.menu_items:
364             media += item.media
365         return media
366
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/wagtail/admin/action_menu.py b/wagtail/admin/action_menu.py
--- a/wagtail/admin/action_menu.py
+++ b/wagtail/admin/action_menu.py
@@ -209,21 +209,6 @@
         return reverse("wagtailadmin_pages:unpublish", args=(context["page"].id,))
 
 
-class DeleteMenuItem(ActionMenuItem):
-    name = "action-delete"
-    label = _("Delete")
-    icon_name = "bin"
-    classname = "action-secondary"
-
-    def is_shown(self, context):
-        if context["view"] == "edit":
-            perms_tester = self.get_user_page_permissions_tester(context)
-            return not perms_tester.page_locked() and perms_tester.can_delete()
-
-    def get_url(self, context):
-        return reverse("wagtailadmin_pages:delete", args=(context["page"].id,))
-
-
 class SaveDraftMenuItem(ActionMenuItem):
     name = "action-save-draft"
     label = _("Save Draft")
@@ -265,7 +250,6 @@
     if BASE_PAGE_ACTION_MENU_ITEMS is None:
         BASE_PAGE_ACTION_MENU_ITEMS = [
             SaveDraftMenuItem(order=0),
-            DeleteMenuItem(order=10),
             UnpublishMenuItem(order=20),
             PublishMenuItem(order=30),
             CancelWorkflowMenuItem(order=40),

{"golden_diff": "diff --git a/wagtail/admin/action_menu.py b/wagtail/admin/action_menu.py\n--- a/wagtail/admin/action_menu.py\n+++ b/wagtail/admin/action_menu.py\n@@ -209,21 +209,6 @@\n         return reverse(\"wagtailadmin_pages:unpublish\", args=(context[\"page\"].id,))\n \n \n-class DeleteMenuItem(ActionMenuItem):\n-    name = \"action-delete\"\n-    label = _(\"Delete\")\n-    icon_name = \"bin\"\n-    classname = \"action-secondary\"\n-\n-    def is_shown(self, context):\n-        if context[\"view\"] == \"edit\":\n-            perms_tester = self.get_user_page_permissions_tester(context)\n-            return not perms_tester.page_locked() and perms_tester.can_delete()\n-\n-    def get_url(self, context):\n-        return reverse(\"wagtailadmin_pages:delete\", args=(context[\"page\"].id,))\n-\n-\n class SaveDraftMenuItem(ActionMenuItem):\n     name = \"action-save-draft\"\n     label = _(\"Save Draft\")\n@@ -265,7 +250,6 @@\n     if BASE_PAGE_ACTION_MENU_ITEMS is None:\n         BASE_PAGE_ACTION_MENU_ITEMS = [\n             SaveDraftMenuItem(order=0),\n-            DeleteMenuItem(order=10),\n             UnpublishMenuItem(order=20),\n             PublishMenuItem(order=30),\n             CancelWorkflowMenuItem(order=40),\n", "issue": "Move \"delete\" from save draft drop up\nWe want to remove the delete action from the publishing menu and instead have it in the three dots \"more\" menu up by the breadcrumbs.\n\n---\n\nNote from @kaedroho: the Delete button should remain available even when the page is locked.\n", "before_files": [{"content": "\"\"\"Handles rendering of the list of actions in the footer of the page create/edit views.\"\"\"\nfrom django.conf import settings\nfrom django.forms import Media\nfrom django.template.loader import render_to_string\nfrom django.urls import reverse\nfrom django.utils.functional import cached_property\nfrom django.utils.translation import gettext_lazy as _\n\nfrom wagtail import hooks\nfrom wagtail.admin.ui.components import Component\nfrom wagtail.models import UserPagePermissionsProxy\n\n\nclass ActionMenuItem(Component):\n    \"\"\"Defines an item in the actions drop-up on the page creation/edit view\"\"\"\n\n    order = 100  # default order index if one is not specified on init\n    template_name = \"wagtailadmin/pages/action_menu/menu_item.html\"\n\n    label = \"\"\n    name = None\n    classname = \"\"\n    icon_name = \"\"\n\n    def __init__(self, order=None):\n        if order is not None:\n            self.order = order\n\n    def get_user_page_permissions_tester(self, context):\n        if \"user_page_permissions_tester\" in context:\n            return context[\"user_page_permissions_tester\"]\n        return context[\"user_page_permissions\"].for_page(context[\"page\"])\n\n    def is_shown(self, context):\n        \"\"\"\n        Whether this action should be shown on this request; permission checks etc should go here.\n        By default, actions are shown for unlocked pages, hidden for locked pages\n\n        context = dictionary containing at least:\n            'request' = the current request object\n            'view' = 'create', 'edit' or 'revisions_revert'\n            'page' (if view = 'edit' or 'revisions_revert') = the page being edited\n            'parent_page' (if view = 'create') = the parent page of the page being created\n            'user_page_permissions' = a UserPagePermissionsProxy for the current user, to test permissions against\n            may also contain:\n            'user_page_permissions_tester' = a PagePermissionTester for the current user and page\n        \"\"\"\n        return (\n            context[\"view\"] == \"create\"\n            or not self.get_user_page_permissions_tester(context).page_locked()\n        )\n\n    def get_context_data(self, parent_context):\n        \"\"\"Defines context for the template, overridable to use more data\"\"\"\n        context = parent_context.copy()\n        url = self.get_url(parent_context)\n\n        context.update(\n            {\n                \"label\": self.label,\n                \"url\": url,\n                \"name\": self.name,\n                \"classname\": self.classname,\n                \"icon_name\": self.icon_name,\n                \"request\": parent_context[\"request\"],\n            }\n        )\n        return context\n\n    def get_url(self, parent_context):\n        return None\n\n\nclass PublishMenuItem(ActionMenuItem):\n    label = _(\"Publish\")\n    name = \"action-publish\"\n    template_name = \"wagtailadmin/pages/action_menu/publish.html\"\n    icon_name = \"upload\"\n\n    def is_shown(self, context):\n        if context[\"view\"] == \"create\":\n            return (\n                context[\"user_page_permissions\"]\n                .for_page(context[\"parent_page\"])\n                .can_publish_subpage()\n            )\n        else:  # view == 'edit' or 'revisions_revert'\n            perms_tester = self.get_user_page_permissions_tester(context)\n            return not perms_tester.page_locked() and perms_tester.can_publish()\n\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        context[\"is_revision\"] = context[\"view\"] == \"revisions_revert\"\n        return context\n\n\nclass SubmitForModerationMenuItem(ActionMenuItem):\n    label = _(\"Submit for moderation\")\n    name = \"action-submit\"\n    icon_name = \"resubmit\"\n\n    def is_shown(self, context):\n        if not getattr(settings, \"WAGTAIL_MODERATION_ENABLED\", True):\n            return False\n\n        if context[\"view\"] == \"create\":\n            return context[\"parent_page\"].has_workflow\n\n        if context[\"view\"] == \"edit\":\n            perms_tester = self.get_user_page_permissions_tester(context)\n            return (\n                perms_tester.can_submit_for_moderation()\n                and not perms_tester.page_locked()\n            )\n        # context == revisions_revert\n        return False\n\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        page = context.get(\"page\")\n        workflow_state = page.current_workflow_state if page else None\n        if (\n            workflow_state\n            and workflow_state.status == workflow_state.STATUS_NEEDS_CHANGES\n        ):\n            context[\"label\"] = _(\"Resubmit to {}\").format(\n                workflow_state.current_task_state.task.name\n            )\n        elif page:\n            workflow = page.get_workflow()\n            if workflow:\n                context[\"label\"] = _(\"Submit to {}\").format(workflow.name)\n        return context\n\n\nclass WorkflowMenuItem(ActionMenuItem):\n    template_name = \"wagtailadmin/pages/action_menu/workflow_menu_item.html\"\n\n    def __init__(self, name, label, launch_modal, *args, **kwargs):\n        self.name = name\n        self.label = label\n        self.launch_modal = launch_modal\n\n        if kwargs.get(\"icon_name\"):\n            self.icon_name = kwargs.pop(\"icon_name\")\n\n        super().__init__(*args, **kwargs)\n\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        context[\"launch_modal\"] = self.launch_modal\n        context[\"current_task_state\"] = context[\"page\"].current_workflow_task_state\n        return context\n\n    def is_shown(self, context):\n        if context[\"view\"] == \"edit\":\n            perms_tester = self.get_user_page_permissions_tester(context)\n            return not perms_tester.page_locked()\n\n\nclass RestartWorkflowMenuItem(ActionMenuItem):\n    label = _(\"Restart workflow \")\n    name = \"action-restart-workflow\"\n    classname = \"button--icon-flipped\"\n    icon_name = \"login\"\n\n    def is_shown(self, context):\n        if not getattr(settings, \"WAGTAIL_MODERATION_ENABLED\", True):\n            return False\n        elif context[\"view\"] == \"edit\":\n            workflow_state = context[\"page\"].current_workflow_state\n            perms_tester = self.get_user_page_permissions_tester(context)\n            return (\n                perms_tester.can_submit_for_moderation()\n                and not perms_tester.page_locked()\n                and workflow_state\n                and workflow_state.user_can_cancel(context[\"request\"].user)\n            )\n        else:\n            return False\n\n\nclass CancelWorkflowMenuItem(ActionMenuItem):\n    label = _(\"Cancel workflow \")\n    name = \"action-cancel-workflow\"\n    icon_name = \"error\"\n\n    def is_shown(self, context):\n        if context[\"view\"] == \"edit\":\n            workflow_state = context[\"page\"].current_workflow_state\n            return workflow_state and workflow_state.user_can_cancel(\n                context[\"request\"].user\n            )\n        return False\n\n\nclass UnpublishMenuItem(ActionMenuItem):\n    label = _(\"Unpublish\")\n    name = \"action-unpublish\"\n    icon_name = \"download-alt\"\n    classname = \"action-secondary\"\n\n    def is_shown(self, context):\n        if context[\"view\"] == \"edit\":\n            perms_tester = self.get_user_page_permissions_tester(context)\n            return not perms_tester.page_locked() and perms_tester.can_unpublish()\n\n    def get_url(self, context):\n        return reverse(\"wagtailadmin_pages:unpublish\", args=(context[\"page\"].id,))\n\n\nclass DeleteMenuItem(ActionMenuItem):\n    name = \"action-delete\"\n    label = _(\"Delete\")\n    icon_name = \"bin\"\n    classname = \"action-secondary\"\n\n    def is_shown(self, context):\n        if context[\"view\"] == \"edit\":\n            perms_tester = self.get_user_page_permissions_tester(context)\n            return not perms_tester.page_locked() and perms_tester.can_delete()\n\n    def get_url(self, context):\n        return reverse(\"wagtailadmin_pages:delete\", args=(context[\"page\"].id,))\n\n\nclass SaveDraftMenuItem(ActionMenuItem):\n    name = \"action-save-draft\"\n    label = _(\"Save Draft\")\n    template_name = \"wagtailadmin/pages/action_menu/save_draft.html\"\n\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        context[\"is_revision\"] = context[\"view\"] == \"revisions_revert\"\n        return context\n\n\nclass PageLockedMenuItem(ActionMenuItem):\n    name = \"action-page-locked\"\n    label = _(\"Page locked\")\n    template_name = \"wagtailadmin/pages/action_menu/page_locked.html\"\n\n    def is_shown(self, context):\n        return (\n            \"page\" in context\n            and self.get_user_page_permissions_tester(context).page_locked()\n        )\n\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        context[\"is_revision\"] = context[\"view\"] == \"revisions_revert\"\n        return context\n\n\nBASE_PAGE_ACTION_MENU_ITEMS = None\n\n\ndef _get_base_page_action_menu_items():\n    \"\"\"\n    Retrieve the global list of menu items for the page action menu,\n    which may then be customised on a per-request basis\n    \"\"\"\n    global BASE_PAGE_ACTION_MENU_ITEMS\n\n    if BASE_PAGE_ACTION_MENU_ITEMS is None:\n        BASE_PAGE_ACTION_MENU_ITEMS = [\n            SaveDraftMenuItem(order=0),\n            DeleteMenuItem(order=10),\n            UnpublishMenuItem(order=20),\n            PublishMenuItem(order=30),\n            CancelWorkflowMenuItem(order=40),\n            RestartWorkflowMenuItem(order=50),\n            SubmitForModerationMenuItem(order=60),\n            PageLockedMenuItem(order=10000),\n        ]\n        for hook in hooks.get_hooks(\"register_page_action_menu_item\"):\n            action_menu_item = hook()\n            if action_menu_item:\n                BASE_PAGE_ACTION_MENU_ITEMS.append(action_menu_item)\n\n    return BASE_PAGE_ACTION_MENU_ITEMS\n\n\nclass PageActionMenu:\n    template = \"wagtailadmin/pages/action_menu/menu.html\"\n\n    def __init__(self, request, **kwargs):\n        self.request = request\n        self.context = kwargs\n        self.context[\"request\"] = request\n        page = self.context.get(\"page\")\n        user_page_permissions = UserPagePermissionsProxy(self.request.user)\n        self.context[\"user_page_permissions\"] = user_page_permissions\n        if page:\n            self.context[\n                \"user_page_permissions_tester\"\n            ] = user_page_permissions.for_page(page)\n\n        self.menu_items = []\n\n        if page:\n            task = page.current_workflow_task\n            current_workflow_state = page.current_workflow_state\n            is_final_task = (\n                current_workflow_state and current_workflow_state.is_at_final_task\n            )\n            if task:\n                actions = task.get_actions(page, request.user)\n                workflow_menu_items = []\n                for name, label, launch_modal in actions:\n                    icon_name = \"edit\"\n                    if name == \"approve\":\n                        if is_final_task and not getattr(\n                            settings,\n                            \"WAGTAIL_WORKFLOW_REQUIRE_REAPPROVAL_ON_EDIT\",\n                            False,\n                        ):\n                            label = _(\"%(label)s and Publish\") % {\"label\": label}\n                        icon_name = \"success\"\n\n                    item = WorkflowMenuItem(\n                        name, label, launch_modal, icon_name=icon_name\n                    )\n\n                    if item.is_shown(self.context):\n                        workflow_menu_items.append(item)\n                self.menu_items.extend(workflow_menu_items)\n\n        for menu_item in _get_base_page_action_menu_items():\n            if menu_item.is_shown(self.context):\n                self.menu_items.append(menu_item)\n\n        self.menu_items.sort(key=lambda item: item.order)\n\n        for hook in hooks.get_hooks(\"construct_page_action_menu\"):\n            hook(self.menu_items, self.request, self.context)\n\n        try:\n            self.default_item = self.menu_items.pop(0)\n        except IndexError:\n            self.default_item = None\n\n    def render_html(self):\n        rendered_menu_items = [\n            menu_item.render_html(self.context) for menu_item in self.menu_items\n        ]\n\n        rendered_default_item = self.default_item.render_html(self.context)\n\n        return render_to_string(\n            self.template,\n            {\n                \"default_menu_item\": rendered_default_item,\n                \"show_menu\": bool(self.menu_items),\n                \"rendered_menu_items\": rendered_menu_items,\n            },\n            request=self.request,\n        )\n\n    @cached_property\n    def media(self):\n        media = Media()\n        for item in self.menu_items:\n            media += item.media\n        return media\n", "path": "wagtail/admin/action_menu.py"}], "after_files": [{"content": "\"\"\"Handles rendering of the list of actions in the footer of the page create/edit views.\"\"\"\nfrom django.conf import settings\nfrom django.forms import Media\nfrom django.template.loader import render_to_string\nfrom django.urls import reverse\nfrom django.utils.functional import cached_property\nfrom django.utils.translation import gettext_lazy as _\n\nfrom wagtail import hooks\nfrom wagtail.admin.ui.components import Component\nfrom wagtail.models import UserPagePermissionsProxy\n\n\nclass ActionMenuItem(Component):\n    \"\"\"Defines an item in the actions drop-up on the page creation/edit view\"\"\"\n\n    order = 100  # default order index if one is not specified on init\n    template_name = \"wagtailadmin/pages/action_menu/menu_item.html\"\n\n    label = \"\"\n    name = None\n    classname = \"\"\n    icon_name = \"\"\n\n    def __init__(self, order=None):\n        if order is not None:\n            self.order = order\n\n    def get_user_page_permissions_tester(self, context):\n        if \"user_page_permissions_tester\" in context:\n            return context[\"user_page_permissions_tester\"]\n        return context[\"user_page_permissions\"].for_page(context[\"page\"])\n\n    def is_shown(self, context):\n        \"\"\"\n        Whether this action should be shown on this request; permission checks etc should go here.\n        By default, actions are shown for unlocked pages, hidden for locked pages\n\n        context = dictionary containing at least:\n            'request' = the current request object\n            'view' = 'create', 'edit' or 'revisions_revert'\n            'page' (if view = 'edit' or 'revisions_revert') = the page being edited\n            'parent_page' (if view = 'create') = the parent page of the page being created\n            'user_page_permissions' = a UserPagePermissionsProxy for the current user, to test permissions against\n            may also contain:\n            'user_page_permissions_tester' = a PagePermissionTester for the current user and page\n        \"\"\"\n        return (\n            context[\"view\"] == \"create\"\n            or not self.get_user_page_permissions_tester(context).page_locked()\n        )\n\n    def get_context_data(self, parent_context):\n        \"\"\"Defines context for the template, overridable to use more data\"\"\"\n        context = parent_context.copy()\n        url = self.get_url(parent_context)\n\n        context.update(\n            {\n                \"label\": self.label,\n                \"url\": url,\n                \"name\": self.name,\n                \"classname\": self.classname,\n                \"icon_name\": self.icon_name,\n                \"request\": parent_context[\"request\"],\n            }\n        )\n        return context\n\n    def get_url(self, parent_context):\n        return None\n\n\nclass PublishMenuItem(ActionMenuItem):\n    label = _(\"Publish\")\n    name = \"action-publish\"\n    template_name = \"wagtailadmin/pages/action_menu/publish.html\"\n    icon_name = \"upload\"\n\n    def is_shown(self, context):\n        if context[\"view\"] == \"create\":\n            return (\n                context[\"user_page_permissions\"]\n                .for_page(context[\"parent_page\"])\n                .can_publish_subpage()\n            )\n        else:  # view == 'edit' or 'revisions_revert'\n            perms_tester = self.get_user_page_permissions_tester(context)\n            return not perms_tester.page_locked() and perms_tester.can_publish()\n\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        context[\"is_revision\"] = context[\"view\"] == \"revisions_revert\"\n        return context\n\n\nclass SubmitForModerationMenuItem(ActionMenuItem):\n    label = _(\"Submit for moderation\")\n    name = \"action-submit\"\n    icon_name = \"resubmit\"\n\n    def is_shown(self, context):\n        if not getattr(settings, \"WAGTAIL_MODERATION_ENABLED\", True):\n            return False\n\n        if context[\"view\"] == \"create\":\n            return context[\"parent_page\"].has_workflow\n\n        if context[\"view\"] == \"edit\":\n            perms_tester = self.get_user_page_permissions_tester(context)\n            return (\n                perms_tester.can_submit_for_moderation()\n                and not perms_tester.page_locked()\n            )\n        # context == revisions_revert\n        return False\n\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        page = context.get(\"page\")\n        workflow_state = page.current_workflow_state if page else None\n        if (\n            workflow_state\n            and workflow_state.status == workflow_state.STATUS_NEEDS_CHANGES\n        ):\n            context[\"label\"] = _(\"Resubmit to {}\").format(\n                workflow_state.current_task_state.task.name\n            )\n        elif page:\n            workflow = page.get_workflow()\n            if workflow:\n                context[\"label\"] = _(\"Submit to {}\").format(workflow.name)\n        return context\n\n\nclass WorkflowMenuItem(ActionMenuItem):\n    template_name = \"wagtailadmin/pages/action_menu/workflow_menu_item.html\"\n\n    def __init__(self, name, label, launch_modal, *args, **kwargs):\n        self.name = name\n        self.label = label\n        self.launch_modal = launch_modal\n\n        if kwargs.get(\"icon_name\"):\n            self.icon_name = kwargs.pop(\"icon_name\")\n\n        super().__init__(*args, **kwargs)\n\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        context[\"launch_modal\"] = self.launch_modal\n        context[\"current_task_state\"] = context[\"page\"].current_workflow_task_state\n        return context\n\n    def is_shown(self, context):\n        if context[\"view\"] == \"edit\":\n            perms_tester = self.get_user_page_permissions_tester(context)\n            return not perms_tester.page_locked()\n\n\nclass RestartWorkflowMenuItem(ActionMenuItem):\n    label = _(\"Restart workflow \")\n    name = \"action-restart-workflow\"\n    classname = \"button--icon-flipped\"\n    icon_name = \"login\"\n\n    def is_shown(self, context):\n        if not getattr(settings, \"WAGTAIL_MODERATION_ENABLED\", True):\n            return False\n        elif context[\"view\"] == \"edit\":\n            workflow_state = context[\"page\"].current_workflow_state\n            perms_tester = self.get_user_page_permissions_tester(context)\n            return (\n                perms_tester.can_submit_for_moderation()\n                and not perms_tester.page_locked()\n                and workflow_state\n                and workflow_state.user_can_cancel(context[\"request\"].user)\n            )\n        else:\n            return False\n\n\nclass CancelWorkflowMenuItem(ActionMenuItem):\n    label = _(\"Cancel workflow \")\n    name = \"action-cancel-workflow\"\n    icon_name = \"error\"\n\n    def is_shown(self, context):\n        if context[\"view\"] == \"edit\":\n            workflow_state = context[\"page\"].current_workflow_state\n            return workflow_state and workflow_state.user_can_cancel(\n                context[\"request\"].user\n            )\n        return False\n\n\nclass UnpublishMenuItem(ActionMenuItem):\n    label = _(\"Unpublish\")\n    name = \"action-unpublish\"\n    icon_name = \"download-alt\"\n    classname = \"action-secondary\"\n\n    def is_shown(self, context):\n        if context[\"view\"] == \"edit\":\n            perms_tester = self.get_user_page_permissions_tester(context)\n            return not perms_tester.page_locked() and perms_tester.can_unpublish()\n\n    def get_url(self, context):\n        return reverse(\"wagtailadmin_pages:unpublish\", args=(context[\"page\"].id,))\n\n\nclass SaveDraftMenuItem(ActionMenuItem):\n    name = \"action-save-draft\"\n    label = _(\"Save Draft\")\n    template_name = \"wagtailadmin/pages/action_menu/save_draft.html\"\n\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        context[\"is_revision\"] = context[\"view\"] == \"revisions_revert\"\n        return context\n\n\nclass PageLockedMenuItem(ActionMenuItem):\n    name = \"action-page-locked\"\n    label = _(\"Page locked\")\n    template_name = \"wagtailadmin/pages/action_menu/page_locked.html\"\n\n    def is_shown(self, context):\n        return (\n            \"page\" in context\n            and self.get_user_page_permissions_tester(context).page_locked()\n        )\n\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        context[\"is_revision\"] = context[\"view\"] == \"revisions_revert\"\n        return context\n\n\nBASE_PAGE_ACTION_MENU_ITEMS = None\n\n\ndef _get_base_page_action_menu_items():\n    \"\"\"\n    Retrieve the global list of menu items for the page action menu,\n    which may then be customised on a per-request basis\n    \"\"\"\n    global BASE_PAGE_ACTION_MENU_ITEMS\n\n    if BASE_PAGE_ACTION_MENU_ITEMS is None:\n        BASE_PAGE_ACTION_MENU_ITEMS = [\n            SaveDraftMenuItem(order=0),\n            UnpublishMenuItem(order=20),\n            PublishMenuItem(order=30),\n            CancelWorkflowMenuItem(order=40),\n            RestartWorkflowMenuItem(order=50),\n            SubmitForModerationMenuItem(order=60),\n            PageLockedMenuItem(order=10000),\n        ]\n        for hook in hooks.get_hooks(\"register_page_action_menu_item\"):\n            action_menu_item = hook()\n            if action_menu_item:\n                BASE_PAGE_ACTION_MENU_ITEMS.append(action_menu_item)\n\n    return BASE_PAGE_ACTION_MENU_ITEMS\n\n\nclass PageActionMenu:\n    template = \"wagtailadmin/pages/action_menu/menu.html\"\n\n    def __init__(self, request, **kwargs):\n        self.request = request\n        self.context = kwargs\n        self.context[\"request\"] = request\n        page = self.context.get(\"page\")\n        user_page_permissions = UserPagePermissionsProxy(self.request.user)\n        self.context[\"user_page_permissions\"] = user_page_permissions\n        if page:\n            self.context[\n                \"user_page_permissions_tester\"\n            ] = user_page_permissions.for_page(page)\n\n        self.menu_items = []\n\n        if page:\n            task = page.current_workflow_task\n            current_workflow_state = page.current_workflow_state\n            is_final_task = (\n                current_workflow_state and current_workflow_state.is_at_final_task\n            )\n            if task:\n                actions = task.get_actions(page, request.user)\n                workflow_menu_items = []\n                for name, label, launch_modal in actions:\n                    icon_name = \"edit\"\n                    if name == \"approve\":\n                        if is_final_task and not getattr(\n                            settings,\n                            \"WAGTAIL_WORKFLOW_REQUIRE_REAPPROVAL_ON_EDIT\",\n                            False,\n                        ):\n                            label = _(\"%(label)s and Publish\") % {\"label\": label}\n                        icon_name = \"success\"\n\n                    item = WorkflowMenuItem(\n                        name, label, launch_modal, icon_name=icon_name\n                    )\n\n                    if item.is_shown(self.context):\n                        workflow_menu_items.append(item)\n                self.menu_items.extend(workflow_menu_items)\n\n        for menu_item in _get_base_page_action_menu_items():\n            if menu_item.is_shown(self.context):\n                self.menu_items.append(menu_item)\n\n        self.menu_items.sort(key=lambda item: item.order)\n\n        for hook in hooks.get_hooks(\"construct_page_action_menu\"):\n            hook(self.menu_items, self.request, self.context)\n\n        try:\n            self.default_item = self.menu_items.pop(0)\n        except IndexError:\n            self.default_item = None\n\n    def render_html(self):\n        rendered_menu_items = [\n            menu_item.render_html(self.context) for menu_item in self.menu_items\n        ]\n\n        rendered_default_item = self.default_item.render_html(self.context)\n\n        return render_to_string(\n            self.template,\n            {\n                \"default_menu_item\": rendered_default_item,\n                \"show_menu\": bool(self.menu_items),\n                \"rendered_menu_items\": rendered_menu_items,\n            },\n            request=self.request,\n        )\n\n    @cached_property\n    def media(self):\n        media = Media()\n        for item in self.menu_items:\n            media += item.media\n        return media\n", "path": "wagtail/admin/action_menu.py"}]}