{ "meta": { "title": "Zu ProxMenux beitragen | ProxMenux-Dokumentation", "description": "Zu ProxMenux beitragen: Branch-Modell (main / develop / feature/*), Pull-Request-Ablauf, Skript-Header mit Autorenangabe und optionalem Sponsoring-Link, zweiphasige UI-Richtlinie, Nachrichtenfunktionen und der Weg vom Feature-Branch zur stabilen Version.", "ogTitle": "Zu ProxMenux beitragen", "ogDescription": "Branch-Modell, Arbeitsablauf, Autorenangabe im Skript-Header und zweiphasige UI-Richtlinie für Mitwirkende." }, "header": { "title": "Zu ProxMenux beitragen", "description": "ProxMenux ist offen für Community-Beiträge - neue Skripte, Fixes für bestehende, Dialogverbesserungen, Übersetzungen, Integrationen. Diese Seite ist die formale Tür: wie das Repository strukturiert ist, das Verzweigungsmodell und der Pull-Request-Workflow, der Skript-Header mit Autorzuweisung und optionalem Sponsor-Link und die Design-Konventionen, denen jeder Beitrag folgen muss.", "section": "Über" }, "twoPagesCallout": { "title": "Zwei verwandte Seiten, ein Projekt", "body": "Verwechseln Sie diese Seite nicht mit Mitwirkende, die bisherige Beiträge von Testern, Reviewern und Entwicklern würdigt. Diese Seite richtet sich an Sie als künftigen Mitwirkenden und erklärt, wie Sie einen Pull Request zur Aufnahme vorbereiten." }, "branching": { "heading": "Verzweigungsmodell", "intro": "ProxMenux verwendet ein dreistufiges Verzweigungsmodell:", "headerBranch": "Branch", "headerPurpose": "Zweck", "rows": [ { "branch": "main", "purposeRich": "Stabiler, produktionsreifer Code. Hier werden nur veröffentlichungsreife Änderungen aufgenommen. Diese Version erhalten Endnutzer bei einer normalen ProxMenux-Installation." }, { "branch": "develop", "purposeRich": "Aktiver Entwicklungsbranch. Neue Arbeiten werden zuerst hier aufgenommen; dies ist der Beta-Kanal. Ist eine stabile Version bereit, wird sie von hier nach main übernommen." }, { "branch": "feature/*", "purposeRich": "Kurzlebige Branchs pro Feature, Fix oder Verbesserung. Erstellt aus develop, nach Überprüfung über einen Pull Request wieder in develop zusammengeführt." } ], "calloutTitle": "Was das für die Nutzer bedeutet", "calloutBody": "Endbenutzer, die main verfolgen, erhalten getestete Releases. Benutzer, die die neuesten Funktionen frühzeitig wünschen - und gelegentliche raue Kanten nicht stören - können develop folgen. Neue Funktionen passieren immer zuerst develop; nichts erreicht main, ohne diesen Zyklus zu durchlaufen." }, "workflow": { "heading": "Pull Request Workflow", "intro": "Von der Idee zum fusionierten Release in fünf Schritten:", "step1Lead": "Erstellen Sie einen Feature Branch aus develop:", "step1Code": "git clone https://github.com/MacRimi/ProxMenux.git\ncd ProxMenux\ngit checkout develop\ngit pull origin develop\ngit checkout -b feature/your-feature-name", "step1Trail": "Verwenden Sie einen beschreibenden Zweignamen: feature/zfs-arc-tuning, feature/fix-iommu-detection, feature/add-tailscale-script.", "step2Lead": "Arbeiten Sie an Ihren Änderungen und schieben Sie den Branch: ", "step2Code": "# Make your changes, then:\ngit add scripts/...\ngit commit -m \"Add ZFS ARC tuning script\"\ngit push -u origin feature/your-feature-name", "step3": "Öffnen Sie einen Pull Request für develop, nicht für main. Prüfen Sie auf GitHub, dass der Basisbranch auf develop steht. Beschreiben Sie, was das Skript tut und ändert und auf welchen Proxmox-VE-Versionen es getestet wurde.", "step4": "Nach der Prüfung werden Änderungen in develop zusammengeführt. Ein Maintainer prüft Codequalität, Header-Konventionen und die zweiphasige UI-Richtlinie. Falls Änderungen nötig sind, pushen Sie weitere Commits in denselben Branch; der PR aktualisiert sich automatisch.", "step5": "Stabile Versionen werden von develop nach main übernommen. Bei der Veröffentlichung wird main per Fast-Forward auf develop gebracht und mit einem Tag versehen. Ihr Beitrag wird Teil der nächsten stabilen Version." }, "scriptHeader": { "heading": "Skript-Header — Metadaten und Beschreibung", "intro": "Jedes Skript in ProxMenux wird mit zwei benachbarten Kommentarblöcken geöffnet, die zusammen den Header bilden. Sie sind beide erforderlich - zusammen lassen sie jeden Leser wissen, wer das Skript geschrieben hat und was es tut, alles ohne den Code selbst zu öffnen.", "bullets": [ "Oberer Block: Metadaten. Autor, optionale GitHub-/Sponsoring-Links, Maintainer, Copyright, Lizenz, Version und Aktualisierungsdatum. Hier erfolgt auch die Würdigung der Mitwirkenden: Bei einem neuen Skript tragen Sie Ihren Namen und optional Links zur persönlichen GitHub-Seite und einem Unterstützungsprofil ein, etwa Ko-fi, GitHub Sponsors oder Buy Me a Coffee.", "Unterer Block: Beschreibung. Ein kurzer Absatz in einfachem Englisch erklärt die Funktion. Nutzer lesen ihn vor dem Code. Er muss für sich allein Zweck, Hauptaktionen, betroffene Ressourcen und Voraussetzungen verständlich machen." ], "licenseCalloutTitle": "Die Lizenzlinie ist festgelegt — GPL-3.0", "licenseCalloutBody": "ProxMenux wird unter der GNU General Public License v3.0 veröffentlicht. Jedes Skript im Projekt wird unter derselben Lizenz ausgeliefert; die License-Zeile im Header ist immer die GPL-3.0-Referenz, die im folgenden Beispiel gezeigt wird - es ist keine Per-Script-Wahl. Indem Sie ein Skript beisteuern, erklären Sie sich damit einverstanden, es unter GPL-3.0 zu veröffentlichen, was bedeutet, dass jeder es lesen, ändern und weiterverteilen kann (einschließlich Änderungen), solange er es unter der gleichen Lizenz behält. Der vollständige Text befindet sich unter MacRimi/ProxMenux/LICENSE.", "templateCode": "#!/bin/bash\n\n# ==========================================================\n# ProxMenux - A menu-driven script for Proxmox VE management\n# ==========================================================\n# Author : Your Name\n# GitHub : github.com/yourhandle\n# Sponsor : ko-fi.com/yourhandle\n# Maintainer : MacRimi\n# Copyright : (c) 2026 MacRimi & contributors\n# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)\n# Version : 1.0\n# Last Updated: DD/MM/YYYY\n# ==========================================================\n# Description:\n# Short paragraph explaining what the script does.\n# Mention the main actions (e.g. \"creates a ZFS pool\",\n# \"configures IOMMU and reboots\", \"imports an ISO into a VM\"),\n# the resources it touches, and any prerequisites the user\n# should be aware of before running it.\n# ==========================================================", "optionalNote": "Die Linien GitHub und Sponsor sind optional - lassen Sie sie aus, wenn Sie sie nicht veröffentlichen möchten. Alles andere ist erforderlich.", "whyCalloutTitle": "Warum das wichtig ist", "whyCalloutBody": "Open-Source-Beiträge sind freiwillige Arbeit. Name und optionaler Sponsoring-Link im Quellcode machen die Urheberschaft bei jedem Lesen sichtbar, statt sie hinter dem Projektnamen zu verbergen. Der Beschreibungsblock ist aus einem anderen Grund wichtig: Er ist der erste Anlaufpunkt künftiger Maintainer und neugieriger Nutzer. Eine klare Erklärung entscheidet oft darüber, ob sie einem Skript vertrauen oder es meiden." }, "structure": { "heading": "Projektstruktur", "intro": "Wo jede Art von Skript im Repository lebt:", "treeCode": "scripts/\n├── menus/ # Top-level menu scripts (entry points)\n├── storage/ # Disk, storage and passthrough scripts\n├── share/ # NFS, Samba, local share scripts\n├── vm/ # VM creation and configuration scripts\n├── gpu_tpu/ # GPU / TPU passthrough scripts\n├── post_install/ # Post-install automation scripts\n├── backup_restore/ # Backup and restore scripts\n├── utilities/ # System utility scripts\n├── global/ # Shared helper libraries (sourced by other scripts)\n├── utils.sh # Shared utility functions and message helpers\n└── help_info_menu.sh # Interactive help and command reference", "outro": "Jedes Skript lädt utils.sh beim Start per source, um Nachrichtenfunktionen, Spinner, Farbvariablen und Übersetzungssystem einzubinden. Gemeinsame Hilfsbibliotheken in scripts/global/ werden ausdrücklich von den Skripten geladen, die sie benötigen." }, "twoPhase": { "heading": "Die zweiphasige UI Design Policy", "intro": "Dies ist die wichtigste Konvention in ProxMenux und die PRs werden am häufigsten gebeten, sie zu beheben. Jedes Skript ist in genau zwei Phasen unterteilt:", "headerPhase": "Phase", "headerPurpose": "Zweck", "headerScreen": "Bildschirmzustand", "rows": [ { "phaseRich": "Phase 1 — Auswahl", "purposeRich": "Sammeln Sie jede Benutzerentscheidung. Führen Sie alle erforderlichen Vorbereitungsarbeiten durch (Sonden, Scans, Überprüfungen).", "screenRich": "dialog-Overlays. Wenn eine Suche zwischen zwei Menüs länger als ein oder zwei Sekunden dauert, zeigen Sie einen msg_info-Spinner an, damit der Benutzer weiß, dass das Skript nicht eingefroren ist, und rufen Sie dann stop_spinner direkt vor dem nächsten Dialog auf." }, { "phaseRich": "Phase 2 — Ausführung", "purposeRich": "Führen Sie jede Operation aus. Zeigen Sie den gesamten Fortschrittsverlauf an, der sich auf dem Bildschirm ansammelt.", "screenRich": "Sichtbare msg_info / msg_ok Nachrichten; niemals dialog." } ], "principle": "Das Prinzip: Sammeln Sie zuerst alles und führen Sie dann alles aus. Der Benutzer sieht ein sauberes dialoggesteuertes Menü (Phase 1), dann eine saubere Ausführungsansicht im Protokollstil (Phase 2). Kein Mischen — kein Dialog erscheint mitten in der Ausführung, kein Fortschrittsrauschen während der Auswahl.", "phase1Heading": "Phase 1 — typisches Muster", "phase1Code": "# Silent preparatory work between dialogs\nmsg_info \"$(translate \"Checking disk assignments...\")\"\nASSIGNED_TO=$(check_assignments \"$DISK\")\nstop_spinner # ← clears line silently, result saved in variable\n\n# Next dialog can now use ASSIGNED_TO\nif [ -n \"$ASSIGNED_TO\" ]; then\n dialog --yesno \"$(translate \"Disk already assigned. Continue?\")\" $UI_YESNO_H $UI_YESNO_W\nfi\n\n# Collect multiple decisions per item with parallel arrays\ndeclare -a DISK_LIST=()\ndeclare -a DISK_FORMAT_TYPES=()\ndeclare -a DISK_MOUNT_POINTS=()\nfor DISK in $SELECTED; do\n msg_info \"$(translate \"Analyzing disk...\")\"\n CURRENT_FS=$(lsblk -no FSTYPE \"$DISK\" | xargs)\n stop_spinner\n\n FORMAT=$(dialog --backtitle \"$BACKTITLE\" \\\n --title \"$(translate \"Select Filesystem\")\" \\\n --menu \"...\" $UI_SHORT_MENU_H $UI_SHORT_MENU_W $UI_SHORT_MENU_LIST_H \\\n \"ext4\" \"...\" \"xfs\" \"...\" \"btrfs\" \"...\" \\\n 2>&1 >/dev/tty)\n [ -z \"$FORMAT\" ] && continue\n\n DISK_LIST+=(\"$DISK\")\n DISK_FORMAT_TYPES+=(\"$FORMAT\")\ndone", "phase1RulesIntro": "Regeln für Phase 1:", "phase1Rules": [ "Läuft gerade ein msg_info-Spinner und soll ein Menü mit dialog oder whiptail geöffnet werden, rufen Sie zuerst stop_spinner auf. Der Spinner verträgt sich nicht mit deren Bildschirmüberlagerung. Ohne aktiven Spinner ist der Aufruf nicht nötig.", "Verwenden Sie show_proxmenux_logo + msg_title + msg_info, um in Phase 1 einen längeren Vorgang sichtbar einzuordnen, etwa eine Prüfung ab fünf Sekunden. Die Funktion leert bereits den Bildschirm; rufen Sie davor nicht clear auf.", "Rufen Sie show_proxmenux_logo nicht zwischen Dialogmenüs auf, in denen nichts angezeigt werden kann - das Löschen des Bildschirms für ein leeres Terminal ist nur visuelles Rauschen.", "Speichern Sie alle Entscheidungen und Sondenergebnisse in Variablen oder parallelen Arrays. Die sichtbare Zusammenfassung erfolgt zu Beginn der Phase 2, nicht in Phase 1." ], "phase2Heading": "Phase 2 — typisches Muster", "phase2Code": "# ── PHASE 2 — EXECUTION ─────────────────────────────\nshow_proxmenux_logo\nmsg_title \"$(translate \"My Script Title\")\"\n\n# Recap Phase 1 preparatory results — show what was already done\nmsg_ok \"$(translate \"CT $CTID selected.\")\"\nmsg_ok \"$(translate \"Repositories verified.\")\"\nmsg_ok \"$(translate \"Disks to process: ${#DISK_LIST[@]}\")\"\n\n# Now execute operations\nfor i in \"${!DISK_LIST[@]}\"; do\n DISK=\"${DISK_LIST[$i]}\"\n FORMAT=\"${DISK_FORMAT_TYPES[$i]}\"\n\n msg_info \"$(translate \"Formatting\") $DISK $(translate \"as\") $FORMAT...\"\n mkfs.\"$FORMAT\" \"$DISK\" >/dev/null 2>&1\n msg_ok \"$(translate \"Formatted.\")\"\ndone\n\nmsg_ok \"$(translate \"Completed. ${#DISK_LIST[@]} disk(s) processed.\")\"\nmsg_success \"$(translate \"Press Enter to return to menu...\")\"\nread -r", "phase2Rules": "Regeln für Phase 2: Beginnen Sie mit show_proxmenux_logo + msg_title und fassen Sie Phase 1 sofort in msg_ok-Zeilen zusammen. Rufen Sie show_proxmenux_logo nicht erneut auf, da dies den bisherigen Verlauf löscht. Verwenden Sie kein dialog; ist eine Entscheidung zur Laufzeit unvermeidbar, nutzen Sie whiptail wie im nächsten Abschnitt." }, "dialogVsWhiptail": { "headingRich": "Wann dialog vs whiptail zu verwenden", "intro": "Beide Tools zeichnen Benutzeroberflächen im Textmodus, aber sie verhalten sich auf dem Bildschirm sehr unterschiedlich - und ProxMenux verwendet sie aus einem bestimmten Grund in zwei verschiedenen Phasen.", "headerTool": "Werkzeug", "headerWhen": "Wann man es benutzt", "headerEffect": "Wirkung auf den Bildschirm", "rows": [ { "toolRich": "dialog", "whenRich": "Immer in Phase 1. Jede interaktive Auswahl – Auswahl einer VM, einer Festplatte, eines Dateisystems, das eine Aktion bestätigt – verwendet dialog. Dies ist das Standard-UI-Tool von ProxMenux.", "effectRich": "Übernimmt das Terminal: löscht den Bildschirm, zieht sein Overlay und bringt das Terminal beim Schließen in seinen vorherigen Zustand zurück. Fein in Phase 1, weil sich noch nichts Nützliches zeigt." }, { "toolRich": "whiptail", "whenRich": "Nur in Phase 2, nur wenn unvermeidlich. Der typische Fall ist eine Neustartaufforderung am Ende der Ausführung. Greifen Sie nicht zu whiptail, um \"Weiter?\" mitten in der Ausführung zu fragen - diese Entscheidung hätte in Phase 1 getroffen werden sollen.", "effectRich": "Leichteres Overlay, das den Terminalkontext nicht löscht. Der akkumulierte msg_ok / msg_info-Verlauf der Phase 2 bleibt hinter dem Dialogfeld sichtbar. Deshalb ist es die richtige Wahl, wenn der Fortschritt bereits auf dem Bildschirm zu sehen ist." } ], "calloutTitle": "Warum die Trennung wichtig ist", "calloutBody": "Wenn Sie dialog in der Mitte der Phase 2 anrufen, verschwindet jede msg_ok-Zeile, die der Benutzer beobachtet hat. Sie wischen den Audit-Trail. whiptail vermeidet das. Die Regel ist also nicht willkürlich - es geht darum, die Sicht des Benutzers auf das, was das Skript bisher getan hat, zu bewahren.", "rebootHeading": "Neustartabfrage: das typische whiptail in Phase 2", "rebootIntro": "Wenn ein Skript endet und ein Neustart erforderlich ist (z.B.) IOMMU aktiviert, Kernelparameter geändert), die Aufforderung am Ende der Phase 2 verwendet whiptail. Fügen Sie immer einen \"Nein\"-Zweig hinzu, der den Benutzer warnt, die betroffene Ressource nicht zu verwenden, bis er neu startet:", "rebootCode": "if [[ \"$HOST_REBOOT_REQUIRED\" == \"yes\" ]]; then\n echo \"\"\n if whiptail --title \"$(translate \"Reboot Required\")\" --yesno \\\n \"\\n$(translate \"A host reboot is required before starting the VM. Reboot now?\")\" \\\n 13 78; then\n msg_warn \"$(translate \"Rebooting the system...\")\"\n reboot\n else\n echo \"\"\n msg_info2 \"$(translate \"Do not start the VM until the system has been rebooted.\")\"\n fi\nfi\n\nmsg_success \"$(translate \"Press Enter to return to menu...\")\"\nread -r" }, "messageFunctions": { "heading": "Referenz der Nachrichtenfunktionen", "intro": "Alle definiert in utils.sh. Verwenden Sie sie als Standard für jede benutzersichtliche Ausgabe - konsistente Visuals über Skripte hinweg ist der springende Punkt. Wenn Ihr Skript eine neue Funktion benötigt, die nicht zum vorhandenen Set passt (ein neuer Schweregrad, ein neuer Layout-Helfer usw.), schlagen Sie es in Ihrem Pull Request vor - es wird überprüft und zu utils.sh hinzugefügt, wenn es allgemein nützlich ist.", "headerFunction": "Funktion", "headerWhen": "Wann zu verwenden", "headerSpinner": "Fortschrittsanzeige", "rows": [ { "function": "msg_info \"text\"", "whenRich": "Operation in Arbeit.", "spinner": "Startet" }, { "function": "stop_spinner", "whenRich": "Ende der stillen Vorbereitungsarbeiten in Phase 1 — tötet Spinner, löscht die Linie.", "spinner": "Stoppt" }, { "function": "msg_ok \"text\"", "whenRich": "Vorgang erfolgreich. Auch für „Funktion aktiviert“ verwenden, wenn noch ein Neustart erforderlich ist.", "spinner": "Stoppt" }, { "function": "msg_warn \"text\"", "whenRich": "Tatsächliche Warnung oder gestörter Zustand.", "spinner": "Stoppt" }, { "function": "msg_error \"text\"", "whenRich": "Schwerwiegender Fehler.", "spinner": "Stoppt" }, { "function": "msg_info2 \"text\"", "whenRich": "Nicht blockierender Hinweis (türkisfarbene Infozeile).", "spinner": "Stoppt" }, { "function": "msg_success \"text\"", "whenRich": "Abschließende Aufforderung „Enter zum Zurückkehren“ am Ende von Phase 2.", "spinner": "Stoppt" }, { "function": "msg_title \"text\"", "whenRich": "Fetter Titel mit eingebautem Abstand. Wird zu Beginn der Phase 2 verwendet.", "spinner": "—" }, { "function": "show_proxmenux_logo", "whenRich": "Leert den Bildschirm und zeigt das Logo. Zu Beginn von Phase 2 einmal aufrufen.", "spinner": "—" } ] }, "dialogConventions": { "heading": "Dialogkonventionen", "bullets": [ "Geben Sie --backtitle \"$BACKTITLE\" immer an jeden dialog- und whiptail-Aufruf weiter. $BACKTITLE ist immer \"ProxMenux\" - einmal im Skript-Header gesetzt und nie außer Kraft gesetzt. Der Benutzer muss den Projektnamen immer als Framing-Kontext sehen, niemals den eigenen Titel des Skripts.", "Verpacken Sie Titel und Nachrichten immer mit $(translate \"...\").", "Immer dialog Ausgabe mit 2>&1 >/dev/tty umleiten — die erfasste stdout wird die Auswahl des Benutzers, während der Dialog selbst auf das Terminal zieht.", "Verwenden Sie die Standard-UI-Dimensionsvariablen ($UI_MENU_H, $UI_MSG_W, usw.) für eine konsistente Dimensionierung über Skripte hinweg.", "Prüfen Sie immer auf leere oder abgebrochene Auswahlen und behandeln Sie diese sauber." ], "exampleIntro": "Vollständiges Beispiel — Erstellung eines VM-Auswahlmenüs und Bearbeitung der Stornierung:", "exampleCode": "# 1) Build the list of VMs as alternating \"ID NAME\" pairs.\n# dialog --menu expects this exact shape: tag1 description1 tag2 description2 ...\nVM_LIST=\"\"\nfor vmid in $(qm list | awk 'NR>1 {print $1}'); do\n vm_name=$(qm config \"$vmid\" | awk -F': ' '/^name:/ {print $2}')\n VM_LIST=\"$VM_LIST $vmid \\\"$vm_name\\\"\"\ndone\n\n# 2) Show the dialog. Captured stdout is the user's selection (the VMID).\nVMID=$(eval \"dialog --backtitle \\\"\\$BACKTITLE\\\" \\\n --title \\\"\\$(translate \\\"Select VM\\\")\\\" \\\n --menu \\\"\\$(translate \\\"Choose a VM from the list:\\\")\\\" \\\n \\$UI_MENU_H \\$UI_MENU_W \\$UI_MENU_LIST_H \\\n $VM_LIST \\\n 2>&1 >/dev/tty\")\n\n# 3) Empty result means the user pressed Cancel or Esc — exit silently.\nif [ -z \"$VMID\" ]; then\n exit 0\nfi\n\n# 4) Continue with the rest of Phase 1, knowing VMID is now set.\necho \"User selected VMID=$VMID\"" }, "translation": { "heading": "Übersetzungspolitik", "intro": "Alle vom Benutzer sichtbaren Zeichenfolgen müssen mit der translate-Funktion gewickelt sein. ProxMenux übersetzt sie automatisch in alle unterstützten Sprachen - Sie schreiben Englisch, der Benutzer liest seine Muttersprache.", "code": "msg_ok \"$(translate \"Operation completed successfully.\")\"\nmsg_error \"$(translate \"Failed to start container\") $CTID.\"\ndialog --title \"$(translate \"Select Storage\")\" ...", "bullets": [ "Schreibe Strings in Englisch – die Übersetzung wird automatisch vom Build bearbeitet.", "Halten Sie Strings kurz. Vermeiden Sie das Einbetten von Variablen in lange Sätze, wenn möglich.", "Variablennamen, Pfade oder technische Bezeichner nichtübersetzen." ] }, "variableStyle": { "heading": "Variable und Stilkonventionen", "bullets": [ "Verwenden Sie UPPER_CASE für Variablen auf Skriptebene.", "Verwenden Sie lower_case für lokale Funktionsvariablen (mit local deklarieren).", "Setzen Sie alle Variablenexpansionen in Anführungszeichen: \"$VAR\" statt $VAR.", "Verwenden Sie [[ ]] für Konditionale, nicht [ ] (außer wenn POSIX erforderlich ist).", "show_proxmenux_logo ist der geeignete Weg, um den Bildschirm zu löschen - er enthält das Clear und zeigt das Projektlogo, so dass der Benutzer immer einen visuellen Kontext hat. Rufen Sie es einmal zu Beginn der Phase 2 (und optional vor einem langen Phase 1-Spinnerblock) auf." ], "standardNamesIntro": "Standardvariablennamen im gesamten Projekt:", "standardNamesCode": "CTID # container ID\nVMID # virtual machine ID\nDISK # device path (e.g. /dev/sdb)\nPARTITION # partition path (e.g. /dev/sdb1)\nSTORAGE # Proxmox storage name\nMOUNT_POINT # filesystem mount path", "redirectHeading": "Umleitung der Werkzeugausgabe während der Phase 2", "redirectIntro": "Phase 2 zeigt ein sauberes Protokoll der msg_info → msg_ok-Zeilen an, die sich auf dem Bildschirm ansammeln. Wenn ein Tool, das Sie aufrufen (apt, mkfs, qm, pct, dd, etc.), seine eigene Ausgabe in stdout/stderr schreibt, scrollt es an Ihren Nachrichten vorbei und unterbricht den visuellen Fluss - Sie haben ein chaotisches Terminal, in dem der Benutzer die eigenen Fortschrittslinien des Skripts nicht vom Rauschen des zugrunde liegenden Tools unterscheiden kann.", "withoutRedirectIntro": "Ohne Umleitung: die Ausgabe für Nutzer, wenn zusätzliche Werkzeugausgaben nicht abgefangen werden.", "withoutRedirectCode": "ℹ Installing kernel package...\nReading package lists... Done\nBuilding dependency tree... Done\nReading state information... Done\nThe following NEW packages will be installed:\n proxmox-kernel-6.5\n0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.\nNeed to get 12.5 MB of archives.\nAfter this operation, 47.2 MB of additional disk space will be used.\nGet:1 http://download.proxmox.com/debian/pve trixie/pve-no-subscription amd64 ...\n... [200+ more lines of dpkg output] ...\n✓ Kernel installed.", "withRedirectIntro": "Mit Umleitung: dieselbe Aktion, wenn zusätzliche Ausgaben an anderer Stelle landen.", "withRedirectCode": "ℹ Installing kernel package...\n✓ Kernel installed.\nℹ Configuring kernel command line...\n✓ Configured.\nℹ Refreshing boot loader...\n✓ Boot loader updated.", "twoPatternsIntro": "Zwei Muster zur Auswahl:", "discardLead": "Ausgabe verwerfen, wenn sie nicht benötigt wird: die einfachste und schnellste Variante.", "discardCode": "DEBIAN_FRONTEND=noninteractive apt-get install -y \"$package\" >/dev/null 2>&1", "logLead": "Ausgabe in eine Protokolldatei schreiben, wenn Sie sie später prüfen möchten, etwa zur Fehlersuche bei einer Installation oder um dpkg-Aktionen nachzuvollziehen. Dies ist das bevorzugte Muster für apt-Aufrufe:", "logCode": "apt-get install -y \"$package\" >> \"$log_file\" 2>&1", "referenceOutro": "scripts/global/update-pve9_2.sh dient als Referenz: Jeder apt-get-Aufruf schreibt in eine Protokolldatei. Nutzer sehen nur den Ablauf msg_info → msg_ok, während die Datei bei Fehlern genau zeigt, was apt getan hat." }, "dosAndDonts": { "heading": "Do's und Don'ts", "doHeading": "✅ Empfohlen", "doBullets": [ "stop_spinner vor einem dialog in Phase 1 nur dann, wenn ein msg_info Spinner gerade läuft.", "Phase 2 beginnt mit show_proxmenux_logo + msg_title + msg_ok als Zusammenfassung der Ergebnisse von Phase 1.", "Verwenden Sie msg_ok für erfolgreich aktivierte Funktionen – auch wenn ein Neustart erforderlich ist.", "Verwenden Sie whiptail (nicht dialog) für jede Aufforderung nach der Ausführung, die in Phase 2 erscheinen muss.", "Fügen Sie immer einen \"Nein\" -Zweig in Reboot-Dialoge ein, der den Benutzer warnt, die betroffene Ressource bis zum Neustart nicht zu starten.", "Schützen Sie die reine VM-Logik, indem Sie [[ -f \"/etc/pve/qemu-server/$'{'vmid'}'.conf\" ]] überprüfen - Controller und NVMe PCIe können nicht zu LXC-Containern hinzugefügt werden.", "Verwenden Sie ensure_repositories von utils-install-functions.sh anstelle von bedingungslosem apt-get update.", "Verwenden Sie parallele Arrays in Phase 1, wenn jedes Element mehrere Dialoge benötigt." ], "dontHeading": "❌ Vermeiden", "dontBullets": [ "Rufen Sie dialog an, während ein Spinner aktiv ist.", "Überspringen Sie die Phase 1 Zusammenfassung zu Beginn der Phase 2.", "Rufen Sie show_proxmenux_logo ein zweites Mal an - es löscht alles, was Phase 2 gedruckt hat.", "Verwenden Sie dialog in Phase 2 (verwenden Sie whiptail für den seltenen unvermeidlichen Fall).", "Verwenden Sie reine clear.", "msg_title mit Leerzeilen aus echo \"\" umgeben; die Abstände sind bereits enthalten.", "Verwenden Sie msg_warn, um eine erfolgreich aktivierte Funktion zu melden - das ist ein msg_ok.", "Führen Sie bedingungslos apt-get update aus - verwenden Sie ensure_repositories." ] }, "submitting": { "heading": "Einreichen Ihres Beitrags", "steps": [ "Fork MacRimi/ProxMenux auf GitHub und klonen Sie Ihre Fork.", "Erstellen Sie einen feature/*-Zweig aus develop (siehe Branching-Modell oben).", "Befolgen Sie diese Anleitung für neue oder geänderte Skripte. Schreiben Sie den Header mit Ihrem Namen; fügen Sie die optionale Sponsorenzeile hinzu, wenn Sie möchten.", "Testen Sie Ihr Skript auf einer echten Proxmox VE-Instanz - sowohl Phase 1 (jeder Dialogzweig) als auch Phase 2 (jede Operation ist erfolgreich und wird bei Fehlern sauber zurückgesetzt).", "Öffnen Sie eine Pull Request gegen develop mit einer klaren Beschreibung: was das Skript macht, was sich geändert hat, auf welcher Proxmox VE-Version es getestet wurde.", "Stellen Sie sicher, dass Ihr Beitrag den Code of Conduct respektiert." ], "securityOutro": "Befolgen Sie bei sicherheitsrelevanten Problemen den Offenlegungsfluss in SECURITY.md, anstatt ein öffentliches Problem zu öffnen." }, "whereNext": { "heading": "Wohin als nächstes", "items": [ { "kind": "external", "url": "https://github.com/MacRimi/ProxMenux/blob/main/CONTRIBUTING.md", "label": "CONTRIBUTING.md (vollständige Anleitung)", "tail": "— die Quelle der Wahrheit für jede Konvention, einschließlich der fortgeschrittenen Hardware-Muster." }, { "kind": "internal", "href": "/docs/about/contributors", "label": "Beitragende", "tail": " — die Menschen, deren Arbeit ProxMenux-Versionen geprägt hat. Eine andere Seite als diese hier." }, { "kind": "internal", "href": "/docs/about/code-of-conduct", "label": "Verhaltenskodex", "tail": "- die Standards, die jeder Mitwirkende zu befolgen bereit ist." }, { "kind": "external", "url": "https://github.com/MacRimi/ProxMenux/discussions", "label": "GitHub Discussions", "tail": "Fragen Sie, bevor Sie bauen, ob Sie nicht sicher sind, ob eine Idee passt, oder um Mitarbeiter für ein größeres Feature zu finden." } ] } }