diff --git a/aleksis/apps/alsijil/forms.py b/aleksis/apps/alsijil/forms.py
index d1d47cb0bb23259aed7695c81cd0ed4ca60d5190..0d741f56a237b73ab42370b547b8c4386ed0811e 100644
--- a/aleksis/apps/alsijil/forms.py
+++ b/aleksis/apps/alsijil/forms.py
@@ -1,8 +1,10 @@
 from datetime import datetime, timedelta
+from typing import Optional, Sequence
 
 from django import forms
 from django.core.exceptions import ValidationError
 from django.db.models import Count, Q
+from django.http import HttpRequest
 from django.utils import timezone
 from django.utils.translation import gettext_lazy as _
 
@@ -278,41 +280,35 @@ class FilterRegisterObjectForm(forms.Form):
             "date_end": date_end,
         }
 
-    def __init__(self, request, for_person=True, *args, **kwargs):
+    def __init__(
+        self,
+        request: HttpRequest,
+        *args,
+        for_person: bool = True,
+        groups: Optional[Sequence[Group]] = None,
+        **kwargs
+    ):
         self.request = request
         person = self.request.user.person
 
-        # Fill in initial data
         kwargs["initial"] = self.get_initial()
         super().__init__(*args, **kwargs)
 
-        # Build querysets
         self.fields["school_term"].queryset = SchoolTerm.objects.all()
 
-        # Filter selectable groups by permissions
-        group_qs = Group.objects.all()
-        if for_person:
-            group_qs = group_qs.filter(
+        if not groups and for_person:
+            groups = Group.objects.filter(
                 Q(lessons__teachers=person)
                 | Q(lessons__lesson_periods__substitutions__teachers=person)
                 | Q(events__teachers=person)
                 | Q(extra_lessons__teachers=person)
             )
-        elif not check_global_permission(self.request.user, "alsijil.view_full_register"):
-            group_qs = group_qs.union(
-                group_qs.filter(
-                    pk__in=get_objects_for_user(
-                        self.request.user, "core.view_full_register_group", Group
-                    ).values_list("pk", flat=True)
-                )
-            )
-
-        # Flatten query by filtering groups by pk
-        groups_flat = Group.objects.filter(pk__in=list(group_qs.values_list("pk", flat=True)))
-        self.fields["group"].queryset = groups_flat
+        elif not for_person:
+            groups = Group.objects.all()
+        self.fields["group"].queryset = groups
 
         # Filter subjects by selectable groups
         subject_qs = Subject.objects.filter(
-            Q(lessons__groups__in=groups_flat) | Q(extra_lessons__groups__in=groups_flat)
+            Q(lessons__groups__in=groups) | Q(extra_lessons__groups__in=groups)
         ).distinct()
         self.fields["subject"].queryset = subject_qs
diff --git a/aleksis/apps/alsijil/menus.py b/aleksis/apps/alsijil/menus.py
index a7e6c8407ba49cf537bc728ffe2794a2a9bb01db..fe720477001be6e5992a71ac62b66fad00186780 100644
--- a/aleksis/apps/alsijil/menus.py
+++ b/aleksis/apps/alsijil/menus.py
@@ -78,6 +78,17 @@ MENUS = {
                         ),
                     ],
                 },
+                {
+                    "name": _("All lessons"),
+                    "url": "all_register_objects",
+                    "icon": "list",
+                    "validators": [
+                        (
+                            "aleksis.core.util.predicates.permission_validator",
+                            "alsijil.view_register_objects_list",
+                        ),
+                    ],
+                },
                 {
                     "name": _("Excuse types"),
                     "url": "excuse_types",
diff --git a/aleksis/apps/alsijil/rules.py b/aleksis/apps/alsijil/rules.py
index f36db7aa5a3b532d2b143c109c7daf089391c96a..7358a9d4a0f556a86886e14583bb17b0639f40d7 100644
--- a/aleksis/apps/alsijil/rules.py
+++ b/aleksis/apps/alsijil/rules.py
@@ -1,6 +1,8 @@
 from rules import add_perm
 
+from aleksis.core.models import Group
 from aleksis.core.util.predicates import (
+    has_any_object,
     has_global_perm,
     has_object_perm,
     has_person,
@@ -273,3 +275,9 @@ delete_group_role_assignment_predicate = (
     has_global_perm("alsjil.assign_grouprole") | is_group_role_assignment_group_owner
 )
 add_perm("alsijil.delete_grouproleassignment", delete_group_role_assignment_predicate)
+
+view_register_objects_list_predicate = has_person & (
+    has_any_object("core.view_full_register_group", Group)
+    | has_global_perm("core.view_full_register")
+)
+add_perm("alsijil.view_register_objects_list", view_register_objects_list_predicate)
diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/all_objects.html b/aleksis/apps/alsijil/templates/alsijil/class_register/all_objects.html
new file mode 100644
index 0000000000000000000000000000000000000000..7fd891a47740fa79ea8ff76371be83f7588f417e
--- /dev/null
+++ b/aleksis/apps/alsijil/templates/alsijil/class_register/all_objects.html
@@ -0,0 +1,30 @@
+{# -*- engine:django -*- #}
+{% extends "core/base.html" %}
+{% load i18n rules static django_tables2 material_form %}
+
+{% block browser_title %}{% blocktrans %}All lessons{% endblocktrans %}{% endblock %}
+
+{% block page_title %}
+  {% blocktrans %}All lessons{% endblocktrans %}
+{% endblock %}
+
+{% block extra_head %}
+  {{ block.super }}
+  <link rel="stylesheet" href="{% static 'css/alsijil/alsijil.css' %}"/>
+{% endblock %}
+
+{% block content %}
+  <h5>{% trans "Lesson filter" %}</h5>
+  <form action="" method="get">
+    {% form form=filter_form %}{% endform %}
+    <button type="submit" class="btn waves-effect waves-light">
+      <i class="material-icons left">refresh</i>
+      {% trans "Update filters" %}
+    </button>
+  </form>
+  <h5>{% trans "Lesson table" %}</h5>
+  {% if table %}
+  {% render_table table %}
+
+  {% endif %}
+{% endblock %}
\ No newline at end of file
diff --git a/aleksis/apps/alsijil/urls.py b/aleksis/apps/alsijil/urls.py
index 16ba0d0b9c5c4c976c26222a8542d3e96a93b1aa..8fb31b625ba068fc3c6ba731fe39155f9974d76e 100644
--- a/aleksis/apps/alsijil/urls.py
+++ b/aleksis/apps/alsijil/urls.py
@@ -100,4 +100,5 @@ urlpatterns = [
         views.AssignGroupRoleMultipleView.as_view(),
         name="assign_group_role_multiple",
     ),
+    path("all/", views.AllRegisterObjectsView.as_view(), name="all_register_objects"),
 ]
diff --git a/aleksis/apps/alsijil/util/alsijil_helpers.py b/aleksis/apps/alsijil/util/alsijil_helpers.py
index 3d30d2395a017c4338a96ee5625f235d9c1aea30..d708589e5921fa2237a9da80e719d9c50fce57f5 100644
--- a/aleksis/apps/alsijil/util/alsijil_helpers.py
+++ b/aleksis/apps/alsijil/util/alsijil_helpers.py
@@ -1,5 +1,5 @@
 from operator import itemgetter
-from typing import List, Optional, Union
+from typing import Any, Dict, List, Optional, Union
 
 from django.db.models.expressions import Exists, OuterRef
 from django.db.models.query import Prefetch, QuerySet
@@ -112,7 +112,7 @@ def register_objects_sorter(register_object: Union[LessonPeriod, Event, ExtraLes
         return 0
 
 
-def generate_list_of_all_register_objects(filter_dict: dict) -> List[dict]:
+def generate_list_of_all_register_objects(filter_dict: Dict[str, Any]) -> List[dict]:
     # Get data for filtering
     initial_filter_data = FilterRegisterObjectForm.get_initial()
     # Always force a selected school term so that queries won't get to big
@@ -120,6 +120,7 @@ def generate_list_of_all_register_objects(filter_dict: dict) -> List[dict]:
     filter_person = filter_dict.get("person")
     should_have_documentation = filter_dict.get("has_documentation")
     filter_group = filter_dict.get("group")
+    filter_groups = filter_dict.get("groups")
     filter_subject = filter_dict.get("subject")
     filter_date_start = filter_dict.get("date_start", initial_filter_data.get("date_start"))
     filter_date_end = filter_dict.get("date_end", initial_filter_data.get("date_end"))
@@ -166,6 +167,10 @@ def generate_list_of_all_register_objects(filter_dict: dict) -> List[dict]:
         lesson_periods = lesson_periods.filter_group(filter_group)
         events = events.filter_group(filter_group)
         extra_lessons = extra_lessons.filter_group(filter_group)
+    if filter_groups:
+        lesson_periods = lesson_periods.filter_groups(filter_groups)
+        events = events.filter_groups(filter_groups)
+        extra_lessons = extra_lessons.filter_groups(filter_groups)
     if filter_subject:
         lesson_periods = lesson_periods.filter(
             Q(lesson__subject=filter_subject) | Q(substitutions__subject=filter_subject)
@@ -293,7 +298,7 @@ def generate_list_of_all_register_objects(filter_dict: dict) -> List[dict]:
                     f"{date_format(register_object.date_start)}"
                     f"–{date_format(register_object.date_end)}"
                 )
-                day_sort = (register_object.date_start,)
+                day_sort = register_object.date_start
                 period = (
                     f"{register_object.period_from.period}.–{register_object.period_to.period}."
                 )
diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py
index 273f19b1d4800d3243e02db88493c4c061e6af98..bf4261ddbdaa9871dbbf2c25e331b94bee9b5ee7 100644
--- a/aleksis/apps/alsijil/views.py
+++ b/aleksis/apps/alsijil/views.py
@@ -13,12 +13,14 @@ from django.urls import reverse, reverse_lazy
 from django.utils import timezone
 from django.utils.decorators import method_decorator
 from django.utils.translation import ugettext as _
+from django.views import View
 from django.views.decorators.cache import never_cache
 from django.views.generic import DetailView
 
 import reversion
 from calendarweek import CalendarWeek
 from django_tables2 import RequestConfig, SingleTableView
+from guardian.shortcuts import get_objects_for_user
 from reversion.views import RevisionMixin
 from rules.contrib.views import PermissionRequiredMixin, permission_required
 
@@ -35,6 +37,7 @@ from aleksis.core.mixins import (
 from aleksis.core.models import Group, Person, SchoolTerm
 from aleksis.core.util import messages
 from aleksis.core.util.core_helpers import get_site_preferences, objectgetter_optional
+from aleksis.core.util.predicates import check_global_permission
 
 from .forms import (
     AssignGroupRoleForm,
@@ -899,10 +902,11 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp
     context["extra_marks"] = extra_marks
 
     # Build filter with own form and logic as django-filter can't work with different models
-    filter_form = FilterRegisterObjectForm(request, True, request.GET or None)
+    filter_form = FilterRegisterObjectForm(request, request.GET or None, for_person=True)
     filter_dict = filter_form.cleaned_data if filter_form.is_valid() else {}
     filter_dict["person"] = person
     context["filter_form"] = filter_form
+
     register_objects = generate_list_of_all_register_objects(filter_dict)
     if register_objects:
         table = RegisterObjectTable(register_objects)
@@ -1246,3 +1250,32 @@ class GroupRoleAssignmentDeleteView(
     def get_success_url(self) -> str:
         pk = self.object.groups.first().pk
         return reverse("assigned_group_roles", args=[pk])
+
+
+class AllRegisterObjectsView(PermissionRequiredMixin, View):
+    permission_required = "alsijil.view_register_objects_list"
+
+    def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
+        context = {}
+        # Filter selectable groups by permissions
+        groups = Group.objects.all()
+        if not check_global_permission(request.user, "alsijil.view_full_register"):
+            allowed_groups = get_objects_for_user(
+                self.request.user, "core.view_full_register_group", Group
+            ).values_list("pk", flat=True)
+            groups = groups.filter(Q(parent_groups__in=allowed_groups) | Q(pk__in=allowed_groups))
+
+        # Build filter with own form and logic as django-filter can't work with different models
+        filter_form = FilterRegisterObjectForm(
+            request, request.GET or None, for_person=False, groups=groups
+        )
+        filter_dict = filter_form.cleaned_data if filter_form.is_valid() else {}
+        filter_dict["groups"] = groups
+        context["filter_form"] = filter_form
+
+        register_objects = generate_list_of_all_register_objects(filter_dict)
+        if register_objects:
+            table = RegisterObjectTable(register_objects)
+            RequestConfig(request,).configure(table)  # paginate={"per_page": 100}
+            context["table"] = table
+        return render(request, "alsijil/class_register/all_objects.html", context)