diff --git a/docs/anleitung/bilder/uebersicht-desktop.png b/docs/anleitung/bilder/uebersicht-desktop.png index 8562869..24bb220 100644 Binary files a/docs/anleitung/bilder/uebersicht-desktop.png and b/docs/anleitung/bilder/uebersicht-desktop.png differ diff --git a/docs/anleitung/bilder/uebersicht-mobil.png b/docs/anleitung/bilder/uebersicht-mobil.png index 8ad67ab..1942574 100644 Binary files a/docs/anleitung/bilder/uebersicht-mobil.png and b/docs/anleitung/bilder/uebersicht-mobil.png differ diff --git a/docs/issues/026-uebersicht.md b/docs/issues/026-uebersicht.md index 806a701..8796029 100644 --- a/docs/issues/026-uebersicht.md +++ b/docs/issues/026-uebersicht.md @@ -1,19 +1,24 @@ # #026 Übersicht (Dashboard) -**Status:** offen +**Status:** erledigt **Meilenstein:** v0.5.0 **Labels:** ui -**Geschätzt:** 2 h **Tatsächlich:** – +**Geschätzt:** 2 h **Tatsächlich:** 0 h 25 min ## Ziel Kennzahlen, Hosts mit Abweichung, bald ablaufend, letzte Aktionen. ## Aufgaben -- [ ] wird zu Beginn der Phase verfeinert +- [x] Kennzahlen, Hosts mit Abweichung, bald ablaufend, letzte Aktionen aus der Datenbank ## Akzeptanzkriterien -- [ ] wird zu Beginn der Phase verfeinert +- [x] Kennzahlen, Hosts mit Abweichung, bald ablaufend, letzte Aktionen aus der Datenbank ## Abhängigkeiten #021 ## Notizen / Entscheidungen +- **Alles berechnet, nichts hinterlegt** (`src/server/queries/uebersicht.ts`): Kacheln und Listen können einander nicht widersprechen. Die Prototyp-Beispieldaten sind entfernt. +- **Hosts mit Abweichung** fasst Befunde je Host und Benutzer zusammen („2 unbekannte Schlüssel · Rechte falsch“, feste Reihenfolge) und zeigt nicht erreichbare Hosts; Link direkt auf die Hostseite. +- **Bald ablaufend** zeigt auch bereits abgelaufene, noch aktive Schlüssel („abgelaufen · noch ausgerollt“ in Koralle). +- **Letzte Aktionen** ohne Anmeldungen – die stehen im Audit-Log. +- Knöpfe nur für passende Rollen (Abgleich: Hosts verwalten; Assistent: Private Keys ausrollen). diff --git a/src/app/(app)/page.tsx b/src/app/(app)/page.tsx index bd5151c..9f437e7 100644 --- a/src/app/(app)/page.tsx +++ b/src/app/(app)/page.tsx @@ -1,15 +1,6 @@ import { ArrowRight, Plus, Route } from "lucide-react"; import type { Metadata } from "next"; import Link from "next/link"; -import { - abweichungen, - BEISPIEL_JETZT, - baldAblaufend, - kennzahlen, - letzteAktionen, - letzterAbgleich, - type AktionsArt, -} from "@/beispiel/uebersicht"; import { AlleAbgleichenKnopf } from "@/components/abgleich/AlleAbgleichenKnopf"; import { Badge } from "@/components/ui/Badge"; import { Button } from "@/components/ui/Button"; @@ -19,7 +10,10 @@ import { Seitenkopf } from "@/components/ui/Seitenkopf"; import { Statuspunkt } from "@/components/ui/Statuspunkt"; import { Tabelle, TabellenZeile, TabellenZelle } from "@/components/ui/Tabelle"; import { datum, datumZeit, relativ, tageBis, uhrzeit } from "@/lib/format"; +import { Leerzustand } from "@/components/ui/Leerzustand"; +import { darf } from "@/server/auth/rechte"; import { sitzungErforderlich } from "@/server/auth/sitzungspflicht"; +import { uebersicht, type AktionsArt } from "@/server/queries/uebersicht"; export const metadata: Metadata = { title: "Übersicht" }; @@ -29,36 +23,45 @@ const AKTION: Record = { erstellt: { text: "Erstellt", farbe: "text-text" }, abgleich: { text: "Abgleich", farbe: "text-info" }, rotiert: { text: "Rotiert", farbe: "text-accent" }, + anmeldung: { text: "Anmeldung", farbe: "text-muted" }, + verweigert: { text: "Verweigert", farbe: "text-danger" }, + sonstiges: { text: "Aktion", farbe: "text-text" }, }; -/** - * Prototyp der Übersicht mit Beispieldaten (#002). Die echte Übersicht mit Lesemodellen - * folgt in #026; Aufbau und Komponenten bleiben. - */ +/** Übersicht (#026): Aufbau aus dem Prototyp (#002), Zahlen aus der Datenbank. */ export default async function Uebersicht() { // Jede Seite prueft selbst; die Huelle ist nur das zweite Netz (CLAUDE.md). - await sitzungErforderlich(); + const { benutzer } = await sitzungErforderlich(); + const jetzt = new Date(); + const { letzterAbgleich, kennzahlen, mitAbweichung, weitereAbweichungen, baldAblaufend, letzteAktionen } = + await uebersicht(jetzt); + const verwalten = darf(benutzer.rolle, "hostsVerwalten"); return (
Prototyp · Beispieldaten} untertitel={ - <> - Letzter Abgleich {relativ(letzterAbgleich, BEISPIEL_JETZT)} ·{" "} - - + letzterAbgleich ? ( + <> + Letzter Abgleich {relativ(letzterAbgleich, jetzt)} ·{" "} + + + ) : ( + "Noch kein Abgleich gelaufen." + ) } aktionen={ <> - - + {verwalten && } + {darf(benutzer.rolle, "privateKeyAusrollen") && ( + + )}
- - - {abweichungen.map((a) => ( - - - {a.host} - - {a.benutzer} - - - - - - Prüfen – {a.host} - - - - ))} - + + {mitAbweichung.length === 0 ? ( +

● Alle Hosts synchron – keine offenen Abweichungen.

+ ) : ( + + {mitAbweichung.map((a) => ( + + + {a.host} + + {a.benutzer} + + + + + + Prüfen – {a.host} + + + + ))} + + )}
+ {baldAblaufend.length === 0 && ( +

Kein Schlüssel läuft in den nächsten 30 Tagen ab.

+ )}
    {baldAblaufend.map((s) => { - const tage = tageBis(s.ablauf, BEISPIEL_JETZT); + const tage = tageBis(s.ablauf, jetzt); return ( -
  • +
  • @@ -146,8 +163,16 @@ export default async function Uebersicht() { {s.person} · {s.typ} - - + +
  • @@ -168,13 +193,17 @@ export default async function Uebersicht() { } > + {letzteAktionen.length === 0 && }
      {letzteAktionen.map((a) => (
    1. -