diff --git a/src/hooks/useHashrateHistory.ts b/src/hooks/useHashrateHistory.ts index a44060b..5bd6a91 100644 --- a/src/hooks/useHashrateHistory.ts +++ b/src/hooks/useHashrateHistory.ts @@ -18,41 +18,40 @@ const SAMPLE_INTERVAL_MS = 5000; // Sample every 5 seconds */ export function useHashrateHistory(currentHashrate: number | undefined): HashrateDataPoint[] { const [history, setHistory] = useState([]); - const lastSampleTime = useRef(0); + const hashrateRef = useRef(currentHashrate); + // Keep ref in sync with latest value without triggering the interval effect useEffect(() => { - if (currentHashrate === undefined || currentHashrate === null) return; + hashrateRef.current = currentHashrate; + }, [currentHashrate]); - const now = Date.now(); - - // Only add a new sample if enough time has passed - if (now - lastSampleTime.current < SAMPLE_INTERVAL_MS) return; - - lastSampleTime.current = now; - - const timeStr = new Date(now).toLocaleTimeString('en-US', { - hour: '2-digit', - minute: '2-digit', - hour12: false, - }); + // Sample on a fixed interval regardless of whether the value changed. + // Previously this used useEffect([currentHashrate]) which only fired on + // value changes — meaning a constant hashrate (including 0) would never + // accumulate more than one data point and the chart would stay blank. + useEffect(() => { + function sample() { + const value = hashrateRef.current; + if (value === undefined || value === null) return; - setHistory(prev => { - const newPoint: HashrateDataPoint = { - time: timeStr, - timestamp: now, - hashrate: currentHashrate, - }; - - const updated = [...prev, newPoint]; - - // Keep only the last MAX_HISTORY_POINTS - if (updated.length > MAX_HISTORY_POINTS) { - return updated.slice(-MAX_HISTORY_POINTS); - } - - return updated; - }); - }, [currentHashrate]); + const now = Date.now(); + const timeStr = new Date(now).toLocaleTimeString('en-US', { + hour: '2-digit', + minute: '2-digit', + hour12: false, + }); + + setHistory(prev => { + const newPoint: HashrateDataPoint = { time: timeStr, timestamp: now, hashrate: value }; + const updated = [...prev, newPoint]; + return updated.length > MAX_HISTORY_POINTS ? updated.slice(-MAX_HISTORY_POINTS) : updated; + }); + } + + sample(); // Capture initial value immediately + const id = setInterval(sample, SAMPLE_INTERVAL_MS); + return () => clearInterval(id); + }, []); // Run once on mount return history; } diff --git a/src/pages/Settings.tsx b/src/pages/Settings.tsx index 8374562..237328c 100644 --- a/src/pages/Settings.tsx +++ b/src/pages/Settings.tsx @@ -83,11 +83,6 @@ export function Settings({ appMode = 'translator' }: SettingsProps) { View connection status, endpoints, and API documentation.

-
- -
diff --git a/src/pages/UnifiedDashboard.tsx b/src/pages/UnifiedDashboard.tsx index c2cf8dd..5767b69 100644 --- a/src/pages/UnifiedDashboard.tsx +++ b/src/pages/UnifiedDashboard.tsx @@ -1,5 +1,5 @@ import { useState, useMemo } from 'react'; -import { AlertTriangle, Search, RefreshCw } from 'lucide-react'; +import { AlertTriangle, Search } from 'lucide-react'; import { Shell } from '@/components/layout/Shell'; import { StatCard } from '@/components/data/StatCard'; import { HashrateChart } from '@/components/data/HashrateChart'; @@ -50,7 +50,6 @@ export function UnifiedDashboard() { const { data: sv1Data, isLoading: sv1Loading, - refetch: refetchSv1, } = useSv1ClientsData(0, 1000); // Fetch all for client-side filtering const { @@ -86,12 +85,26 @@ export function UnifiedDashboard() { return allClients.reduce((sum, c) => sum + (c.hashrate || 0), 0); }, [allClients]); - // Total hashrate: - // - JD mode: from SV2 client channels (poolGlobal.sv2_clients.total_hashrate) - // - Translator-only mode: from SV1 clients (poolGlobal.sv1_clients.total_hashrate or calculated) - const totalHashrate = isJdMode - ? (poolGlobal?.sv2_clients?.total_hashrate || 0) - : (poolGlobal?.sv1_clients?.total_hashrate || sv1TotalHashrate); + // Sum nominal hashrates from downstream client channels (JD mode fallback) + const clientChannelHashrate = useMemo(() => { + if (!clientChannels) return undefined; + const ext = clientChannels.extended_channels.reduce((sum, ch) => sum + (ch.nominal_hashrate || 0), 0); + const std = clientChannels.standard_channels.reduce((sum, ch) => sum + (ch.nominal_hashrate || 0), 0); + return ext + std; + }, [clientChannels]); + + // Total hashrate, with multiple fallback sources: + // - JD mode: sv2_clients summary → client channel nominal hashrates + // - Translator-only mode: sv1_clients summary → individual client sum → server reported total + // Use nullish coalescing so an explicit 0 hashrate is preserved. + const totalHashrate = isJdMode + ? (poolGlobal?.sv2_clients?.total_hashrate ?? clientChannelHashrate ?? 0) + : ( + poolGlobal?.sv1_clients?.total_hashrate + ?? (sv1Data ? sv1TotalHashrate : undefined) + ?? poolGlobal?.server?.total_hashrate + ?? 0 + ); const totalClientChannels = isJdMode ? (poolGlobal?.sv2_clients?.total_channels || 0) @@ -281,15 +294,6 @@ export function UnifiedDashboard() { -
- -
)}