from django.utils.html import format_html import django_filters from wagtail import hooks from wagtail.admin.filters import WagtailFilterSet from wagtail.admin.ui.components import Component from wagtail.admin.ui.tables import Column, DateColumn from wagtail.admin.ui.tables.pages import BulkActionsColumn, PageStatusColumn, PageTitleColumn from wagtail.admin.viewsets.pages import PageListingViewSet from wagtail.snippets.models import register_snippet from wagtail.snippets.views.snippets import SnippetViewSet from apps.authors.models import Author from apps.blog.models import ArticlePage, Category, TagMetadata class TagMetadataViewSet(SnippetViewSet): model = TagMetadata icon = "tag" list_display = ["tag", "colour"] register_snippet(TagMetadataViewSet) class CategoryViewSet(SnippetViewSet): model = Category icon = "folder-open-inverse" list_display = ["name", "slug", "show_in_nav", "sort_order"] list_filter = ["show_in_nav"] ordering = ["sort_order", "name"] register_snippet(CategoryViewSet) # ── Articles page listing ──────────────────────────────────────────────────── class ArticleFilterSet(WagtailFilterSet): category = django_filters.ModelChoiceFilter( queryset=Category.objects.all(), empty_label="All categories", ) author = django_filters.ModelChoiceFilter( queryset=Author.objects.all(), empty_label="All authors", ) class Meta: model = ArticlePage fields = [] class ArticlePageListingViewSet(PageListingViewSet): model = ArticlePage icon = "doc-full" menu_label = "Articles" menu_order = 200 add_to_admin_menu = True name = "articles" columns = [ BulkActionsColumn("bulk_actions"), PageTitleColumn("title", classname="title"), Column("author", label="Author", sort_key="author__name"), Column("category", label="Category"), DateColumn("published_date", label="Published", sort_key="published_date"), PageStatusColumn("status", sort_key="live"), ] filterset_class = ArticleFilterSet @hooks.register("register_admin_viewset") def register_article_listing(): return ArticlePageListingViewSet("articles") # ── Dashboard panel ────────────────────────────────────────────────────────── class ArticlesSummaryPanel(Component): name = "articles_summary" template_name = "blog/panels/articles_summary.html" order = 110 def get_context_data(self, parent_context): context = super().get_context_data(parent_context) context["drafts"] = ( ArticlePage.objects.not_live() .order_by("-latest_revision_created_at")[:5] ) context["scheduled"] = ( ArticlePage.objects.filter(go_live_at__isnull=False, live=False) .order_by("go_live_at")[:5] ) context["recent"] = ( ArticlePage.objects.live() .order_by("-published_date")[:5] ) return context @hooks.register("construct_homepage_panels") def add_articles_summary_panel(request, panels): panels.append(ArticlesSummaryPanel())