import { useEffect, useMemo, useRef, useState } from 'react'; import { usePerfLiveSnapshot } from '../../../utils/perf/perfLiveStore'; import { syncPerfLiveThreadGroupsNeed, } from '../../../utils/perf/perfLivePollSettings'; import { togglePerfLiveOverlayPin, togglePipelineOverlayPin, usePerfLiveOverlayPins, usePipelineOverlayPinned, type PerfLiveOverlayPinId, } from '../../../utils/perf/perfOverlayPins'; import PerfProbeMetricCard, { PerfProbeMetricSection } from './PerfProbeMetricCard'; import PerfOverlayAppearanceControls from './PerfOverlayAppearanceControls'; import PerfOverlayModeControls from './PerfOverlayModeControls'; import PerfLivePollControls from './PerfLivePollControls'; function memoryBarPct(rssKb: number, maxKb: number): number { if (maxKb <= 0) return 0; return (rssKb / maxKb) * 100; } export default function SidebarPerfProbeMonitorTab() { const live = usePerfLiveSnapshot(); const livePins = usePerfLiveOverlayPins(); const fpsPinned = usePipelineOverlayPinned('pipeline:fps'); const analysisPinned = usePipelineOverlayPinned('pipeline:analysis'); const coverPinned = usePipelineOverlayPinned('pipeline:cover'); const cpu = live.cpu; const collecting = live.collecting && cpu == null; const peakMemoryKbRef = useRef(1); const peakThreadCpuRef = useRef(1); const [threadSectionOpen, setThreadSectionOpen] = useState(false); useEffect(() => { syncPerfLiveThreadGroupsNeed(threadSectionOpen, livePins); }, [threadSectionOpen, livePins]); const maxMemoryKb = useMemo(() => { const current = Math.max(1, ...(cpu?.memory.map(m => m.rss_kb) ?? [1])); if (current > peakMemoryKbRef.current) peakMemoryKbRef.current = current; return peakMemoryKbRef.current; }, [cpu?.memory]); const maxThreadCpu = useMemo(() => { const current = Math.max(1, ...(cpu?.threadCpu.map(t => t.pct) ?? [1])); if (current > peakThreadCpuRef.current) peakThreadCpuRef.current = current; return peakThreadCpuRef.current; }, [cpu?.threadCpu]); if (collecting) { return (