Skip to main content

kiwi-tcms-admin-overlay

A Kiwi TCMS plugin that overlays a sophisticated admin shell on top of Django's stock admin — dashboard, command palette, smart sidebar grouping, contextual badges, and live notifications — without modifying Kiwi TCMS or any other plugin.

Screenshots

The overlay layered on a real Kiwi TCMS install:

Dashboard with categorised sidebar, hero, three cards (Quick stats / System health / Recent activity), and the plugin tile grid below Dashboard
Same view zoomed on the cards — note the per-card monospace data, hairline grid, and the top-right ▤ ◐ ↻ action buttons Dashboard detail
Notifications bell dropdown — per-user activity stream with read markers and the Mark all action Notifications bell
Recent activity card with long Django content-type pills wrapping cleanly inside the column Recent activity
Stock Django changelist restyled — mono uppercase headers, hairline rules, hover paper-sunken; the trailing column shows the per-row badges (e.g. 45 pass · 9 fail on TestRun) Changelist

The full design preview is at docs/design-preview.html — open it in any browser to see every component at full fidelity, including the light/dark/system theme toggle, without spinning up Django.

Why

Kiwi's /admin/ is the stock Django admin (lightly skinned by Grappelli). Once several plugins are installed, the index becomes a flat alphabetic wall of model classes. There's no global search, no dashboard, no per-domain grouping, no contextual signal. This plugin enriches that experience without forking anything.

How it stays out of the way

  • Pure additive. Composes the existing Django admin via response-rewriting middleware (the same pattern used by kiwitcms-review and kiwitcms-requirements). No AdminSite subclass. No template inheritance fights with Grappelli.
  • No Kiwi changes. Drops in via the kiwitcms.plugins entry point.
  • Easily disabled. Set KIWI_TCMS_ADMIN_OVERLAY = {"enabled": False} and the overlay deactivates without uninstall.
  • No rebranding. "Kiwi TCMS" wordmark is preserved everywhere, per upstream license.

What it adds

Surface Where What
Console rail top of every admin page Brand mark + status line + theme/density/refresh actions
Dashboard /admin/ Quick stats, system health, recent activity, plugin tiles
Sidebar /admin/ Categorised model navigation grouped by domain
Command palette anywhere via Cmd/Ctrl+K Substring search across admin models, add-forms, recent objects
Row badges every changelist Per-row context like 45 pass · 9 fail on TestRun, severity pill on Bug
Notifications bell topbar Per-user activity stream with persistent read markers
Accessibility everywhere WCAG 2.1 AA contrast in light/dark; prefers-reduced-motion respected; full keyboard nav

Compatibility

Versions tested
Django 4.2 LTS, 5.0, 5.1, 5.2
Python 3.9, 3.10, 3.11, 3.12
Kiwi TCMS any release that loads plugins via kiwitcms.plugins entry point

Install (development)

pip install -e /path/to/kiwi-tcms-admin-overlay
./manage.py migrate kiwi_tcms_admin_overlay
./manage.py runserver

Visit /admin/ — the new shell renders. Stock admin pages still work.

Configure

Every option is optional. Defaults shown:

# settings.py (or local_settings.py)
KIWI_TCMS_ADMIN_OVERLAY = {
    "enabled": True,
    "categories": None,                  # None → use defaults; list → replace
    "category_overrides": {},            # surgical {"app_label": "category_key"}
    "dashboard_cache_seconds": 30,
    "notifications_poll_seconds": 60,
    "show_uncategorised_warning": True,
    "theme_default": "system",           # light | dark | system
}

Extending — for plugin authors

Three registries are available; call them from your own AppConfig.ready():

from kiwi_tcms_admin_overlay import (
    AdminCategory, register_category,
    Badge, register_badge,
    register_notification_source,
)

class MyPluginConfig(AppConfig):
    def ready(self):
        # Sidebar grouping
        register_category(AdminCategory(
            "my_domain", "My Domain", "fa-flask", 25,
            ("my_plugin_app",),
        ))

        # Per-row changelist badges
        def badge_provider(model, queryset):
            return {row.pk: [Badge("active", "pass")] for row in queryset.filter(active=True)}
        register_badge("my_plugin_app", "mything", badge_provider)

        # Notification source for the bell
        def notifs(request, limit):
            for item in MyNotification.objects.filter(user=request.user)[:limit]:
                yield {
                    "source": "my_plugin",
                    "key": str(item.pk),
                    "label": item.title,
                    "hint": "my_plugin.mything",
                    "verb": "needs review",
                    "actor": item.from_user.username,
                    "time": item.created_at.isoformat(),
                    "href": item.get_absolute_url(),
                }
        register_notification_source("my_plugin", notifs)

All registrations are app-startup-only; runtime mutation is rejected so per-user caches stay consistent.

Architecture

┌─────────────────────────────────────────────────────┐
│  Browser (admin page)                                │
│  ┌────────────────────────────────────────────────┐ │
│  │ overlay.css + shell.js + palette.js +          │ │
│  │ badges.js + notifications.js                   │ │
│  └────────────────────────────────────────────────┘ │
│                       ↕                              │
│  /admin_overlay/api/{dashboard,health,sidebar,…}/    │
└─────────────────────────────────────────────────────┘
                       ↕
┌─────────────────────────────────────────────────────┐
│  Django (your existing Kiwi install)                 │
│   • AdminOverlayMiddleware injects bundle into HTML  │
│   • ModelAdmin permissions gate every endpoint       │
│   • OverlayNotificationRead persists read markers    │
└─────────────────────────────────────────────────────┘

Testing

make test                 # full pytest suite (107 tests at 0.1.0)
make test-a11y            # contrast + accessibility-only (fast canary)
make lint                 # flake8 + pylint

The accessibility CI surface includes a contrast verifier that asserts every documented design-token pair meets WCAG AA in both light and dark mode. See docs/accessibility.md for the manual axe-core audit procedure.

Design preview

docs/design-preview.html is a single self-contained file demonstrating every UI component at full fidelity, with light/dark/system theme cycling. Open it in any browser without Django running.

Status

v0.1.0 — feature-complete, internal use only. PyPI publish on hold pending broader review.

License

GPL-2.0-or-later, matching Kiwi TCMS upstream.

Metadata

Release files for kiwi-tcms-admin-overlay 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for kiwi-tcms-admin-overlay 0.1.0
File Size Uploaded
kiwi_tcms_admin_overlay-0.1.0.tar.gz 68.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for kiwi-tcms-admin-overlay 0.1.0
File Interpreter ABI Platform
kiwi_tcms_admin_overlay-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 151.5 kB

Release files / kiwi_tcms_admin_overlay-0.1.0.tar.gz

Download URL kiwi_tcms_admin_overlay-0.1.0.tar.gz
Size 68.2 kB
Tags Source
SHA-256 checksum
How to use checksums
72e7498b30ca238e38d7dfdfc3cf9c54c7f35726a1654db448b7236c453effa4
BLAKE2b-256 checksum
How to use checksums
083ae3d7c0a0a73a1004abe0885308d4a07fe871f38a3c7e678d192ee7a96c15
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.14

Release files / kiwi_tcms_admin_overlay-0.1.0-py3-none-any.whl

Download URL kiwi_tcms_admin_overlay-0.1.0-py3-none-any.whl
Size 83.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1326e6da1217b00e679e9d3a11c42e7f6a0415f733c4e86c50382a05b20084d4
BLAKE2b-256 checksum
How to use checksums
999c19f35e43fc6132754609ff5011ed4ed020802f9f32335934d81ab77d917e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.14

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page