We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
UX Unification - Cleanup for slim header in page listing
### Issue Summary

#8792 introduced some issues due to conflict with other PRs that have been merged previously. In addition, there are also other improvements that can be made.

### Details

- [ ] When moving `.form-side` styles to its own `_form-side.scss` file, some updates introduced in #8671 weren't carried over. By the way, should this be in `components` rather than `layouts`?
  **Original:** https://github.com/wagtail/wagtail/blob/0693eed2454240b4d0f31da5166772bdd106dbb9/client/scss/layouts/_page-editor.scss#L61-L103
  **Moved:** https://github.com/wagtail/wagtail/blob/35b5ed350a30dfb626d55c0b2c021976c1f65761/client/scss/layouts/_form-side.scss#L5-L47
- [ ] When moving side panel init code to a separate `sidePanel.js` file, the original code in `page-editor.js` hasn't been removed. This results in the event listeners being registered twice, making the side panels inaccessible in the page editor (it immediately closes again). To fix this, remove the following: https://github.com/wagtail/wagtail/blob/35b5ed350a30dfb626d55c0b2c021976c1f65761/client/src/entrypoints/admin/page-editor.js#L333-L407
- [ ] The locale selector in the side panel should take the user to the localised page in the **page explorer**. Right now, it brings you to the editor instead. Possible solutions: add another keyword argument to `PageSidePanels`, e.g. `in_explorer`, or make a subclass e.g. `PageExplorerSidePanels` in case we need more customisations in the future.

There may be other issues I haven't noticed. Will update later if I find more.

--- 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/ui/side_panels.py`
Content:
```
1 from django.conf import settings
2 from django.forms import Media
3 from django.urls import reverse
4 from django.utils.functional import cached_property
5 from django.utils.text import capfirst
6 from django.utils.translation import gettext_lazy
7 
8 from wagtail.admin.ui.components import Component
9 from wagtail.models import Page, UserPagePermissionsProxy
10 
11 
12 class BaseSidePanel(Component):
13     def __init__(self, object, request):
14         self.object = object
15         self.request = request
16         self.model = type(self.object)
17 
18     def get_context_data(self, parent_context):
19         context = {"panel": self, "object": self.object, "request": self.request}
20         if issubclass(self.model, Page):
21             context["page"] = self.object
22         return context
23 
24 
25 class BaseStatusSidePanel(BaseSidePanel):
26     name = "status"
27     title = gettext_lazy("Status")
28     template_name = "wagtailadmin/shared/side_panels/status.html"
29     order = 100
30     toggle_aria_label = gettext_lazy("Toggle status")
31     toggle_icon_name = "info-circle"
32 
33     def get_status_templates(self, context):
34         templates = []
35 
36         if self.object.pk:
37             templates += [
38                 "wagtailadmin/shared/side_panels/includes/status/workflow.html",
39             ]
40 
41         if context.get("locale"):
42             templates += ["wagtailadmin/shared/side_panels/includes/status/locale.html"]
43 
44         return templates
45 
46     def get_context_data(self, parent_context):
47         context = super().get_context_data(parent_context)
48         context["model_name"] = capfirst(self.model._meta.verbose_name)
49         context["status_templates"] = self.get_status_templates(context)
50         return context
51 
52 
53 class PageStatusSidePanel(BaseStatusSidePanel):
54     def get_status_templates(self, context):
55         templates = super().get_status_templates(context)
56         if self.object.pk:
57             templates += ["wagtailadmin/shared/side_panels/includes/status/locked.html"]
58         templates += ["wagtailadmin/shared/side_panels/includes/status/privacy.html"]
59         return templates
60 
61     def get_context_data(self, parent_context):
62         context = super().get_context_data(parent_context)
63         user_perms = UserPagePermissionsProxy(self.request.user)
64         page = self.object
65 
66         if page.id:
67             context.update(
68                 {
69                     "history_url": reverse(
70                         "wagtailadmin_pages:history", args=(page.id,)
71                     ),
72                     "lock_url": reverse("wagtailadmin_pages:lock", args=(page.id,)),
73                     "unlock_url": reverse("wagtailadmin_pages:unlock", args=(page.id,)),
74                     "user_can_lock": user_perms.for_page(page).can_lock(),
75                     "user_can_unlock": user_perms.for_page(page).can_unlock(),
76                     "locale": None,
77                     "translations": [],
78                 }
79             )
80         else:
81             context.update(
82                 {
83                     "locale": None,
84                     "translations": [],
85                 }
86             )
87 
88         if getattr(settings, "WAGTAIL_I18N_ENABLED", False):
89             context.update(
90                 {
91                     "locale": page.locale,
92                     "translations": [
93                         {
94                             "locale": translation.locale,
95                             "url": reverse(
96                                 "wagtailadmin_pages:edit", args=[translation.id]
97                             ),
98                         }
99                         for translation in page.get_translations()
100                         .only("id", "locale", "depth")
101                         .select_related("locale")
102                         if user_perms.for_page(translation).can_edit()
103                     ],
104                     # The sum of translated pages plus 1 to account for the current page
105                     "translations_total": page.get_translations().count() + 1,
106                 }
107             )
108 
109         context.update(
110             {
111                 "model_name": self.model.get_verbose_name(),
112                 "model_description": self.model.get_page_description(),
113                 "status_templates": self.get_status_templates(context),
114             }
115         )
116 
117         return context
118 
119 
120 class CommentsSidePanel(BaseSidePanel):
121     name = "comments"
122     title = gettext_lazy("Comments")
123     template_name = "wagtailadmin/shared/side_panels/comments.html"
124     order = 300
125     toggle_aria_label = gettext_lazy("Toggle comments")
126     toggle_icon_name = "comment"
127 
128 
129 class BasePreviewSidePanel(BaseSidePanel):
130     name = "preview"
131     title = gettext_lazy("Preview")
132     template_name = "wagtailadmin/shared/side_panels/preview.html"
133     order = 400
134     toggle_aria_label = gettext_lazy("Toggle preview")
135     toggle_icon_name = "mobile-alt"
136 
137     def get_context_data(self, parent_context):
138         context = super().get_context_data(parent_context)
139         context["has_multiple_modes"] = len(self.object.preview_modes) > 1
140         return context
141 
142 
143 class PagePreviewSidePanel(BasePreviewSidePanel):
144     def get_context_data(self, parent_context):
145         context = super().get_context_data(parent_context)
146         if self.object.id:
147             context["preview_url"] = reverse(
148                 "wagtailadmin_pages:preview_on_edit", args=[self.object.id]
149             )
150         else:
151             content_type = parent_context["content_type"]
152             parent_page = parent_context["parent_page"]
153             context["preview_url"] = reverse(
154                 "wagtailadmin_pages:preview_on_add",
155                 args=[content_type.app_label, content_type.model, parent_page.id],
156             )
157         return context
158 
159 
160 class BaseSidePanels:
161     def __init__(self, request, object):
162         self.request = request
163         self.object = object
164 
165         self.side_panels = [
166             BaseStatusSidePanel(object, self.request),
167         ]
168 
169     def __iter__(self):
170         return iter(sorted(self.side_panels, key=lambda p: p.order))
171 
172     @cached_property
173     def media(self):
174         media = Media()
175         for panel in self:
176             media += panel.media
177         return media
178 
179 
180 class PageSidePanels(BaseSidePanels):
181     def __init__(self, request, page, *, preview_enabled, comments_enabled):
182         super().__init__(request, page)
183 
184         self.side_panels = [
185             PageStatusSidePanel(page, self.request),
186         ]
187 
188         if preview_enabled and page.preview_modes:
189             self.side_panels += [
190                 PagePreviewSidePanel(page, self.request),
191             ]
192 
193         if comments_enabled:
194             self.side_panels += [
195                 CommentsSidePanel(page, self.request),
196             ]
197
```

Path: `wagtail/admin/views/pages/listing.py`
Content:
```
1 from django.conf import settings
2 from django.core.paginator import Paginator
3 from django.db.models import Count
4 from django.shortcuts import get_object_or_404, redirect
5 from django.template.response import TemplateResponse
6 from django.urls import reverse
7 
8 from wagtail import hooks
9 from wagtail.admin.auth import user_has_any_page_permission, user_passes_test
10 from wagtail.admin.navigation import get_explorable_root_page
11 from wagtail.admin.ui.side_panels import PageSidePanels
12 from wagtail.models import Page, UserPagePermissionsProxy
13 
14 
15 @user_passes_test(user_has_any_page_permission)
16 def index(request, parent_page_id=None):
17     if parent_page_id:
18         parent_page = get_object_or_404(Page, id=parent_page_id)
19     else:
20         parent_page = Page.get_first_root_node()
21 
22     # This will always succeed because of the @user_passes_test above.
23     root_page = get_explorable_root_page(request.user)
24 
25     # If this page isn't a descendant of the user's explorable root page,
26     # then redirect to that explorable root page instead.
27     if not (parent_page.pk == root_page.pk or parent_page.is_descendant_of(root_page)):
28         return redirect("wagtailadmin_explore", root_page.pk)
29 
30     parent_page = parent_page.specific
31 
32     user_perms = UserPagePermissionsProxy(request.user)
33     pages = (
34         parent_page.get_children().prefetch_related("content_type", "sites_rooted_here")
35         & user_perms.explorable_pages()
36     )
37 
38     # Get page ordering
39     ordering = request.GET.get("ordering", "-latest_revision_created_at")
40     if ordering not in [
41         "title",
42         "-title",
43         "content_type",
44         "-content_type",
45         "live",
46         "-live",
47         "latest_revision_created_at",
48         "-latest_revision_created_at",
49         "ord",
50     ]:
51         ordering = "-latest_revision_created_at"
52 
53     if ordering == "ord":
54         # preserve the native ordering from get_children()
55         pass
56     elif ordering == "latest_revision_created_at":
57         # order by oldest revision first.
58         # Special case NULL entries - these should go at the top of the list.
59         # Do this by annotating with Count('latest_revision_created_at'),
60         # which returns 0 for these
61         pages = pages.annotate(
62             null_position=Count("latest_revision_created_at")
63         ).order_by("null_position", "latest_revision_created_at")
64     elif ordering == "-latest_revision_created_at":
65         # order by oldest revision first.
66         # Special case NULL entries - these should go at the end of the list.
67         pages = pages.annotate(
68             null_position=Count("latest_revision_created_at")
69         ).order_by("-null_position", "-latest_revision_created_at")
70     else:
71         pages = pages.order_by(ordering)
72 
73     # Don't paginate if sorting by page order - all pages must be shown to
74     # allow drag-and-drop reordering
75     do_paginate = ordering != "ord"
76 
77     # We want specific page instances, but do not need streamfield values here
78     pages = pages.defer_streamfields().specific()
79 
80     # allow hooks defer_streamfieldsyset
81     for hook in hooks.get_hooks("construct_explorer_page_queryset"):
82         pages = hook(parent_page, pages, request)
83 
84     # Annotate queryset with various states to be used later for performance optimisations
85     if getattr(settings, "WAGTAIL_WORKFLOW_ENABLED", True):
86         pages = pages.prefetch_workflow_states()
87 
88     pages = pages.annotate_site_root_state().annotate_approved_schedule()
89 
90     # Pagination
91     if do_paginate:
92         paginator = Paginator(pages, per_page=50)
93         pages = paginator.get_page(request.GET.get("p"))
94 
95     show_ordering_column = request.GET.get("ordering") == "ord"
96 
97     side_panels = PageSidePanels(
98         request,
99         parent_page.specific,
100         preview_enabled=False,
101         comments_enabled=False,
102     )
103 
104     context = {
105         "parent_page": parent_page.specific,
106         "ordering": ordering,
107         "side_panels": side_panels,
108         "pages": pages,
109         "do_paginate": do_paginate,
110         "locale": None,
111         "translations": [],
112         "show_ordering_column": show_ordering_column,
113         "show_bulk_actions": not show_ordering_column,
114         "show_locale_labels": False,
115     }
116 
117     if getattr(settings, "WAGTAIL_I18N_ENABLED", False):
118         if not parent_page.is_root():
119             context.update(
120                 {
121                     "locale": parent_page.locale,
122                     "translations": [
123                         {
124                             "locale": translation.locale,
125                             "url": reverse(
126                                 "wagtailadmin_explore", args=[translation.id]
127                             ),
128                         }
129                         for translation in parent_page.get_translations()
130                         .only("id", "locale")
131                         .select_related("locale")
132                     ],
133                 }
134             )
135         else:
136             context["show_locale_labels"] = True
137 
138     return TemplateResponse(request, "wagtailadmin/pages/index.html", context)
139
```
--- 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/ui/side_panels.py b/wagtail/admin/ui/side_panels.py
--- a/wagtail/admin/ui/side_panels.py
+++ b/wagtail/admin/ui/side_panels.py
@@ -30,6 +30,10 @@
     toggle_aria_label = gettext_lazy("Toggle status")
     toggle_icon_name = "info-circle"
 
+    def __init__(self, *args, in_explorer=False, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.in_explorer = in_explorer
+
     def get_status_templates(self, context):
         templates = []
 
@@ -86,15 +90,17 @@
             )
 
         if getattr(settings, "WAGTAIL_I18N_ENABLED", False):
+            url_name = "wagtailadmin_pages:edit"
+            if self.in_explorer:
+                url_name = "wagtailadmin_explore"
+
             context.update(
                 {
                     "locale": page.locale,
                     "translations": [
                         {
                             "locale": translation.locale,
-                            "url": reverse(
-                                "wagtailadmin_pages:edit", args=[translation.id]
-                            ),
+                            "url": reverse(url_name, args=[translation.id]),
                         }
                         for translation in page.get_translations()
                         .only("id", "locale", "depth")
@@ -178,11 +184,13 @@
 
 
 class PageSidePanels(BaseSidePanels):
-    def __init__(self, request, page, *, preview_enabled, comments_enabled):
+    def __init__(
+        self, request, page, *, preview_enabled, comments_enabled, in_explorer=False
+    ):
         super().__init__(request, page)
 
         self.side_panels = [
-            PageStatusSidePanel(page, self.request),
+            PageStatusSidePanel(page, self.request, in_explorer=in_explorer),
         ]
 
         if preview_enabled and page.preview_modes:
diff --git a/wagtail/admin/views/pages/listing.py b/wagtail/admin/views/pages/listing.py
--- a/wagtail/admin/views/pages/listing.py
+++ b/wagtail/admin/views/pages/listing.py
@@ -97,6 +97,7 @@
     side_panels = PageSidePanels(
         request,
         parent_page.specific,
+        in_explorer=True,
         preview_enabled=False,
         comments_enabled=False,
     )

{"golden_diff": "diff --git a/wagtail/admin/ui/side_panels.py b/wagtail/admin/ui/side_panels.py\n--- a/wagtail/admin/ui/side_panels.py\n+++ b/wagtail/admin/ui/side_panels.py\n@@ -30,6 +30,10 @@\n     toggle_aria_label = gettext_lazy(\"Toggle status\")\n     toggle_icon_name = \"info-circle\"\n \n+    def __init__(self, *args, in_explorer=False, **kwargs):\n+        super().__init__(*args, **kwargs)\n+        self.in_explorer = in_explorer\n+\n     def get_status_templates(self, context):\n         templates = []\n \n@@ -86,15 +90,17 @@\n             )\n \n         if getattr(settings, \"WAGTAIL_I18N_ENABLED\", False):\n+            url_name = \"wagtailadmin_pages:edit\"\n+            if self.in_explorer:\n+                url_name = \"wagtailadmin_explore\"\n+\n             context.update(\n                 {\n                     \"locale\": page.locale,\n                     \"translations\": [\n                         {\n                             \"locale\": translation.locale,\n-                            \"url\": reverse(\n-                                \"wagtailadmin_pages:edit\", args=[translation.id]\n-                            ),\n+                            \"url\": reverse(url_name, args=[translation.id]),\n                         }\n                         for translation in page.get_translations()\n                         .only(\"id\", \"locale\", \"depth\")\n@@ -178,11 +184,13 @@\n \n \n class PageSidePanels(BaseSidePanels):\n-    def __init__(self, request, page, *, preview_enabled, comments_enabled):\n+    def __init__(\n+        self, request, page, *, preview_enabled, comments_enabled, in_explorer=False\n+    ):\n         super().__init__(request, page)\n \n         self.side_panels = [\n-            PageStatusSidePanel(page, self.request),\n+            PageStatusSidePanel(page, self.request, in_explorer=in_explorer),\n         ]\n \n         if preview_enabled and page.preview_modes:\ndiff --git a/wagtail/admin/views/pages/listing.py b/wagtail/admin/views/pages/listing.py\n--- a/wagtail/admin/views/pages/listing.py\n+++ b/wagtail/admin/views/pages/listing.py\n@@ -97,6 +97,7 @@\n     side_panels = PageSidePanels(\n         request,\n         parent_page.specific,\n+        in_explorer=True,\n         preview_enabled=False,\n         comments_enabled=False,\n     )\n", "issue": "UX Unification - Cleanup for slim header in page listing\n### Issue Summary\r\n\r\n#8792 introduced some issues due to conflict with other PRs that have been merged previously. In addition, there are also other improvements that can be made.\r\n\r\n### Details\r\n\r\n- [ ] When moving `.form-side` styles to its own `_form-side.scss` file, some updates introduced in #8671 weren't carried over. By the way, should this be in `components` rather than `layouts`?\r\n  **Original:** https://github.com/wagtail/wagtail/blob/0693eed2454240b4d0f31da5166772bdd106dbb9/client/scss/layouts/_page-editor.scss#L61-L103\r\n  **Moved:** https://github.com/wagtail/wagtail/blob/35b5ed350a30dfb626d55c0b2c021976c1f65761/client/scss/layouts/_form-side.scss#L5-L47\r\n- [ ] When moving side panel init code to a separate `sidePanel.js` file, the original code in `page-editor.js` hasn't been removed. This results in the event listeners being registered twice, making the side panels inaccessible in the page editor (it immediately closes again). To fix this, remove the following: https://github.com/wagtail/wagtail/blob/35b5ed350a30dfb626d55c0b2c021976c1f65761/client/src/entrypoints/admin/page-editor.js#L333-L407\r\n- [ ] The locale selector in the side panel should take the user to the localised page in the **page explorer**. Right now, it brings you to the editor instead. Possible solutions: add another keyword argument to `PageSidePanels`, e.g. `in_explorer`, or make a subclass e.g. `PageExplorerSidePanels` in case we need more customisations in the future.\r\n\r\nThere may be other issues I haven't noticed. Will update later if I find more.\n", "before_files": [{"content": "from django.conf import settings\nfrom django.forms import Media\nfrom django.urls import reverse\nfrom django.utils.functional import cached_property\nfrom django.utils.text import capfirst\nfrom django.utils.translation import gettext_lazy\n\nfrom wagtail.admin.ui.components import Component\nfrom wagtail.models import Page, UserPagePermissionsProxy\n\n\nclass BaseSidePanel(Component):\n    def __init__(self, object, request):\n        self.object = object\n        self.request = request\n        self.model = type(self.object)\n\n    def get_context_data(self, parent_context):\n        context = {\"panel\": self, \"object\": self.object, \"request\": self.request}\n        if issubclass(self.model, Page):\n            context[\"page\"] = self.object\n        return context\n\n\nclass BaseStatusSidePanel(BaseSidePanel):\n    name = \"status\"\n    title = gettext_lazy(\"Status\")\n    template_name = \"wagtailadmin/shared/side_panels/status.html\"\n    order = 100\n    toggle_aria_label = gettext_lazy(\"Toggle status\")\n    toggle_icon_name = \"info-circle\"\n\n    def get_status_templates(self, context):\n        templates = []\n\n        if self.object.pk:\n            templates += [\n                \"wagtailadmin/shared/side_panels/includes/status/workflow.html\",\n            ]\n\n        if context.get(\"locale\"):\n            templates += [\"wagtailadmin/shared/side_panels/includes/status/locale.html\"]\n\n        return templates\n\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        context[\"model_name\"] = capfirst(self.model._meta.verbose_name)\n        context[\"status_templates\"] = self.get_status_templates(context)\n        return context\n\n\nclass PageStatusSidePanel(BaseStatusSidePanel):\n    def get_status_templates(self, context):\n        templates = super().get_status_templates(context)\n        if self.object.pk:\n            templates += [\"wagtailadmin/shared/side_panels/includes/status/locked.html\"]\n        templates += [\"wagtailadmin/shared/side_panels/includes/status/privacy.html\"]\n        return templates\n\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        user_perms = UserPagePermissionsProxy(self.request.user)\n        page = self.object\n\n        if page.id:\n            context.update(\n                {\n                    \"history_url\": reverse(\n                        \"wagtailadmin_pages:history\", args=(page.id,)\n                    ),\n                    \"lock_url\": reverse(\"wagtailadmin_pages:lock\", args=(page.id,)),\n                    \"unlock_url\": reverse(\"wagtailadmin_pages:unlock\", args=(page.id,)),\n                    \"user_can_lock\": user_perms.for_page(page).can_lock(),\n                    \"user_can_unlock\": user_perms.for_page(page).can_unlock(),\n                    \"locale\": None,\n                    \"translations\": [],\n                }\n            )\n        else:\n            context.update(\n                {\n                    \"locale\": None,\n                    \"translations\": [],\n                }\n            )\n\n        if getattr(settings, \"WAGTAIL_I18N_ENABLED\", False):\n            context.update(\n                {\n                    \"locale\": page.locale,\n                    \"translations\": [\n                        {\n                            \"locale\": translation.locale,\n                            \"url\": reverse(\n                                \"wagtailadmin_pages:edit\", args=[translation.id]\n                            ),\n                        }\n                        for translation in page.get_translations()\n                        .only(\"id\", \"locale\", \"depth\")\n                        .select_related(\"locale\")\n                        if user_perms.for_page(translation).can_edit()\n                    ],\n                    # The sum of translated pages plus 1 to account for the current page\n                    \"translations_total\": page.get_translations().count() + 1,\n                }\n            )\n\n        context.update(\n            {\n                \"model_name\": self.model.get_verbose_name(),\n                \"model_description\": self.model.get_page_description(),\n                \"status_templates\": self.get_status_templates(context),\n            }\n        )\n\n        return context\n\n\nclass CommentsSidePanel(BaseSidePanel):\n    name = \"comments\"\n    title = gettext_lazy(\"Comments\")\n    template_name = \"wagtailadmin/shared/side_panels/comments.html\"\n    order = 300\n    toggle_aria_label = gettext_lazy(\"Toggle comments\")\n    toggle_icon_name = \"comment\"\n\n\nclass BasePreviewSidePanel(BaseSidePanel):\n    name = \"preview\"\n    title = gettext_lazy(\"Preview\")\n    template_name = \"wagtailadmin/shared/side_panels/preview.html\"\n    order = 400\n    toggle_aria_label = gettext_lazy(\"Toggle preview\")\n    toggle_icon_name = \"mobile-alt\"\n\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        context[\"has_multiple_modes\"] = len(self.object.preview_modes) > 1\n        return context\n\n\nclass PagePreviewSidePanel(BasePreviewSidePanel):\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        if self.object.id:\n            context[\"preview_url\"] = reverse(\n                \"wagtailadmin_pages:preview_on_edit\", args=[self.object.id]\n            )\n        else:\n            content_type = parent_context[\"content_type\"]\n            parent_page = parent_context[\"parent_page\"]\n            context[\"preview_url\"] = reverse(\n                \"wagtailadmin_pages:preview_on_add\",\n                args=[content_type.app_label, content_type.model, parent_page.id],\n            )\n        return context\n\n\nclass BaseSidePanels:\n    def __init__(self, request, object):\n        self.request = request\n        self.object = object\n\n        self.side_panels = [\n            BaseStatusSidePanel(object, self.request),\n        ]\n\n    def __iter__(self):\n        return iter(sorted(self.side_panels, key=lambda p: p.order))\n\n    @cached_property\n    def media(self):\n        media = Media()\n        for panel in self:\n            media += panel.media\n        return media\n\n\nclass PageSidePanels(BaseSidePanels):\n    def __init__(self, request, page, *, preview_enabled, comments_enabled):\n        super().__init__(request, page)\n\n        self.side_panels = [\n            PageStatusSidePanel(page, self.request),\n        ]\n\n        if preview_enabled and page.preview_modes:\n            self.side_panels += [\n                PagePreviewSidePanel(page, self.request),\n            ]\n\n        if comments_enabled:\n            self.side_panels += [\n                CommentsSidePanel(page, self.request),\n            ]\n", "path": "wagtail/admin/ui/side_panels.py"}, {"content": "from django.conf import settings\nfrom django.core.paginator import Paginator\nfrom django.db.models import Count\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.template.response import TemplateResponse\nfrom django.urls import reverse\n\nfrom wagtail import hooks\nfrom wagtail.admin.auth import user_has_any_page_permission, user_passes_test\nfrom wagtail.admin.navigation import get_explorable_root_page\nfrom wagtail.admin.ui.side_panels import PageSidePanels\nfrom wagtail.models import Page, UserPagePermissionsProxy\n\n\n@user_passes_test(user_has_any_page_permission)\ndef index(request, parent_page_id=None):\n    if parent_page_id:\n        parent_page = get_object_or_404(Page, id=parent_page_id)\n    else:\n        parent_page = Page.get_first_root_node()\n\n    # This will always succeed because of the @user_passes_test above.\n    root_page = get_explorable_root_page(request.user)\n\n    # If this page isn't a descendant of the user's explorable root page,\n    # then redirect to that explorable root page instead.\n    if not (parent_page.pk == root_page.pk or parent_page.is_descendant_of(root_page)):\n        return redirect(\"wagtailadmin_explore\", root_page.pk)\n\n    parent_page = parent_page.specific\n\n    user_perms = UserPagePermissionsProxy(request.user)\n    pages = (\n        parent_page.get_children().prefetch_related(\"content_type\", \"sites_rooted_here\")\n        & user_perms.explorable_pages()\n    )\n\n    # Get page ordering\n    ordering = request.GET.get(\"ordering\", \"-latest_revision_created_at\")\n    if ordering not in [\n        \"title\",\n        \"-title\",\n        \"content_type\",\n        \"-content_type\",\n        \"live\",\n        \"-live\",\n        \"latest_revision_created_at\",\n        \"-latest_revision_created_at\",\n        \"ord\",\n    ]:\n        ordering = \"-latest_revision_created_at\"\n\n    if ordering == \"ord\":\n        # preserve the native ordering from get_children()\n        pass\n    elif ordering == \"latest_revision_created_at\":\n        # order by oldest revision first.\n        # Special case NULL entries - these should go at the top of the list.\n        # Do this by annotating with Count('latest_revision_created_at'),\n        # which returns 0 for these\n        pages = pages.annotate(\n            null_position=Count(\"latest_revision_created_at\")\n        ).order_by(\"null_position\", \"latest_revision_created_at\")\n    elif ordering == \"-latest_revision_created_at\":\n        # order by oldest revision first.\n        # Special case NULL entries - these should go at the end of the list.\n        pages = pages.annotate(\n            null_position=Count(\"latest_revision_created_at\")\n        ).order_by(\"-null_position\", \"-latest_revision_created_at\")\n    else:\n        pages = pages.order_by(ordering)\n\n    # Don't paginate if sorting by page order - all pages must be shown to\n    # allow drag-and-drop reordering\n    do_paginate = ordering != \"ord\"\n\n    # We want specific page instances, but do not need streamfield values here\n    pages = pages.defer_streamfields().specific()\n\n    # allow hooks defer_streamfieldsyset\n    for hook in hooks.get_hooks(\"construct_explorer_page_queryset\"):\n        pages = hook(parent_page, pages, request)\n\n    # Annotate queryset with various states to be used later for performance optimisations\n    if getattr(settings, \"WAGTAIL_WORKFLOW_ENABLED\", True):\n        pages = pages.prefetch_workflow_states()\n\n    pages = pages.annotate_site_root_state().annotate_approved_schedule()\n\n    # Pagination\n    if do_paginate:\n        paginator = Paginator(pages, per_page=50)\n        pages = paginator.get_page(request.GET.get(\"p\"))\n\n    show_ordering_column = request.GET.get(\"ordering\") == \"ord\"\n\n    side_panels = PageSidePanels(\n        request,\n        parent_page.specific,\n        preview_enabled=False,\n        comments_enabled=False,\n    )\n\n    context = {\n        \"parent_page\": parent_page.specific,\n        \"ordering\": ordering,\n        \"side_panels\": side_panels,\n        \"pages\": pages,\n        \"do_paginate\": do_paginate,\n        \"locale\": None,\n        \"translations\": [],\n        \"show_ordering_column\": show_ordering_column,\n        \"show_bulk_actions\": not show_ordering_column,\n        \"show_locale_labels\": False,\n    }\n\n    if getattr(settings, \"WAGTAIL_I18N_ENABLED\", False):\n        if not parent_page.is_root():\n            context.update(\n                {\n                    \"locale\": parent_page.locale,\n                    \"translations\": [\n                        {\n                            \"locale\": translation.locale,\n                            \"url\": reverse(\n                                \"wagtailadmin_explore\", args=[translation.id]\n                            ),\n                        }\n                        for translation in parent_page.get_translations()\n                        .only(\"id\", \"locale\")\n                        .select_related(\"locale\")\n                    ],\n                }\n            )\n        else:\n            context[\"show_locale_labels\"] = True\n\n    return TemplateResponse(request, \"wagtailadmin/pages/index.html\", context)\n", "path": "wagtail/admin/views/pages/listing.py"}], "after_files": [{"content": "from django.conf import settings\nfrom django.forms import Media\nfrom django.urls import reverse\nfrom django.utils.functional import cached_property\nfrom django.utils.text import capfirst\nfrom django.utils.translation import gettext_lazy\n\nfrom wagtail.admin.ui.components import Component\nfrom wagtail.models import Page, UserPagePermissionsProxy\n\n\nclass BaseSidePanel(Component):\n    def __init__(self, object, request):\n        self.object = object\n        self.request = request\n        self.model = type(self.object)\n\n    def get_context_data(self, parent_context):\n        context = {\"panel\": self, \"object\": self.object, \"request\": self.request}\n        if issubclass(self.model, Page):\n            context[\"page\"] = self.object\n        return context\n\n\nclass BaseStatusSidePanel(BaseSidePanel):\n    name = \"status\"\n    title = gettext_lazy(\"Status\")\n    template_name = \"wagtailadmin/shared/side_panels/status.html\"\n    order = 100\n    toggle_aria_label = gettext_lazy(\"Toggle status\")\n    toggle_icon_name = \"info-circle\"\n\n    def __init__(self, *args, in_explorer=False, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.in_explorer = in_explorer\n\n    def get_status_templates(self, context):\n        templates = []\n\n        if self.object.pk:\n            templates += [\n                \"wagtailadmin/shared/side_panels/includes/status/workflow.html\",\n            ]\n\n        if context.get(\"locale\"):\n            templates += [\"wagtailadmin/shared/side_panels/includes/status/locale.html\"]\n\n        return templates\n\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        context[\"model_name\"] = capfirst(self.model._meta.verbose_name)\n        context[\"status_templates\"] = self.get_status_templates(context)\n        return context\n\n\nclass PageStatusSidePanel(BaseStatusSidePanel):\n    def get_status_templates(self, context):\n        templates = super().get_status_templates(context)\n        if self.object.pk:\n            templates += [\"wagtailadmin/shared/side_panels/includes/status/locked.html\"]\n        templates += [\"wagtailadmin/shared/side_panels/includes/status/privacy.html\"]\n        return templates\n\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        user_perms = UserPagePermissionsProxy(self.request.user)\n        page = self.object\n\n        if page.id:\n            context.update(\n                {\n                    \"history_url\": reverse(\n                        \"wagtailadmin_pages:history\", args=(page.id,)\n                    ),\n                    \"lock_url\": reverse(\"wagtailadmin_pages:lock\", args=(page.id,)),\n                    \"unlock_url\": reverse(\"wagtailadmin_pages:unlock\", args=(page.id,)),\n                    \"user_can_lock\": user_perms.for_page(page).can_lock(),\n                    \"user_can_unlock\": user_perms.for_page(page).can_unlock(),\n                    \"locale\": None,\n                    \"translations\": [],\n                }\n            )\n        else:\n            context.update(\n                {\n                    \"locale\": None,\n                    \"translations\": [],\n                }\n            )\n\n        if getattr(settings, \"WAGTAIL_I18N_ENABLED\", False):\n            url_name = \"wagtailadmin_pages:edit\"\n            if self.in_explorer:\n                url_name = \"wagtailadmin_explore\"\n\n            context.update(\n                {\n                    \"locale\": page.locale,\n                    \"translations\": [\n                        {\n                            \"locale\": translation.locale,\n                            \"url\": reverse(url_name, args=[translation.id]),\n                        }\n                        for translation in page.get_translations()\n                        .only(\"id\", \"locale\", \"depth\")\n                        .select_related(\"locale\")\n                        if user_perms.for_page(translation).can_edit()\n                    ],\n                    # The sum of translated pages plus 1 to account for the current page\n                    \"translations_total\": page.get_translations().count() + 1,\n                }\n            )\n\n        context.update(\n            {\n                \"model_name\": self.model.get_verbose_name(),\n                \"model_description\": self.model.get_page_description(),\n                \"status_templates\": self.get_status_templates(context),\n            }\n        )\n\n        return context\n\n\nclass CommentsSidePanel(BaseSidePanel):\n    name = \"comments\"\n    title = gettext_lazy(\"Comments\")\n    template_name = \"wagtailadmin/shared/side_panels/comments.html\"\n    order = 300\n    toggle_aria_label = gettext_lazy(\"Toggle comments\")\n    toggle_icon_name = \"comment\"\n\n\nclass BasePreviewSidePanel(BaseSidePanel):\n    name = \"preview\"\n    title = gettext_lazy(\"Preview\")\n    template_name = \"wagtailadmin/shared/side_panels/preview.html\"\n    order = 400\n    toggle_aria_label = gettext_lazy(\"Toggle preview\")\n    toggle_icon_name = \"mobile-alt\"\n\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        context[\"has_multiple_modes\"] = len(self.object.preview_modes) > 1\n        return context\n\n\nclass PagePreviewSidePanel(BasePreviewSidePanel):\n    def get_context_data(self, parent_context):\n        context = super().get_context_data(parent_context)\n        if self.object.id:\n            context[\"preview_url\"] = reverse(\n                \"wagtailadmin_pages:preview_on_edit\", args=[self.object.id]\n            )\n        else:\n            content_type = parent_context[\"content_type\"]\n            parent_page = parent_context[\"parent_page\"]\n            context[\"preview_url\"] = reverse(\n                \"wagtailadmin_pages:preview_on_add\",\n                args=[content_type.app_label, content_type.model, parent_page.id],\n            )\n        return context\n\n\nclass BaseSidePanels:\n    def __init__(self, request, object):\n        self.request = request\n        self.object = object\n\n        self.side_panels = [\n            BaseStatusSidePanel(object, self.request),\n        ]\n\n    def __iter__(self):\n        return iter(sorted(self.side_panels, key=lambda p: p.order))\n\n    @cached_property\n    def media(self):\n        media = Media()\n        for panel in self:\n            media += panel.media\n        return media\n\n\nclass PageSidePanels(BaseSidePanels):\n    def __init__(\n        self, request, page, *, preview_enabled, comments_enabled, in_explorer=False\n    ):\n        super().__init__(request, page)\n\n        self.side_panels = [\n            PageStatusSidePanel(page, self.request, in_explorer=in_explorer),\n        ]\n\n        if preview_enabled and page.preview_modes:\n            self.side_panels += [\n                PagePreviewSidePanel(page, self.request),\n            ]\n\n        if comments_enabled:\n            self.side_panels += [\n                CommentsSidePanel(page, self.request),\n            ]\n", "path": "wagtail/admin/ui/side_panels.py"}, {"content": "from django.conf import settings\nfrom django.core.paginator import Paginator\nfrom django.db.models import Count\nfrom django.shortcuts import get_object_or_404, redirect\nfrom django.template.response import TemplateResponse\nfrom django.urls import reverse\n\nfrom wagtail import hooks\nfrom wagtail.admin.auth import user_has_any_page_permission, user_passes_test\nfrom wagtail.admin.navigation import get_explorable_root_page\nfrom wagtail.admin.ui.side_panels import PageSidePanels\nfrom wagtail.models import Page, UserPagePermissionsProxy\n\n\n@user_passes_test(user_has_any_page_permission)\ndef index(request, parent_page_id=None):\n    if parent_page_id:\n        parent_page = get_object_or_404(Page, id=parent_page_id)\n    else:\n        parent_page = Page.get_first_root_node()\n\n    # This will always succeed because of the @user_passes_test above.\n    root_page = get_explorable_root_page(request.user)\n\n    # If this page isn't a descendant of the user's explorable root page,\n    # then redirect to that explorable root page instead.\n    if not (parent_page.pk == root_page.pk or parent_page.is_descendant_of(root_page)):\n        return redirect(\"wagtailadmin_explore\", root_page.pk)\n\n    parent_page = parent_page.specific\n\n    user_perms = UserPagePermissionsProxy(request.user)\n    pages = (\n        parent_page.get_children().prefetch_related(\"content_type\", \"sites_rooted_here\")\n        & user_perms.explorable_pages()\n    )\n\n    # Get page ordering\n    ordering = request.GET.get(\"ordering\", \"-latest_revision_created_at\")\n    if ordering not in [\n        \"title\",\n        \"-title\",\n        \"content_type\",\n        \"-content_type\",\n        \"live\",\n        \"-live\",\n        \"latest_revision_created_at\",\n        \"-latest_revision_created_at\",\n        \"ord\",\n    ]:\n        ordering = \"-latest_revision_created_at\"\n\n    if ordering == \"ord\":\n        # preserve the native ordering from get_children()\n        pass\n    elif ordering == \"latest_revision_created_at\":\n        # order by oldest revision first.\n        # Special case NULL entries - these should go at the top of the list.\n        # Do this by annotating with Count('latest_revision_created_at'),\n        # which returns 0 for these\n        pages = pages.annotate(\n            null_position=Count(\"latest_revision_created_at\")\n        ).order_by(\"null_position\", \"latest_revision_created_at\")\n    elif ordering == \"-latest_revision_created_at\":\n        # order by oldest revision first.\n        # Special case NULL entries - these should go at the end of the list.\n        pages = pages.annotate(\n            null_position=Count(\"latest_revision_created_at\")\n        ).order_by(\"-null_position\", \"-latest_revision_created_at\")\n    else:\n        pages = pages.order_by(ordering)\n\n    # Don't paginate if sorting by page order - all pages must be shown to\n    # allow drag-and-drop reordering\n    do_paginate = ordering != \"ord\"\n\n    # We want specific page instances, but do not need streamfield values here\n    pages = pages.defer_streamfields().specific()\n\n    # allow hooks defer_streamfieldsyset\n    for hook in hooks.get_hooks(\"construct_explorer_page_queryset\"):\n        pages = hook(parent_page, pages, request)\n\n    # Annotate queryset with various states to be used later for performance optimisations\n    if getattr(settings, \"WAGTAIL_WORKFLOW_ENABLED\", True):\n        pages = pages.prefetch_workflow_states()\n\n    pages = pages.annotate_site_root_state().annotate_approved_schedule()\n\n    # Pagination\n    if do_paginate:\n        paginator = Paginator(pages, per_page=50)\n        pages = paginator.get_page(request.GET.get(\"p\"))\n\n    show_ordering_column = request.GET.get(\"ordering\") == \"ord\"\n\n    side_panels = PageSidePanels(\n        request,\n        parent_page.specific,\n        in_explorer=True,\n        preview_enabled=False,\n        comments_enabled=False,\n    )\n\n    context = {\n        \"parent_page\": parent_page.specific,\n        \"ordering\": ordering,\n        \"side_panels\": side_panels,\n        \"pages\": pages,\n        \"do_paginate\": do_paginate,\n        \"locale\": None,\n        \"translations\": [],\n        \"show_ordering_column\": show_ordering_column,\n        \"show_bulk_actions\": not show_ordering_column,\n        \"show_locale_labels\": False,\n    }\n\n    if getattr(settings, \"WAGTAIL_I18N_ENABLED\", False):\n        if not parent_page.is_root():\n            context.update(\n                {\n                    \"locale\": parent_page.locale,\n                    \"translations\": [\n                        {\n                            \"locale\": translation.locale,\n                            \"url\": reverse(\n                                \"wagtailadmin_explore\", args=[translation.id]\n                            ),\n                        }\n                        for translation in parent_page.get_translations()\n                        .only(\"id\", \"locale\")\n                        .select_related(\"locale\")\n                    ],\n                }\n            )\n        else:\n            context[\"show_locale_labels\"] = True\n\n    return TemplateResponse(request, \"wagtailadmin/pages/index.html\", context)\n", "path": "wagtail/admin/views/pages/listing.py"}]}