import type { Metadata } from "next" import { getTranslations, getMessages, setRequestLocale } from "next-intl/server" import { Link } from "@/i18n/navigation" import Image from "next/image" import { DocHeader } from "@/components/ui/doc-header" import { Callout } from "@/components/ui/callout" import CopyableCode from "@/components/CopyableCode" export async function generateMetadata({ params, }: { params: Promise<{ locale: string }> }): Promise { const { locale } = await params const t = await getTranslations({ locale, namespace: "docs.diskManager.importDiskLxc.meta" }) return { title: t("title"), description: t("description"), openGraph: { title: t("ogTitle"), description: t("ogDescription"), type: "article", url: "https://macrimi.github.io/ProxMenux/docs/disk-manager/import-disk-lxc", }, } } type StepData = { title: string body?: string bodyRich?: string intro?: string items?: string[] img?: string caption?: string extraImg?: string extraAlt?: string extraCaption?: string } type StringItem = string type RelatedItem = { href: string; label: string; tail?: string } export default async function ImportDiskLXCPage({ params, }: { params: Promise<{ locale: string }> }) { const { locale } = await params setRequestLocale(locale) const t = await getTranslations({ locale, namespace: "docs.diskManager.importDiskLxc" }) const messages = (await getMessages({ locale })) as unknown as { docs: { diskManager: { importDiskLxc: { prereqs: { items: StringItem[] } steps: { list: StepData[] } important: { items: StringItem[] } related: { items: RelatedItem[] } } } } } const prereqItems = messages.docs.diskManager.importDiskLxc.prereqs.items const stepList = messages.docs.diskManager.importDiskLxc.steps.list const importantItems = messages.docs.diskManager.importDiskLxc.important.items const relatedItems = messages.docs.diskManager.importDiskLxc.related.items const code = (chunks: React.ReactNode) => {chunks} const strong = (chunks: React.ReactNode) => {chunks} const em = (chunks: React.ReactNode) => {chunks} const wipeLink = (chunks: React.ReactNode) => ( {chunks} ) return (
{t.rich("intro.body", { strong, em })}

{t("howRuns.heading")}

{t("howRuns.body")}

{`┌─────────────────────────────────────────────┐
│  PHASE 1 — Pick CT, detect disk, plan       │
│  (nothing touched yet)                      │
└──────────────────┬──────────────────────────┘
                   ▼
      pct list — user picks target CT
                   │
                   ▼
      Privileged check
      ├─ unprivileged: 1 in config
      │    → offer to convert now
      │      (edits /etc/pve/lxc/.conf,
      │       writes unprivileged: 0)
      │      ├─ accept   → continue
      │      └─ cancel   → abort
      └─ privileged → continue
                   │
                   ▼
      Detect disks on host (lsblk)
                   │
                   ▼
      Visibility filter
      ├─ Hidden: root / swap / system-mounted
      ├─ Hidden: active ZFS / LVM / RAID members
      ├─ Hidden: already in any VM/CT config
      ├─ Shown: free disks
      └─ Shown with ⚠ label: stale metadata
                   │
                   ▼
      User selects ONE disk
      (only a single disk per run)
                   │
                   ▼
      Filesystem probe on the first partition
      ├─ ext4 / xfs / btrfs  → reuse as-is
      │                        (data is preserved)
      └─ empty / unsupported → offer to format
                               ├─ pick fs: ext4 / xfs / btrfs
                               └─ mkfs. will run in Phase 2
                   │
                   ▼
      User types mount point path
      (e.g. /mnt/data  /mnt/disk_passthrough)
                   │
                   ▼
      Summary: disk → mount point
                   │
   ┌──────── Cancel   OR   Confirm ────┐
   ▼                                   ▼
Exit, nothing        ┌─────────────────┴─────────────────┐
was changed          │  PHASE 2 — Apply                   │
                     └─────────────────┬─────────────────┘
                                       ▼
                       If conversion was accepted:
                       └─ rewrite CT config line:
                          unprivileged: 1  →  0
                                       │
                                       ▼
                       If formatting was chosen:
                       └─ mkfs. /dev/disk/by-id/…-part1
                                       │
                                       ▼
                       Resolve best persistent partition
                       path (/dev/disk/by-id/...-partN)
                                       │
                                       ▼
                       Find next free mpN index
                       (scans pct config output)
                                       │
                                       ▼
                       pct set  -mpN \\
                          , \\
                          mp=, \\
                          backup=0,ro=0[,acl=1]
                                       │
                                       ▼
                       Verify: pct config  shows
                       the new mpN entry
                                       │
                                       ▼
                       Container sees the directory at
                       the chosen mount point path`}
      

{t("howRuns.summary")}

{t("prereqs.heading")}

    {prereqItems.map((_, idx) => (
  • {t.rich(`prereqs.items.${idx}`, { strong })}
  • ))}
{t.rich("prereqs.warnBody", { strong, code })}

{t("steps.heading")}

{stepList.map((step, idx) => (
{t("steps.stepLabel")} {idx + 1}

{step.title}

{step.bodyRich ? (

{t.rich(`steps.list.${idx}.bodyRich`, { code, strong, em })}

) : step.intro ? ( <>

{step.intro}

{step.items && (
    {step.items.map((_, i) => (
  • {t(`steps.list.${idx}.items.${i}`)}
  • ))}
)} ) : ( step.body &&

{step.body}

)}
{step.img && (
{step.caption
{step.caption && {step.caption}}
)} {step.extraImg && (
{step.extraAlt
{step.extraCaption && {step.extraCaption}}
)}
))}

{t("manual.heading")}

{t.rich("manual.body", { code })}

{t("important.heading")}

    {importantItems.map((_, idx) => (
  • {t.rich(`important.items.${idx}`, { strong, code, wipeLink })}
  • ))}

{t("troubleshoot.heading")}

{t.rich("troubleshoot.unprivBody", { code })} {t.rich("troubleshoot.permsBody", { code })}

{t("related.heading")}

    {relatedItems.map((item) => (
  • {item.label} {item.tail}
  • ))}
) }