Update a multi-container OCI application from its main container

This commit is contained in:
MacRimi
2026-09-26 02:11:22 +02:00
parent 756851350a
commit 00bc122611
15 changed files with 59 additions and 9 deletions
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
814516b9d35533b39822bc8fa6452b7d3131a8734ddd8bbd14679d9d9b6bb93f ProxMenux-1.2.6.2-beta.AppImage
f8a5748d1beb986b3beafc9c4f2ce5071184fae39911bbe4927dc2ed52edb364 ProxMenux-1.2.6.2-beta.AppImage
+34
View File
@@ -5223,6 +5223,13 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
: "bg-green-500/10 hover:bg-green-500/20 border border-green-500/30 text-green-400 hover:text-green-300"
const neutralBtnCls = "border border-input bg-background text-foreground/80 hover:bg-accent hover:text-accent-foreground"
const storageForBackup = applyBackupStorage || selectedBackupStorage
// A stack is updated as a whole from its main container;
// the other members only show their image.
const stackMember = ociInstance.stack && ociInstance.primary_vmid !== selectedVM.vmid
const primaryVM = (vmData || []).find((v) => v.vmid === ociInstance.primary_vmid)
const primaryLabel = primaryVM
? `${primaryVM.name} (CT ${ociInstance.primary_vmid})`
: `CT ${ociInstance.primary_vmid}`
return (
<>
<Card className="border border-border bg-card/50">
@@ -5262,6 +5269,29 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
<span>{t("vmLxc.ociUpdates.installedImage")} <code className="text-foreground/80">{installedLabel || "—"}</code></span>
</div>
)}
{stackMember ? (
<div className="mt-4 pt-4 border-t border-border/50 space-y-3">
<div className="text-sm text-muted-foreground flex items-start gap-2 leading-relaxed">
<Info className="h-4 w-4 text-blue-400 flex-shrink-0 mt-0.5" />
<span>{t("vmLxc.ociUpdates.memberNote", { primary: primaryLabel, count: ociInstance.members.length })}</span>
</div>
{primaryVM && (
<div className="flex justify-end">
<Button
size="sm"
className={neutralBtnCls}
onClick={() => window.dispatchEvent(new CustomEvent("openLxcAppModal", {
detail: { vmid: ociInstance.primary_vmid, tab: "updates" },
}))}
>
<ChevronRight className="h-4 w-4 mr-1.5" />
{t("vmLxc.ociUpdates.openPrimary")}
</Button>
</div>
)}
</div>
) : (
<>
{ociInstance.stack && (
<div className="text-xs text-muted-foreground mt-3 leading-relaxed">
{t("vmLxc.ociUpdates.stackNote", { primary: ociInstance.primary_vmid, count: ociInstance.members.length })}
@@ -5292,11 +5322,14 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
{ociInstance.pending ? t("vmLxc.ociUpdates.recover") : t("vmLxc.ociUpdates.update")}
</Button>
</div>
</>
)}
</CardContent>
</Card>
{/* Options — the backup the update keeps and the
scheduled image update. */}
{!stackMember && (
<Card className={optionsEditMode ? "border border-border bg-card" : "border border-border bg-card/50"}>
<CardContent className="p-4 space-y-4">
<h3 className="text-sm font-semibold text-foreground">{t("vmLxc.options.title")}</h3>
@@ -5494,6 +5527,7 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
</div>
</CardContent>
</Card>
)}
</>
)
})()}
+2
View File
@@ -1193,6 +1193,8 @@
"installedImage": "Installiertes Image",
"newImage": "Neues Image {image} verfügbar",
"stackNote": "Teil einer Multi-Container-Anwendung (Haupt-CT {primary}, {count} Container): Das Update umfasst alle.",
"memberNote": "Dieser Container gehört zu einer Multi-Container-Anwendung mit dem Haupt-CT {primary} und wird nicht einzeln aktualisiert. Die Aktualisierung erfolgt über den Haupt-CT, der alle {count} Container gemeinsam aktualisiert.",
"openPrimary": "Haupt-CT öffnen",
"pendingNote": "Ein Vorgang an diesem Container wurde unterbrochen; Wiederherstellen öffnet seine Wiederherstellung.",
"update": "Aktualisieren",
"recreate": "Neu erstellen",
+2
View File
@@ -1214,6 +1214,8 @@
"installedImage": "Installed image",
"newImage": "New image {image} available",
"stackNote": "Part of a multi-container application (main CT {primary}, {count} containers): the update covers all of them.",
"memberNote": "This container belongs to a multi-container application whose main container is {primary}, and it is not updated on its own. Updates are applied from the main container, which updates all {count} containers together.",
"openPrimary": "Open the main container",
"pendingNote": "An operation on this container was interrupted; Recover opens its recovery.",
"update": "Update",
"recreate": "Recreate",
+5 -3
View File
@@ -1193,6 +1193,8 @@
"installedImage": "Imagen instalada",
"newImage": "Nueva imagen {image} disponible",
"stackNote": "Forma parte de una aplicación multicontenedor (CT principal {primary}, {count} contenedores): la actualización los abarca a todos.",
"memberNote": "Este contenedor forma parte de una aplicación multicontenedor cuyo contenedor principal es {primary}, y no se actualiza de forma individual. La actualización se hace desde el contenedor principal, que actualiza a la vez los {count} contenedores.",
"openPrimary": "Abrir el contenedor principal",
"pendingNote": "Una operación sobre este contenedor quedó interrumpida; Recuperar abre su recuperación.",
"update": "Actualizar",
"recreate": "Recrear",
@@ -1200,8 +1202,8 @@
"terminalTitleUpdate": "Actualizar aplicación OCI",
"terminalTitleRecreate": "Recrear aplicación OCI",
"terminalDescription": "El mismo recorrido que OCI manager Apps → Gestionar aplicaciones OCI instaladas.",
"keepBackup": "Conservar el backup previo a la actualización",
"noKeepBackup": "El backup previo a la actualización no se conserva",
"keepBackup": "Conservar el backup realizado antes de actualizar",
"noKeepBackup": "No se conserva el backup realizado antes de actualizar",
"keepBackupHelp": "Cada actualización hace un backup del contenedor antes de sustituir su imagen, para restaurarlo si la actualización falla. Con esta opción ese backup se conserva en el almacenamiento elegido; en Proxmox Backup Server se escribe un backup antes de actualizar.",
"scheduleHelp": "Solo se actualiza la imagen, y solo cuando su registro publica una nueva.",
"releaseDelayHelp": "Una imagen nueva solo se instala cuando tiene al menos esta antigüedad.",
@@ -3370,7 +3372,7 @@
"groupedAppUpdates": "Notificaciones de actualización de aplicaciones agrupadas — un mensaje completo por escaneo en lugar de uno por aplicación, agrupado por LXC con las versiones instalada y disponible.",
"adminTokenScope": "Ámbito administrativo — abrir un terminal del Monitor y desactivar la autenticación ahora requieren un token de administrador completo, así que un token de API de solo lectura se mantiene de solo lectura (reportado por @f3rs3n).",
"ociAppTab": "Contenedores OCI en la pestaña App — un contenedor instalado por OCI manager Apps se reconoce desde su registro de instalación: la aplicación y su imagen, una imagen nueva detectada por digest y el enlace al repositorio de la imagen.",
"ociUpdatesTab": "Actualizaciones de contenedores OCI — Actualizar y Recrear abren el mismo recorrido que el menú OCI, el backup previo a la actualización puede conservarse en un almacenamiento de backups y la imagen puede actualizarse de forma programada.",
"ociUpdatesTab": "Actualizaciones de contenedores OCI — Actualizar y Recrear abren el mismo recorrido que el menú OCI, el backup realizado antes de actualizar puede conservarse en un almacenamiento de backups y la imagen puede actualizarse de forma programada.",
"ociLogsTab": "Pestaña Logs para contenedores OCI — la salida de consola de la aplicación, guardada en el host y seguida en directo, con filtro y descarga. La consola de Proxmox de estos contenedores abre un shell.",
"appsUpdateShortcut": "El icono de actualización de la página Apps abre el contenedor directamente en su pestaña Actualizaciones.",
"webhookHttps": "Las notificaciones de Proxmox llegan al Monitor con HTTPS activado — se entregan en una dirección solo local y ya no fallan por un error de certificado.",
+2
View File
@@ -1193,6 +1193,8 @@
"installedImage": "Image installée",
"newImage": "Nouvelle image {image} disponible",
"stackNote": "Fait partie d'une application multi-conteneurs (CT principal {primary}, {count} conteneurs) : la mise à jour les couvre tous.",
"memberNote": "Ce conteneur fait partie d'une application multi-conteneurs dont le CT principal est {primary} et n'est pas mis à jour séparément. La mise à jour se fait depuis le CT principal, qui met à jour les {count} conteneurs ensemble.",
"openPrimary": "Ouvrir le CT principal",
"pendingNote": "Une opération sur ce conteneur a été interrompue ; Récupérer ouvre sa récupération.",
"update": "Mettre à jour",
"recreate": "Recréer",
+2
View File
@@ -1193,6 +1193,8 @@
"installedImage": "Immagine installata",
"newImage": "Nuova immagine {image} disponibile",
"stackNote": "Parte di un'applicazione multi-container (CT principale {primary}, {count} container): l'aggiornamento li comprende tutti.",
"memberNote": "Questo container fa parte di un'applicazione multi-container il cui CT principale è {primary} e non viene aggiornato singolarmente. L'aggiornamento si esegue dal CT principale, che aggiorna insieme tutti i {count} container.",
"openPrimary": "Apri il CT principale",
"pendingNote": "Un'operazione su questo container è stata interrotta; Recupera ne apre il ripristino.",
"update": "Aggiorna",
"recreate": "Ricrea",
+2
View File
@@ -1193,6 +1193,8 @@
"installedImage": "Imagem instalada",
"newImage": "Nova imagem {image} disponível",
"stackNote": "Faz parte de uma aplicação com vários contentores (CT principal {primary}, {count} contentores): a atualização abrange todos.",
"memberNote": "Este contentor faz parte de uma aplicação com vários contentores cujo CT principal é {primary} e não é atualizado individualmente. A atualização é feita a partir do CT principal, que atualiza os {count} contentores em conjunto.",
"openPrimary": "Abrir o CT principal",
"pendingNote": "Uma operação neste contentor foi interrompida; Recuperar abre a sua recuperação.",
"update": "Atualizar",
"recreate": "Recriar",
+2
View File
@@ -1214,6 +1214,8 @@
"installedImage": "Nainštalovaný obraz",
"newImage": "K dispozícii je nový obraz {image}",
"stackNote": "Súčasť aplikácie s viacerými kontajnermi (hlavný CT {primary}, {count} kontajnerov): aktualizácia sa týka všetkých.",
"memberNote": "Tento kontajner patrí do aplikácie s viacerými kontajnermi, ktorej hlavný CT je {primary}, a neaktualizuje sa samostatne. Aktualizácia sa vykonáva z hlavného CT, ktorý aktualizuje všetkých {count} kontajnerov naraz.",
"openPrimary": "Otvoriť hlavný CT",
"pendingNote": "Operácia na tomto kontajneri bola prerušená; Obnoviť otvorí jej obnovenie.",
"update": "Aktualizovať",
"recreate": "Znovu vytvoriť",
+2
View File
@@ -1193,6 +1193,8 @@
"installedImage": "Installerad avbild",
"newImage": "Ny avbild {image} tillgänglig",
"stackNote": "Del av en applikation med flera containrar (huvud-CT {primary}, {count} containrar): uppdateringen omfattar alla.",
"memberNote": "Den här containern ingår i en applikation med flera containrar vars huvud-CT är {primary} och uppdateras inte separat. Uppdateringen görs från huvud-CT:n, som uppdaterar alla {count} containrar tillsammans.",
"openPrimary": "Öppna huvud-CT:n",
"pendingNote": "En åtgärd på den här containern avbröts; Återställ öppnar dess återställning.",
"update": "Uppdatera",
"recreate": "Återskapa",