{ "meta": { "title": "Contribuir para ProxMenux | ProxMenux Documentação", "description": "Como contribuir para o ProxMenux: modelo de ramos (main / develop / feature/*), processo de pull request, cabeçalho com autoria e ligação de apoio opcional, interface em duas fases, funções de mensagens e percurso até uma versão estável.", "ogTitle": "Contribuição para ProxMenux", "ogDescription": "Modelo de ramos, processo, autoria no cabeçalho e regra da interface em duas fases a seguir pelos colaboradores." }, "header": { "title": "Contribuição para ProxMenux", "description": "O ProxMenux está aberto a contribuições comunitárias — novos scripts, correções para os existentes, melhorias de diálogo, traduções, integrações. Esta página é a porta formal: como o repositório é estruturado, o modelo de ramificação e fluxo de trabalho pull-request, o cabeçalho do script com atribuição do autor e link de patrocinador opcional, e as convenções de projeto cada contribuição deve seguir.", "section": "Sobre" }, "twoPagesCallout": { "title": "Duas páginas relacionadas, um projecto", "body": "Não confunda esta página com Colaboradores, que reconhece testadores, revisores e programadores já envolvidos. Esta página é para si, futuro colaborador, e explica como preparar uma pull request para integração." }, "branching": { "heading": "Modelo de ramificação", "intro": "ProxMenux usa um modelo de ramificação de três camadas:", "headerBranch": "Ramo", "headerPurpose": "Finalidade", "rows": [ { "branch": "main", "purposeRich": "Código estável, pronto para produção. Só são integradas aqui alterações prontas para lançamento. É a versão recebida numa instalação normal do ProxMenux." }, { "branch": "develop", "purposeRich": "Ramo de desenvolvimento ativo. O trabalho novo é integrado primeiro aqui: é o canal beta. Quando uma versão estável está pronta, passa daqui para main." }, { "branch": "feature/*", "purposeRich": "Ramos de curta duração por recurso, correção ou melhoria. Criado a partir de develop, fundiu-se novamente em develop através de um Pull Request após revisão." } ], "calloutTitle": "O que isto significa para os utilizadores", "calloutBody": "Usuários finais rastreando main recebem versões testadas. Usuários que querem os recursos mais recentes cedo — e não se importem com as bordas ásperas ocasionais — podem seguir o develop. Novos recursos sempre passam por develop primeiro; nada atinge main sem passar por esse ciclo." }, "workflow": { "heading": "Processo de pull request", "intro": "Da ideia ao lançamento mesclado em cinco etapas:", "step1Lead": "Criar um ramo de recursos de 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": "Use um nome de ramo descritivo: feature/zfs-arc-tuning, feature/fix-iommu-detection, feature/add-tailscale-script.", "step2Lead": "Trabalhe nas suas alterações e empurre o 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": "Abra um pedido de pull contra develop (não contra main). Na página de criação de GitHub PR, verifique novamente se o ramo base está definido como develop. Incluir na descrição: o que o script faz, o que ele muda, e em quais versões Proxmox VE você testou.", "step4": "Após a revisão, as alterações são integradas em develop. Um responsável verifica o código, o cabeçalho e a interface em duas fases. Se pedir alterações, envie novos commits para o mesmo ramo: a PR atualiza-se automaticamente.", "step5": "As versões estáveis passam de develop para main. No lançamento, main avança até develop por fast-forward e recebe uma etiqueta. A contribuição passa a integrar a próxima versão estável." }, "scriptHeader": { "heading": "Cabeçalho do programa — metadados e descrição", "intro": "Cada script em ProxMenux abre com dois blocos de comentários adjacentes que juntos formam o cabeçalho. Eles são ambos necessários — juntos eles deixam qualquer leitor saber quem escreveu o script e o que ele faz, tudo sem abrir o próprio código.", "bullets": [ "Bloco superior: metadados. Autor, ligações GitHub/de apoio opcionais, responsável, copyright, licença, versão e data de atualização. É também o reconhecimento dos colaboradores: num script novo, inclua o seu nome e, se quiser, a página GitHub e um perfil como Ko-fi, GitHub Sponsors ou Buy Me a Coffee.", "Bloco inferior: descrição. Um parágrafo curto em inglês simples explica o script. É lido antes do código e deve bastar para compreender o objetivo, ações principais, recursos afetados e requisitos." ], "licenseCalloutTitle": "A linha de licença é fixa — GPL-3.0", "licenseCalloutBody": "ProxMenux é publicado sob a Licença Pública Geral GNU v3.0. Cada script no projeto envia sob essa mesma licença; a linha License no cabeçalho é sempre a referência GPL-3.0 mostrada no exemplo abaixo — não é uma escolha por script. Ao contribuir com um script, você concorda em lançá-lo sob GPL-3.0, o que significa que qualquer um pode lê-lo, modificá-lo e redistribuí-lo (incluindo modificações), desde que o mantenha sob a mesma licença. O texto completo vive em 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": "As linhas GitHub e Sponsor são opcionais — deixe-as de fora se não quiser publicá-las. Tudo o resto é necessário.", "whyCalloutTitle": "Por que isso importa?", "whyCalloutBody": "A contribuição de código aberto é trabalho voluntário. Colocar o nome do contribuinte e (quando fornecido) o link do patrocinador diretamente na fonte dá às pessoas que constroem os scripts reconhecimento visível cada vez que alguém lê o código — sua autoria é preservada, não escondida sob “o projeto”. O bloco de descrição importa por uma razão diferente: é a primeira coisa que um futuro mantenedor ou usuário curioso lê, e uma descrição clara é muitas vezes a diferença entre um script que as pessoas confiam e uma que elas evitam." }, "structure": { "heading": "Estrutura do projecto", "intro": "Onde cada tipo de script vive no repositório:", "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": "Cada script carrega utils.sh no arranque através de source para obter funções de mensagens, indicador de espera, cores e sistema de tradução. As bibliotecas partilhadas em scripts/global/ são carregadas explicitamente pelos scripts que delas precisam." }, "twoPhase": { "heading": "A política de design de IU em duas fases", "intro": "É a convenção mais importante do ProxMenux e a que mais frequentemente leva a pedidos de correção nas PR. Cada script divide-se em exatamente duas fases:", "headerPhase": "Fase", "headerPurpose": "Finalidade", "headerScreen": "Estado da tela", "rows": [ { "phaseRich": "Fase 1 — Selecção", "purposeRich": "Recolha todas as decisões do utilizador. Executar todos os trabalhos preparatórios necessários (sondas, sondagens, verificações).", "screenRich": "Janelas dialog. Se uma verificação entre dois menus demorar mais de um ou dois segundos, mostre um indicador msg_info para sinalizar que o script não bloqueou, e chame stop_spinner imediatamente antes do próximo diálogo." }, { "phaseRich": "Fase 2 — Execução", "purposeRich": "Executar todas as operações. Mostra o histórico de progresso completo acumulado na tela.", "screenRich": "Mensagens visíveis msg_info / msg_ok; nunca dialog." } ], "principle": "O princípio: colha tudo primeiro, depois executa tudo. O usuário vê um menu de diálogo limpo (Fase 1), em seguida, uma visão de execução de log-style limpo (Fase 2). Nenhuma mistura — nenhuma janela que apareça no meio da execução, nenhum ruído de progresso durante a selecção.", "phase1Heading": "Fase 1 — padrão típico", "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": "Regras para fase 1:", "phase1Rules": [ "Se estiver ativo um indicador msg_info e precisar de abrir um menu dialog ou whiptail, chame primeiro stop_spinner: o indicador não pode coexistir com a sobreposição das ferramentas. Se nenhum estiver ativo, a chamada não é necessária.", "Use show_proxmenux_logo + msg_title + msg_info quando você precisa dar ao usuário contexto visual para uma operação de longa duração em fase 1 (por exemplo, uma sonda que leva 5+ segundos). A função inclui uma tela limpa, então não chame clear antes.", "Não chame o show_proxmenux_logo entre menus de diálogo onde não há nada para exibir — limpar a tela para um terminal vazio é apenas ruído visual.", "Armazene todas as decisões e resultados de sonda em variáveis ou arrays paralelos. A recapitulação visível ocorre no início da Fase 2, não na Fase 1." ], "phase2Heading": "Fase 2 — padrão típico", "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": "Regras para a fase 2: comece com show_proxmenux_logo + msg_title e resuma de imediato a fase 1 em linhas msg_ok. Não volte a chamar show_proxmenux_logo, pois apagaria o progresso acumulado. Não utilize dialog; se uma decisão durante a execução for inevitável, utilize whiptail como na secção seguinte." }, "dialogVsWhiptail": { "headingRich": "Quando usar dialog vs whiptail", "intro": "Ambas as ferramentas desenham interfaces de usuário de modo texto, mas elas se comportam de forma muito diferente na tela — e ProxMenux as usa em duas fases distintas por uma razão.", "headerTool": "Ferramenta", "headerWhen": "Quando usá-lo", "headerEffect": "Efeito no ecrã", "rows": [ { "toolRich": "dialog", "whenRich": "Sempre em fase 1. Cada seleção interativa — escolhendo um VM, um disco, um sistema de arquivos, confirmando uma ação — usa dialog. Esta é a ferramenta padrão de UI do ProxMenux.", "effectRich": "Assume o terminal: limpa a tela, desenha sua sobreposição, e ao fechar retorna o terminal ao seu estado anterior. Tudo bem na fase 1 porque nada de útil está mostrando ainda." }, { "toolRich": "whiptail", "whenRich": "Apenas na Fase 2, somente quando inevitável. O caso típico é um prompt de reinicialização no final da execução. Não procure o whiptail para pedir “continuar?” no meio da execução — essa decisão deveria ter sido tomada na Fase 1.", "effectRich": "Sobreposição mais leve que não limpa o contexto do terminal. O histórico msg_ok/msg_info da fase 2 permanece visível atrás do diálogo. É por isso a escolha indicada quando o progresso já está no ecrã." } ], "calloutTitle": "Por que a divisão importa", "calloutBody": "Se você chamar dialog no meio da fase 2, cada linha msg_ok que o usuário tem assistido desaparece. Limpas o rasto da auditoria. whiptail evita isso. Então a regra não é arbitrária — é sobre preservar a visão do usuário sobre o que o script tem feito até agora.", "rebootHeading": "Pedido de reinício: o caso típico de whiptail na fase 2", "rebootIntro": "Quando um script termina e uma reinicialização pode ser necessária (por exemplo: IOMMU habilitado, parâmetros do kernel alterados), o prompt no final da Fase 2 usa whiptail. Sempre inclua um branch “Não” que avisa o usuário para não usar o recurso afetado até que ele reinicie:", "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": "Referência das funções da mensagem", "intro": "Todos definidos em utils.sh. Use-os como padrão para qualquer saída visível pelo usuário — visual consistente entre scripts é o ponto principal. Se seu script precisar de uma nova função que não se encaixe no conjunto existente (um novo nível de gravidade, um novo auxiliar de layout, etc.), proponha-o em seu pedido de pull — ele será revisado e adicionado ao utils.sh se for amplamente útil.", "headerFunction": "Função", "headerWhen": "Quando utilizar", "headerSpinner": "Indicador de progresso", "rows": [ { "function": "msg_info \"text\"", "whenRich": "Operação em curso.", "spinner": "Inicia" }, { "function": "stop_spinner", "whenRich": "Fim dos trabalhos preparatórios silenciosos na fase 1 — mata spinner, limpa a linha.", "spinner": "Para" }, { "function": "msg_ok \"text\"", "whenRich": "Operação concluída. Utilize também para uma funcionalidade ativada, mesmo que ainda seja necessário reiniciar.", "spinner": "Para" }, { "function": "msg_warn \"text\"", "whenRich": "Aviso real ou estado degradado.", "spinner": "Para" }, { "function": "msg_error \"text\"", "whenRich": "Erro fatal.", "spinner": "Para" }, { "function": "msg_info2 \"text\"", "whenRich": "Informação sem bloqueio, numa linha ciano.", "spinner": "Para" }, { "function": "msg_success \"text\"", "whenRich": "Final “Pressione Enter para retornar” no final da fase 2.", "spinner": "Para" }, { "function": "msg_title \"text\"", "whenRich": "Título negrito com espaçamento embutido. Utilizado no início da fase 2.", "spinner": "—" }, { "function": "show_proxmenux_logo", "whenRich": "Limpa o ecrã, mostra o logótipo. Chamado uma vez apenas no início da Fase 2.", "spinner": "—" } ] }, "dialogConventions": { "heading": "convenções de diálogo", "bullets": [ "Passe sempre --backtitle \"$BACKTITLE\" para cada chamada dialog e whiptail. $BACKTITLE é sempre \"ProxMenux\" — definido uma vez no cabeçalho do script e nunca substituído. O usuário deve sempre ver o nome do projeto como o contexto de enquadramento, nunca o próprio título do script.", "Enrole sempre títulos e mensagens com $(translate \"...\").", "Sempre redirecionar saída dialog com 2>&1 >/dev/tty - o stdout capturado torna-se a seleção do usuário, enquanto o diálogo em si desenha no terminal.", "Use as variáveis de dimensão padrão de UI ($UI_MENU_H, $UI_MSG_W, etc.) para dimensionamento consistente entre scripts.", "Verifique sempre escolhas vazias ou canceladas e trate-as corretamente." ], "exampleIntro": "Exemplo completo: criar um menu de seleção de VM e tratar o cancelamento.", "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": "Política de tradução", "intro": "Todas as strings visíveis ao usuário devem ser enroladas com a função translate. ProxMenux traduz-os automaticamente em todas as línguas suportadas — você escreve inglês, o usuário lê sua língua nativa.", "code": "msg_ok \"$(translate \"Operation completed successfully.\")\"\nmsg_error \"$(translate \"Failed to start container\") $CTID.\"\ndialog --title \"$(translate \"Select Storage\")\" ...", "bullets": [ "Escreva strings em inglês — a tradução é tratada automaticamente pela compilação.", "Mantenha as cadeias de texto concisas. Evite, se possível, variáveis dentro de frases longas.", "Não traduza nomes de variáveis, caminhos ou identificadores técnicos." ] }, "variableStyle": { "heading": "Convenções de variáveis e estilo", "bullets": [ "Usar UPPER_CASE para variáveis de nível de script.", "Use lower_case para variáveis de função local (declare com local).", "Coloque todas as expansões de variáveis entre aspas: \"$VAR\", não $VAR.", "Usar [[ ]] para condicionantes, não [ ] (exceto onde POSIX é necessário).", "show_proxmenux_logo é a forma prevista de limpar o ecrã: limpa-o e mostra o logótipo do projeto para manter o contexto visual. Chame-o uma vez no início da fase 2, e opcionalmente antes de uma espera longa na fase 1." ], "standardNamesIntro": "Nomes de variáveis padrão em todo o projeto:", "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": "Redirecionando a saída da ferramenta durante a fase 2", "redirectIntro": "A fase 2 mostra um registo de linhas msg_info → msg_ok. Se uma ferramenta chamada, como apt, mkfs, qm, pct ou dd, escrever em stdout/stderr, a sua saída desloca as mensagens e confunde o ecrã. O utilizador deixa de distinguir o progresso do script dos detalhes da ferramenta.", "withoutRedirectIntro": "Sem redirecionar — o que o usuário vê se você não lidar com o ruído:", "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": "Com redirecionamento — como é a mesma operação quando o ruído é enviado para outro lugar:", "withRedirectCode": "ℹ Installing kernel package...\n✓ Kernel installed.\nℹ Configuring kernel command line...\n✓ Configured.\nℹ Refreshing boot loader...\n✓ Boot loader updated.", "twoPatternsIntro": "Dois padrões para escolher:", "discardLead": "Descarte a saída quando você não precisar — mais rápido, mais simples:", "discardCode": "DEBIAN_FRONTEND=noninteractive apt-get install -y \"$package\" >/dev/null 2>&1", "logLead": "Envie a saída para um arquivo de log quando você quiser inspeccioná-lo mais tarde (depurando uma instalação falhada, verificando o que o dpkg realmente fez). Este é o padrão preferido para qualquer operação apt:", "logCode": "apt-get install -y \"$package\" >> \"$log_file\" 2>&1", "referenceOutro": "O script scripts/global/update-pve9_2.sh é uma implementação de referência — cada chamada apt-get envia saída para um arquivo de log para que o usuário apenas veja o fluxo limpo msg_info → msg_ok, enquanto o log no disco permite reconstruir exatamente o que o apt fez se algo der errado." }, "dosAndDonts": { "heading": "Fazer e Não Fazer", "doHeading": "✅ Fazer", "doBullets": [ "stop_spinner antes de um dialog em fase 1 somente quando um spinner msg_info está em execução atualmente.", "Fase 2 começa com show_proxmenux_logo + msg_title + msg_ok recap dos resultados da Fase 1.", "Use msg_ok para recursos habilitados com sucesso — mesmo que seja necessário reiniciar.", "Use whiptail (não dialog) para qualquer prompt pós-execução que deve aparecer na Fase 2.", "Sempre inclua um branch \"Não\" nas janelas de reinicialização que alerta o usuário para não iniciar o recurso afetado até reiniciar.", "Limite a lógica exclusiva de VM verificando [[ -f \"/etc/pve/qemu-server/$'{'vmid'}'.conf\" ]]: controladores e NVMe PCIe não podem ser atribuídos a LXC por passthrough PCI.", "Utilizar ensure_repositories de utils-install-functions.sh em vez de apt-get update incondicional.", "Use arrays paralelos na Fase 1 quando cada item precisar de múltiplas janelas." ], "dontHeading": "❌ Não fazer", "dontBullets": [ "Chame dialog enquanto um spinner está ativo.", "Pular a fase 1 recap no início da fase 2.", "Chame o show_proxmenux_logo pela segunda vez — ele apaga tudo que a Fase 2 imprimiu.", "Utilizar dialog na Fase 2 (utilizar whiptail para o caso raro inevitável).", "Utilizar apenas clear.", "Enrole msg_title em linhas em branco echo \"\" — já inclui espaçamento.", "Use o msg_warn para relatar um recurso habilitado com sucesso — que é um msg_ok.", "Executar apt-get update incondicional — utilizar ensure_repositories." ] }, "submitting": { "heading": "Submissão da sua contribuição", "steps": [ "Crie um fork de MacRimi/ProxMenux no GitHub e clone esse fork.", "Crie um ramo feature/* a partir de develop (veja Modelo de ramos acima).", "Siga este guia para quaisquer scripts novos ou modificados. Escreva o cabeçalho com o seu nome; adicione a linha de patrocinador opcional se quiser.", "Teste o script numa instância real do Proxmox VE: fase 1 com todos os ramos dos diálogos e fase 2 com cada operação e a reversão correta em caso de erro.", "Abra um Pull Request contra develop com uma descrição clara: o que o script faz, o que mudou, em que versão Proxmox VE foi testado.", "Certifique-se de que sua contribuição respeite o Código de Conduta." ], "securityOutro": "Para questões sensíveis à segurança, siga o fluxo de divulgação em SECURITY.md em vez de abrir um problema público." }, "whereNext": { "heading": "Para onde seguir", "items": [ { "kind": "external", "url": "https://github.com/MacRimi/ProxMenux/blob/main/CONTRIBUTING.md", "label": "CONTRIBUTING.md (guia completo)", "tail": " — a fonte da verdade para cada convenção, incluindo os padrões avançados de hardware." }, { "kind": "internal", "href": "/docs/about/contributors", "label": "Contribuidores", "tail": " — as pessoas cuja obra moldou os lançamentos do ProxMenux (página diferente deste)." }, { "kind": "internal", "href": "/docs/about/code-of-conduct", "label": "Código de Conduta", "tail": " — as normas que cada contribuinte aceita respeitar." }, { "kind": "external", "url": "https://github.com/MacRimi/ProxMenux/discussions", "label": "GitHub Discussions", "tail": " — pergunte antes de você construir se você não tem certeza se uma ideia se encaixa, ou para encontrar colaboradores em um recurso maior." } ] } }