diff --git a/frontend-modern/src/components/Storage/EnhancedStorageBar.tsx b/frontend-modern/src/components/Storage/EnhancedStorageBar.tsx new file mode 100644 index 0000000..4e7e4c5 --- /dev/null +++ b/frontend-modern/src/components/Storage/EnhancedStorageBar.tsx @@ -0,0 +1,146 @@ +import { Show, createMemo, createSignal } from 'solid-js'; +import { Portal } from 'solid-js/web'; +import { formatBytes, formatPercent } from '@/utils/format'; +import type { ZFSPool } from '@/types/api'; + +interface EnhancedStorageBarProps { + used: number; + total: number; + free: number; + zfsPool?: ZFSPool; +} + +export function EnhancedStorageBar(props: EnhancedStorageBarProps) { + const [showTooltip, setShowTooltip] = createSignal(false); + const [tooltipPos, setTooltipPos] = createSignal({ x: 0, y: 0 }); + let containerRef: HTMLDivElement | undefined; + + const usagePercent = createMemo(() => { + if (props.total <= 0) return 0; + return (props.used / props.total) * 100; + }); + + const barColor = createMemo(() => { + const p = usagePercent(); + if (p >= 90) return 'bg-red-500/60 dark:bg-red-500/50'; + if (p >= 80) return 'bg-yellow-500/60 dark:bg-yellow-500/50'; + return 'bg-green-500/60 dark:bg-green-500/50'; + }); + + const isScrubbing = createMemo(() => { + return props.zfsPool?.scan?.toLowerCase().includes('scrub') ?? false; + }); + + const isResilvering = createMemo(() => { + return props.zfsPool?.scan?.toLowerCase().includes('resilver') ?? false; + }); + + const hasErrors = createMemo(() => { + if (!props.zfsPool) return false; + return ( + props.zfsPool.readErrors > 0 || + props.zfsPool.writeErrors > 0 || + props.zfsPool.checksumErrors > 0 + ); + }); + + const handleMouseEnter = (e: MouseEvent) => { + const rect = (e.currentTarget as HTMLElement).getBoundingClientRect(); + setTooltipPos({ x: rect.left + rect.width / 2, y: rect.top }); + setShowTooltip(true); + }; + + const handleMouseLeave = () => { + setShowTooltip(false); + }; + + return ( +