P1: Rollenbasiertes Dashboard mit Plugin-Karten

- Plugin-Vertrag erweitert: optionaler Hook dashboard_karten(user) +
  DashboardKarte-Dataclass (Kern bleibt schlank, Fachlogik im Plugin)
- Karten: Neuheiten+System-Status (neuheiten), Planungs-Stats bzw.
  eigene Einträge (planung), offene Dedup-Konflikte (dedup), nächste
  Redaktionsschlüsse (erinnerung), ungelesene Benachrichtigungen
  (benachrichtigung), letzte Audit-Einträge (audit-log, nur Admin),
  Benutzer-Anzahl (Kern, nur Admin)
- 'Geladene Plugins' als aufklappbarer Admin-Technikbereich
This commit is contained in:
Flo Hartmann
2026-08-26 08:48:30 +00:00
parent 742c265df8
commit 9bd3b700c4
9 changed files with 326 additions and 17 deletions

View File

@@ -1,17 +1,56 @@
{% extends "base.html" %}
{% block titel %}Übersicht — {{ app_name }}{% endblock %}
{% block inhalt %}
<h1 class="text-2xl font-bold mb-1">Willkommen, {{ user.display_name }}!</h1>
<h1 class="text-2xl font-bold text-slate-900 mb-1">Willkommen, {{ user.display_name }}!</h1>
<p class="text-slate-600 mb-6">
Rolle: <span class="font-medium">{{ rollen_anzeige[user.role] or user.role }}</span>
</p>
<section class="mb-8">
<h2 class="text-lg font-semibold mb-1">Geladene Plugins</h2>
<p class="text-sm text-slate-500 mb-3">
Der Kern ist schlank &mdash; alle Funktionen kommen aus Plugins.
</p>
<div class="bg-white rounded-xl border border-slate-200 divide-y divide-slate-100">
{% if karten %}
<section aria-label="Übersicht" class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 mb-8">
{% for karte in karten %}
{% set ton_rand = {
'neutral': 'border-slate-200',
'ok': 'border-emerald-200',
'warnung': 'border-amber-300',
'fehler': 'border-red-300',
}[karte.ton] | default('border-slate-200') %}
{% set ton_wert = {
'neutral': 'text-slate-900',
'ok': 'text-emerald-700',
'warnung': 'text-amber-700',
'fehler': 'text-red-700',
}[karte.ton] | default('text-slate-900') %}
<div class="bg-white rounded-xl border {{ ton_rand }} shadow-sm p-4 flex flex-col">
<h2 class="text-base font-semibold text-slate-800 mb-1">{{ karte.titel }}</h2>
{% if karte.wert %}
<p class="text-3xl font-bold {{ ton_wert }} leading-tight mb-1">{{ karte.wert }}</p>
{% endif %}
{% if karte.beschreibung %}
<p class="text-sm text-slate-500 mb-1">{{ karte.beschreibung }}</p>
{% endif %}
{% if karte.zeilen %}
<ul class="text-sm text-slate-600 space-y-0.5 mt-1">
{% for zeile in karte.zeilen %}
<li class="truncate" title="{{ zeile }}">{{ zeile }}</li>
{% endfor %}
</ul>
{% endif %}
{% if karte.link_url %}
<a href="{{ karte.link_url }}"
class="mt-auto pt-3 text-sm font-medium text-emerald-700 hover:text-emerald-900">{{ karte.link_label }} &rarr;</a>
{% endif %}
</div>
{% endfor %}
</section>
{% endif %}
{% if user.role == 'admin' %}
<details class="mb-8">
<summary class="text-sm text-slate-500 cursor-pointer hover:text-emerald-700">
Technik: geladene Plugins ({{ geladene_plugins|length }})
</summary>
<div class="mt-3 bg-white rounded-xl border border-slate-200 divide-y divide-slate-100">
{% for plugin in geladene_plugins %}
<div class="px-4 py-3 flex flex-wrap items-baseline gap-x-3 gap-y-1">
<span class="font-medium">{{ plugin.title or plugin.name }}</span>
@@ -20,5 +59,6 @@
</div>
{% endfor %}
</div>
</section>
</details>
{% endif %}
{% endblock %}