Add host drives section for non-enclosure drives
This commit is contained in:
@@ -580,6 +580,107 @@ function DriveDetail({ slot, onClose, t }) {
|
||||
);
|
||||
}
|
||||
|
||||
const driveTypeBadge = (type, t) => {
|
||||
const labels = { nvme: "NVMe", raid: "RAID", ssd: "SSD", hdd: "HDD", disk: "Disk" };
|
||||
return (
|
||||
<span style={{
|
||||
fontSize: 10, fontWeight: 700, textTransform: "uppercase", letterSpacing: 0.5,
|
||||
padding: "2px 8px", borderRadius: 4,
|
||||
background: type === "nvme" ? t.toggleActive + "22" : t.health.empty.bg,
|
||||
color: type === "nvme" ? t.toggleActive : t.textSecondary,
|
||||
border: `1px solid ${type === "nvme" ? t.toggleActive + "44" : t.cardBorder}`,
|
||||
}}>
|
||||
{labels[type] || type}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
function HostDrivesCard({ drives, onSelect, t }) {
|
||||
if (!drives || drives.length === 0) return null;
|
||||
return (
|
||||
<div style={{
|
||||
background: t.cardBg, borderRadius: 16,
|
||||
boxShadow: "0 2px 8px rgba(0,0,0,0.1)",
|
||||
border: `1px solid ${t.cardBorder}`,
|
||||
overflow: "hidden",
|
||||
}}>
|
||||
<div style={{
|
||||
padding: "16px 20px",
|
||||
borderBottom: `1px solid ${t.divider}`,
|
||||
display: "flex", alignItems: "center", justifyContent: "space-between",
|
||||
}}>
|
||||
<div>
|
||||
<div style={{ fontSize: 16, fontWeight: 700, color: t.text }}>Host Drives</div>
|
||||
<div style={{ fontSize: 12, color: t.textSecondary, marginTop: 2 }}>
|
||||
{drives.length} drive{drives.length !== 1 ? "s" : ""} · non-enclosure
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ padding: 16 }}>
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
|
||||
{drives.map((d) => {
|
||||
const healthStatus = d.health_status || "healthy";
|
||||
const c = t.health[healthStatus] || t.health.healthy;
|
||||
return (
|
||||
<button
|
||||
key={d.device}
|
||||
onClick={() => onSelect({ slot: "-", device: d.device, populated: true, drive: d })}
|
||||
style={{
|
||||
display: "flex", alignItems: "center", gap: 16,
|
||||
padding: "12px 16px", borderRadius: 12,
|
||||
background: c.bg, border: `1px solid ${c.border}`,
|
||||
cursor: "pointer", width: "100%", textAlign: "left",
|
||||
transition: "all 0.18s",
|
||||
}}
|
||||
onMouseEnter={(e) => { e.currentTarget.style.transform = "scale(1.01)"; e.currentTarget.style.boxShadow = "0 4px 12px rgba(0,0,0,0.15)"; }}
|
||||
onMouseLeave={(e) => { e.currentTarget.style.transform = "scale(1)"; e.currentTarget.style.boxShadow = "none"; }}
|
||||
>
|
||||
<span style={{ width: 9, height: 9, borderRadius: "50%", background: c.dot, flexShrink: 0 }} />
|
||||
<span style={{
|
||||
fontSize: 14, fontWeight: 700, color: t.text,
|
||||
fontFamily: "'JetBrains Mono', monospace", minWidth: 80,
|
||||
}}>
|
||||
{d.device}
|
||||
</span>
|
||||
{driveTypeBadge(d.drive_type, t)}
|
||||
<span style={{
|
||||
fontSize: 13, color: t.text, flex: 1,
|
||||
overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap",
|
||||
}}>
|
||||
{d.model || "\u2014"}
|
||||
</span>
|
||||
<span style={{
|
||||
fontSize: 12, color: t.textSecondary,
|
||||
fontFamily: "'JetBrains Mono', monospace",
|
||||
}}>
|
||||
{formatCapacity(d.capacity_bytes)}
|
||||
</span>
|
||||
{d.temperature_c != null && (
|
||||
<span style={{
|
||||
fontSize: 12, fontWeight: 600,
|
||||
color: d.temperature_c >= 40 ? t.health.warning.text : t.text,
|
||||
}}>
|
||||
{d.temperature_c}°C
|
||||
</span>
|
||||
)}
|
||||
{d.zfs_pool && (
|
||||
<span style={{
|
||||
fontSize: 11, fontWeight: 700, color: t.accent,
|
||||
fontFamily: "'JetBrains Mono', monospace",
|
||||
}}>
|
||||
{d.zfs_pool}
|
||||
</span>
|
||||
)}
|
||||
<StatusPill status={healthStatus} t={t} />
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function EnclosureCard({ enclosure, view, onSelect, selectedSerial, t }) {
|
||||
return (
|
||||
<div style={{
|
||||
@@ -762,6 +863,13 @@ export default function App() {
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Host Drives */}
|
||||
{data.host_drives && data.host_drives.length > 0 && (
|
||||
<div style={{ marginTop: 20 }}>
|
||||
<HostDrivesCard drives={data.host_drives} onSelect={setSelected} t={t} />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user