"use client"
import { cn } from "@/lib/utils"
import { useT } from "../lib/i18n/provider"
interface SriovInfo {
role: "vf" | "pf-active" | "pf-idle"
physfn?: string // VF only: parent PF BDF
vfCount?: number // PF only: active VF count
totalvfs?: number // PF only: maximum VFs
}
interface GpuSwitchModeIndicatorProps {
mode: "lxc" | "vm" | "sriov" | "unknown"
isEditing?: boolean
pendingMode?: "lxc" | "vm" | null
onToggle?: (e: React.MouseEvent) => void
className?: string
sriovInfo?: SriovInfo
}
export function GpuSwitchModeIndicator({
mode,
isEditing = false,
pendingMode = null,
onToggle,
className,
sriovInfo,
}: GpuSwitchModeIndicatorProps) {
const t = useT()
// SR-IOV is a non-editable hardware state. Pending toggles don't apply here.
const displayMode = mode === "sriov" ? "sriov" : (pendingMode ?? mode)
const isLxcActive = displayMode === "lxc"
const isVmActive = displayMode === "vm"
const isSriovActive = displayMode === "sriov"
const hasChanged =
mode !== "sriov" && pendingMode !== null && pendingMode !== mode
// Colors
const sriovColor = "#14b8a6" // teal-500
const activeColor = isSriovActive
? sriovColor
: isLxcActive
? "#3b82f6"
: isVmActive
? "#a855f7"
: "#6b7280"
const inactiveColor = "#374151" // gray-700 for dark theme
const dimmedColor = "#4b5563" // gray-600 for dashed SR-IOV branches
const lxcColor = isLxcActive ? "#3b82f6" : inactiveColor
const vmColor = isVmActive ? "#a855f7" : inactiveColor
const handleClick = (e: React.MouseEvent) => {
// SR-IOV state can't be toggled — swallow the click so it doesn't reach
// the card (which would open the detail modal unexpectedly from this
// area). For lxc/vm, preserve the original behavior.
if (isSriovActive) {
e.stopPropagation()
return
}
if (isEditing) {
e.stopPropagation()
if (onToggle) {
onToggle(e)
}
}
// When not editing, let the click propagate to the card to open the modal
}
// Build the VF count label shown in the SR-IOV badge. For PFs we know
// exactly how many VFs are active; for a VF we show its parent PF.
const sriovBadgeText = (() => {
if (!isSriovActive) return ""
if (sriovInfo?.role === "vf") return t("hardware.gpuSwitch.sriovVf")
if (sriovInfo?.vfCount && sriovInfo.vfCount > 0) {
return t("hardware.gpuSwitch.sriovCount", { count: sriovInfo.vfCount })
}
return t("hardware.gpuSwitch.sriov")
})()
return (
{/* Large SVG Diagram */}
{/* Status Text - Large like GPU name */}
{isSriovActive
? t("hardware.gpuSwitch.sriovActive")
: isLxcActive
? t("hardware.gpuSwitch.readyForLxc")
: isVmActive
? t("hardware.gpuSwitch.readyForVm")
: t("hardware.gpuSwitch.modeUnknown")}
{isSriovActive
? t("hardware.gpuSwitch.virtualFunctionsExternal")
: isLxcActive
? t("hardware.gpuSwitch.nativeDriverActive")
: isVmActive
? t("hardware.gpuSwitch.vfioDriverActive")
: t("hardware.gpuSwitch.noDriverDetected")}
{isSriovActive && sriovInfo && (
{sriovInfo.role === "vf"
? t(
sriovInfo.physfn
? "hardware.gpuSwitch.virtualFunctionWithParent"
: "hardware.gpuSwitch.virtualFunction",
{ parent: sriovInfo.physfn || "" },
)
: sriovInfo.vfCount !== undefined
? t(
sriovInfo.totalvfs
? "hardware.gpuSwitch.physicalFunctionWithMax"
: "hardware.gpuSwitch.physicalFunction",
{
count: sriovInfo.vfCount,
max: sriovInfo.totalvfs || "",
},
)
: null}
)}
{hasChanged && (
{t("hardware.gpuSwitch.changePending")}
)}
)
}