Der Test liest Version, Cluster, Nodes, Storages, Bridges, VNets und die effektiven Rechte des Tokens und leitet daraus ab, welcher Vorgang per API, per SSH oder gar nicht geht – je PVE-Version: Template-Bau per API erst ab 8.4 mit import-Storage, Snippets und LXC-Exec nur per SSH. Fehlende Rechte erscheinen einzeln mit Pfad und Zweck; die Rollenliste in docs/proxmox-rechte.md prüft ein Test gegen den Code. SSH-Host-Keys werden wie Zertifikate erst nach Bestätigung genutzt, und bestätigt werden kann nur ein Schlüssel, den der letzte Test gesehen hat. Statussymbole in der GUI sind jetzt gezeichnet: ◐ und ○ fehlen im Web-Subset von JetBrains Mono. Refs #003 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
66 lines
1.9 KiB
TypeScript
66 lines
1.9 KiB
TypeScript
import { clsx } from "clsx";
|
||
|
||
/**
|
||
* Status immer als Symbol + Farbe + Text, nie nur Farbe (Vorgabe Barrierearmut). Die Symbole
|
||
* entsprechen ✓ ◐ ✗ ○ der CLI, sind hier aber gezeichnet: ◐ und ○ fehlen im Web-Subset von
|
||
* JetBrains Mono, der Browser fiele auf eine beliebige Schrift mit winzigem Glyph zurück.
|
||
*/
|
||
export type StatusArt = "erledigt" | "laeuft" | "fehler" | "offen";
|
||
|
||
/** Die Zeichen der CLI – für Textausgaben (Terminal-Karte, Kopiertext). */
|
||
export const STATUS_SYMBOL: Record<StatusArt, string> = {
|
||
erledigt: "✓",
|
||
laeuft: "◐",
|
||
fehler: "✗",
|
||
offen: "○",
|
||
};
|
||
|
||
const STATUS_FARBE: Record<StatusArt, string> = {
|
||
erledigt: "text-akzent",
|
||
laeuft: "text-laeuft",
|
||
fehler: "text-fehler",
|
||
offen: "text-muted",
|
||
};
|
||
|
||
export function StatusSymbol({ art, className }: { art: StatusArt; className?: string }) {
|
||
return (
|
||
<svg
|
||
viewBox="0 0 16 16"
|
||
aria-hidden="true"
|
||
className={clsx("inline-block h-[1em] w-[1em] shrink-0", className)}
|
||
fill="none"
|
||
stroke="currentColor"
|
||
strokeWidth="2"
|
||
strokeLinecap="round"
|
||
strokeLinejoin="round"
|
||
>
|
||
{art === "erledigt" ? <path d="M3 8.5 6.5 12 13 4.5" /> : null}
|
||
{art === "fehler" ? <path d="M4 4 12 12M12 4 4 12" /> : null}
|
||
{art === "offen" ? <circle cx="8" cy="8" r="5.5" strokeWidth="1.6" /> : null}
|
||
{art === "laeuft" ? (
|
||
<>
|
||
<circle cx="8" cy="8" r="5.5" strokeWidth="1.6" />
|
||
<path d="M8 2.5a5.5 5.5 0 0 1 0 11Z" fill="currentColor" stroke="none" />
|
||
</>
|
||
) : null}
|
||
</svg>
|
||
);
|
||
}
|
||
|
||
export function Status({
|
||
art,
|
||
children,
|
||
className,
|
||
}: {
|
||
art: StatusArt;
|
||
children: React.ReactNode;
|
||
className?: string;
|
||
}) {
|
||
return (
|
||
<span className={clsx("inline-flex items-baseline gap-1.5", STATUS_FARBE[art], className)}>
|
||
<StatusSymbol art={art} className="translate-y-[0.125em]" />
|
||
<span>{children}</span>
|
||
</span>
|
||
);
|
||
}
|