diff --git a/ui/src/layout/ActivityPanel.jsx b/ui/src/layout/ActivityPanel.jsx index 806c49d8..6b50cee0 100644 --- a/ui/src/layout/ActivityPanel.jsx +++ b/ui/src/layout/ActivityPanel.jsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { useSelector } from 'react-redux' import { useNotify, useTranslate } from 'react-admin' import { Popover, @@ -15,11 +15,11 @@ import { Typography, } from '@material-ui/core' import { FiActivity } from 'react-icons/fi' -import { BiError, BiCheckCircle } from 'react-icons/bi' +import { BiError } from 'react-icons/bi' import { VscSync } from 'react-icons/vsc' import { GiMagnifyingGlass } from 'react-icons/gi' import subsonic from '../subsonic' -import { scanStatusUpdate } from '../actions' +import { useInitialScanStatus } from './useInitialScanStatus' import { useInterval } from '../common' import { useScanElapsedTime } from './useScanElapsedTime' import { formatDuration, formatShortDuration } from '../utils' @@ -80,24 +80,12 @@ const ActivityPanel = () => { const notify = useNotify() const [anchorEl, setAnchorEl] = useState(null) const open = Boolean(anchorEl) - const dispatch = useDispatch() + useInitialScanStatus() const handleMenuOpen = (event) => setAnchorEl(event.currentTarget) const handleMenuClose = () => setAnchorEl(null) const triggerScan = (full) => () => subsonic.startScan({ fullScan: full }) - // Get updated status on component mount - useEffect(() => { - subsonic - .getScanStatus() - .then((resp) => resp.json['subsonic-response']) - .then((data) => { - if (data.status === 'ok') { - dispatch(scanStatusUpdate(data.scanStatus)) - } - }) - }, [dispatch]) - useEffect(() => { if (serverStart.version && serverStart.version !== config.version) { notify('ra.notification.new_version', 'info', {}, false, 604800000 * 50) diff --git a/ui/src/layout/useInitialScanStatus.jsx b/ui/src/layout/useInitialScanStatus.jsx new file mode 100644 index 00000000..913f68e4 --- /dev/null +++ b/ui/src/layout/useInitialScanStatus.jsx @@ -0,0 +1,18 @@ +import { useEffect } from 'react' +import { useDispatch } from 'react-redux' +import subsonic from '../subsonic' +import { scanStatusUpdate } from '../actions' + +export const useInitialScanStatus = () => { + const dispatch = useDispatch() + useEffect(() => { + subsonic + .getScanStatus() + .then((resp) => resp.json['subsonic-response']) + .then((data) => { + if (data.status === 'ok') { + dispatch(scanStatusUpdate(data.scanStatus)) + } + }) + }, [dispatch]) +} diff --git a/ui/src/layout/useScanElapsedTime.jsx b/ui/src/layout/useScanElapsedTime.jsx index c501ba50..af084a12 100644 --- a/ui/src/layout/useScanElapsedTime.jsx +++ b/ui/src/layout/useScanElapsedTime.jsx @@ -6,16 +6,17 @@ export const useScanElapsedTime = (scanning, elapsedTime) => { const prevScanningRef = useRef(scanning) useEffect(() => { - // Only update from server when scan starts or stops const prevScanning = prevScanningRef.current - if (!prevScanning && scanning) { - // Scan just started - initialize with server value - setElapsed(Number(elapsedTime) || 0) - } else if (prevScanning && !scanning) { - // Scan just finished - use final server value - setElapsed(Number(elapsedTime) || 0) + const serverElapsed = Number(elapsedTime) || 0 + + if (scanning !== prevScanning) { + // Scan has just started or stopped - sync with server value + setElapsed(serverElapsed) + } else if (!scanning) { + // Not scanning -> always reflect server value (initial load or after finish) + setElapsed(serverElapsed) } - // Update ref for next comparison + prevScanningRef.current = scanning }, [scanning, elapsedTime]) diff --git a/ui/src/layout/useScanElapsedTime.test.jsx b/ui/src/layout/useScanElapsedTime.test.jsx index 96f0eec2..1e948504 100644 --- a/ui/src/layout/useScanElapsedTime.test.jsx +++ b/ui/src/layout/useScanElapsedTime.test.jsx @@ -70,6 +70,20 @@ describe('useScanElapsedTime', () => { expect(result.current).toBe(12e9) }) + it('updates elapsed time when not scanning and server value changes', () => { + const { result, rerender } = renderHook( + ({ scanning, elapsed }) => useScanElapsedTime(scanning, elapsed), + { + initialProps: { scanning: false, elapsed: 0 }, + }, + ) + + // Server reports new elapsed time without changing scanning state + rerender({ scanning: false, elapsed: 8e9 }) + + expect(result.current).toBe(8e9) + }) + it('ignores server updates during scanning', () => { const { result, rerender } = renderHook( ({ scanning, elapsed }) => useScanElapsedTime(scanning, elapsed),