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:
+71
-16
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user