docs(readme): Banner, Screenshots, Installation und erste Schritte

Screenshots per scripts/screenshots.ts aus dem gebauten Stand. Dabei gefunden und gefüllt: die Übersicht zeigte nur einen Platzhalter statt der letzten Deployments.

Closes #018

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 17:37:26 +02:00
co-authored by Claude Opus 5.5
parent 533a821087
commit 5379f34a0c
13 changed files with 265 additions and 47 deletions
+71 -16
View File
@@ -1,16 +1,21 @@
import type { Metadata } from "next";
import Link from "next/link";
import { Karte } from "@/components/karte";
import { Status } from "@/components/status";
import Link from "next/link";
import { ART_TEXT, STATUS_ANZEIGE } from "@/lib/auftrag-text";
import { bytes, zeitpunkt } from "@/lib/formate";
import { seiteSchuetzen } from "@/server/auth/zugang";
import { auftraegeSuchen } from "@/server/services/auftraege";
import { serverListe } from "@/server/services/server";
import { ServerStatus } from "./server/server-status";
export const metadata: Metadata = { title: "Übersicht" };
/** Server mit Status und freien Ressourcen (aus dem letzten Verbindungstest), letzte Aufträge. */
export default async function Uebersicht() {
const benutzer = await seiteSchuetzen("lesen", "/");
const server = await serverListe();
const [server, { eintraege }] = await Promise.all([serverListe(), auftraegeSuchen({ seite: 1 })]);
const letzte = eintraege.slice(0, 8);
return (
<div className="flex flex-col gap-6">
@@ -32,23 +37,73 @@ export default async function Uebersicht() {
<Status art="offen">Noch kein Proxmox-Server angelegt.</Status>
) : (
<ul className="divide-linie flex flex-col divide-y">
{server.map((eintrag) => (
<li
key={eintrag.name}
className="flex items-center justify-between gap-3 py-2.5 first:pt-0 last:pb-0"
>
<Link href={`/server/${eintrag.name}`} className="min-w-0 hover:underline">
<span className="font-medium">{eintrag.titel}</span>{" "}
<span className="text-muted font-mono text-sm">{eintrag.name}</span>
</Link>
<ServerStatus server={eintrag} />
</li>
))}
{server.map((eintrag) => {
const knoten = eintrag.letzterTest?.knoten ?? [];
const online = knoten.filter((k) => k.online);
const frei = online.reduce(
(s, k) => s + ((k.speicherGesamt ?? 0) - (k.speicherBelegt ?? 0)),
0,
);
const cpus = online.reduce((s, k) => s + (k.cpus ?? 0), 0);
return (
<li key={eintrag.name} className="flex flex-col gap-1 py-2.5 first:pt-0 last:pb-0">
<div className="flex items-center justify-between gap-3">
<Link href={`/server/${eintrag.name}`} className="min-w-0 hover:underline">
<span className="font-medium">{eintrag.titel}</span>{" "}
<span className="text-muted font-mono text-sm">{eintrag.name}</span>
</Link>
<ServerStatus server={eintrag} />
</div>
{knoten.length > 0 ? (
<p className="text-muted text-xs">
{online.length} von {knoten.length} {knoten.length === 1 ? "Node" : "Nodes"} online
{online.length > 0 ? ` · ${cpus} CPUs · ${bytes(frei)} RAM frei` : ""}
{eintrag.letzterTest?.cluster ? ` · Cluster ${eintrag.letzterTest.cluster.name}` : ""}
</p>
) : null}
</li>
);
})}
</ul>
)}
</Karte>
<Karte titel="Letzte Deployments">
<Status art="offen">Noch keine Deployments.</Status>
<Karte
titel="Letzte Deployments"
aktion={
<Link href="/auftraege" className="text-akzent text-sm">
Verlauf
</Link>
}
>
{letzte.length === 0 ? (
<Status art="offen">Noch keine Deployments.</Status>
) : (
<ul className="divide-linie flex flex-col divide-y">
{letzte.map((a) => {
const [art, text] = STATUS_ANZEIGE[a.status];
return (
<li key={a.id}>
<Link
href={`/auftraege/${a.kurzId}`}
className="hover:bg-panel-hoch/60 -mx-2 flex items-center justify-between gap-3 rounded-lg px-2 py-2"
>
<span className="min-w-0 truncate">
<span className="font-medium">{a.name ?? ART_TEXT[a.art]}</span>
<span className="text-muted text-sm">
{" "}
{a.art !== "AUSROLLEN" && a.name ? `· ${ART_TEXT[a.art]} ` : ""}· {a.server.name}
{a.vmid ? ` · ${a.vmid}` : ""} · {zeitpunkt(a.erstelltAm)}
</span>
</span>
<Status art={art} className="shrink-0 text-sm">
{text}
</Status>
</Link>
</li>
);
})}
</ul>
)}
</Karte>
</div>
</div>