feat(hosts): Seiten fuer Hosts und Hostgruppen (#008)
Ersetzt die Platzhalter: Hostliste mit Suche und Gruppenfilter per GET (teilbare Links), Formulare fuer Hosts und Gruppen, Hostdetail als Geruest und Gruppendetail mit Mitgliederauswahl. Bearbeiten-Knoepfe entscheidet der Server per darf(); jede Seite prueft die Sitzung selbst. Die Detailseite rendert HostKeyAktionen (#009) und BootstrapAktionen (#010) als feste Platzhalter mit fertigen Props, damit die Folge-Issues nur ihre eigene Datei ersetzen. Formulare senden per onSubmit, weil React ein <form action> nach jeder Antwort zuruecksetzt und Eingaben bei Feldfehlern sonst verloren gingen. Unter md zeigt die Hostliste Karten statt Tabelle, damit Status und Host-Key auf 390 px ohne Wischen sichtbar bleiben. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
import { Server } from "lucide-react";
|
||||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import { notFound } from "next/navigation";
|
||||
import { adresseMitPort } from "@/components/hosts/Anzeige";
|
||||
import { GruppenFormular } from "@/components/hosts/GruppenFormular";
|
||||
import { Breadcrumb } from "@/components/ui/Breadcrumb";
|
||||
import { Karte } from "@/components/ui/Karte";
|
||||
import { Leerzustand } from "@/components/ui/Leerzustand";
|
||||
import { Seitenkopf } from "@/components/ui/Seitenkopf";
|
||||
import { Statuspunkt } from "@/components/ui/Statuspunkt";
|
||||
import { Tabelle, TabellenZeile, TabellenZelle } from "@/components/ui/Tabelle";
|
||||
import { datum } from "@/lib/format";
|
||||
import { darf } from "@/server/auth/rechte";
|
||||
import { sitzungErforderlich } from "@/server/auth/sitzungspflicht";
|
||||
import { gruppeDetail, hostAuswahl } from "@/server/queries/hosts";
|
||||
|
||||
export const metadata: Metadata = { title: "Hostgruppe" };
|
||||
|
||||
/** Gruppendetail mit Mitgliedern; wer Hosts verwalten darf, bearbeitet hier auch (#008). */
|
||||
export default async function HostgruppeSeite({ params }: { params: Promise<{ id: string }> }) {
|
||||
const { id } = await params;
|
||||
const { benutzer } = await sitzungErforderlich("lesen", `/hostgruppen/${id}`);
|
||||
const gruppe = await gruppeDetail(id);
|
||||
if (!gruppe) notFound();
|
||||
const verwalten = darf(benutzer.rolle, "hostsVerwalten");
|
||||
const hosts = verwalten ? await hostAuswahl() : [];
|
||||
const anzahl = gruppe.mitglieder.length;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6 sm:gap-7">
|
||||
<Seitenkopf
|
||||
oben={<Breadcrumb pfad={[{ titel: "Hostgruppen", href: "/hostgruppen" }, { titel: gruppe.name }]} />}
|
||||
titel={gruppe.name}
|
||||
untertitel={
|
||||
<>
|
||||
{gruppe.beschreibung && <span className="mb-1 block">{gruppe.beschreibung}</span>}
|
||||
{anzahl === 1 ? "1 Mitglied" : `${anzahl} Mitglieder`} · angelegt am {datum(gruppe.angelegtAm)}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="grid items-start gap-6 xl:grid-cols-[minmax(0,1.2fr)_minmax(0,1fr)]">
|
||||
<Karte titel="Mitglieder">
|
||||
{anzahl === 0 ? (
|
||||
<Leerzustand
|
||||
icon={<Server className="size-5" />}
|
||||
titel="Keine Mitglieder"
|
||||
text={
|
||||
verwalten
|
||||
? "Hosts lassen sich unter „Bearbeiten“ auswählen."
|
||||
: "Dieser Gruppe ist noch kein Host zugeordnet."
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<Tabelle beschriftung="Mitglieder" spalten={[{ titel: "Host" }, { titel: "Status" }]}>
|
||||
{gruppe.mitglieder.map((h) => (
|
||||
<TabellenZeile key={h.id}>
|
||||
<TabellenZelle className="min-w-0">
|
||||
<Link
|
||||
href={`/hosts/${h.id}`}
|
||||
className="text-text hover:text-accent -my-2 inline-flex min-h-11 items-center font-mono text-[13.5px] font-medium break-all transition-colors"
|
||||
>
|
||||
{h.name}
|
||||
</Link>
|
||||
<p className="text-muted font-mono text-[12.5px] break-all">
|
||||
{adresseMitPort(h.adresse, h.port)}
|
||||
</p>
|
||||
</TabellenZelle>
|
||||
<TabellenZelle className="whitespace-nowrap">
|
||||
<Statuspunkt status={h.status} />
|
||||
</TabellenZelle>
|
||||
</TabellenZeile>
|
||||
))}
|
||||
</Tabelle>
|
||||
)}
|
||||
</Karte>
|
||||
|
||||
{verwalten && (
|
||||
<Karte titel="Bearbeiten" untertitel="Name, Beschreibung und Mitglieder">
|
||||
<GruppenFormular
|
||||
vorgabe={{
|
||||
id: gruppe.id,
|
||||
name: gruppe.name,
|
||||
beschreibung: gruppe.beschreibung ?? "",
|
||||
hostIds: gruppe.mitglieder.map((m) => m.id),
|
||||
}}
|
||||
hosts={hosts}
|
||||
/>
|
||||
</Karte>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user