mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-10-07 14:06:40 +00:00
feat(oci): run official container images as native LXC containers
Adds the OCI manager: an engine that turns a Docker Compose file into an LXC definition, a catalog of 365 applications drawn from LinuxServer.io and other container image sources, and a per-instance registry recording what each container was built from. Reachable from the main menu. Catalog text is translated like every other string in the project: the taglines go through translate() and land in lang/*.json, so the entries read in all eight languages instead of only English. Translation cache builder: - a failed translation leaves the key absent rather than writing English, which previously made the string count as translated forever - a result identical to a 3+ word source is rejected, catching a provider that silently returns the text it was given - strings that are nothing but glossary terms keep their source spelling instead of being discarded as failures - no backoff between attempts when the provider is deterministic - application names are protected so "HAOS One" survives translation - argos joins the provider list, and the workflow reads the OCI sources Audit & Report: - findings that moved in the wrong direction between runs are reported alongside the ones that improved - an accepted risk can carry a review date and is flagged when it falls due - backup checks explain in plain language what they looked at and what to do next Monitor: - disks can be excluded from periodic reads, and an idle disk says so instead of showing a stale temperature - per-disk identity survives a controller or enclosure change - scheduled Borg backups resolve their SSH key from the repository entry - PVE upgrades log the package list and the resulting dpkg changes The web build no longer copies scripts/ into public/: the documentation links to GitHub, so nothing read that folder. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,7 @@ import { Badge } from "./ui/badge"
|
||||
import { Progress } from "./ui/progress"
|
||||
import { Button } from "./ui/button"
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription } from "./ui/dialog"
|
||||
import { Server, Play, Square, Cpu, MemoryStick, HardDrive, Network, Power, RotateCcw, StopCircle, Container, ChevronDown, ChevronUp, ChevronRight, Terminal, Archive, Plus, PlusCircle, Loader2, Clock, Database, Shield, Bell, FileText, Settings2, Activity, Package, RefreshCw, EthernetPort, ArrowUpCircle, Info, CheckCircle2, EyeOff, Eye, Trash2, Check, X, AlertTriangle, AlertCircle, Search, Tag as TagIcon } from 'lucide-react'
|
||||
import { Server, Play, Square, Cpu, MemoryStick, HardDrive, Network, Power, RotateCcw, StopCircle, Container, ChevronDown, ChevronUp, ChevronRight, Terminal, Archive, Plus, PlusCircle, Loader2, Clock, Database, Shield, Bell, FileText, Settings2, Activity, Package, RefreshCw, EthernetPort, ArrowUpCircle, Info, CheckCircle2, EyeOff, Eye, Trash2, Check, X, AlertTriangle, AlertCircle, Search, Pin, Tag as TagIcon } from 'lucide-react'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select"
|
||||
import { Checkbox } from "./ui/checkbox"
|
||||
import { Switch } from "./ui/switch"
|
||||
@@ -100,6 +100,7 @@ interface LxcAppWatch {
|
||||
// once, through the image.
|
||||
docker_available_version?: string | null
|
||||
docker_update_available?: boolean | null
|
||||
docker_pinned?: boolean | null
|
||||
docker_image_reference?: string | null
|
||||
docker_binding_error?: string | null
|
||||
ports?: LxcAppPort[]
|
||||
@@ -179,6 +180,7 @@ interface LxcDockerImageUpdate {
|
||||
update_targets?: LxcDockerComposeTarget[]
|
||||
standalone_containers?: string[]
|
||||
update_available: boolean | null
|
||||
pinned?: boolean
|
||||
error: string | null
|
||||
}
|
||||
|
||||
@@ -5740,7 +5742,7 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
|
||||
) : (
|
||||
<span className={image.update_available === false ? "text-green-500" : undefined}>
|
||||
{t("vmLxc.updates.imageInstalledTag")} {" "}
|
||||
<code className={image.update_available === false ? "text-green-500" : "text-foreground/80"}>{image.tag}</code>
|
||||
<code className={image.update_available === false ? "text-green-500" : "text-foreground/80"}>{image.tag || image.local_digest?.slice(0, 19)}</code>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
@@ -5758,11 +5760,17 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
|
||||
{t("vmLxc.updates.imageUpToDate")}
|
||||
</span>
|
||||
)}
|
||||
{image.update_available === null && (
|
||||
{image.update_available === null && !image.pinned && (
|
||||
<span className="sm:hidden mt-1 text-xs text-muted-foreground inline-flex" title={image.error || undefined}>
|
||||
{t("vmLxc.updates.imageDigestUnknown")}
|
||||
</span>
|
||||
)}
|
||||
{image.pinned && (
|
||||
<span className="sm:hidden mt-1 text-xs text-muted-foreground inline-flex items-center gap-1.5" title={t("vmLxc.updates.imagePinnedTitle")}>
|
||||
<Pin className="h-3.5 w-3.5 flex-shrink-0" />
|
||||
{t("vmLxc.updates.imagePinned")}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center justify-end gap-2">
|
||||
@@ -5772,11 +5780,17 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
|
||||
{t("vmLxc.updates.imageUpToDate")}
|
||||
</span>
|
||||
)}
|
||||
{image.update_available === null && (
|
||||
{image.update_available === null && !image.pinned && (
|
||||
<span className="hidden sm:inline-flex text-xs text-muted-foreground flex-shrink-0" title={image.error || undefined}>
|
||||
{t("vmLxc.updates.imageDigestUnknown")}
|
||||
</span>
|
||||
)}
|
||||
{image.pinned && (
|
||||
<span className="hidden sm:inline-flex items-center gap-1.5 text-xs text-muted-foreground flex-shrink-0" title={t("vmLxc.updates.imagePinnedTitle")}>
|
||||
<Pin className="h-3.5 w-3.5 flex-shrink-0" />
|
||||
{t("vmLxc.updates.imagePinned")}
|
||||
</span>
|
||||
)}
|
||||
{image.update_available === true && (image.update_targets || []).map((target) => (
|
||||
<Button
|
||||
key={`${image.reference}-${target.project}`}
|
||||
@@ -6066,6 +6080,11 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
|
||||
<CheckCircle2 className="h-4 w-4 flex-shrink-0" />
|
||||
<span>{t("vmLxc.updates.imageUpToDate")}</span>
|
||||
</div>
|
||||
) : aw.docker_pinned ? (
|
||||
<div className="flex items-center gap-2" title={t("vmLxc.updates.imagePinnedTitle")}>
|
||||
<Pin className="h-4 w-4 flex-shrink-0" />
|
||||
<span>{t("vmLxc.updates.imagePinned")}</span>
|
||||
</div>
|
||||
) : null
|
||||
) : (
|
||||
<div>{t("vmLxc.updates.versionTrackingPendingShort")}</div>
|
||||
|
||||
Reference in New Issue
Block a user