Repository: digitalfabrik/integreat-cms

Issue:
Pages list filter
Add filter options to the pages overview. The following checkboxes should be available:

- [ ] "Translation is up-to-date" / "Übersetzung ist aktuell"
- [ ] "Translation is outdated" / "Übersetzung ist veraltet"
- [ ] "Translation is missing" / "Übersetzung fehlt"

Also, drag and drop should be deactivated when filters are applied.


Discussion:
Is the information in the issue description about the need of an archived-filter still up to date?
We already have a button to change from active to archived pages.
> Is the information in the issue description about the need of an archived-filter still up to date?
> We already have a button to change from active to archived pages.

Good point, I guess not. The current separation of archived and non-archived pages will probably stay the same.
This is the current UI of wordpress:

![Screenshot_2021-01-09 Seiten ‹ Bad Tölz — WordPress](https://user-images.githubusercontent.com/16021269/104088022-11933780-5264-11eb-9172-998aff16a139.png)

~The new solution should also provide this functionality. If you have ideas how to improve it, go on!~
~Also keep in mind the current implementation for the event filter.~
=> moved to #630 Improve content language switcher
![104088022-11933780-5264-11eb-9172-998aff16a139](https://user-images.githubusercontent.com/4182469/104161297-ed199580-53f2-11eb-9892-6f473a8ed63b.png)

just from a functional perspektive :D what we need and what we do not need

Resolving patch:
diff --git a/src/cms/constants/translation_status.py b/src/cms/constants/translation_status.py
new file mode 100644
--- /dev/null
+++ b/src/cms/constants/translation_status.py
@@ -0,0 +1,13 @@
+from django.utils.translation import ugettext_lazy as _
+
+DATATYPE = int
+
+UP_TO_DATE = 0
+MISSING = 1
+OUTDATED = 2
+
+CHOICES = (
+    (UP_TO_DATE, _("Translation up-to-date")),
+    (MISSING, _("Translation missing")),
+    (OUTDATED, _("Translation outdated")),
+)
diff --git a/src/cms/forms/pages/page_filter_form.py b/src/cms/forms/pages/page_filter_form.py
new file mode 100644
--- /dev/null
+++ b/src/cms/forms/pages/page_filter_form.py
@@ -0,0 +1,13 @@
+from django import forms
+
+from cms.constants import translation_status
+
+
+class PageFilterForm(forms.Form):
+    translation_status = forms.TypedMultipleChoiceField(
+        widget=forms.CheckboxSelectMultiple(attrs={"class": "default-checked"}),
+        choices=translation_status.CHOICES,
+        initial=[key for (key, val) in translation_status.CHOICES],
+        coerce=translation_status.DATATYPE,
+        required=False,
+    )
diff --git a/src/cms/views/pages/page_tree_view.py b/src/cms/views/pages/page_tree_view.py
--- a/src/cms/views/pages/page_tree_view.py
+++ b/src/cms/views/pages/page_tree_view.py
@@ -4,10 +4,11 @@
 from django.shortcuts import render, redirect
 from django.utils.decorators import method_decorator
 from django.utils.translation import ugettext as _
-
 from django.views.generic import TemplateView
 
+from ...constants import translation_status
 from ...decorators import region_permission_required
+from ...forms.pages.page_filter_form import PageFilterForm
 from ...models import Region, Language
 from .page_mixin import PageMixin
 
@@ -43,6 +44,7 @@ def template_name(self):
 
         return self.template_archived if self.archived else self.template
 
+    # pylint: disable=too-many-locals
     def get(self, request, *args, **kwargs):
         """
         Render page tree
@@ -93,15 +95,64 @@ def get(self, request, *args, **kwargs):
                 request, _("You don't have the permission to edit or create pages.")
             )
         context = self.get_context_data(**kwargs)
+
+        pages = region.get_pages(archived=self.archived)
+        enable_drag_and_drop = True
+        # Filter pages according to given filters, if any
+        filter_data = kwargs.get("filter_data")
+        if filter_data:
+            # Set data for filter form rendering
+            filter_form = PageFilterForm(data=filter_data)
+            if filter_form.is_valid():
+                # only filter if at least one checkbox but not all are checked
+                if (
+                    0
+                    < len(filter_form.cleaned_data["translation_status"])
+                    < len(translation_status.CHOICES)
+                ):
+                    enable_drag_and_drop = False
+                    up_to_date_filter = (
+                        translation_status.UP_TO_DATE
+                        in filter_form.cleaned_data["translation_status"]
+                    )
+                    missing_filter = (
+                        translation_status.MISSING
+                        in filter_form.cleaned_data["translation_status"]
+                    )
+                    outdated_filter = (
+                        translation_status.OUTDATED
+                        in filter_form.cleaned_data["translation_status"]
+                    )
+
+                    def page_filter(page):
+                        translation = page.get_translation(language_code)
+                        if not translation:
+                            return missing_filter
+                        return (
+                            outdated_filter
+                            if translation.is_outdated
+                            else up_to_date_filter
+                        )
+
+                    pages = list(filter(page_filter, pages))
+        else:
+            filter_form = PageFilterForm()
+            filter_form.changed_data.clear()
+
         return render(
             request,
             self.template_name,
             {
                 **context,
                 "current_menu_item": "pages",
-                "pages": region.get_pages(archived=self.archived),
+                "pages": pages,
                 "archived_count": region.archived_pages.count(),
                 "language": language,
                 "languages": region.languages,
+                "filter_form": filter_form,
+                "enable_drag_and_drop": enable_drag_and_drop,
             },
         )
+
+    def post(self, request, *args, **kwargs):
+        return self.get(request, *args, **kwargs, filter_data=request.POST)


Test patch: